From 1ad06b82a68642844bf3f46b39891abfd6d54168 Mon Sep 17 00:00:00 2001 From: Belal Elsabbagh Date: Sun, 15 Mar 2026 13:56:00 +0200 Subject: [PATCH] quickshell and hyprland additions --- .config/btop/themes/caelestia.theme | 83 + .config/hypr/hyprland.conf | 46 +- .config/hypr/hyprpaper.conf | 2 +- .config/hypr/scheme/current.conf | 110 ++ .config/hypr/start.sh | 3 +- .config/quickshell/caelestia/.clang-format | 25 + .config/quickshell/caelestia/.envrc | 15 + .../caelestia/.github/CONTRIBUTING.md | 21 + .../quickshell/caelestia/.github/FUNDING.yml | 15 + .../.github/ISSUE_TEMPLATE/config.yml | 1 + .../.github/ISSUE_TEMPLATE/feature.yml | 24 + .../.github/ISSUE_TEMPLATE/issue.yml | 56 + .../caelestia/.github/workflows/release.yml | 37 + .../.github/workflows/update-flake-inputs.yml | 85 ++ .config/quickshell/caelestia/.gitignore | 6 + .../caelestia/.vscode/settings.json | 6 + .config/quickshell/caelestia/CMakeLists.txt | 67 + .config/quickshell/caelestia/LICENSE | 674 ++++++++ .config/quickshell/caelestia/README.md | 763 ++++++++++ .../quickshell/caelestia/assets/bongocat.gif | Bin 0 -> 7350 bytes .config/quickshell/caelestia/assets/dino.png | Bin 0 -> 9441 bytes .../quickshell/caelestia/assets/kurukuru.gif | Bin 0 -> 99006 bytes .config/quickshell/caelestia/assets/logo.svg | 79 + .../quickshell/caelestia/assets/pam.d/fprint | 3 + .../quickshell/caelestia/assets/pam.d/passwd | 6 + .../caelestia/assets/shaders/opacitymask.frag | 19 + .../assets/shaders/opacitymask.frag.qsb | Bin 0 -> 1337 bytes .../caelestia/assets/wrap_term_launch.sh | 5 + .../quickshell/caelestia/components/Anim.qml | 8 + .../quickshell/caelestia/components/CAnim.qml | 8 + .../caelestia/components/ConnectionHeader.qml | 31 + .../components/ConnectionInfoSection.qml | 59 + .../quickshell/caelestia/components/Logo.qml | 69 + .../caelestia/components/MaterialIcon.qml | 16 + .../caelestia/components/PropertyRow.qml | 26 + .../caelestia/components/SectionContainer.qml | 32 + .../caelestia/components/SectionHeader.qml | 27 + .../caelestia/components/StateLayer.qml | 95 ++ .../components/StyledClippingRect.qml | 12 + .../caelestia/components/StyledRect.qml | 11 + .../caelestia/components/StyledText.qml | 48 + .../components/containers/StyledFlickable.qml | 14 + .../components/containers/StyledListView.qml | 14 + .../components/containers/StyledWindow.qml | 9 + .../components/controls/CircularIndicator.qml | 108 ++ .../components/controls/CircularProgress.qml | 69 + .../controls/CollapsibleSection.qml | 132 ++ .../components/controls/CustomMouseArea.qml | 21 + .../components/controls/CustomSpinBox.qml | 170 +++ .../components/controls/FilledSlider.qml | 146 ++ .../components/controls/IconButton.qml | 83 + .../components/controls/IconTextButton.qml | 88 ++ .../caelestia/components/controls/Menu.qml | 113 ++ .../components/controls/MenuItem.qml | 11 + .../components/controls/SpinBoxRow.qml | 52 + .../components/controls/SplitButton.qml | 164 ++ .../components/controls/SplitButtonRow.qml | 62 + .../components/controls/StyledInputField.qml | 79 + .../components/controls/StyledRadioButton.qml | 57 + .../components/controls/StyledScrollBar.qml | 190 +++ .../components/controls/StyledSlider.qml | 57 + .../components/controls/StyledSwitch.qml | 152 ++ .../components/controls/StyledTextField.qml | 76 + .../components/controls/SwitchRow.qml | 48 + .../components/controls/TextButton.qml | 78 + .../components/controls/ToggleButton.qml | 124 ++ .../components/controls/ToggleRow.qml | 28 + .../caelestia/components/controls/Tooltip.qml | 185 +++ .../components/effects/ColouredIcon.qml | 35 + .../components/effects/Colouriser.qml | 14 + .../components/effects/Elevation.qml | 18 + .../components/effects/InnerBorder.qml | 44 + .../components/effects/OpacityMask.qml | 9 + .../components/filedialog/CurrentItem.qml | 102 ++ .../components/filedialog/DialogButtons.qml | 93 ++ .../components/filedialog/FileDialog.qml | 102 ++ .../components/filedialog/FolderContents.qml | 228 +++ .../components/filedialog/HeaderBar.qml | 139 ++ .../components/filedialog/Sidebar.qml | 113 ++ .../caelestia/components/filedialog/Sizes.qml | 8 + .../components/images/CachingIconImage.qml | 42 + .../components/images/CachingImage.qml | 28 + .../components/misc/CustomShortcut.qml | 5 + .../caelestia/components/misc/Ref.qml | 8 + .../components/widgets/ExtraIndicator.qml | 51 + .../caelestia/config/Appearance.qml | 14 + .../caelestia/config/AppearanceConfig.qml | 94 ++ .../caelestia/config/BackgroundConfig.qml | 37 + .../quickshell/caelestia/config/BarConfig.qml | 118 ++ .../caelestia/config/BorderConfig.qml | 6 + .../quickshell/caelestia/config/Config.qml | 522 +++++++ .../caelestia/config/ControlCenterConfig.qml | 10 + .../caelestia/config/DashboardConfig.qml | 36 + .../caelestia/config/GeneralConfig.qml | 60 + .../caelestia/config/LauncherConfig.qml | 147 ++ .../caelestia/config/LockConfig.qml | 14 + .../caelestia/config/NotifsConfig.qml | 18 + .../quickshell/caelestia/config/OsdConfig.qml | 14 + .../caelestia/config/ServiceConfig.qml | 22 + .../caelestia/config/SessionConfig.qml | 29 + .../caelestia/config/SidebarConfig.qml | 11 + .../quickshell/caelestia/config/UserPaths.qml | 8 + .../caelestia/config/UtilitiesConfig.qml | 35 + .../caelestia/config/WInfoConfig.qml | 10 + .../caelestia/extras/CMakeLists.txt | 9 + .../quickshell/caelestia/extras/version.cpp | 26 + .config/quickshell/caelestia/flake.lock | 70 + .config/quickshell/caelestia/flake.nix | 60 + .../caelestia/modules/BatteryMonitor.qml | 56 + .../caelestia/modules/IdleMonitors.qml | 51 + .../caelestia/modules/Shortcuts.qml | 142 ++ .../modules/areapicker/AreaPicker.qml | 124 ++ .../caelestia/modules/areapicker/Picker.qml | 300 ++++ .../modules/background/Background.qml | 153 ++ .../modules/background/DesktopClock.qml | 169 +++ .../modules/background/Visualiser.qml | 151 ++ .../modules/background/Wallpaper.qml | 145 ++ .../quickshell/caelestia/modules/bar/Bar.qml | 205 +++ .../caelestia/modules/bar/BarWrapper.qml | 87 ++ .../modules/bar/components/ActiveWindow.qml | 100 ++ .../modules/bar/components/Clock.qml | 38 + .../modules/bar/components/OsIcon.qml | 46 + .../modules/bar/components/Power.qml | 40 + .../modules/bar/components/Settings.qml | 41 + .../modules/bar/components/SettingsIcon.qml | 41 + .../modules/bar/components/StatusIcons.qml | 270 ++++ .../caelestia/modules/bar/components/Tray.qml | 121 ++ .../modules/bar/components/TrayItem.qml | 34 + .../components/workspaces/ActiveIndicator.qml | 98 ++ .../bar/components/workspaces/OccupiedBg.qml | 103 ++ .../workspaces/SpecialWorkspaces.qml | 359 +++++ .../bar/components/workspaces/Workspace.qml | 107 ++ .../bar/components/workspaces/Workspaces.qml | 137 ++ .../modules/bar/popouts/ActiveWindow.qml | 102 ++ .../caelestia/modules/bar/popouts/Audio.qml | 120 ++ .../modules/bar/popouts/Background.qml | 73 + .../caelestia/modules/bar/popouts/Battery.qml | 230 +++ .../modules/bar/popouts/Bluetooth.qml | 197 +++ .../caelestia/modules/bar/popouts/Content.qml | 222 +++ .../modules/bar/popouts/LockStatus.qml | 16 + .../caelestia/modules/bar/popouts/Network.qml | 388 +++++ .../modules/bar/popouts/TrayMenu.qml | 225 +++ .../modules/bar/popouts/WirelessPassword.qml | 605 ++++++++ .../caelestia/modules/bar/popouts/Wrapper.qml | 215 +++ .../modules/bar/popouts/kblayout/KbLayout.qml | 211 +++ .../bar/popouts/kblayout/KbLayoutModel.qml | 216 +++ .../modules/controlcenter/ControlCenter.qml | 100 ++ .../modules/controlcenter/NavRail.qml | 231 +++ .../modules/controlcenter/PaneRegistry.qml | 92 ++ .../caelestia/modules/controlcenter/Panes.qml | 175 +++ .../modules/controlcenter/Session.qml | 23 + .../modules/controlcenter/WindowFactory.qml | 62 + .../modules/controlcenter/WindowTitle.qml | 51 + .../appearance/AppearancePane.qml | 254 ++++ .../appearance/sections/AnimationsSection.qml | 44 + .../appearance/sections/BackgroundSection.qml | 345 +++++ .../appearance/sections/BorderSection.qml | 68 + .../sections/ColorSchemeSection.qml | 145 ++ .../sections/ColorVariantSection.qml | 91 ++ .../appearance/sections/FontsSection.qml | 282 ++++ .../appearance/sections/ScalesSection.qml | 92 ++ .../appearance/sections/ThemeModeSection.qml | 23 + .../sections/TransparencySection.qml | 79 + .../modules/controlcenter/audio/AudioPane.qml | 621 ++++++++ .../controlcenter/bluetooth/BtPane.qml | 73 + .../controlcenter/bluetooth/Details.qml | 671 ++++++++ .../controlcenter/bluetooth/DeviceList.qml | 264 ++++ .../controlcenter/bluetooth/Settings.qml | 532 +++++++ .../components/ConnectedButtonGroup.qml | 108 ++ .../components/DeviceDetails.qml | 70 + .../controlcenter/components/DeviceList.qml | 84 + .../components/PaneTransition.qml | 71 + .../components/ReadonlySlider.qml | 67 + .../components/SettingsHeader.qml | 37 + .../controlcenter/components/SliderInput.qml | 180 +++ .../components/SplitPaneLayout.qml | 109 ++ .../components/SplitPaneWithDetails.qml | 93 ++ .../components/WallpaperGrid.qml | 233 +++ .../controlcenter/dashboard/DashboardPane.qml | 123 ++ .../dashboard/GeneralSection.qml | 81 + .../dashboard/PerformanceSection.qml | 85 ++ .../controlcenter/launcher/LauncherPane.qml | 658 ++++++++ .../controlcenter/launcher/Settings.qml | 217 +++ .../controlcenter/network/EthernetDetails.qml | 118 ++ .../controlcenter/network/EthernetList.qml | 177 +++ .../controlcenter/network/EthernetPane.qml | 50 + .../network/EthernetSettings.qml | 76 + .../controlcenter/network/NetworkSettings.qml | 171 +++ .../controlcenter/network/NetworkingPane.qml | 373 +++++ .../controlcenter/network/VpnDetails.qml | 396 +++++ .../modules/controlcenter/network/VpnList.qml | 686 +++++++++ .../controlcenter/network/VpnSettings.qml | 232 +++ .../controlcenter/network/WirelessDetails.qml | 211 +++ .../controlcenter/network/WirelessList.qml | 228 +++ .../controlcenter/network/WirelessPane.qml | 57 + .../network/WirelessPasswordDialog.qml | 511 +++++++ .../network/WirelessSettings.qml | 73 + .../controlcenter/state/BluetoothState.qml | 12 + .../controlcenter/state/EthernetState.qml | 7 + .../controlcenter/state/LauncherState.qml | 7 + .../controlcenter/state/NetworkState.qml | 9 + .../modules/controlcenter/state/VpnState.qml | 5 + .../controlcenter/taskbar/TaskbarPane.qml | 648 ++++++++ .../modules/dashboard/Background.qml | 66 + .../caelestia/modules/dashboard/Content.qml | 152 ++ .../caelestia/modules/dashboard/Dash.qml | 105 ++ .../caelestia/modules/dashboard/Media.qml | 403 +++++ .../modules/dashboard/Performance.qml | 967 ++++++++++++ .../caelestia/modules/dashboard/Tabs.qml | 247 +++ .../caelestia/modules/dashboard/Weather.qml | 280 ++++ .../caelestia/modules/dashboard/Wrapper.qml | 105 ++ .../modules/dashboard/dash/Calendar.qml | 253 +++ .../modules/dashboard/dash/DateTime.qml | 65 + .../modules/dashboard/dash/Media.qml | 254 ++++ .../modules/dashboard/dash/Resources.qml | 87 ++ .../caelestia/modules/dashboard/dash/User.qml | 195 +++ .../modules/dashboard/dash/Weather.qml | 57 + .../caelestia/modules/drawers/Backgrounds.qml | 86 ++ .../caelestia/modules/drawers/Border.qml | 44 + .../caelestia/modules/drawers/Drawers.qml | 181 +++ .../caelestia/modules/drawers/Exclusions.qml | 39 + .../modules/drawers/Interactions.qml | 274 ++++ .../caelestia/modules/drawers/Panels.qml | 136 ++ .../caelestia/modules/launcher/AppList.qml | 257 ++++ .../caelestia/modules/launcher/Background.qml | 60 + .../caelestia/modules/launcher/Content.qml | 191 +++ .../modules/launcher/ContentList.qml | 170 +++ .../modules/launcher/WallpaperList.qml | 97 ++ .../caelestia/modules/launcher/Wrapper.qml | 130 ++ .../modules/launcher/items/ActionItem.qml | 70 + .../modules/launcher/items/AppItem.qml | 88 ++ .../modules/launcher/items/CalcItem.qml | 123 ++ .../modules/launcher/items/SchemeItem.qml | 104 ++ .../modules/launcher/items/VariantItem.qml | 80 + .../modules/launcher/items/WallpaperItem.qml | 98 ++ .../modules/launcher/services/Actions.qml | 52 + .../modules/launcher/services/Apps.qml | 78 + .../modules/launcher/services/M3Variants.qml | 85 ++ .../modules/launcher/services/Schemes.qml | 88 ++ .../caelestia/modules/lock/Center.qml | 416 +++++ .../caelestia/modules/lock/Content.qml | 93 ++ .../caelestia/modules/lock/Fetch.qml | 178 +++ .../caelestia/modules/lock/InputField.qml | 149 ++ .../caelestia/modules/lock/Lock.qml | 55 + .../caelestia/modules/lock/LockSurface.qml | 230 +++ .../caelestia/modules/lock/Media.qml | 208 +++ .../caelestia/modules/lock/NotifDock.qml | 145 ++ .../caelestia/modules/lock/NotifGroup.qml | 316 ++++ .../quickshell/caelestia/modules/lock/Pam.qml | 193 +++ .../caelestia/modules/lock/Resources.qml | 93 ++ .../caelestia/modules/lock/WeatherInfo.qml | 176 +++ .../modules/notifications/Background.qml | 54 + .../modules/notifications/Content.qml | 204 +++ .../modules/notifications/Notification.qml | 480 ++++++ .../modules/notifications/Wrapper.qml | 39 + .../caelestia/modules/osd/Background.qml | 60 + .../caelestia/modules/osd/Content.qml | 127 ++ .../caelestia/modules/osd/Wrapper.qml | 134 ++ .../caelestia/modules/session/Background.qml | 60 + .../caelestia/modules/session/Content.qml | 135 ++ .../caelestia/modules/session/Wrapper.qml | 63 + .../caelestia/modules/sidebar/Background.qml | 52 + .../caelestia/modules/sidebar/Content.qml | 40 + .../caelestia/modules/sidebar/Notif.qml | 164 ++ .../modules/sidebar/NotifActionList.qml | 200 +++ .../caelestia/modules/sidebar/NotifDock.qml | 207 +++ .../modules/sidebar/NotifDockList.qml | 167 ++ .../caelestia/modules/sidebar/NotifGroup.qml | 241 +++ .../modules/sidebar/NotifGroupList.qml | 213 +++ .../caelestia/modules/sidebar/Props.qml | 7 + .../caelestia/modules/sidebar/Wrapper.qml | 68 + .../modules/utilities/Background.qml | 55 + .../caelestia/modules/utilities/Content.qml | 39 + .../utilities/RecordingDeleteModal.qml | 207 +++ .../caelestia/modules/utilities/Wrapper.qml | 96 ++ .../modules/utilities/cards/IdleInhibit.qml | 125 ++ .../modules/utilities/cards/Record.qml | 277 ++++ .../modules/utilities/cards/RecordingList.qml | 241 +++ .../modules/utilities/cards/Toggles.qml | 113 ++ .../modules/utilities/toasts/ToastItem.qml | 135 ++ .../modules/utilities/toasts/Toasts.qml | 143 ++ .../caelestia/modules/windowinfo/Buttons.qml | 180 +++ .../caelestia/modules/windowinfo/Details.qml | 164 ++ .../caelestia/modules/windowinfo/Preview.qml | 96 ++ .../modules/windowinfo/WindowInfo.qml | 64 + .config/quickshell/caelestia/nix/app2unit.nix | 14 + .config/quickshell/caelestia/nix/default.nix | 158 ++ .../quickshell/caelestia/nix/hm-module.nix | 136 ++ .../caelestia/plugin/CMakeLists.txt | 1 + .../plugin/src/Caelestia/CMakeLists.txt | 62 + .../src/Caelestia/Internal/CMakeLists.txt | 15 + .../Internal/cachingimagemanager.cpp | 223 +++ .../Internal/cachingimagemanager.hpp | 65 + .../Internal/circularindicatormanager.cpp | 211 +++ .../Internal/circularindicatormanager.hpp | 72 + .../src/Caelestia/Internal/hyprdevices.cpp | 134 ++ .../src/Caelestia/Internal/hyprdevices.hpp | 74 + .../src/Caelestia/Internal/hyprextras.cpp | 217 +++ .../src/Caelestia/Internal/hyprextras.hpp | 56 + .../src/Caelestia/Internal/logindmanager.cpp | 65 + .../src/Caelestia/Internal/logindmanager.hpp | 27 + .../src/Caelestia/Models/CMakeLists.txt | 8 + .../src/Caelestia/Models/filesystemmodel.cpp | 479 ++++++ .../src/Caelestia/Models/filesystemmodel.hpp | 148 ++ .../src/Caelestia/Services/CMakeLists.txt | 14 + .../src/Caelestia/Services/audiocollector.cpp | 246 +++ .../src/Caelestia/Services/audiocollector.hpp | 76 + .../src/Caelestia/Services/audioprovider.cpp | 78 + .../src/Caelestia/Services/audioprovider.hpp | 48 + .../src/Caelestia/Services/beattracker.cpp | 58 + .../src/Caelestia/Services/beattracker.hpp | 49 + .../src/Caelestia/Services/cavaprovider.cpp | 140 ++ .../src/Caelestia/Services/cavaprovider.hpp | 64 + .../plugin/src/Caelestia/Services/service.cpp | 26 + .../plugin/src/Caelestia/Services/service.hpp | 24 + .../src/Caelestia/Services/serviceref.cpp | 36 + .../src/Caelestia/Services/serviceref.hpp | 28 + .../caelestia/plugin/src/Caelestia/appdb.cpp | 312 ++++ .../caelestia/plugin/src/Caelestia/appdb.hpp | 116 ++ .../caelestia/plugin/src/Caelestia/cutils.cpp | 131 ++ .../caelestia/plugin/src/Caelestia/cutils.hpp | 29 + .../plugin/src/Caelestia/imageanalyser.cpp | 223 +++ .../plugin/src/Caelestia/imageanalyser.hpp | 61 + .../plugin/src/Caelestia/qalculator.cpp | 52 + .../plugin/src/Caelestia/qalculator.hpp | 19 + .../plugin/src/Caelestia/requests.cpp | 35 + .../plugin/src/Caelestia/requests.hpp | 23 + .../plugin/src/Caelestia/toaster.cpp | 116 ++ .../plugin/src/Caelestia/toaster.hpp | 82 + .../quickshell/caelestia/services/Audio.qml | 157 ++ .../caelestia/services/Brightness.qml | 226 +++ .../quickshell/caelestia/services/Colours.qml | 237 +++ .../caelestia/services/GameMode.qml | 76 + .../quickshell/caelestia/services/Hypr.qml | 213 +++ .../caelestia/services/IdleInhibitor.qml | 56 + .../quickshell/caelestia/services/Network.qml | 324 ++++ .../caelestia/services/NetworkUsage.qml | 233 +++ .../quickshell/caelestia/services/Nmcli.qml | 1352 +++++++++++++++++ .../quickshell/caelestia/services/Notifs.qml | 338 +++++ .../quickshell/caelestia/services/Players.qml | 126 ++ .../caelestia/services/Recorder.qml | 82 + .../caelestia/services/SystemUsage.qml | 342 +++++ .../quickshell/caelestia/services/Time.qml | 28 + .config/quickshell/caelestia/services/VPN.qml | 179 +++ .../caelestia/services/Visibilities.qml | 16 + .../caelestia/services/Wallpapers.qml | 93 ++ .../quickshell/caelestia/services/Weather.qml | 206 +++ .config/quickshell/caelestia/shell.qml | 25 + .config/quickshell/caelestia/utils/Icons.qml | 221 +++ .config/quickshell/caelestia/utils/Images.qml | 12 + .../caelestia/utils/NetworkConnection.qml | 116 ++ .config/quickshell/caelestia/utils/Paths.qml | 37 + .../quickshell/caelestia/utils/Searcher.qml | 56 + .../quickshell/caelestia/utils/Strings.qml | 20 + .../quickshell/caelestia/utils/SysInfo.qml | 88 ++ .../caelestia/utils/scripts/fuzzysort.js | 705 +++++++++ .../quickshell/caelestia/utils/scripts/fzf.js | 1307 ++++++++++++++++ .../quickshell/nucleus-shell/CMakeLists.txt | 24 + .../nucleus-shell/assets/gifs/bongo-cat.gif | Bin 0 -> 23125 bytes .../nucleus-shell/config/Appearance.qml | 262 ++++ .../nucleus-shell/config/Config.qml | 282 ++++ .../nucleus-shell/config/Directories.qml | 39 + .../nucleus-shell/config/Globals.qml | 23 + .../quickshell/nucleus-shell/config/Ipc.qml | 97 ++ .../nucleus-shell/config/MaterialColors.qml | 89 ++ .../nucleus-shell/config/Metrics.qml | 133 ++ .../nucleus-shell/defaults/default.jpg | Bin 0 -> 2148034 bytes .../nucleus-shell/extras/matugen/config.toml | 6 + .../extras/matugen/templates/colors.json | 6 + .../components/CircularProgressBar.qml | 57 + .../modules/components/ContentCard.qml | 38 + .../modules/components/ContentMenu.qml | 101 ++ .../modules/components/ContentRowCard.qml | 51 + .../modules/components/InfoCard.qml | 58 + .../modules/components/LoadingIcon.qml | 26 + .../modules/components/MaterialSymbol.qml | 15 + .../components/MaterialSymbolButton.qml | 56 + .../modules/components/NumberStepper.qml | 88 ++ .../modules/components/StyledButton.qml | 185 +++ .../modules/components/StyledDropDown.qml | 196 +++ .../modules/components/StyledImage.qml | 13 + .../modules/components/StyledPopout.qml | 327 ++++ .../modules/components/StyledRect.qml | 15 + .../modules/components/StyledSlider.qml | 118 ++ .../modules/components/StyledSwitch.qml | 138 ++ .../modules/components/StyledSwitchOption.qml | 37 + .../modules/components/StyledText.qml | 54 + .../modules/components/StyledTextField.qml | 195 +++ .../nucleus-shell/modules/components/Tint.qml | 22 + .../morphedPolygons/MorphedPolygon.qml | 103 ++ .../morphedPolygons/geometry/offset.js | 177 +++ .../morphedPolygons/graphics/matrix.js | 198 +++ .../morphedPolygons/material-shapes.js | 712 +++++++++ .../morphedPolygons/shapes/corner-rounding.js | 18 + .../morphedPolygons/shapes/cubic.js | 371 +++++ .../morphedPolygons/shapes/feature-mapping.js | 166 ++ .../morphedPolygons/shapes/feature.js | 103 ++ .../morphedPolygons/shapes/float-mapping.js | 86 ++ .../morphedPolygons/shapes/morph.js | 94 ++ .../morphedPolygons/shapes/point.js | 154 ++ .../morphedPolygons/shapes/polygon-measure.js | 192 +++ .../morphedPolygons/shapes/rounded-corner.js | 229 +++ .../morphedPolygons/shapes/rounded-polygon.js | 343 +++++ .../morphedPolygons/shapes/utils.js | 94 ++ .../modules/functions/ColorUtils.qml | 70 + .../modules/functions/DisplayMetrics.qml | 15 + .../modules/functions/FileUtils.qml | 106 ++ .../modules/functions/StringUtils.qml | 42 + .../modules/functions/fuzzy/fuzzysort.js | 679 +++++++++ .../interface/background/Background.qml | 267 ++++ .../modules/interface/background/Clock.qml | 287 ++++ .../interface/background/ClockDial.qml | 56 + .../modules/interface/bar/Bar.qml | 163 ++ .../modules/interface/bar/BarContent.qml | 178 +++ .../modules/interface/bar/GothCorners.qml | 82 + .../bar/content/ActiveWindowModule.qml | 136 ++ .../bar/content/BatteryIndicatorModule.qml | 57 + .../interface/bar/content/BongoCat.qml | 27 + .../interface/bar/content/ClockModule.qml | 36 + .../bar/content/MediaPlayerModule.qml | 127 ++ .../bar/content/StatusIconsModule.qml | 65 + .../interface/bar/content/SystemTray.qml | 165 ++ .../bar/content/SystemUsageModule.qml | 99 ++ .../interface/bar/content/ToggleModule.qml | 43 + .../interface/bar/content/WorkspaceModule.qml | 254 ++++ .../interface/intelligence/Intelligence.qml | 576 +++++++ .../modules/interface/launcher/AppItem.qml | 122 ++ .../modules/interface/launcher/Launcher.qml | 170 +++ .../interface/launcher/LauncherContent.qml | 313 ++++ .../interface/lockscreen/LockContext.qml | 56 + .../interface/lockscreen/LockScreen.qml | 41 + .../interface/lockscreen/LockSurface.qml | 267 ++++ .../interface/lockscreen/pam/password.conf | 1 + .../notifications/NotificationChild.qml | 144 ++ .../interface/notifications/Notifications.qml | 154 ++ .../interface/overlays/BrightnessOverlay.qml | 99 ++ .../modules/interface/overlays/Overlays.qml | 8 + .../interface/overlays/VolumeOverlay.qml | 109 ++ .../modules/interface/polkit/PolkitAgent.qml | 207 +++ .../modules/interface/polkit/Prompt.qml | 151 ++ .../modules/interface/powermenu/Powermenu.qml | 153 ++ .../interface/screencapture/ScreenCapture.qml | 606 ++++++++ .../modules/interface/settings/About.qml | 115 ++ .../interface/settings/AppearanceConfig.qml | 364 +++++ .../interface/settings/AudioConfig.qml | 355 +++++ .../modules/interface/settings/BarConfig.qml | 300 ++++ .../interface/settings/BluetoothConfig.qml | 187 +++ .../settings/BluetoothDeviceCard.qml | 90 ++ .../interface/settings/LauncherConfig.qml | 79 + .../modules/interface/settings/MiscConfig.qml | 109 ++ .../interface/settings/NetworkCard.qml | 136 ++ .../interface/settings/NetworkConfig.qml | 172 +++ .../interface/settings/NotificationConfig.qml | 215 +++ .../modules/interface/settings/Plugins.qml | 51 + .../modules/interface/settings/Settings.qml | 201 +++ .../modules/interface/settings/Store.qml | 104 ++ .../interface/settings/WallpaperConfig.qml | 294 ++++ .../sidebarLeft/IntelligencePanel.qml | 525 +++++++ .../interface/sidebarLeft/SidebarLeft.qml | 90 ++ .../sidebarLeft/SidebarLeftContent.qml | 142 ++ .../interface/sidebarLeft/SystemOverview.qml | 486 ++++++ .../interface/sidebarLeft/WallpapersPage.qml | 114 ++ .../interface/sidebarRight/SidebarRight.qml | 97 ++ .../sidebarRight/SidebarRightContent.qml | 247 +++ .../sidebarRight/content/BluetoothToggle.qml | 91 ++ .../sidebarRight/content/BrightnessSlider.qml | 28 + .../sidebarRight/content/FlightModeToggle.qml | 73 + .../interface/sidebarRight/content/Media.qml | 196 +++ .../sidebarRight/content/NetworkToggle.qml | 78 + .../sidebarRight/content/NightModeToggle.qml | 33 + .../sidebarRight/content/NotifModal.qml | 110 ++ .../sidebarRight/content/ThemeToggle.qml | 34 + .../sidebarRight/content/VolumeSlider.qml | 34 + .../nucleus-shell/plugins/PluginHost.qml | 27 + .../nucleus-shell/plugins/PluginLoader.qml | 32 + .../nucleus-shell/plugins/PluginParser.qml | 137 ++ .../plugins/PluginSettingsLoader.qml | 34 + .../scripts/finders/find-apps.sh | 118 ++ .../scripts/interface/changebg.sh | 33 + .../scripts/interface/gencolors.sh | 66 + .../scripts/interface/selectfolder.sh | 24 + .../scripts/interface/switchTheme.sh | 37 + .../nucleus-shell/scripts/plugins/plugins.sh | 242 +++ .../nucleus-shell/scripts/system/reload.sh | 4 + .../nucleus-shell/scripts/system/update.sh | 126 ++ .../nucleus-shell/services/AppRegistry.qml | 168 ++ .../nucleus-shell/services/Apps.qml | 30 + .../nucleus-shell/services/Bluetooth.qml | 24 + .../nucleus-shell/services/Brightness.qml | 142 ++ .../nucleus-shell/services/Compositor.qml | 89 ++ .../nucleus-shell/services/ConfigResolver.qml | 34 + .../nucleus-shell/services/Contracts.qml | 69 + .../nucleus-shell/services/Hyprland.qml | 216 +++ .../nucleus-shell/services/Mpris.qml | 136 ++ .../nucleus-shell/services/Network.qml | 309 ++++ .../nucleus-shell/services/Niri.qml | 242 +++ .../nucleus-shell/services/NotifServer.qml | 110 ++ .../nucleus-shell/services/Polkit.qml | 22 + .../nucleus-shell/services/SystemDetails.qml | 394 +++++ .../nucleus-shell/services/Theme.qml | 54 + .../nucleus-shell/services/Time.qml | 20 + .../nucleus-shell/services/UPower.qml | 136 ++ .../nucleus-shell/services/UpdateNotifier.qml | 100 ++ .../nucleus-shell/services/Volume.qml | 50 + .../services/WallpaperSlideshow.qml | 140 ++ .../nucleus-shell/services/Xrandr.qml | 55 + .../nucleus-shell/services/Zenith.qml | 82 + .config/quickshell/nucleus-shell/shell.qml | 87 ++ .config/quickshell/zenbar/shell.qml | 87 ++ 509 files changed, 68371 insertions(+), 19 deletions(-) create mode 100644 .config/btop/themes/caelestia.theme create mode 100644 .config/hypr/scheme/current.conf create mode 100644 .config/quickshell/caelestia/.clang-format create mode 100644 .config/quickshell/caelestia/.envrc create mode 100644 .config/quickshell/caelestia/.github/CONTRIBUTING.md create mode 100644 .config/quickshell/caelestia/.github/FUNDING.yml create mode 100644 .config/quickshell/caelestia/.github/ISSUE_TEMPLATE/config.yml create mode 100644 .config/quickshell/caelestia/.github/ISSUE_TEMPLATE/feature.yml create mode 100644 .config/quickshell/caelestia/.github/ISSUE_TEMPLATE/issue.yml create mode 100644 .config/quickshell/caelestia/.github/workflows/release.yml create mode 100644 .config/quickshell/caelestia/.github/workflows/update-flake-inputs.yml create mode 100644 .config/quickshell/caelestia/.gitignore create mode 100644 .config/quickshell/caelestia/.vscode/settings.json create mode 100644 .config/quickshell/caelestia/CMakeLists.txt create mode 100644 .config/quickshell/caelestia/LICENSE create mode 100644 .config/quickshell/caelestia/README.md create mode 100644 .config/quickshell/caelestia/assets/bongocat.gif create mode 100644 .config/quickshell/caelestia/assets/dino.png create mode 100644 .config/quickshell/caelestia/assets/kurukuru.gif create mode 100644 .config/quickshell/caelestia/assets/logo.svg create mode 100644 .config/quickshell/caelestia/assets/pam.d/fprint create mode 100644 .config/quickshell/caelestia/assets/pam.d/passwd create mode 100644 .config/quickshell/caelestia/assets/shaders/opacitymask.frag create mode 100644 .config/quickshell/caelestia/assets/shaders/opacitymask.frag.qsb create mode 100755 .config/quickshell/caelestia/assets/wrap_term_launch.sh create mode 100644 .config/quickshell/caelestia/components/Anim.qml create mode 100644 .config/quickshell/caelestia/components/CAnim.qml create mode 100644 .config/quickshell/caelestia/components/ConnectionHeader.qml create mode 100644 .config/quickshell/caelestia/components/ConnectionInfoSection.qml create mode 100644 .config/quickshell/caelestia/components/Logo.qml create mode 100644 .config/quickshell/caelestia/components/MaterialIcon.qml create mode 100644 .config/quickshell/caelestia/components/PropertyRow.qml create mode 100644 .config/quickshell/caelestia/components/SectionContainer.qml create mode 100644 .config/quickshell/caelestia/components/SectionHeader.qml create mode 100644 .config/quickshell/caelestia/components/StateLayer.qml create mode 100644 .config/quickshell/caelestia/components/StyledClippingRect.qml create mode 100644 .config/quickshell/caelestia/components/StyledRect.qml create mode 100644 .config/quickshell/caelestia/components/StyledText.qml create mode 100644 .config/quickshell/caelestia/components/containers/StyledFlickable.qml create mode 100644 .config/quickshell/caelestia/components/containers/StyledListView.qml create mode 100644 .config/quickshell/caelestia/components/containers/StyledWindow.qml create mode 100644 .config/quickshell/caelestia/components/controls/CircularIndicator.qml create mode 100644 .config/quickshell/caelestia/components/controls/CircularProgress.qml create mode 100644 .config/quickshell/caelestia/components/controls/CollapsibleSection.qml create mode 100644 .config/quickshell/caelestia/components/controls/CustomMouseArea.qml create mode 100644 .config/quickshell/caelestia/components/controls/CustomSpinBox.qml create mode 100644 .config/quickshell/caelestia/components/controls/FilledSlider.qml create mode 100644 .config/quickshell/caelestia/components/controls/IconButton.qml create mode 100644 .config/quickshell/caelestia/components/controls/IconTextButton.qml create mode 100644 .config/quickshell/caelestia/components/controls/Menu.qml create mode 100644 .config/quickshell/caelestia/components/controls/MenuItem.qml create mode 100644 .config/quickshell/caelestia/components/controls/SpinBoxRow.qml create mode 100644 .config/quickshell/caelestia/components/controls/SplitButton.qml create mode 100644 .config/quickshell/caelestia/components/controls/SplitButtonRow.qml create mode 100644 .config/quickshell/caelestia/components/controls/StyledInputField.qml create mode 100644 .config/quickshell/caelestia/components/controls/StyledRadioButton.qml create mode 100644 .config/quickshell/caelestia/components/controls/StyledScrollBar.qml create mode 100644 .config/quickshell/caelestia/components/controls/StyledSlider.qml create mode 100644 .config/quickshell/caelestia/components/controls/StyledSwitch.qml create mode 100644 .config/quickshell/caelestia/components/controls/StyledTextField.qml create mode 100644 .config/quickshell/caelestia/components/controls/SwitchRow.qml create mode 100644 .config/quickshell/caelestia/components/controls/TextButton.qml create mode 100644 .config/quickshell/caelestia/components/controls/ToggleButton.qml create mode 100644 .config/quickshell/caelestia/components/controls/ToggleRow.qml create mode 100644 .config/quickshell/caelestia/components/controls/Tooltip.qml create mode 100644 .config/quickshell/caelestia/components/effects/ColouredIcon.qml create mode 100644 .config/quickshell/caelestia/components/effects/Colouriser.qml create mode 100644 .config/quickshell/caelestia/components/effects/Elevation.qml create mode 100644 .config/quickshell/caelestia/components/effects/InnerBorder.qml create mode 100644 .config/quickshell/caelestia/components/effects/OpacityMask.qml create mode 100644 .config/quickshell/caelestia/components/filedialog/CurrentItem.qml create mode 100644 .config/quickshell/caelestia/components/filedialog/DialogButtons.qml create mode 100644 .config/quickshell/caelestia/components/filedialog/FileDialog.qml create mode 100644 .config/quickshell/caelestia/components/filedialog/FolderContents.qml create mode 100644 .config/quickshell/caelestia/components/filedialog/HeaderBar.qml create mode 100644 .config/quickshell/caelestia/components/filedialog/Sidebar.qml create mode 100644 .config/quickshell/caelestia/components/filedialog/Sizes.qml create mode 100644 .config/quickshell/caelestia/components/images/CachingIconImage.qml create mode 100644 .config/quickshell/caelestia/components/images/CachingImage.qml create mode 100644 .config/quickshell/caelestia/components/misc/CustomShortcut.qml create mode 100644 .config/quickshell/caelestia/components/misc/Ref.qml create mode 100644 .config/quickshell/caelestia/components/widgets/ExtraIndicator.qml create mode 100644 .config/quickshell/caelestia/config/Appearance.qml create mode 100644 .config/quickshell/caelestia/config/AppearanceConfig.qml create mode 100644 .config/quickshell/caelestia/config/BackgroundConfig.qml create mode 100644 .config/quickshell/caelestia/config/BarConfig.qml create mode 100644 .config/quickshell/caelestia/config/BorderConfig.qml create mode 100644 .config/quickshell/caelestia/config/Config.qml create mode 100644 .config/quickshell/caelestia/config/ControlCenterConfig.qml create mode 100644 .config/quickshell/caelestia/config/DashboardConfig.qml create mode 100644 .config/quickshell/caelestia/config/GeneralConfig.qml create mode 100644 .config/quickshell/caelestia/config/LauncherConfig.qml create mode 100644 .config/quickshell/caelestia/config/LockConfig.qml create mode 100644 .config/quickshell/caelestia/config/NotifsConfig.qml create mode 100644 .config/quickshell/caelestia/config/OsdConfig.qml create mode 100644 .config/quickshell/caelestia/config/ServiceConfig.qml create mode 100644 .config/quickshell/caelestia/config/SessionConfig.qml create mode 100644 .config/quickshell/caelestia/config/SidebarConfig.qml create mode 100644 .config/quickshell/caelestia/config/UserPaths.qml create mode 100644 .config/quickshell/caelestia/config/UtilitiesConfig.qml create mode 100644 .config/quickshell/caelestia/config/WInfoConfig.qml create mode 100644 .config/quickshell/caelestia/extras/CMakeLists.txt create mode 100644 .config/quickshell/caelestia/extras/version.cpp create mode 100644 .config/quickshell/caelestia/flake.lock create mode 100644 .config/quickshell/caelestia/flake.nix create mode 100644 .config/quickshell/caelestia/modules/BatteryMonitor.qml create mode 100644 .config/quickshell/caelestia/modules/IdleMonitors.qml create mode 100644 .config/quickshell/caelestia/modules/Shortcuts.qml create mode 100644 .config/quickshell/caelestia/modules/areapicker/AreaPicker.qml create mode 100644 .config/quickshell/caelestia/modules/areapicker/Picker.qml create mode 100644 .config/quickshell/caelestia/modules/background/Background.qml create mode 100644 .config/quickshell/caelestia/modules/background/DesktopClock.qml create mode 100644 .config/quickshell/caelestia/modules/background/Visualiser.qml create mode 100644 .config/quickshell/caelestia/modules/background/Wallpaper.qml create mode 100644 .config/quickshell/caelestia/modules/bar/Bar.qml create mode 100644 .config/quickshell/caelestia/modules/bar/BarWrapper.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/ActiveWindow.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/Clock.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/OsIcon.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/Power.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/Settings.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/SettingsIcon.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/StatusIcons.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/Tray.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/TrayItem.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/workspaces/ActiveIndicator.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/workspaces/OccupiedBg.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/workspaces/SpecialWorkspaces.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/workspaces/Workspace.qml create mode 100644 .config/quickshell/caelestia/modules/bar/components/workspaces/Workspaces.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/ActiveWindow.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/Audio.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/Background.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/Battery.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/Bluetooth.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/Content.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/LockStatus.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/Network.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/TrayMenu.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/WirelessPassword.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/Wrapper.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/kblayout/KbLayout.qml create mode 100644 .config/quickshell/caelestia/modules/bar/popouts/kblayout/KbLayoutModel.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/ControlCenter.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/NavRail.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/PaneRegistry.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/Panes.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/Session.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/WindowFactory.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/WindowTitle.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/appearance/AppearancePane.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/appearance/sections/AnimationsSection.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/appearance/sections/BackgroundSection.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/appearance/sections/BorderSection.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/appearance/sections/ColorSchemeSection.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/appearance/sections/ColorVariantSection.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/appearance/sections/FontsSection.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/appearance/sections/ScalesSection.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/appearance/sections/ThemeModeSection.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/appearance/sections/TransparencySection.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/audio/AudioPane.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/bluetooth/BtPane.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/bluetooth/Details.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/bluetooth/DeviceList.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/bluetooth/Settings.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/components/ConnectedButtonGroup.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/components/DeviceDetails.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/components/DeviceList.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/components/PaneTransition.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/components/ReadonlySlider.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/components/SettingsHeader.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/components/SliderInput.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/components/SplitPaneLayout.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/components/SplitPaneWithDetails.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/components/WallpaperGrid.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/dashboard/DashboardPane.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/dashboard/GeneralSection.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/dashboard/PerformanceSection.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/launcher/LauncherPane.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/launcher/Settings.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/EthernetDetails.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/EthernetList.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/EthernetPane.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/EthernetSettings.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/NetworkSettings.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/NetworkingPane.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/VpnDetails.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/VpnList.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/VpnSettings.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/WirelessDetails.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/WirelessList.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/WirelessPane.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/WirelessPasswordDialog.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/network/WirelessSettings.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/state/BluetoothState.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/state/EthernetState.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/state/LauncherState.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/state/NetworkState.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/state/VpnState.qml create mode 100644 .config/quickshell/caelestia/modules/controlcenter/taskbar/TaskbarPane.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/Background.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/Content.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/Dash.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/Media.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/Performance.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/Tabs.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/Weather.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/Wrapper.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/dash/Calendar.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/dash/DateTime.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/dash/Media.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/dash/Resources.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/dash/User.qml create mode 100644 .config/quickshell/caelestia/modules/dashboard/dash/Weather.qml create mode 100644 .config/quickshell/caelestia/modules/drawers/Backgrounds.qml create mode 100644 .config/quickshell/caelestia/modules/drawers/Border.qml create mode 100644 .config/quickshell/caelestia/modules/drawers/Drawers.qml create mode 100644 .config/quickshell/caelestia/modules/drawers/Exclusions.qml create mode 100644 .config/quickshell/caelestia/modules/drawers/Interactions.qml create mode 100644 .config/quickshell/caelestia/modules/drawers/Panels.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/AppList.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/Background.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/Content.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/ContentList.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/WallpaperList.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/Wrapper.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/items/ActionItem.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/items/AppItem.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/items/CalcItem.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/items/SchemeItem.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/items/VariantItem.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/items/WallpaperItem.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/services/Actions.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/services/Apps.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/services/M3Variants.qml create mode 100644 .config/quickshell/caelestia/modules/launcher/services/Schemes.qml create mode 100644 .config/quickshell/caelestia/modules/lock/Center.qml create mode 100644 .config/quickshell/caelestia/modules/lock/Content.qml create mode 100644 .config/quickshell/caelestia/modules/lock/Fetch.qml create mode 100644 .config/quickshell/caelestia/modules/lock/InputField.qml create mode 100644 .config/quickshell/caelestia/modules/lock/Lock.qml create mode 100644 .config/quickshell/caelestia/modules/lock/LockSurface.qml create mode 100644 .config/quickshell/caelestia/modules/lock/Media.qml create mode 100644 .config/quickshell/caelestia/modules/lock/NotifDock.qml create mode 100644 .config/quickshell/caelestia/modules/lock/NotifGroup.qml create mode 100644 .config/quickshell/caelestia/modules/lock/Pam.qml create mode 100644 .config/quickshell/caelestia/modules/lock/Resources.qml create mode 100644 .config/quickshell/caelestia/modules/lock/WeatherInfo.qml create mode 100644 .config/quickshell/caelestia/modules/notifications/Background.qml create mode 100644 .config/quickshell/caelestia/modules/notifications/Content.qml create mode 100644 .config/quickshell/caelestia/modules/notifications/Notification.qml create mode 100644 .config/quickshell/caelestia/modules/notifications/Wrapper.qml create mode 100644 .config/quickshell/caelestia/modules/osd/Background.qml create mode 100644 .config/quickshell/caelestia/modules/osd/Content.qml create mode 100644 .config/quickshell/caelestia/modules/osd/Wrapper.qml create mode 100644 .config/quickshell/caelestia/modules/session/Background.qml create mode 100644 .config/quickshell/caelestia/modules/session/Content.qml create mode 100644 .config/quickshell/caelestia/modules/session/Wrapper.qml create mode 100644 .config/quickshell/caelestia/modules/sidebar/Background.qml create mode 100644 .config/quickshell/caelestia/modules/sidebar/Content.qml create mode 100644 .config/quickshell/caelestia/modules/sidebar/Notif.qml create mode 100644 .config/quickshell/caelestia/modules/sidebar/NotifActionList.qml create mode 100644 .config/quickshell/caelestia/modules/sidebar/NotifDock.qml create mode 100644 .config/quickshell/caelestia/modules/sidebar/NotifDockList.qml create mode 100644 .config/quickshell/caelestia/modules/sidebar/NotifGroup.qml create mode 100644 .config/quickshell/caelestia/modules/sidebar/NotifGroupList.qml create mode 100644 .config/quickshell/caelestia/modules/sidebar/Props.qml create mode 100644 .config/quickshell/caelestia/modules/sidebar/Wrapper.qml create mode 100644 .config/quickshell/caelestia/modules/utilities/Background.qml create mode 100644 .config/quickshell/caelestia/modules/utilities/Content.qml create mode 100644 .config/quickshell/caelestia/modules/utilities/RecordingDeleteModal.qml create mode 100644 .config/quickshell/caelestia/modules/utilities/Wrapper.qml create mode 100644 .config/quickshell/caelestia/modules/utilities/cards/IdleInhibit.qml create mode 100644 .config/quickshell/caelestia/modules/utilities/cards/Record.qml create mode 100644 .config/quickshell/caelestia/modules/utilities/cards/RecordingList.qml create mode 100644 .config/quickshell/caelestia/modules/utilities/cards/Toggles.qml create mode 100644 .config/quickshell/caelestia/modules/utilities/toasts/ToastItem.qml create mode 100644 .config/quickshell/caelestia/modules/utilities/toasts/Toasts.qml create mode 100644 .config/quickshell/caelestia/modules/windowinfo/Buttons.qml create mode 100644 .config/quickshell/caelestia/modules/windowinfo/Details.qml create mode 100644 .config/quickshell/caelestia/modules/windowinfo/Preview.qml create mode 100644 .config/quickshell/caelestia/modules/windowinfo/WindowInfo.qml create mode 100644 .config/quickshell/caelestia/nix/app2unit.nix create mode 100644 .config/quickshell/caelestia/nix/default.nix create mode 100644 .config/quickshell/caelestia/nix/hm-module.nix create mode 100644 .config/quickshell/caelestia/plugin/CMakeLists.txt create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/CMakeLists.txt create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Internal/CMakeLists.txt create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Internal/cachingimagemanager.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Internal/cachingimagemanager.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Internal/circularindicatormanager.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Internal/circularindicatormanager.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprdevices.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprdevices.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprextras.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprextras.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Internal/logindmanager.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Internal/logindmanager.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Models/CMakeLists.txt create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Models/filesystemmodel.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Models/filesystemmodel.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/CMakeLists.txt create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/audiocollector.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/audiocollector.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/audioprovider.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/audioprovider.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/beattracker.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/beattracker.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/cavaprovider.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/cavaprovider.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/service.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/service.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/serviceref.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/Services/serviceref.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/appdb.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/appdb.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/cutils.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/cutils.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/imageanalyser.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/imageanalyser.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/qalculator.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/qalculator.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/requests.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/requests.hpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/toaster.cpp create mode 100644 .config/quickshell/caelestia/plugin/src/Caelestia/toaster.hpp create mode 100644 .config/quickshell/caelestia/services/Audio.qml create mode 100644 .config/quickshell/caelestia/services/Brightness.qml create mode 100644 .config/quickshell/caelestia/services/Colours.qml create mode 100644 .config/quickshell/caelestia/services/GameMode.qml create mode 100644 .config/quickshell/caelestia/services/Hypr.qml create mode 100644 .config/quickshell/caelestia/services/IdleInhibitor.qml create mode 100644 .config/quickshell/caelestia/services/Network.qml create mode 100644 .config/quickshell/caelestia/services/NetworkUsage.qml create mode 100644 .config/quickshell/caelestia/services/Nmcli.qml create mode 100644 .config/quickshell/caelestia/services/Notifs.qml create mode 100644 .config/quickshell/caelestia/services/Players.qml create mode 100644 .config/quickshell/caelestia/services/Recorder.qml create mode 100644 .config/quickshell/caelestia/services/SystemUsage.qml create mode 100644 .config/quickshell/caelestia/services/Time.qml create mode 100644 .config/quickshell/caelestia/services/VPN.qml create mode 100644 .config/quickshell/caelestia/services/Visibilities.qml create mode 100644 .config/quickshell/caelestia/services/Wallpapers.qml create mode 100644 .config/quickshell/caelestia/services/Weather.qml create mode 100644 .config/quickshell/caelestia/shell.qml create mode 100644 .config/quickshell/caelestia/utils/Icons.qml create mode 100644 .config/quickshell/caelestia/utils/Images.qml create mode 100644 .config/quickshell/caelestia/utils/NetworkConnection.qml create mode 100644 .config/quickshell/caelestia/utils/Paths.qml create mode 100644 .config/quickshell/caelestia/utils/Searcher.qml create mode 100644 .config/quickshell/caelestia/utils/Strings.qml create mode 100644 .config/quickshell/caelestia/utils/SysInfo.qml create mode 100644 .config/quickshell/caelestia/utils/scripts/fuzzysort.js create mode 100644 .config/quickshell/caelestia/utils/scripts/fzf.js create mode 100644 .config/quickshell/nucleus-shell/CMakeLists.txt create mode 100644 .config/quickshell/nucleus-shell/assets/gifs/bongo-cat.gif create mode 100644 .config/quickshell/nucleus-shell/config/Appearance.qml create mode 100644 .config/quickshell/nucleus-shell/config/Config.qml create mode 100644 .config/quickshell/nucleus-shell/config/Directories.qml create mode 100644 .config/quickshell/nucleus-shell/config/Globals.qml create mode 100644 .config/quickshell/nucleus-shell/config/Ipc.qml create mode 100644 .config/quickshell/nucleus-shell/config/MaterialColors.qml create mode 100644 .config/quickshell/nucleus-shell/config/Metrics.qml create mode 100644 .config/quickshell/nucleus-shell/defaults/default.jpg create mode 100644 .config/quickshell/nucleus-shell/extras/matugen/config.toml create mode 100644 .config/quickshell/nucleus-shell/extras/matugen/templates/colors.json create mode 100644 .config/quickshell/nucleus-shell/modules/components/CircularProgressBar.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/ContentCard.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/ContentMenu.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/ContentRowCard.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/InfoCard.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/LoadingIcon.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/MaterialSymbol.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/MaterialSymbolButton.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/NumberStepper.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/StyledButton.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/StyledDropDown.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/StyledImage.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/StyledPopout.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/StyledRect.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/StyledSlider.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/StyledSwitch.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/StyledSwitchOption.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/StyledText.qml create mode 100755 .config/quickshell/nucleus-shell/modules/components/StyledTextField.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/Tint.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/MorphedPolygon.qml create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/geometry/offset.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/graphics/matrix.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/material-shapes.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/corner-rounding.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/cubic.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/feature-mapping.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/feature.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/float-mapping.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/morph.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/point.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/polygon-measure.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/rounded-corner.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/rounded-polygon.js create mode 100644 .config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/utils.js create mode 100644 .config/quickshell/nucleus-shell/modules/functions/ColorUtils.qml create mode 100644 .config/quickshell/nucleus-shell/modules/functions/DisplayMetrics.qml create mode 100644 .config/quickshell/nucleus-shell/modules/functions/FileUtils.qml create mode 100644 .config/quickshell/nucleus-shell/modules/functions/StringUtils.qml create mode 100644 .config/quickshell/nucleus-shell/modules/functions/fuzzy/fuzzysort.js create mode 100644 .config/quickshell/nucleus-shell/modules/interface/background/Background.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/background/Clock.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/background/ClockDial.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/Bar.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/BarContent.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/GothCorners.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/content/ActiveWindowModule.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/content/BatteryIndicatorModule.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/content/BongoCat.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/content/ClockModule.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/content/MediaPlayerModule.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/content/StatusIconsModule.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/content/SystemTray.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/content/SystemUsageModule.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/content/ToggleModule.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/bar/content/WorkspaceModule.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/intelligence/Intelligence.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/launcher/AppItem.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/launcher/Launcher.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/launcher/LauncherContent.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/lockscreen/LockContext.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/lockscreen/LockScreen.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/lockscreen/LockSurface.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/lockscreen/pam/password.conf create mode 100644 .config/quickshell/nucleus-shell/modules/interface/notifications/NotificationChild.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/notifications/Notifications.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/overlays/BrightnessOverlay.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/overlays/Overlays.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/overlays/VolumeOverlay.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/polkit/PolkitAgent.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/polkit/Prompt.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/powermenu/Powermenu.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/screencapture/ScreenCapture.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/About.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/AppearanceConfig.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/AudioConfig.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/BarConfig.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/BluetoothConfig.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/BluetoothDeviceCard.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/LauncherConfig.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/MiscConfig.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/NetworkCard.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/NetworkConfig.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/NotificationConfig.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/Plugins.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/Settings.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/Store.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/settings/WallpaperConfig.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarLeft/IntelligencePanel.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SidebarLeft.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SidebarLeftContent.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SystemOverview.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarLeft/WallpapersPage.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarRight/SidebarRight.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarRight/SidebarRightContent.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/BluetoothToggle.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/BrightnessSlider.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/FlightModeToggle.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/Media.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NetworkToggle.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NightModeToggle.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NotifModal.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/ThemeToggle.qml create mode 100644 .config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/VolumeSlider.qml create mode 100644 .config/quickshell/nucleus-shell/plugins/PluginHost.qml create mode 100644 .config/quickshell/nucleus-shell/plugins/PluginLoader.qml create mode 100644 .config/quickshell/nucleus-shell/plugins/PluginParser.qml create mode 100644 .config/quickshell/nucleus-shell/plugins/PluginSettingsLoader.qml create mode 100755 .config/quickshell/nucleus-shell/scripts/finders/find-apps.sh create mode 100755 .config/quickshell/nucleus-shell/scripts/interface/changebg.sh create mode 100755 .config/quickshell/nucleus-shell/scripts/interface/gencolors.sh create mode 100755 .config/quickshell/nucleus-shell/scripts/interface/selectfolder.sh create mode 100755 .config/quickshell/nucleus-shell/scripts/interface/switchTheme.sh create mode 100755 .config/quickshell/nucleus-shell/scripts/plugins/plugins.sh create mode 100755 .config/quickshell/nucleus-shell/scripts/system/reload.sh create mode 100755 .config/quickshell/nucleus-shell/scripts/system/update.sh create mode 100644 .config/quickshell/nucleus-shell/services/AppRegistry.qml create mode 100644 .config/quickshell/nucleus-shell/services/Apps.qml create mode 100644 .config/quickshell/nucleus-shell/services/Bluetooth.qml create mode 100755 .config/quickshell/nucleus-shell/services/Brightness.qml create mode 100644 .config/quickshell/nucleus-shell/services/Compositor.qml create mode 100644 .config/quickshell/nucleus-shell/services/ConfigResolver.qml create mode 100644 .config/quickshell/nucleus-shell/services/Contracts.qml create mode 100755 .config/quickshell/nucleus-shell/services/Hyprland.qml create mode 100755 .config/quickshell/nucleus-shell/services/Mpris.qml create mode 100755 .config/quickshell/nucleus-shell/services/Network.qml create mode 100644 .config/quickshell/nucleus-shell/services/Niri.qml create mode 100755 .config/quickshell/nucleus-shell/services/NotifServer.qml create mode 100644 .config/quickshell/nucleus-shell/services/Polkit.qml create mode 100644 .config/quickshell/nucleus-shell/services/SystemDetails.qml create mode 100644 .config/quickshell/nucleus-shell/services/Theme.qml create mode 100755 .config/quickshell/nucleus-shell/services/Time.qml create mode 100644 .config/quickshell/nucleus-shell/services/UPower.qml create mode 100644 .config/quickshell/nucleus-shell/services/UpdateNotifier.qml create mode 100755 .config/quickshell/nucleus-shell/services/Volume.qml create mode 100644 .config/quickshell/nucleus-shell/services/WallpaperSlideshow.qml create mode 100644 .config/quickshell/nucleus-shell/services/Xrandr.qml create mode 100644 .config/quickshell/nucleus-shell/services/Zenith.qml create mode 100644 .config/quickshell/nucleus-shell/shell.qml create mode 100644 .config/quickshell/zenbar/shell.qml diff --git a/.config/btop/themes/caelestia.theme b/.config/btop/themes/caelestia.theme new file mode 100644 index 0000000..190368f --- /dev/null +++ b/.config/btop/themes/caelestia.theme @@ -0,0 +1,83 @@ +# Main background, empty for terminal default, need to be empty if you want transparent background +theme[main_bg]=#18120b + +# Main text color +theme[main_fg]=#ede0d4 + +# Title color for boxes +theme[title]=#ede0d4 + +# Highlight color for keyboard shortcuts +theme[hi_fg]=#f3bd6e + +# Background color of selected item in processes box +theme[selected_bg]=#251f17 + +# Foreground color of selected item in processes box +theme[selected_fg]=#f3bd6e + +# Color of inactive/disabled text +theme[inactive_fg]=#9b8f80 + +# Color of text appearing on top of graphs, i.e uptime and current network graph scaling +theme[graph_text]=#b7cea2 + +# Background color of the percentage meters +theme[meter_bg]=#9b8f80 + +# Misc colors for processes box including mini cpu graphs, details memory graph and details status text +theme[proc_misc]=#b7cea2 + +# CPU, Memory, Network, Proc box outline colors +theme[cpu_box]=#ffad7f +theme[mem_box]=#ffdc85 +theme[net_box]=#f0b279 +theme[proc_box]=#ffa2bd + +# Box divider line and small boxes line color +theme[div_line]=#4f4539 + +# Temperature graph color (Green -> Yellow -> Red) +theme[temp_start]=#ffdc85 +theme[temp_mid]=#ffefdb +theme[temp_end]=#f6a14d + +# CPU graph colors (Teal -> Sapphire -> Lavender) +theme[cpu_start]=#f5df89 +theme[cpu_mid]=#b3d27e +theme[cpu_end]=#ffbcbb + +# Mem/Disk free meter (Mauve -> Lavender -> Blue) +theme[free_start]=#ffad7f +theme[free_mid]=#ffbcbb +theme[free_end]=#ffa2bd + +# Mem/Disk cached meter (Sapphire -> Blue -> Lavender) +theme[cached_start]=#b3d27e +theme[cached_mid]=#ffa2bd +theme[cached_end]=#ffbcbb + +# Mem/Disk available meter (Peach -> Maroon -> Red) +theme[available_start]=#fac482 +theme[available_mid]=#f0b279 +theme[available_end]=#f6a14d + +# Mem/Disk used meter (Green -> Teal -> Sky) +theme[used_start]=#ffdc85 +theme[used_mid]=#f5df89 +theme[used_end]=#e1df87 + +# Download graph colors (Peach -> Maroon -> Red) +theme[download_start]=#fac482 +theme[download_mid]=#f0b279 +theme[download_end]=#f6a14d + +# Upload graph colors (Green -> Teal -> Sky) +theme[upload_start]=#ffdc85 +theme[upload_mid]=#f5df89 +theme[upload_end]=#e1df87 + +# Process box color gradient for threads, mem and cpu usage (Sapphire -> Lavender -> Mauve) +theme[process_start]=#b3d27e +theme[process_mid]=#ffbcbb +theme[process_end]=#ffad7f diff --git a/.config/hypr/hyprland.conf b/.config/hypr/hyprland.conf index 7ad7556..b504bc1 100755 --- a/.config/hypr/hyprland.conf +++ b/.config/hypr/hyprland.conf @@ -23,9 +23,18 @@ env = XDG_SESSION_TYPE,wayland env = XDG_SESSION_DESKTOP,Hyprland env = XDG_SCREENSHOTS_DIR,$HOME/Pictures/Screenshots -env = LIBVA_DRIVER_NAME,nvidia -env = GBM_BACKEND,nvidia-drm -env = __GLX_VENDOR_LIBRARY_NAME,nvidia +# env = LIBVA_DRIVER_NAME,nvidia +# env = GBM_BACKEND,nvidia-drm +# env = __GLX_VENDOR_LIBRARY_NAME,nvidia + +env = AQ_DRM_DEVICES,/dev/dri/card2:/dev/dri/card1 + +# Toolkit Backend Variables +env = GDK_BACKEND,wayland,x11,* +env = QT_QPA_PLATFORM,wayland;xcb +env = CLUTTER_BACKEND,wayland + +env = GDK_BACKEND,wayland,x11,* env = QT_AUTO_SCREEN_SCALE_FACTOR,1 env = QT_QPA_PLATFORM,wayland;xcb @@ -33,6 +42,7 @@ env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1 env = QT_QPA_PLATFORMTHEME,qt5ct env = XCURSOR_SIZE,24 +env = HYPRCURSOR_SIZE,24 ################ ### MONITORS ### ################ @@ -63,14 +73,14 @@ exec-once = ~/.config/hypr/start.sh # https://wiki.hyprland.org/Configuring/Variables/#general general { - gaps_in = 5 - gaps_out = 20 + gaps_in = 3 + gaps_out = 5 border_size = 2 - col.active_border = rgb(44475a) rgb(bd93f9) 90deg - col.inactive_border = rgba(44475aaa) - col.nogroup_border = rgba(282a36dd) - col.nogroup_border_active = rgb(bd93f9) rgb(44475a) 90deg + col.active_border = 0xffd3869b + col.inactive_border = 0xff45475a + # col.nogroup_border = rgba(282a36dd) + # col.nogroup_border_active = rgb(bd93f9) rgb(44475a) 90deg # Set to true enable resizing windows by clicking and dragging on borders and gaps resize_on_border = false @@ -89,19 +99,20 @@ decoration { rounding = 10 # Change transparency of focused and unfocused windows - active_opacity = 1.0 - inactive_opacity = 1.0 + active_opacity = 0.9 + inactive_opacity = 0.9 shadow { enabled = true - range = 4 - render_power = 3 - color = rgba(1E202966) -} + range = 4 + render_power = 3 + color = 0x33000000 + color_inactive = 0x22000000 + } # https://wiki.hyprland.org/Configuring/Variables/#blur blur { enabled = true - size = 3 - passes = 1 + size = 2 + passes = 4 vibrancy = 0.1696 } } @@ -141,6 +152,7 @@ misc { animate_mouse_windowdragging = true enable_swallow = true disable_hyprland_logo = true + vfr = true } diff --git a/.config/hypr/hyprpaper.conf b/.config/hypr/hyprpaper.conf index d137d0a..e34ef1f 100755 --- a/.config/hypr/hyprpaper.conf +++ b/.config/hypr/hyprpaper.conf @@ -1,4 +1,4 @@ -$path = ~/Pictures/Wallpapers/kdh.jpg +$path = ~/Pictures/Wallpapers/gruvroad.png wallpaper { monitor = eDP-1 path = $path diff --git a/.config/hypr/scheme/current.conf b/.config/hypr/scheme/current.conf new file mode 100644 index 0000000..96ec23e --- /dev/null +++ b/.config/hypr/scheme/current.conf @@ -0,0 +1,110 @@ +$primary_paletteKeyColor = 9b6f28 +$secondary_paletteKeyColor = 8a7457 +$tertiary_paletteKeyColor = 697d57 +$neutral_paletteKeyColor = 7f766c +$neutral_variant_paletteKeyColor = 817567 +$background = 18120b +$onBackground = ede0d4 +$surface = 18120b +$surfaceDim = 18120b +$surfaceBright = 3f382f +$surfaceContainerLowest = 120d07 +$surfaceContainerLow = 201b13 +$surfaceContainer = 251f17 +$surfaceContainerHigh = 2f2921 +$surfaceContainerHighest = 3b342b +$onSurface = ede0d4 +$surfaceVariant = 4f4539 +$onSurfaceVariant = d3c4b4 +$inverseSurface = ede0d4 +$inverseOnSurface = 362f27 +$outline = 9b8f80 +$outlineVariant = 4f4539 +$shadow = 000000 +$scrim = 000000 +$surfaceTint = f3bd6e +$primary = f3bd6e +$onPrimary = 442b00 +$primaryContainer = 624000 +$onPrimaryContainer = ffddb2 +$inversePrimary = 7f5610 +$secondary = ddc2a1 +$onSecondary = 3e2e16 +$secondaryContainer = 56442a +$onSecondaryContainer = fadebc +$tertiary = b7cea2 +$onTertiary = 243516 +$tertiaryContainer = 82976f +$onTertiaryContainer = 000000 +$error = ffb4ab +$onError = 690005 +$errorContainer = 93000a +$onErrorContainer = ffdad6 +$primaryFixed = ffddb2 +$primaryFixedDim = f3bd6e +$onPrimaryFixed = 291800 +$onPrimaryFixedVariant = 624000 +$secondaryFixed = fadebc +$secondaryFixedDim = ddc2a1 +$onSecondaryFixed = 271904 +$onSecondaryFixedVariant = 56442a +$tertiaryFixed = d3eabc +$tertiaryFixedDim = b7cea2 +$onTertiaryFixed = 0f2004 +$onTertiaryFixedVariant = 3a4c2a +$term0 = 353433 +$term1 = d07d00 +$term2 = ffc243 +$term3 = ffe1bb +$term4 = b9ab66 +$term5 = e79953 +$term6 = e8c66d +$term7 = e8d5bf +$term8 = afa090 +$term9 = f19300 +$term10 = ffd891 +$term11 = fff2e4 +$term12 = cfc092 +$term13 = f6b072 +$term14 = ffd673 +$term15 = ffffff +$rosewater = ffefe2 +$flamingo = fbdcc3 +$pink = ffd5b8 +$mauve = ffad7f +$red = f6a14d +$maroon = f0b279 +$peach = fac482 +$yellow = ffefdb +$green = ffdc85 +$teal = f5df89 +$sky = e1df87 +$sapphire = b3d27e +$blue = ffa2bd +$lavender = ffbcbb +$klink = 559652 +$klinkSelection = 559652 +$kvisited = c66716 +$kvisitedSelection = c66716 +$knegative = c67400 +$knegativeSelection = c67400 +$kneutral = ed9800 +$kneutralSelection = ed9800 +$kpositive = cea400 +$kpositiveSelection = cea400 +$text = ede0d4 +$subtext1 = d3c4b4 +$subtext0 = 9b8f80 +$overlay2 = 887c6e +$overlay1 = 73695c +$overlay0 = 61584c +$surface2 = 50473c +$surface1 = 3e362d +$surface0 = 2b241c +$base = 18120b +$mantle = 18120b +$crust = 17110a +$success = B5CCBA +$onSuccess = 213528 +$successContainer = 374B3E +$onSuccessContainer = D1E9D6 diff --git a/.config/hypr/start.sh b/.config/hypr/start.sh index c467732..5a163c1 100755 --- a/.config/hypr/start.sh +++ b/.config/hypr/start.sh @@ -20,10 +20,11 @@ run_and_time() { echo "--- Hyprland Startup: $(date) ---" -run_and_time qs -c nucleus-shell +run_and_time qs -c caelestia # run_and_time systemctl --user start hyprpaper # run_and_time systemctl --user start hypridle # run_and_time systemctl --user start hyprpolkitagent +run_and_time systemctl --user start xdg-desktop-portal-hyprland run_and_time ssh-agent run_and_time copyq run_and_time kdeconnect-indicator diff --git a/.config/quickshell/caelestia/.clang-format b/.config/quickshell/caelestia/.clang-format new file mode 100644 index 0000000..75eab98 --- /dev/null +++ b/.config/quickshell/caelestia/.clang-format @@ -0,0 +1,25 @@ +--- +BasedOnStyle: LLVM +IndentWidth: 4 +ColumnLimit: 120 +--- +Language: Cpp +DerivePointerAlignment: false +PointerAlignment: Left +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortLambdasOnASingleLine: None +BinPackArguments: true +BreakBeforeBraces: Attach +BreakConstructorInitializers: BeforeComma +Cpp11BracedListStyle: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: Always +IndentAccessModifiers: false +IndentCaseLabels: false +InsertNewlineAtEOF: true +SeparateDefinitionBlocks: Always +WrapNamespaceBodyWithEmptyLines: Always +... diff --git a/.config/quickshell/caelestia/.envrc b/.config/quickshell/caelestia/.envrc new file mode 100644 index 0000000..c90b500 --- /dev/null +++ b/.config/quickshell/caelestia/.envrc @@ -0,0 +1,15 @@ +if has nix; then + use flake +fi + +shopt -s globstar +watch_file assets/cpp/**/*.cpp +watch_file assets/cpp/**/*.hpp +watch_file plugin/**/*.cpp +watch_file plugin/**/*.hpp +watch_file **/CMakeLists.txt + +cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_COMPILER=clazy -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DDISTRIBUTOR=direnv +cmake --build build +export CAELESTIA_LIB_DIR="$PWD/build/lib" +export QML2_IMPORT_PATH="$PWD/build/qml:${QML2_IMPORT_PATH:-}" diff --git a/.config/quickshell/caelestia/.github/CONTRIBUTING.md b/.config/quickshell/caelestia/.github/CONTRIBUTING.md new file mode 100644 index 0000000..d0239c0 --- /dev/null +++ b/.config/quickshell/caelestia/.github/CONTRIBUTING.md @@ -0,0 +1,21 @@ +# Contributing + +There are only a few rules: +- Follow the commit convention as follows: + - The name of the commit should be `module: change` + - Try to be consistent with the module names; you can look at existing commits for the module names I use + - If there is more than one change, the change in the commit name should be the most impactful change + - Put other changes in the description +- Format your code + - I use the vscode qml extension with default arguments to format the code, however you do not have to use it + - Just try to follow the code style of the rest of the code and ensure that there is: + - no trailing whitespace on any lines + - a single space between operators +- No AI slop allowed + - AI readme/docs slop = instant block +- PLEASE TEST YOUR PRS + - I can't believe I have to put this here, but please test your PRs before submitting them + - Your PR must not break anything currently existing, or specify in the description if it does +- PR descriptions should be descriptive + - Please explain what the PR does and how to use it in your PR description + - Also include any breaking changes and/or side effects of the PR diff --git a/.config/quickshell/caelestia/.github/FUNDING.yml b/.config/quickshell/caelestia/.github/FUNDING.yml new file mode 100644 index 0000000..30f44f7 --- /dev/null +++ b/.config/quickshell/caelestia/.github/FUNDING.yml @@ -0,0 +1,15 @@ +# These are supported funding model platforms + +github: soramanew +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: soramane +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +polar: # Replace with a single Polar username +buy_me_a_coffee: soramane +thanks_dev: # Replace with a single thanks.dev username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.config/quickshell/caelestia/.github/ISSUE_TEMPLATE/config.yml b/.config/quickshell/caelestia/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3ba13e0 --- /dev/null +++ b/.config/quickshell/caelestia/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.config/quickshell/caelestia/.github/ISSUE_TEMPLATE/feature.yml b/.config/quickshell/caelestia/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 0000000..c5caffa --- /dev/null +++ b/.config/quickshell/caelestia/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,24 @@ +name: Feature request +description: Suggest a new feature +labels: ["enhancement"] +type: "Feature" +title: "[FEATURE] " +body: + - type: markdown + attributes: + value: "NOTE: Please write in **English**." + + - type: textarea + attributes: + label: "What would you like to be added?" + description: "Can be a suggestion for an existing feature. You can suggest a widget, minor user interaction changes.. whatever." + + - type: textarea + attributes: + label: "How will it help?" + description: "It's helpful to include examples (like in your use case)." + + - type: textarea + attributes: + label: "Extra info" + description: "If you want a new widget, a pic of the inspiration (if available) would be awesome." diff --git a/.config/quickshell/caelestia/.github/ISSUE_TEMPLATE/issue.yml b/.config/quickshell/caelestia/.github/ISSUE_TEMPLATE/issue.yml new file mode 100644 index 0000000..b767104 --- /dev/null +++ b/.config/quickshell/caelestia/.github/ISSUE_TEMPLATE/issue.yml @@ -0,0 +1,56 @@ +name: Issue +description: Report an issue with the dots +labels: ["bug"] +type: "Bug" +title: "[BUG] " +body: + - type: markdown + attributes: + value: "**Welcome to submit a new issue!**\n- It takes only 3 steps, so please be patient :)\n- Tip: If your issue is not a feature request and is not an issue with the dots (e.g. \"how do I use X feature\"), please use [Discussions](https://github.com/caelestia-dots/shell/discussions) instead." + - type: checkboxes + attributes: + label: "Step 1. Before you submit" + description: "Hint: The 2nd and 3rd checkbox is **not** forcely required as you may have failed to do so." + options: + - label: I have read the above instructions and am sure that this is supposed to be posted here. + required: true + - label: I've successfully updated to the latest versions following the [updating guide](https://github.com/caelestia-dots/caelestia?tab=readme-ov-file#updating). + required: false # Not required cuz user may have failed to do so + - label: I've successfully updated the system packages to the latest. + required: false # Not required cuz user may have failed to do so + - label: I've ticked the checkboxes without reading their contents + required: false # Obviously + + - type: textarea + attributes: + label: "Step 2. Version info" + description: "Run `caelestia -v` and paste the result below." + value: "
Version info\n\n```\n\n```\n\n
" + validations: + required: true + + - type: markdown + attributes: + value: | + **Tips for the following Step 3** + 1. Use `LANG=C LC_ALL=C` to get the output of a command in English, eg. `LANG=C LC_ALL=C date` displays time in English. + 2. If it throws errors, **PLEASE**, attach logs and describe in detail if possible. + - Something happened to the shell (bar, dashboard, etc)? Run `caelestia shell -l` WITHOUT exiting the shell for logs. + - Installation failed? Run installation again for logs. + - You may use more code blocks when needed. + 3. In case you are confused, the `
`, ``, ``, `
` are HTML tags for folding the logs (typically very long) inside. Please do not touch them (unless you know what you are doing). + 4. If the logs are suuuuuuper long, consider using an online pastebin service instead. + + - type: textarea + attributes: + label: "Step 3. Describe the issue" + value: "\n\n\n
Logs\n\n```\n\n```\n\n
" + validations: + required: true + + - type: checkboxes + attributes: + label: Reminder + options: + - label: I agree that it's usually impossible for others to help me without my logs. + required: true diff --git a/.config/quickshell/caelestia/.github/workflows/release.yml b/.config/quickshell/caelestia/.github/workflows/release.yml new file mode 100644 index 0000000..ac43772 --- /dev/null +++ b/.config/quickshell/caelestia/.github/workflows/release.yml @@ -0,0 +1,37 @@ +name: Create release + +on: + push: + tags: + - 'v*' + +jobs: + build-and-release: + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + + - name: Create packages + run: | + mkdir -p release + rsync -av \ + --exclude='release' \ + --exclude='.*' \ + --exclude='nix' \ + --exclude='flake.lock' \ + --exclude='flake.nix' \ + . release + tar -czf caelestia-shell-${{ github.ref_name }}.tar.gz release + cp caelestia-shell-${{ github.ref_name }}.tar.gz caelestia-shell-latest.tar.gz + + - name: Create release + uses: softprops/action-gh-release@v2 + with: + files: | + caelestia-shell-${{ github.ref_name }}.tar.gz + caelestia-shell-latest.tar.gz + generate_release_notes: true diff --git a/.config/quickshell/caelestia/.github/workflows/update-flake-inputs.yml b/.config/quickshell/caelestia/.github/workflows/update-flake-inputs.yml new file mode 100644 index 0000000..1a8bd07 --- /dev/null +++ b/.config/quickshell/caelestia/.github/workflows/update-flake-inputs.yml @@ -0,0 +1,85 @@ +name: Update flake inputs + +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * 0' + +jobs: + update-flake: + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + + - name: Install Nix + uses: nixbuild/nix-quick-install-action@v31 + with: + nix_conf: | + keep-env-derivations = true + keep-outputs = true + + - name: Restore and save Nix store + uses: nix-community/cache-nix-action@v6 + with: + # restore and save a cache using this key + primary-key: nix-${{ hashFiles('**/*.nix', '**/flake.lock') }} + # if there's no cache hit, restore a cache by this prefix + restore-prefixes-first-match: nix- + # collect garbage until the Nix store size (in bytes) is at most this number + # before trying to save a new cache + # 1G = 1073741824 + gc-max-store-size-linux: 1G + # do purge caches + purge: true + # purge all versions of the cache + purge-prefixes: nix- + # created more than this number of seconds ago + purge-created: 0 + # or, last accessed more than this number of seconds ago + # relative to the start of the `Post Restore and save Nix store` phase + purge-last-accessed: 0 + # except any version with the key that is the same as the `primary-key` + purge-primary-key: never + + - name: Update flake inputs + run: nix flake update + + - name: Attempt to build flake + run: nix build + + - name: Test on Sway + env: + XDG_RUNTIME_DIR: /home/runner/runtime + WLR_BACKENDS: headless + WLR_LIBINPUT_NO_DEVICES: 1 + WAYLAND_DISPLAY: wayland-1 + run: | + mkdir $XDG_RUNTIME_DIR + chown $USER $XDG_RUNTIME_DIR + chmod 0700 $XDG_RUNTIME_DIR + + nix profile install 'nixpkgs#sway' + sway & + sleep 3 # Give Sway some time to start + result/bin/caelestia-shell -d + sleep 3 # Give the shell some time to start (and die) + pgrep .quickshell-wra # Fail job if shell died + + result/bin/caelestia-shell kill + killall sway # Screw using IPC + + - name: Check for changes + id: check + run: echo modified=$(git diff --exit-code flake.lock &>/dev/null && echo 'false' || echo 'true') >> $GITHUB_OUTPUT + + - name: Commit and push changes + if: steps.check.outputs.modified == 'true' + uses: EndBug/add-and-commit@v9 + with: + add: flake.lock + default_author: github_actions + message: "[CI] chore: update flake" diff --git a/.config/quickshell/caelestia/.gitignore b/.config/quickshell/caelestia/.gitignore new file mode 100644 index 0000000..c30a6d9 --- /dev/null +++ b/.config/quickshell/caelestia/.gitignore @@ -0,0 +1,6 @@ +.direnv +/result +/.qmlls.ini +build/ +.cache/ +logs \ No newline at end of file diff --git a/.config/quickshell/caelestia/.vscode/settings.json b/.config/quickshell/caelestia/.vscode/settings.json new file mode 100644 index 0000000..13763e4 --- /dev/null +++ b/.config/quickshell/caelestia/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "editor.defaultFormatter": "theqtcompany.qt-qml", + "[cpp]": { + "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" + } +} diff --git a/.config/quickshell/caelestia/CMakeLists.txt b/.config/quickshell/caelestia/CMakeLists.txt new file mode 100644 index 0000000..7b95855 --- /dev/null +++ b/.config/quickshell/caelestia/CMakeLists.txt @@ -0,0 +1,67 @@ +cmake_minimum_required(VERSION 3.19) + +if(NOT DEFINED VERSION) + execute_process(COMMAND git describe --tags --abbrev=0 + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if("${VERSION}" STREQUAL "") + message(FATAL_ERROR "VERSION is not set and failed to get from git") + endif() +endif() + +if(NOT DEFINED GIT_REVISION) + execute_process(COMMAND git rev-parse HEAD + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_REVISION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if("${GIT_REVISION}" STREQUAL "") + message(FATAL_ERROR "GIT_REVISION is not set and failed to get from git") + endif() +endif() + +string(REGEX REPLACE "^v" "" VERSION "${VERSION}") + +project(caelestia-shell VERSION ${VERSION} LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") + +set(DISTRIBUTOR "Unset" CACHE STRING "Distributor") +set(ENABLE_MODULES "extras;plugin;shell" CACHE STRING "Modules to build/install") +set(INSTALL_LIBDIR "usr/lib/caelestia" CACHE STRING "Library install dir") +set(INSTALL_QMLDIR "usr/lib/qt6/qml" CACHE STRING "QML install dir") +set(INSTALL_QSCONFDIR "etc/xdg/quickshell/caelestia" CACHE STRING "Quickshell config install dir") + +add_compile_options( + -Wall -Wextra -Wpedantic -Wshadow -Wconversion + -Wold-style-cast -Wnull-dereference -Wdouble-promotion + -Wformat=2 -Wfloat-equal -Woverloaded-virtual + -Wsign-conversion -Wredundant-decls -Wswitch + -Wunreachable-code +) + +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wunused-lambda-capture) +endif() + +if("extras" IN_LIST ENABLE_MODULES) + add_subdirectory(extras) +endif() + +if("plugin" IN_LIST ENABLE_MODULES) + add_subdirectory(plugin) +endif() + +if("shell" IN_LIST ENABLE_MODULES) + foreach(dir assets components config modules services utils) + install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}") + endforeach() + install(FILES shell.qml LICENSE DESTINATION "${INSTALL_QSCONFDIR}") +endif() diff --git a/.config/quickshell/caelestia/LICENSE b/.config/quickshell/caelestia/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/.config/quickshell/caelestia/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/.config/quickshell/caelestia/README.md b/.config/quickshell/caelestia/README.md new file mode 100644 index 0000000..886f061 --- /dev/null +++ b/.config/quickshell/caelestia/README.md @@ -0,0 +1,763 @@ +

caelestia-shell

+ +
+ +![GitHub last commit](https://img.shields.io/github/last-commit/caelestia-dots/shell?style=for-the-badge&labelColor=101418&color=9ccbfb) +![GitHub Repo stars](https://img.shields.io/github/stars/caelestia-dots/shell?style=for-the-badge&labelColor=101418&color=b9c8da) +![GitHub repo size](https://img.shields.io/github/repo-size/caelestia-dots/shell?style=for-the-badge&labelColor=101418&color=d3bfe6) +[![Ko-Fi donate](https://img.shields.io/badge/donate-kofi?style=for-the-badge&logo=ko-fi&logoColor=ffffff&label=ko-fi&labelColor=101418&color=f16061&link=https%3A%2F%2Fko-fi.com%2Fsoramane)](https://ko-fi.com/soramane) +[![Discord invite](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fdiscordapp.com%2Fapi%2Finvites%2FBGDCFCmMBk%3Fwith_counts%3Dtrue&query=approximate_member_count&style=for-the-badge&logo=discord&logoColor=ffffff&label=discord&labelColor=101418&color=96f1f1&link=https%3A%2F%2Fdiscord.gg%2FBGDCFCmMBk)](https://discord.gg/BGDCFCmMBk) + +
+ +https://github.com/user-attachments/assets/0840f496-575c-4ca6-83a8-87bb01a85c5f + +## Components + +- Widgets: [`Quickshell`](https://quickshell.outfoxxed.me) +- Window manager: [`Hyprland`](https://hyprland.org) +- Dots: [`caelestia`](https://github.com/caelestia-dots) + +## Installation + +> [!NOTE] +> This repo is for the desktop shell of the caelestia dots. If you want installation instructions +> for the entire dots, head to [the main repo](https://github.com/caelestia-dots/caelestia) instead. + +### Arch linux + +> [!NOTE] +> If you want to make your own changes/tweaks to the shell do NOT edit the files installed by the AUR +> package. Instead, follow the instructions in the [manual installation section](#manual-installation). + +The shell is available from the AUR as `caelestia-shell`. You can install it with an AUR helper +like [`yay`](https://github.com/Jguer/yay) or manually downloading the PKGBUILD and running `makepkg -si`. + +A package following the latest commit also exists as `caelestia-shell-git`. This is bleeding edge +and likely to be unstable/have bugs. Regular users are recommended to use the stable package +(`caelestia-shell`). + +### Nix + +You can run the shell directly via `nix run`: + +```sh +nix run github:caelestia-dots/shell +``` + +Or add it to your system configuration: + +```nix +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + caelestia-shell = { + url = "github:caelestia-dots/shell"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; +} +``` + +The package is available as `caelestia-shell.packages..default`, which can be added to your +`environment.systemPackages`, `users.users..packages`, `home.packages` if using home-manager, +or a devshell. The shell can then be run via `caelestia-shell`. + +> [!TIP] +> The default package does not have the CLI enabled by default, which is required for full funcionality. +> To enable the CLI, use the `with-cli` package. + +For home-manager, you can also use the Caelestia's home manager module (explained in [configuring](https://github.com/caelestia-dots/shell?tab=readme-ov-file#home-manager-module)) that installs and configures the shell and the CLI. + +### Manual installation + +Dependencies: + +- [`caelestia-cli`](https://github.com/caelestia-dots/cli) +- [`quickshell-git`](https://quickshell.outfoxxed.me) - this has to be the git version, not the latest tagged version +- [`ddcutil`](https://github.com/rockowitz/ddcutil) +- [`brightnessctl`](https://github.com/Hummer12007/brightnessctl) +- [`app2unit`](https://github.com/Vladimir-csp/app2unit) +- [`libcava`](https://github.com/LukashonakV/cava) +- [`networkmanager`](https://networkmanager.dev) +- [`lm-sensors`](https://github.com/lm-sensors/lm-sensors) +- [`fish`](https://github.com/fish-shell/fish-shell) +- [`aubio`](https://github.com/aubio/aubio) +- [`libpipewire`](https://pipewire.org) +- `glibc` +- `qt6-declarative` +- `gcc-libs` +- [`material-symbols`](https://fonts.google.com/icons) +- [`caskaydia-cove-nerd`](https://www.nerdfonts.com/font-downloads) +- [`swappy`](https://github.com/jtheoof/swappy) +- [`libqalculate`](https://github.com/Qalculate/libqalculate) +- [`bash`](https://www.gnu.org/software/bash) +- `qt6-base` +- `qt6-declarative` + +Build dependencies: + +- [`cmake`](https://cmake.org) +- [`ninja`](https://github.com/ninja-build/ninja) + +To install the shell manually, install all dependencies and clone this repo to `$XDG_CONFIG_HOME/quickshell/caelestia`. +Then simply build and install using `cmake`. + +```sh +cd $XDG_CONFIG_HOME/quickshell +git clone https://github.com/caelestia-dots/shell.git caelestia + +cd caelestia +cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/ +cmake --build build +sudo cmake --install build +``` + +> [!TIP] +> You can customise the installation location via the `cmake` flags `INSTALL_LIBDIR`, `INSTALL_QMLDIR` and +> `INSTALL_QSCONFDIR` for the libraries (the beat detector), QML plugin and Quickshell config directories +> respectively. If changing the library directory, remember to set the `CAELESTIA_LIB_DIR` environment +> variable to the custom directory when launching the shell. +> +> e.g. installing to `~/.config/quickshell/caelestia` for easy local changes: +> +> ```sh +> mkdir -p ~/.config/quickshell/caelestia +> cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/ -DINSTALL_QSCONFDIR=~/.config/quickshell/caelestia +> cmake --build build +> sudo cmake --install build +> sudo chown -R $USER ~/.config/quickshell/caelestia +> ``` + +## Usage + +The shell can be started via the `caelestia shell -d` command or `qs -c caelestia`. +If the entire caelestia dots are installed, the shell will be autostarted on login +via an `exec-once` in the hyprland config. + +### Shortcuts/IPC + +All keybinds are accessible via Hyprland [global shortcuts](https://wiki.hyprland.org/Configuring/Binds/#dbus-global-shortcuts). +If using the entire caelestia dots, the keybinds are already configured for you. +Otherwise, [this file](https://github.com/caelestia-dots/caelestia/blob/main/hypr/hyprland/keybinds.conf#L1-L39) +contains an example on how to use global shortcuts. + +All IPC commands can be accessed via `caelestia shell ...`. For example + +```sh +caelestia shell mpris getActive trackTitle +``` + +The list of IPC commands can be shown via `caelestia shell -s`: + +``` +$ caelestia shell -s +target drawers + function toggle(drawer: string): void + function list(): string +target notifs + function clear(): void +target lock + function lock(): void + function unlock(): void + function isLocked(): bool +target mpris + function playPause(): void + function getActive(prop: string): string + function next(): void + function stop(): void + function play(): void + function list(): string + function pause(): void + function previous(): void +target picker + function openFreeze(): void + function open(): void +target wallpaper + function set(path: string): void + function get(): string + function list(): string +``` + +### PFP/Wallpapers + +The profile picture for the dashboard is read from the file `~/.face`, so to set +it you can copy your image to there or set it via the dashboard. + +The wallpapers for the wallpaper switcher are read from `~/Pictures/Wallpapers` +by default. To change it, change the wallpapers path in `~/.config/caelestia/shell.json`. + +To set the wallpaper, you can use the command `caelestia wallpaper`. Use `caelestia wallpaper -h` for more info about +the command. + +## Updating + +If installed via the AUR package, simply update your system (e.g. using `yay`). + +If installed manually, you can update by running `git pull` in `$XDG_CONFIG_HOME/quickshell/caelestia`. + +```sh +cd $XDG_CONFIG_HOME/quickshell/caelestia +git pull +``` + +## Configuring + +All configuration options should be put in `~/.config/caelestia/shell.json`. This file is _not_ created by +default, you must create it manually. + +### Example configuration + +> [!NOTE] +> The example configuration only includes recommended configuration options. For more advanced customisation +> such as modifying the size of individual items or changing constants in the code, there are some other +> options which can be found in the source files in the `config` directory. + +
Example + +```json +{ + "appearance": { + "mediaGifSpeedAdjustment": 300, + "sessionGifSpeed": 0.7, + "anim": { + "durations": { + "scale": 1 + } + }, + "font": { + "family": { + "clock": "Rubik", + "material": "Material Symbols Rounded", + "mono": "CaskaydiaCove NF", + "sans": "Rubik" + }, + "size": { + "scale": 1 + } + }, + "padding": { + "scale": 1 + }, + "rounding": { + "scale": 1 + }, + "spacing": { + "scale": 1 + }, + "transparency": { + "enabled": false, + "base": 0.85, + "layers": 0.4 + } + }, + "general": { + "logo": "caelestia", + "apps": { + "terminal": ["foot"], + "audio": ["pavucontrol"], + "playback": ["mpv"], + "explorer": ["thunar"] + }, + "battery": { + "warnLevels": [ + { + "level": 20, + "title": "Low battery", + "message": "You might want to plug in a charger", + "icon": "battery_android_frame_2" + }, + { + "level": 10, + "title": "Did you see the previous message?", + "message": "You should probably plug in a charger now", + "icon": "battery_android_frame_1" + }, + { + "level": 5, + "title": "Critical battery level", + "message": "PLUG THE CHARGER RIGHT NOW!!", + "icon": "battery_android_alert", + "critical": true + } + ], + "criticalLevel": 3 + }, + "idle": { + "lockBeforeSleep": true, + "inhibitWhenAudio": true, + "timeouts": [ + { + "timeout": 180, + "idleAction": "lock" + }, + { + "timeout": 300, + "idleAction": "dpms off", + "returnAction": "dpms on" + }, + { + "timeout": 600, + "idleAction": ["systemctl", "suspend-then-hibernate"] + } + ] + } + }, + "background": { + "desktopClock": { + "enabled": false, + "scale": 1.0, + "position": "bottom-right", + "shadow": { + "enabled": true, + "opacity": 0.7, + "blur": 0.4 + }, + "background": { + "enabled": false, + "opacity": 0.7, + "blur": true + }, + "invertColors": false + }, + "enabled": true, + "visualiser": { + "blur": false, + "enabled": false, + "autoHide": true, + "rounding": 1, + "spacing": 1 + } + }, + "bar": { + "clock": { + "showIcon": true + }, + "dragThreshold": 20, + "entries": [ + { + "id": "logo", + "enabled": true + }, + { + "id": "workspaces", + "enabled": true + }, + { + "id": "spacer", + "enabled": true + }, + { + "id": "activeWindow", + "enabled": true + }, + { + "id": "spacer", + "enabled": true + }, + { + "id": "tray", + "enabled": true + }, + { + "id": "clock", + "enabled": true + }, + { + "id": "statusIcons", + "enabled": true + }, + { + "id": "power", + "enabled": true + } + ], + "persistent": true, + "popouts": { + "activeWindow": true, + "statusIcons": true, + "tray": true + }, + "scrollActions": { + "brightness": true, + "workspaces": true, + "volume": true + }, + "showOnHover": true, + "status": { + "showAudio": false, + "showBattery": true, + "showBluetooth": true, + "showKbLayout": false, + "showMicrophone": false, + "showNetwork": true, + "showWifi": true, + "showLockStatus": true + }, + "tray": { + "background": false, + "compact": false, + "iconSubs": [], + "recolour": false + }, + "workspaces": { + "activeIndicator": true, + "activeLabel": "󰮯", + "activeTrail": false, + "label": " ", + "occupiedBg": false, + "occupiedLabel": "󰮯", + "perMonitorWorkspaces": true, + "showWindows": true, + "shown": 5, + "specialWorkspaceIcons": [ + { + "name": "steam", + "icon": "sports_esports" + } + ] + }, + "excludedScreens": [""], + "activeWindow": { + "inverted": false + } + }, + "border": { + "rounding": 25, + "thickness": 10 + }, + "dashboard": { + "enabled": true, + "dragThreshold": 50, + "mediaUpdateInterval": 500, + "showOnHover": true + }, + "launcher": { + "actionPrefix": ">", + "actions": [ + { + "name": "Calculator", + "icon": "calculate", + "description": "Do simple math equations (powered by Qalc)", + "command": ["autocomplete", "calc"], + "enabled": true, + "dangerous": false + }, + { + "name": "Scheme", + "icon": "palette", + "description": "Change the current colour scheme", + "command": ["autocomplete", "scheme"], + "enabled": true, + "dangerous": false + }, + { + "name": "Wallpaper", + "icon": "image", + "description": "Change the current wallpaper", + "command": ["autocomplete", "wallpaper"], + "enabled": true, + "dangerous": false + }, + { + "name": "Variant", + "icon": "colors", + "description": "Change the current scheme variant", + "command": ["autocomplete", "variant"], + "enabled": true, + "dangerous": false + }, + { + "name": "Transparency", + "icon": "opacity", + "description": "Change shell transparency", + "command": ["autocomplete", "transparency"], + "enabled": false, + "dangerous": false + }, + { + "name": "Random", + "icon": "casino", + "description": "Switch to a random wallpaper", + "command": ["caelestia", "wallpaper", "-r"], + "enabled": true, + "dangerous": false + }, + { + "name": "Light", + "icon": "light_mode", + "description": "Change the scheme to light mode", + "command": ["setMode", "light"], + "enabled": true, + "dangerous": false + }, + { + "name": "Dark", + "icon": "dark_mode", + "description": "Change the scheme to dark mode", + "command": ["setMode", "dark"], + "enabled": true, + "dangerous": false + }, + { + "name": "Shutdown", + "icon": "power_settings_new", + "description": "Shutdown the system", + "command": ["systemctl", "poweroff"], + "enabled": true, + "dangerous": true + }, + { + "name": "Reboot", + "icon": "cached", + "description": "Reboot the system", + "command": ["systemctl", "reboot"], + "enabled": true, + "dangerous": true + }, + { + "name": "Logout", + "icon": "exit_to_app", + "description": "Log out of the current session", + "command": ["loginctl", "terminate-user", ""], + "enabled": true, + "dangerous": true + }, + { + "name": "Lock", + "icon": "lock", + "description": "Lock the current session", + "command": ["loginctl", "lock-session"], + "enabled": true, + "dangerous": false + }, + { + "name": "Sleep", + "icon": "bedtime", + "description": "Suspend then hibernate", + "command": ["systemctl", "suspend-then-hibernate"], + "enabled": true, + "dangerous": false + }, + { + "name": "Settings", + "icon": "settings", + "description": "Configure the shell", + "command": ["caelestia", "shell", "controlCenter", "open"], + "enabled": true, + "dangerous": false + } + ], + "dragThreshold": 50, + "vimKeybinds": false, + "enableDangerousActions": false, + "maxShown": 7, + "maxWallpapers": 9, + "specialPrefix": "@", + "useFuzzy": { + "apps": false, + "actions": false, + "schemes": false, + "variants": false, + "wallpapers": false + }, + "showOnHover": false, + "favouriteApps": [], + "hiddenApps": [] + }, + "lock": { + "recolourLogo": false + }, + "notifs": { + "actionOnClick": false, + "clearThreshold": 0.3, + "defaultExpireTimeout": 5000, + "expandThreshold": 20, + "openExpanded": false, + "expire": false + }, + "osd": { + "enabled": true, + "enableBrightness": true, + "enableMicrophone": false, + "hideDelay": 2000 + }, + "paths": { + "mediaGif": "root:/assets/bongocat.gif", + "sessionGif": "root:/assets/kurukuru.gif", + "wallpaperDir": "~/Pictures/Wallpapers" + }, + "services": { + "audioIncrement": 0.1, + "brightnessIncrement": 0.1, + "maxVolume": 1.0, + "defaultPlayer": "Spotify", + "gpuType": "", + "playerAliases": [{ "from": "com.github.th_ch.youtube_music", "to": "YT Music" }], + "weatherLocation": "", + "useFahrenheit": false, + "useFahrenheitPerformance": false, + "useTwelveHourClock": false, + "smartScheme": true, + "visualiserBars": 45 + }, + "session": { + "dragThreshold": 30, + "enabled": true, + "vimKeybinds": false, + "icons": { + "logout": "logout", + "shutdown": "power_settings_new", + "hibernate": "downloading", + "reboot": "cached" + }, + "commands": { + "logout": ["loginctl", "terminate-user", ""], + "shutdown": ["systemctl", "poweroff"], + "hibernate": ["systemctl", "hibernate"], + "reboot": ["systemctl", "reboot"] + } + }, + "sidebar": { + "dragThreshold": 80, + "enabled": true + }, + "utilities": { + "enabled": true, + "maxToasts": 4, + "toasts": { + "audioInputChanged": true, + "audioOutputChanged": true, + "capsLockChanged": true, + "chargingChanged": true, + "configLoaded": true, + "dndChanged": true, + "gameModeChanged": true, + "kbLayoutChanged": true, + "kbLimit": true, + "numLockChanged": true, + "vpnChanged": true, + "nowPlaying": false + }, + "vpn": { + "enabled": true, + "provider": [ + { + "name": "wireguard", + "interface": "your-connection-name", + "displayName": "Wireguard (Your VPN)", + "enabled": false + } + ] + } + } +} +``` + +
+ +### Home Manager Module + +For NixOS users, a home manager module is also available. + +
home.nix + +```nix +programs.caelestia = { + enable = true; + systemd = { + enable = false; # if you prefer starting from your compositor + target = "graphical-session.target"; + environment = []; + }; + settings = { + bar.status = { + showBattery = false; + }; + paths.wallpaperDir = "~/Images"; + }; + cli = { + enable = true; # Also add caelestia-cli to path + settings = { + theme.enableGtk = false; + }; + }; +}; +``` + +The module automatically adds Caelestia shell to the path with **full functionality**. The CLI is not required, however you have the option to enable and configure it. + +
+ +## FAQ + +### Need help or support? + +You can join the community Discord server for assistance and discussion: +https://discord.gg/BGDCFCmMBk + +### My screen is flickering, help pls! + +Try disabling VRR in the hyprland config. You can do this by adding the following to `~/.config/caelestia/hypr-user.conf`: + +```conf +misc { + vrr = 0 +} +``` + +### I want to make my own changes to the hyprland config! + +You can add your custom hyprland configs to `~/.config/caelestia/hypr-user.conf`. + +### I want to make my own changes to other stuff! + +See the [manual installation](https://github.com/caelestia-dots/shell?tab=readme-ov-file#manual-installation) section +for the corresponding repo. + +### I want to disable XXX feature! + +Please read the [configuring](https://github.com/caelestia-dots/shell?tab=readme-ov-file#configuring) section in the readme. +If there is no corresponding option, make feature request. + +### How do I make my colour scheme change with my wallpaper? + +Set a wallpaper via the launcher or `caelestia wallpaper` and set the scheme to the dynamic scheme via the launcher +or `caelestia scheme set`. e.g. + +```sh +caelestia wallpaper -f +caelestia scheme set -n dynamic +``` + +### My wallpapers aren't showing up in the launcher! + +The launcher pulls wallpapers from `~/Pictures/Wallpapers` by default. You can change this in the config. Additionally, +the launcher only shows an odd number of wallpapers at one time. If you only have 2 wallpapers, consider getting more +(or just putting one). + +## Credits + +Thanks to the Hyprland discord community (especially the homies in #rice-discussion) for all the help and suggestions +for improving these dots! + +A special thanks to [@outfoxxed](https://github.com/outfoxxed) for making Quickshell and the effort put into fixing issues +and implementing various feature requests. + +Another special thanks to [@end_4](https://github.com/end-4) for his [config](https://github.com/end-4/dots-hyprland) +which helped me a lot with learning how to use Quickshell. + +Finally another thank you to all the configs I took inspiration from (only one for now): + +- [Axenide/Ax-Shell](https://github.com/Axenide/Ax-Shell) + +## Stonks 📈 + + + + + + Star History Chart + + diff --git a/.config/quickshell/caelestia/assets/bongocat.gif b/.config/quickshell/caelestia/assets/bongocat.gif new file mode 100644 index 0000000000000000000000000000000000000000..f960fecd7d91c028506ddf7a7ace5bcb84c473bd GIT binary patch literal 7350 zcmcha*IUy|w6K5aAt8`Z0t663ml{d{3mQu3U?@_g7^*Ze6a^I70YV22NRwvhMK;oG zh#HU%V(3`521LPzh=6@_*x&R01Lx+vYt76vS2GuD=2@?mjis@X-w2Qdd;|Ui3iP(MMXs=B_%aARaI3r4Gj&=J#=(*v~@^2ByC+?eSL#HjE#&9jg1c-Iz%x! zVseynJ0AtB-65fR}Lj5CZg(NQrmv2pS7aS8E>iHVJHLJeHDP>5KDQB0FiZAB@! zqLsTb8h1q0dxdn1RgLPE$dAxkqsaXeD9r(!_FqZN^dx3#YHDUiW=>8{Zcgsy%k0Z+ zcHx!6(vrO>EiW&xsHnJhjZ?+p)YjJ4)zvjNHa0ajwYIk2Xm7vK(cab7y~pi4|Iypq z`>UvYr?m2GMb&C~!-w+Pe+#R(Dr&bYYd6d4x6A5&?`1{vv)ZPox9+Y~H+-n6U#V;P zSkv;puK9i4_2rhp9vvMX86Th6V|rp@ew;TwIW@!M&CJX$E-XHO{`|%B z7w-m!SBFMEjZc0ZoY)?ocs(__HaWHPc;@~5;?B(C*0UEspTB&?fAwMI<*Qfx*RPhg zU%mbH&+^L3%6mS4b?v`+xB6~%ZSCX7kH41Re1E&Ty}I`M&4=yx@Be)G^!ww-ZyTR} zd|ChWdE@ivjjx|J|Ez!c^XcompF5v+e{F4T{rS4}XKQQw&(5!3JHLPJeEar&=i86p zJ3s&I{M`Qc_x8Vkc6WFGUrGMoO~hTaBh}T#+>}Pu(rEuCTn3 z=s<+QWJR{D-L2NAr9E|>3_5vj{u%*oJW??J)F5JJeR9_FbXgZk*fPw3CoAh_>~Orvay)$hsvY$juq%JUVj;Hlg-7{BifzXMV}#Zg&G3 zZpR_`Nt)yt^=^3vo`2CE1wl%Z#ZL4y3++m@ojI+mFPZ)cesf+hhXy)SH?Vq0wdaK; zpJnKf3bT@VCuZ&;W=M9BtR&tkN^w`__F;rlrqTXcXV(-WyN<&uG7ZjKD%c4#N#^*7 z%mVwIf&Jthi~`OykENqWc2NhCK}^IU;cZ|{@|U%I-@jIwI!ZZp5B+bvcc6}+Y3 z66bcQs8l=bJEzaGbKdhh)&0*oaWhR^u(`_1ZS~XkpSJ6Bq&jYit6TbndWzV2(PCa0 zG$?f<+&o*ucnmA2Jkcw%>`03yH0hRM{)zpk7={aM8p z5xnVe{Z)f44-8XC_H($dSRR}w(Rpw^!A^G3gh;*{XqGOl#^NO-NkGS_KO1UzYqiEP zmCcB>C96~q)IM=P^JjZlNJXS+G45FH zj>+1x`^m09Z~y#Q%W^d@Dh)Tc6?|K(bJV;(yUqpdE#Ef#hHb(5_N@EHs? zn&Av->EYmVg+TluM83Xf8&F`I{dM2gQYDje*T2#}#dFFR`See6}7EilnOTQgGQ0?Mo;%?j<^WT3mK zxW9GMx5H&TB6)Il~4mb(u_9G^9q|zuK=yoqc(b$y|q=Y zm!|F$!66P=Z|zIrBiJsRgf(p26K9Xk=3=Sm(5wDIR0~f|FSp*Op;HL3NaN8+X5rC zmY9T1=NXAlX&A)o58vLG0Fd^js#*Ddw6b(Rz@Ws6K7K25Acs>N0;s%-8dB+GfOl_p zS%4_XwrK>>irwy_ZbfB5LG9$@4aTWrq3xzENdjIV-!|DAz`Qqm|g4~vey!4ROaun;1n7EVPy?K#6yxg=u#25Maj{c{5(Y=i;;T$sHbccD+OsZ z^lE&kX%-jL%NBsVPZw+b^gi#B_p>%2SJ0FkY$dIa$x&e>d#ZuFf~jxv_nn6Na;O0U z26qvod3{1&RHUujqp2Egj5Uq8G(^f;TPVUcCEu!X8`I)pQ=tZD zyMxyw?C=zj;P(??Sy2Pi-!}nbgz>z0m5p;`2TTZhCf@CbSR>?V0U=O<5RY4k52=RB zU_CB?Buxb_vp#;NKaz@Q0!6Lns)&SAZhU;3?I?CZDTHD!S%;H|Du`Cn`!0M4zSyUI z=I&~ANm}u`Mt}PR>%+P6rvOpS3={x<8h@0fOd5fOHTa<^N@l{BLjtuN7EdX}&VkPC zmZm#nUJ_4n{SaD8_UYN;AUSTeMCPSYwZ@BI4uc=FpM|8!LvcvA0i|5I##F^HKZ3P2 z2ax@4(dVgM>D61^6jce5v`ysJe|!-FD(!1A^qmSdNR@ibOV^OUI(DGDKd6gz4CCf_ zHdI_jNHcv0?+?zg(gcflRls$70x%(Jsgh$%6|Gk^us~qSw0GNuj74@_VBSh+9nxYD zOhkJ^mxVYt%+(8%Cs9ic<0B+6j{_de`JkilE82%jO-Eb#$A24NaQ~colq?-%q7HRu+j;e}9`NdsxkIk6Z z^w$z8)&sJWH#1LmBMuwha|A2Vf1PRhy-j|X)avjx9rbM{M>9Z_M?+r+&|^I7^?Zps zK17ytNRbZf!fJ&YfMxPww$Jf}yFHOmRS%2Cmlt9{Y=}&>Ou&-f{b`BZIIAeKh!E{BQWGYu-IF&DYI@^zKUV4Y5Ny#;K@kAs z8& zS#3s(wF8EvPz8NV1Q6m#Ru~os&?K;03i&!X^=iAn0#QVI7i>7WlkDSc$fQC8*#dXl zlbtM5w46MDE~Q-}Cl;tF1c{!;Q6SzFV*#>L<+4un5~NH`mev8WdhP$XK!reqP?_*@ zHu~oRQQZnvPRczQpwkc~P^h2EHgm3@1{rZ-XK2Q?qO12YNgDB98p2VE}SJ9V>&a^c-#J?A|N#yG_+lSg1=ljow+*VPCKiv z#)r@WfwUO>#eB3c1?p^-H?u70-joZ+yFJV|aO1!^>?{N{E>;8}@Em-KjVCEN7^4uO z3@bth;2Ly%6bp}VN`JUWyw5R8&MaWADKNf^ zO{jwp>Rz!?xO}>!aOgO2ZCmdy1KmYJ-v_dl0`zK)LkQKNYrwt>$%54!xCH75m7LAORjF;3=P?d>?JsvU;ey@#tY2F4UP%BJ-K_BhJ`)TzFV2z4|UzB+z5hBH2ZE-tKw>^w$fBBdC=K+Rr&pgamk0B={`G8 zO}_8_pP>J}Lda7n9P1mtR3sLO1#16Oh?Z9C=#?zmw0~H+P1jp{J){`hdru*b6)B}E z#D7U!ms1fgmJL#vKtQ$|#?-iD`eTg0tNW*1MwZ6xn7e_~0tF8BT9hk|&YagZ* zTtUiE!1!tf9HreKR5Gyct_0A$o6hLaT-qozr`t z&F~dsx`}2BA>;Y!z9e_=TKv;CuP|x7l5=-i9R!AE;I#^ zpP{)t9#IoP2`_g#{DrlKnQGReDn%AP>k#cFSx7M$dSlqpt89bQOY6#yB@lJgZq~U8yaYheREhf_R4vV> ze-f6bsl|mYZXVXhrNRxewR^e8;o-HWZP82&niTIS%~_L1v*x2r3COhjTV|Lr6U=;DZ=smYjW&l z@lwcmH)|OLktqj1pz)%n10_sJrE%Puv~(~}>QpJ^oGTyBc*>TDluSV)Dc8J4>OwSU zOYt4;QgH{xP6V|B-biLz_(mh)ZH1{$=TvSuzeXsN14)iQZ>&QNz-Y>I1?n=%UB-}$ zxiVhx+;7tfU(DcyzG8Ij@jN-U1>$4=kbbf5l}F7f*hD@=;a`6Csfhs$775_l&c*sG zx+WlAva!+YTv~TBLNGHY4hw)pRw#m{%tGq8dtM`?Z`jS?OOuT)WSz~sM;8FI=2aDD%qPw11(8J%sD*c|iM!9N`gPmCh zO4Yr_V(+lc?8j;?bN$J&+OZXf>}e0om^bRed%ADVfQWCw#6rK@7e3jQ$q!}K%ijJ~DX3N=bu;C~&NN&$auVslY%|YoXQ_l- zez2{Kg9>{7^Z7m{Gx|bUv~>j>x)l zDfbQT+#A46EhXn(#T)X!K-#lAX&A$aAU)OgT@5G_j8a@F3vXQl&7Y0A{IJEbd}|ru z71>o~Mb;Sm$AwTj0-S@IggE4ffCJ8ZV|-oL zXz0@$O%YM#oet5v3I)#q5zq20yZtJ8PVq}H3@7qjqsi6lYFw24-z|m}eObCATzXDb zeR*066M-~6^Y@W@gUx75tr7XQtG$~!PO<pWviy<2`@yQ2z zt~aRxQt@Y+apGb~C=q|YdFWR711VN`fEbm&PI!J++>glLYayZO&#`NEb9!iv;PZnO zpbVL{@O;mDacB~NxN|_GQ1;sRaeJC?$F)s-B*!!bbQi#)uiO*=H4OQF?Om1(1*E~n|Pre`)w@F!hPn8*_D>?zcI5u zTb=oE9YfmrLT@VcwDIASk*2>|5cKqRoxGBeq4@QD*7_55&p8|k;x2elP=Dx>@Vp-LO)pMI~CCK{%mVSiNz@(AR zBn?iOi`G~MpWq5C1>wUf2_v^avL45K>JHxMgZ-ISm!^RC0ZEz^LP!3wIX?WNi@y&8 zZWa#@V#2gZ3JZE-B&X=a1`?^#XGf*khBIN4w66>t_Sp^;Cv7$h=y^G!L)MZKLnAVVKGx| zO!Wqc&j z0tveqK#J!3mny~=khp6KI2$|kl2A>nwCgp5oIZ%n6xu@^0K<(xDu=p51e35x78Y4Z z67;CG^X36^fM{Sork6{Ov{paNNMSC;PPW5!__9z2h)jo_;t2FI6PCdjYdHcHT!9aw zsJR-Tn1gx1L9!?a79hB=fof!++US=J2YsJ0$iIpOPm%To(Zt0XC(?SN{9^g}O+z=RdpfD1XnhGR$f85hYMXgss3`1K)oFw+DHvQQVhy~39y|B5;G07?3$Uk0ZWR| zO9~kwQG$BxLo093KEL^wC-3M>lTcC3QGpTD$_!fx#4NCn;ZLez7Fr}09Bf|i^pU1O kJmRlaWjAFxw=|WtwDh#JK5J?F+0st9-q~_$&!`Ul57_51f&c&j literal 0 HcmV?d00001 diff --git a/.config/quickshell/caelestia/assets/dino.png b/.config/quickshell/caelestia/assets/dino.png new file mode 100644 index 0000000000000000000000000000000000000000..b5bc7bb3bb76e96fec17939f8256f898ff330786 GIT binary patch literal 9441 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 KVd#zwz5fGU95{Ob literal 0 HcmV?d00001 diff --git a/.config/quickshell/caelestia/assets/logo.svg b/.config/quickshell/caelestia/assets/logo.svg new file mode 100644 index 0000000..6879c92 --- /dev/null +++ b/.config/quickshell/caelestia/assets/logo.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + diff --git a/.config/quickshell/caelestia/assets/pam.d/fprint b/.config/quickshell/caelestia/assets/pam.d/fprint new file mode 100644 index 0000000..d4814e9 --- /dev/null +++ b/.config/quickshell/caelestia/assets/pam.d/fprint @@ -0,0 +1,3 @@ +#%PAM-1.0 + +auth required pam_fprintd.so max-tries=1 diff --git a/.config/quickshell/caelestia/assets/pam.d/passwd b/.config/quickshell/caelestia/assets/pam.d/passwd new file mode 100644 index 0000000..4b14064 --- /dev/null +++ b/.config/quickshell/caelestia/assets/pam.d/passwd @@ -0,0 +1,6 @@ +#%PAM-1.0 + +auth required pam_faillock.so preauth +auth [success=1 default=bad] pam_unix.so nullok +auth [default=die] pam_faillock.so authfail +auth required pam_faillock.so authsucc diff --git a/.config/quickshell/caelestia/assets/shaders/opacitymask.frag b/.config/quickshell/caelestia/assets/shaders/opacitymask.frag new file mode 100644 index 0000000..94a80b8 --- /dev/null +++ b/.config/quickshell/caelestia/assets/shaders/opacitymask.frag @@ -0,0 +1,19 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + // qt_Matrix and qt_Opacity must always be both present + // if the built-in vertex shader is used. + mat4 qt_Matrix; + float qt_Opacity; +}; + +layout(binding = 1) uniform sampler2D source; +layout(binding = 2) uniform sampler2D maskSource; + +void main() +{ + fragColor = texture(source, qt_TexCoord0.st) * (texture(maskSource, qt_TexCoord0.st).a) * qt_Opacity; +} diff --git a/.config/quickshell/caelestia/assets/shaders/opacitymask.frag.qsb b/.config/quickshell/caelestia/assets/shaders/opacitymask.frag.qsb new file mode 100644 index 0000000000000000000000000000000000000000..7bf97c280f5b98e09f7e83c6dc2c678d7901e9ec GIT binary patch literal 1337 zcmV-91;+XS01%LPoZVM#Pa8)N9@`KXLtdaHAx%gwp^fYoxyEs-s1Aq<(l$~e+8Cvk zEOa`~XLG^6bME$tQN&;9$Nq+X>Hq7Os-4-L^R3S|L8>ZMJ#_eH_L*m9pPk*a0bmXQ zX7JA7y#jARfC>BHzyNl@$G-qtP{FY*-tZS+FySJCC1_)S1sxgOmEns1gQ1t;5F!kx zClemQ20ra-n5?8%^}WOt0;yfB5@4PY+Zy^>{IJX+d(g)q8$$$~a?0(vwrLmTT!0X# z5n(nPRRJjSBr=l%mZ67PLO6!T#GveX*)Dor;?Gv%%KethuH~tydH4t(vUd^lQJM1? zLZ9EgXuK$gqE)UvrWJ)NkdrtXy9#-!1>HT%^~gUbIY`W$^yi5KpU8igbC7)*KkqY7 zY(LP(7gP9U#%DD z9M4Hr==ladk=O>_HxZv_@n@uO29*YhC4ZgmIriPcrvl^CtrFX}5lPKkV7>+R&odv{ zm)S@8uQFej@z)?;JB25Ek$rLeGRI#>dxhsh*B5Nx;(AxmzQc2&`Q2sh?{H4acb9Xo zGC$e(*hl;Z^JkdffTS-d{sCi&?<-uREF}AnYWM>^w9cF8B@M3d{5N^-OFX}y5S5o} zrZ7ud%yph~9CITTbCWUT{}Fvu%O~uo8h&BiZRV%3Z_r1zukn2EGe5w!A`bN9!TcSSZc0F_! zLJ>r^Fb<=3;eEltt7nOt@m82GEfKhby7Wl~a_;pl+ZCtv!Wo7}p4;|=9>p5wqYcfY z5`D3u6IFkhcTM2A5!(7 zX-darHPJLDY}BCb1X7Bxjlk)+p>TrYVI{6H@ZXs|>kZZ@wX6+ll)@b9j8T~C*l)K( zM-=T!Nf(}xTucgDE2-7kkK5&`%CN=S>-7lYZKx$^2unDIsX!*Liw+J6JkFX3H^RIz z#+(2rvQq$dpCw$IHPIJe9~f%^?%Bo<&tJVZcLF~Q&F5Y}5^+C_2Vv&@XFu=k?Y-Kq zD7hwZ>_s9)qLqXUjo0SB6?7cI6tWWuU`}sGC2v_NQ%tEn-kphN!;ojSxW9Be@^MR2C? zNBYXLknG3o?`y7SccYeLJncEc>YDf!yXziq6%v2w_F7-kzw*%*9$X=v<(}1ZLKM(3 zWYna$_;B}L=!E2OsFj1R3UNPmecMaIiMr=_T59!F zj0y2u3P#4OdT_9A*uICRCnx)m+6l+isV2)>AHI)T>L?hVFU@9rrcS|WCq{zZkl6TO zP*e>xNDTHeUyMm;(m3KO4PRgJgz4Ti-k+%j@>4w)?@Yx})CyQfZOZ3tOpZvEGafbh vMWQvdulkr8c~+LqZ/dev/null + +exec "$@" diff --git a/.config/quickshell/caelestia/components/Anim.qml b/.config/quickshell/caelestia/components/Anim.qml new file mode 100644 index 0000000..6883a79 --- /dev/null +++ b/.config/quickshell/caelestia/components/Anim.qml @@ -0,0 +1,8 @@ +import qs.config +import QtQuick + +NumberAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard +} diff --git a/.config/quickshell/caelestia/components/CAnim.qml b/.config/quickshell/caelestia/components/CAnim.qml new file mode 100644 index 0000000..49484b7 --- /dev/null +++ b/.config/quickshell/caelestia/components/CAnim.qml @@ -0,0 +1,8 @@ +import qs.config +import QtQuick + +ColorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard +} diff --git a/.config/quickshell/caelestia/components/ConnectionHeader.qml b/.config/quickshell/caelestia/components/ConnectionHeader.qml new file mode 100644 index 0000000..12b4276 --- /dev/null +++ b/.config/quickshell/caelestia/components/ConnectionHeader.qml @@ -0,0 +1,31 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property string icon + required property string title + + spacing: Appearance.spacing.normal + Layout.alignment: Qt.AlignHCenter + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + animate: true + text: root.icon + font.pointSize: Appearance.font.size.extraLarge * 3 + font.bold: true + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + animate: true + text: root.title + font.pointSize: Appearance.font.size.large + font.bold: true + } +} diff --git a/.config/quickshell/caelestia/components/ConnectionInfoSection.qml b/.config/quickshell/caelestia/components/ConnectionInfoSection.qml new file mode 100644 index 0000000..927ef28 --- /dev/null +++ b/.config/quickshell/caelestia/components/ConnectionInfoSection.qml @@ -0,0 +1,59 @@ +import qs.components +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property var deviceDetails + + spacing: Appearance.spacing.small / 2 + + StyledText { + text: qsTr("IP Address") + } + + StyledText { + text: root.deviceDetails?.ipAddress || qsTr("Not available") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Subnet Mask") + } + + StyledText { + text: root.deviceDetails?.subnet || qsTr("Not available") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Gateway") + } + + StyledText { + text: root.deviceDetails?.gateway || qsTr("Not available") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("DNS Servers") + } + + StyledText { + text: (root.deviceDetails && root.deviceDetails.dns && root.deviceDetails.dns.length > 0) ? root.deviceDetails.dns.join(", ") : qsTr("Not available") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + wrapMode: Text.Wrap + Layout.maximumWidth: parent.width + } +} diff --git a/.config/quickshell/caelestia/components/Logo.qml b/.config/quickshell/caelestia/components/Logo.qml new file mode 100644 index 0000000..3ab4f2b --- /dev/null +++ b/.config/quickshell/caelestia/components/Logo.qml @@ -0,0 +1,69 @@ +import QtQuick +import QtQuick.Shapes +import qs.services + +Item { + id: root + implicitWidth: designWidth + implicitHeight: designHeight + + readonly property real designWidth: 128 + readonly property real designHeight: 90.38 + + property color topColour: Colours.palette.m3primary + property color bottomColour: Colours.palette.m3onSurface + + Shape { + anchors.centerIn: parent + width: root.designWidth + height: root.designHeight + scale: Math.min(root.width / width, root.height / height) + transformOrigin: Item.Center + preferredRendererType: Shape.CurveRenderer + + ShapePath { + fillColor: root.topColour + strokeColor: "transparent" + + PathSvg { + path: "m42.56,42.96c-7.76,1.6-16.36,4.22-22.44,6.22-.49.16-.88-.44-.53-.82,5.37-5.85,9.66-13.3,9.66-13.3,8.66-14.67,22.97-23.51,39.85-21.14,6.47.91,12.33,3.38,17.26,6.98.99.72,1.14,2.14.31,3.04-.4.44-.95.67-1.51.67-.34,0-.69-.09-1-.26-3.21-1.84-6.82-2.69-10.71-3.24-13.1-1.84-25.41,4.75-31.06,15.83-.94,1.84-.61,3.81.45,5.21.22.3.07.72-.29.8Z" + } + } + + ShapePath { + fillColor: root.bottomColour + strokeColor: "transparent" + + PathSvg { + path: "m103.02,51.8c-.65.11-1.26-.37-1.28-1.03-.06-1.96.15-3.89-.2-5.78-.28-1.48-1.66-2.5-3.16-2.34h-.05c-6.53.73-24.63,3.1-48,9.32-6.89,1.83-9.83,10-5.67,15.79,4.62,6.44,11.84,10.93,20.41,12.13,11.82,1.66,22.99-3.36,29.21-12.65.54-.81,1.54-1.17,2.47-.86.91.3,1.47,1.15,1.47,2.04,0,.33-.08.66-.24.98-7.23,14.21-22.91,22.95-39.59,20.6-7.84-1.1-14.8-4.5-20.28-9.43,0,0,0,0-.02-.01-7.28-5.14-14.7-9.99-27.24-11.98-18.82-2.98-9.53-8.75.46-13.78,7.36-3.13,25.17-7.9,36.24-10.73.16-.03.31-.06.47-.1,1.52-.4,3.2-.83,5.02-1.29,1.06-.26,1.93-.48,2.58-.64.09-.02.18-.04.26-.06.31-.08.56-.14.73-.18.03,0,.06-.01.08-.02.03,0,.05-.01.07-.02.02,0,.04,0,.06-.01.01,0,.03,0,.04-.01,0,0,.02,0,.03,0,.01,0,.02,0,.02,0,10.62-2.58,24.63-5.62,37.74-7.34,1.02-.13,2.03-.26,3.03-.37,7.49-.87,14.58-1.26,20.42-.81,25.43,1.95-4.71,16.77-15.12,18.61Z" + } + } + + ShapePath { + fillColor: root.topColour + strokeColor: "transparent" + + PathSvg { + path: "m98.12.06c-.29,2.08-1.72,8.42-8.36,9.19-.09,0-.09.13,0,.14,6.64.78,8.07,7.11,8.36,9.19.01.08.13.08.14,0,.29-2.08,1.72-8.42,8.36-9.19.09,0,.09-.13,0-.14-6.64-.78-8.07-7.11-8.36-9.19-.01-.08-.13-.08-.14,0Z" + } + } + + ShapePath { + fillColor: root.topColour + strokeColor: "transparent" + + PathSvg { + path: "m113.36,15.5c-.22,1.29-1.08,4.35-4.38,4.87-.08.01-.08.13,0,.14,3.3.52,4.17,3.58,4.38,4.87.01.08.13.08.14,0,.22-1.29,1.08-4.35,4.38-4.87.08-.01.08-.13,0-.14-3.3-.52-4.17-3.58-4.38-4.87-.01-.08-.13-.08-.14,0Z" + } + } + + ShapePath { + fillColor: root.topColour + strokeColor: "transparent" + + PathSvg { + path: "m112.69,65.22c-.19,1.01-.86,3.15-3.2,3.57-.08.01-.08.13,0,.14,2.34.42,3.01,2.56,3.2,3.57.01.08.13.08.14,0,.19-1.01.86-3.15,3.2-3.57.08-.01.08-.13,0-.14-2.34-.42-3.01-2.56-3.2-3.57-.01-.08-.13-.08-.14,0Z" + } + } + } +} diff --git a/.config/quickshell/caelestia/components/MaterialIcon.qml b/.config/quickshell/caelestia/components/MaterialIcon.qml new file mode 100644 index 0000000..a1d19d3 --- /dev/null +++ b/.config/quickshell/caelestia/components/MaterialIcon.qml @@ -0,0 +1,16 @@ +import qs.services +import qs.config + +StyledText { + property real fill + property int grade: Colours.light ? 0 : -25 + + font.family: Appearance.font.family.material + font.pointSize: Appearance.font.size.larger + font.variableAxes: ({ + FILL: fill.toFixed(1), + GRAD: grade, + opsz: fontInfo.pixelSize, + wght: fontInfo.weight + }) +} diff --git a/.config/quickshell/caelestia/components/PropertyRow.qml b/.config/quickshell/caelestia/components/PropertyRow.qml new file mode 100644 index 0000000..640d5f7 --- /dev/null +++ b/.config/quickshell/caelestia/components/PropertyRow.qml @@ -0,0 +1,26 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property string label + required property string value + property bool showTopMargin: false + + spacing: Appearance.spacing.small / 2 + + StyledText { + Layout.topMargin: root.showTopMargin ? Appearance.spacing.normal : 0 + text: root.label + } + + StyledText { + text: root.value + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } +} diff --git a/.config/quickshell/caelestia/components/SectionContainer.qml b/.config/quickshell/caelestia/components/SectionContainer.qml new file mode 100644 index 0000000..2b653a5 --- /dev/null +++ b/.config/quickshell/caelestia/components/SectionContainer.qml @@ -0,0 +1,32 @@ +import qs.components +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + default property alias content: contentColumn.data + property real contentSpacing: Appearance.spacing.larger + property bool alignTop: false + + Layout.fillWidth: true + implicitHeight: contentColumn.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.transparency.enabled ? Colours.layer(Colours.palette.m3surfaceContainer, 2) : Colours.palette.m3surfaceContainerHigh + + ColumnLayout { + id: contentColumn + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: root.alignTop ? parent.top : undefined + anchors.verticalCenter: root.alignTop ? undefined : parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: root.contentSpacing + } +} diff --git a/.config/quickshell/caelestia/components/SectionHeader.qml b/.config/quickshell/caelestia/components/SectionHeader.qml new file mode 100644 index 0000000..502e918 --- /dev/null +++ b/.config/quickshell/caelestia/components/SectionHeader.qml @@ -0,0 +1,27 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property string title + property string description: "" + + spacing: 0 + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: root.title + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + visible: root.description !== "" + text: root.description + color: Colours.palette.m3outline + } +} diff --git a/.config/quickshell/caelestia/components/StateLayer.qml b/.config/quickshell/caelestia/components/StateLayer.qml new file mode 100644 index 0000000..a20e266 --- /dev/null +++ b/.config/quickshell/caelestia/components/StateLayer.qml @@ -0,0 +1,95 @@ +import qs.services +import qs.config +import QtQuick + +MouseArea { + id: root + + property bool disabled + property bool showHoverBackground: true + property color color: Colours.palette.m3onSurface + property real radius: parent?.radius ?? 0 + property alias rect: hoverLayer + + function onClicked(): void { + } + + anchors.fill: parent + + enabled: !disabled + cursorShape: disabled ? undefined : Qt.PointingHandCursor + hoverEnabled: true + + onPressed: event => { + if (disabled) + return; + + rippleAnim.x = event.x; + rippleAnim.y = event.y; + + const dist = (ox, oy) => ox * ox + oy * oy; + rippleAnim.radius = Math.sqrt(Math.max(dist(event.x, event.y), dist(event.x, height - event.y), dist(width - event.x, event.y), dist(width - event.x, height - event.y))); + + rippleAnim.restart(); + } + + onClicked: event => !disabled && onClicked(event) + + SequentialAnimation { + id: rippleAnim + + property real x + property real y + property real radius + + PropertyAction { + target: ripple + property: "x" + value: rippleAnim.x + } + PropertyAction { + target: ripple + property: "y" + value: rippleAnim.y + } + PropertyAction { + target: ripple + property: "opacity" + value: 0.08 + } + Anim { + target: ripple + properties: "implicitWidth,implicitHeight" + from: 0 + to: rippleAnim.radius * 2 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + target: ripple + property: "opacity" + to: 0 + } + } + + StyledClippingRect { + id: hoverLayer + + anchors.fill: parent + + color: Qt.alpha(root.color, root.disabled ? 0 : root.pressed ? 0.12 : (root.showHoverBackground && root.containsMouse) ? 0.08 : 0) + radius: root.radius + + StyledRect { + id: ripple + + radius: Appearance.rounding.full + color: root.color + opacity: 0 + + transform: Translate { + x: -ripple.width / 2 + y: -ripple.height / 2 + } + } + } +} diff --git a/.config/quickshell/caelestia/components/StyledClippingRect.qml b/.config/quickshell/caelestia/components/StyledClippingRect.qml new file mode 100644 index 0000000..8f2630c --- /dev/null +++ b/.config/quickshell/caelestia/components/StyledClippingRect.qml @@ -0,0 +1,12 @@ +import Quickshell.Widgets +import QtQuick + +ClippingRectangle { + id: root + + color: "transparent" + + Behavior on color { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/components/StyledRect.qml b/.config/quickshell/caelestia/components/StyledRect.qml new file mode 100644 index 0000000..f5d5143 --- /dev/null +++ b/.config/quickshell/caelestia/components/StyledRect.qml @@ -0,0 +1,11 @@ +import QtQuick + +Rectangle { + id: root + + color: "transparent" + + Behavior on color { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/components/StyledText.qml b/.config/quickshell/caelestia/components/StyledText.qml new file mode 100644 index 0000000..ed961d2 --- /dev/null +++ b/.config/quickshell/caelestia/components/StyledText.qml @@ -0,0 +1,48 @@ +pragma ComponentBehavior: Bound + +import qs.services +import qs.config +import QtQuick + +Text { + id: root + + property bool animate: false + property string animateProp: "scale" + property real animateFrom: 0 + property real animateTo: 1 + property int animateDuration: Appearance.anim.durations.normal + + renderType: Text.NativeRendering + textFormat: Text.PlainText + color: Colours.palette.m3onSurface + font.family: Appearance.font.family.sans + font.pointSize: Appearance.font.size.smaller + + Behavior on color { + CAnim {} + } + + Behavior on text { + enabled: root.animate + + SequentialAnimation { + Anim { + to: root.animateFrom + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + PropertyAction {} + Anim { + to: root.animateTo + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + } + + component Anim: NumberAnimation { + target: root + property: root.animateProp + duration: root.animateDuration / 2 + easing.type: Easing.BezierSpline + } +} diff --git a/.config/quickshell/caelestia/components/containers/StyledFlickable.qml b/.config/quickshell/caelestia/components/containers/StyledFlickable.qml new file mode 100644 index 0000000..bc6ae0f --- /dev/null +++ b/.config/quickshell/caelestia/components/containers/StyledFlickable.qml @@ -0,0 +1,14 @@ +import ".." +import QtQuick + +Flickable { + id: root + + maximumFlickVelocity: 3000 + + rebound: Transition { + Anim { + properties: "x,y" + } + } +} diff --git a/.config/quickshell/caelestia/components/containers/StyledListView.qml b/.config/quickshell/caelestia/components/containers/StyledListView.qml new file mode 100644 index 0000000..626d206 --- /dev/null +++ b/.config/quickshell/caelestia/components/containers/StyledListView.qml @@ -0,0 +1,14 @@ +import ".." +import QtQuick + +ListView { + id: root + + maximumFlickVelocity: 3000 + + rebound: Transition { + Anim { + properties: "x,y" + } + } +} diff --git a/.config/quickshell/caelestia/components/containers/StyledWindow.qml b/.config/quickshell/caelestia/components/containers/StyledWindow.qml new file mode 100644 index 0000000..8c6e39f --- /dev/null +++ b/.config/quickshell/caelestia/components/containers/StyledWindow.qml @@ -0,0 +1,9 @@ +import Quickshell +import Quickshell.Wayland + +PanelWindow { + required property string name + + WlrLayershell.namespace: `caelestia-${name}` + color: "transparent" +} diff --git a/.config/quickshell/caelestia/components/controls/CircularIndicator.qml b/.config/quickshell/caelestia/components/controls/CircularIndicator.qml new file mode 100644 index 0000000..957899e --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/CircularIndicator.qml @@ -0,0 +1,108 @@ +import ".." +import qs.services +import qs.config +import Caelestia.Internal +import QtQuick +import QtQuick.Templates + +BusyIndicator { + id: root + + enum AnimType { + Advance = 0, + Retreat + } + + enum AnimState { + Stopped, + Running, + Completing + } + + property real implicitSize: Appearance.font.size.normal * 3 + property real strokeWidth: Appearance.padding.small * 0.8 + property color fgColour: Colours.palette.m3primary + property color bgColour: Colours.palette.m3secondaryContainer + + property alias type: manager.indeterminateAnimationType + readonly property alias progress: manager.progress + + property real internalStrokeWidth: strokeWidth + property int animState + + padding: 0 + implicitWidth: implicitSize + implicitHeight: implicitSize + + Component.onCompleted: { + if (running) { + running = false; + running = true; + } + } + + onRunningChanged: { + if (running) { + manager.completeEndProgress = 0; + animState = CircularIndicator.Running; + } else { + if (animState == CircularIndicator.Running) + animState = CircularIndicator.Completing; + } + } + + states: State { + name: "stopped" + when: !root.running + + PropertyChanges { + root.opacity: 0 + root.internalStrokeWidth: root.strokeWidth / 3 + } + } + + transitions: Transition { + Anim { + properties: "opacity,internalStrokeWidth" + duration: manager.completeEndDuration * Appearance.anim.durations.scale + } + } + + contentItem: CircularProgress { + anchors.fill: parent + strokeWidth: root.internalStrokeWidth + fgColour: root.fgColour + bgColour: root.bgColour + padding: root.padding + rotation: manager.rotation + startAngle: manager.startFraction * 360 + value: manager.endFraction - manager.startFraction + } + + CircularIndicatorManager { + id: manager + } + + NumberAnimation { + running: root.animState !== CircularIndicator.Stopped + loops: Animation.Infinite + target: manager + property: "progress" + from: 0 + to: 1 + duration: manager.duration * Appearance.anim.durations.scale + } + + NumberAnimation { + running: root.animState === CircularIndicator.Completing + target: manager + property: "completeEndProgress" + from: 0 + to: 1 + duration: manager.completeEndDuration * Appearance.anim.durations.scale + onFinished: { + if (root.animState === CircularIndicator.Completing) + root.animState = CircularIndicator.Stopped; + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/CircularProgress.qml b/.config/quickshell/caelestia/components/controls/CircularProgress.qml new file mode 100644 index 0000000..a15cd90 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/CircularProgress.qml @@ -0,0 +1,69 @@ +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Shapes + +Shape { + id: root + + property real value + property int startAngle: -90 + property int strokeWidth: Appearance.padding.smaller + property int padding: 0 + property int spacing: Appearance.spacing.small + property color fgColour: Colours.palette.m3primary + property color bgColour: Colours.palette.m3secondaryContainer + + readonly property real size: Math.min(width, height) + readonly property real arcRadius: (size - padding - strokeWidth) / 2 + readonly property real vValue: value || 1 / 360 + readonly property real gapAngle: ((spacing + strokeWidth) / (arcRadius || 1)) * (180 / Math.PI) + + preferredRendererType: Shape.CurveRenderer + asynchronous: true + + ShapePath { + fillColor: "transparent" + strokeColor: root.bgColour + strokeWidth: root.strokeWidth + capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap + + PathAngleArc { + startAngle: root.startAngle + 360 * root.vValue + root.gapAngle + sweepAngle: Math.max(-root.gapAngle, 360 * (1 - root.vValue) - root.gapAngle * 2) + radiusX: root.arcRadius + radiusY: root.arcRadius + centerX: root.size / 2 + centerY: root.size / 2 + } + + Behavior on strokeColor { + CAnim { + duration: Appearance.anim.durations.large + } + } + } + + ShapePath { + fillColor: "transparent" + strokeColor: root.fgColour + strokeWidth: root.strokeWidth + capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap + + PathAngleArc { + startAngle: root.startAngle + sweepAngle: 360 * root.vValue + radiusX: root.arcRadius + radiusY: root.arcRadius + centerX: root.size / 2 + centerY: root.size / 2 + } + + Behavior on strokeColor { + CAnim { + duration: Appearance.anim.durations.large + } + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/CollapsibleSection.qml b/.config/quickshell/caelestia/components/controls/CollapsibleSection.qml new file mode 100644 index 0000000..e3d8eef --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/CollapsibleSection.qml @@ -0,0 +1,132 @@ +import ".." +import qs.components +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property string title + property string description: "" + property bool expanded: false + property bool showBackground: false + property bool nested: false + + signal toggleRequested + + spacing: Appearance.spacing.small + Layout.fillWidth: true + + Item { + id: sectionHeaderItem + Layout.fillWidth: true + Layout.preferredHeight: Math.max(titleRow.implicitHeight + Appearance.padding.normal * 2, 48) + + RowLayout { + id: titleRow + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.padding.normal + anchors.rightMargin: Appearance.padding.normal + spacing: Appearance.spacing.normal + + StyledText { + text: root.title + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + + MaterialIcon { + text: "expand_more" + rotation: root.expanded ? 180 : 0 + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.normal + Behavior on rotation { + Anim { + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standard + } + } + } + } + + StateLayer { + anchors.fill: parent + color: Colours.palette.m3onSurface + radius: Appearance.rounding.normal + showHoverBackground: false + function onClicked(): void { + root.toggleRequested(); + root.expanded = !root.expanded; + } + } + } + + default property alias content: contentColumn.data + + Item { + id: contentWrapper + Layout.fillWidth: true + Layout.preferredHeight: root.expanded ? (contentColumn.implicitHeight + Appearance.spacing.small * 2) : 0 + clip: true + + Behavior on Layout.preferredHeight { + Anim { + easing.bezierCurve: Appearance.anim.curves.standard + } + } + + StyledRect { + id: backgroundRect + anchors.fill: parent + radius: Appearance.rounding.normal + color: Colours.transparency.enabled ? Colours.layer(Colours.palette.m3surfaceContainer, root.nested ? 3 : 2) : (root.nested ? Colours.palette.m3surfaceContainerHigh : Colours.palette.m3surfaceContainer) + opacity: root.showBackground && root.expanded ? 1.0 : 0.0 + visible: root.showBackground + + Behavior on opacity { + Anim { + easing.bezierCurve: Appearance.anim.curves.standard + } + } + } + + ColumnLayout { + id: contentColumn + anchors.left: parent.left + anchors.right: parent.right + y: Appearance.spacing.small + anchors.leftMargin: Appearance.padding.normal + anchors.rightMargin: Appearance.padding.normal + anchors.bottomMargin: Appearance.spacing.small + spacing: Appearance.spacing.small + opacity: root.expanded ? 1.0 : 0.0 + + Behavior on opacity { + Anim { + easing.bezierCurve: Appearance.anim.curves.standard + } + } + + StyledText { + id: descriptionText + Layout.fillWidth: true + Layout.topMargin: root.description !== "" ? Appearance.spacing.smaller : 0 + Layout.bottomMargin: root.description !== "" ? Appearance.spacing.small : 0 + visible: root.description !== "" + text: root.description + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + wrapMode: Text.Wrap + } + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/CustomMouseArea.qml b/.config/quickshell/caelestia/components/controls/CustomMouseArea.qml new file mode 100644 index 0000000..7c973c2 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/CustomMouseArea.qml @@ -0,0 +1,21 @@ +import QtQuick + +MouseArea { + property int scrollAccumulatedY: 0 + + function onWheel(event: WheelEvent): void { + } + + onWheel: event => { + // Update accumulated scroll + if (Math.sign(event.angleDelta.y) !== Math.sign(scrollAccumulatedY)) + scrollAccumulatedY = 0; + scrollAccumulatedY += event.angleDelta.y; + + // Trigger handler and reset if above threshold + if (Math.abs(scrollAccumulatedY) >= 120) { + onWheel(event); + scrollAccumulatedY = 0; + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/CustomSpinBox.qml b/.config/quickshell/caelestia/components/controls/CustomSpinBox.qml new file mode 100644 index 0000000..438dc08 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/CustomSpinBox.qml @@ -0,0 +1,170 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +RowLayout { + id: root + + property real value + property real max: Infinity + property real min: -Infinity + property real step: 1 + property alias repeatRate: timer.interval + + signal valueModified(value: real) + + spacing: Appearance.spacing.small + + property bool isEditing: false + property string displayText: root.value.toString() + + onValueChanged: { + if (!root.isEditing) { + root.displayText = root.value.toString(); + } + } + + StyledTextField { + id: textField + + inputMethodHints: Qt.ImhFormattedNumbersOnly + text: root.isEditing ? text : root.displayText + validator: DoubleValidator { + bottom: root.min + top: root.max + decimals: root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0 + } + onActiveFocusChanged: { + if (activeFocus) { + root.isEditing = true; + } else { + root.isEditing = false; + root.displayText = root.value.toString(); + } + } + onAccepted: { + const numValue = parseFloat(text); + if (!isNaN(numValue)) { + const clampedValue = Math.max(root.min, Math.min(root.max, numValue)); + root.value = clampedValue; + root.displayText = clampedValue.toString(); + root.valueModified(clampedValue); + } else { + text = root.displayText; + } + root.isEditing = false; + } + onEditingFinished: { + if (text !== root.displayText) { + const numValue = parseFloat(text); + if (!isNaN(numValue)) { + const clampedValue = Math.max(root.min, Math.min(root.max, numValue)); + root.value = clampedValue; + root.displayText = clampedValue.toString(); + root.valueModified(clampedValue); + } else { + text = root.displayText; + } + } + root.isEditing = false; + } + + padding: Appearance.padding.small + leftPadding: Appearance.padding.normal + rightPadding: Appearance.padding.normal + + background: StyledRect { + implicitWidth: 100 + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainerHigh + } + } + + StyledRect { + radius: Appearance.rounding.small + color: Colours.palette.m3primary + + implicitWidth: implicitHeight + implicitHeight: upIcon.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + id: upState + + color: Colours.palette.m3onPrimary + + onPressAndHold: timer.start() + onReleased: timer.stop() + + function onClicked(): void { + let newValue = Math.min(root.max, root.value + root.step); + // Round to avoid floating point precision errors + const decimals = root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0; + newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals); + root.value = newValue; + root.displayText = newValue.toString(); + root.valueModified(newValue); + } + } + + MaterialIcon { + id: upIcon + + anchors.centerIn: parent + text: "keyboard_arrow_up" + color: Colours.palette.m3onPrimary + } + } + + StyledRect { + radius: Appearance.rounding.small + color: Colours.palette.m3primary + + implicitWidth: implicitHeight + implicitHeight: downIcon.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + id: downState + + color: Colours.palette.m3onPrimary + + onPressAndHold: timer.start() + onReleased: timer.stop() + + function onClicked(): void { + let newValue = Math.max(root.min, root.value - root.step); + // Round to avoid floating point precision errors + const decimals = root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0; + newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals); + root.value = newValue; + root.displayText = newValue.toString(); + root.valueModified(newValue); + } + } + + MaterialIcon { + id: downIcon + + anchors.centerIn: parent + text: "keyboard_arrow_down" + color: Colours.palette.m3onPrimary + } + } + + Timer { + id: timer + + interval: 100 + repeat: true + triggeredOnStart: true + onTriggered: { + if (upState.pressed) + upState.onClicked(); + else if (downState.pressed) + downState.onClicked(); + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/FilledSlider.qml b/.config/quickshell/caelestia/components/controls/FilledSlider.qml new file mode 100644 index 0000000..80dd44c --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/FilledSlider.qml @@ -0,0 +1,146 @@ +import ".." +import "../effects" +import qs.services +import qs.config +import QtQuick +import QtQuick.Templates + +Slider { + id: root + + required property string icon + property real oldValue + property bool initialized + + orientation: Qt.Vertical + + background: StyledRect { + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + radius: Appearance.rounding.full + + StyledRect { + anchors.left: parent.left + anchors.right: parent.right + + y: root.handle.y + implicitHeight: parent.height - y + + color: Colours.palette.m3secondary + radius: parent.radius + } + } + + handle: Item { + id: handle + + property alias moving: icon.moving + + y: root.visualPosition * (root.availableHeight - height) + implicitWidth: root.width + implicitHeight: root.width + + Elevation { + anchors.fill: parent + radius: rect.radius + level: handleInteraction.containsMouse ? 2 : 1 + } + + StyledRect { + id: rect + + anchors.fill: parent + + color: Colours.palette.m3inverseSurface + radius: Appearance.rounding.full + + MouseArea { + id: handleInteraction + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + acceptedButtons: Qt.NoButton + } + + MaterialIcon { + id: icon + + property bool moving + + function update(): void { + animate = !moving; + binding.when = moving; + font.pointSize = moving ? Appearance.font.size.small : Appearance.font.size.larger; + font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material; + } + + text: root.icon + color: Colours.palette.m3inverseOnSurface + anchors.centerIn: parent + + onMovingChanged: anim.restart() + + Binding { + id: binding + + target: icon + property: "text" + value: Math.round(root.value * 100) + when: false + } + + SequentialAnimation { + id: anim + + Anim { + target: icon + property: "scale" + to: 0 + duration: Appearance.anim.durations.normal / 2 + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + ScriptAction { + script: icon.update() + } + Anim { + target: icon + property: "scale" + to: 1 + duration: Appearance.anim.durations.normal / 2 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + } + } + } + + onPressedChanged: handle.moving = pressed + + onValueChanged: { + if (!initialized) { + initialized = true; + return; + } + if (Math.abs(value - oldValue) < 0.01) + return; + oldValue = value; + handle.moving = true; + stateChangeDelay.restart(); + } + + Timer { + id: stateChangeDelay + + interval: 500 + onTriggered: { + if (!root.pressed) + handle.moving = false; + } + } + + Behavior on value { + Anim { + duration: Appearance.anim.durations.large + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/IconButton.qml b/.config/quickshell/caelestia/components/controls/IconButton.qml new file mode 100644 index 0000000..ffb1d06 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/IconButton.qml @@ -0,0 +1,83 @@ +import ".." +import qs.services +import qs.config +import QtQuick + +StyledRect { + id: root + + enum Type { + Filled, + Tonal, + Text + } + + property alias icon: label.text + property bool checked + property bool toggle + property real padding: type === IconButton.Text ? Appearance.padding.small / 2 : Appearance.padding.smaller + property alias font: label.font + property int type: IconButton.Filled + property bool disabled + + property alias stateLayer: stateLayer + property alias label: label + property alias radiusAnim: radiusAnim + + property bool internalChecked + property color activeColour: type === IconButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary + property color inactiveColour: { + if (!toggle && type === IconButton.Filled) + return Colours.palette.m3primary; + return type === IconButton.Filled ? Colours.tPalette.m3surfaceContainer : Colours.palette.m3secondaryContainer; + } + property color activeOnColour: type === IconButton.Filled ? Colours.palette.m3onPrimary : type === IconButton.Tonal ? Colours.palette.m3onSecondary : Colours.palette.m3primary + property color inactiveOnColour: { + if (!toggle && type === IconButton.Filled) + return Colours.palette.m3onPrimary; + return type === IconButton.Tonal ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurfaceVariant; + } + property color disabledColour: Qt.alpha(Colours.palette.m3onSurface, 0.1) + property color disabledOnColour: Qt.alpha(Colours.palette.m3onSurface, 0.38) + + signal clicked + + onCheckedChanged: internalChecked = checked + + radius: internalChecked ? Appearance.rounding.small : implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) + color: type === IconButton.Text ? "transparent" : disabled ? disabledColour : internalChecked ? activeColour : inactiveColour + + implicitWidth: implicitHeight + implicitHeight: label.implicitHeight + padding * 2 + + StateLayer { + id: stateLayer + + color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour + disabled: root.disabled + + function onClicked(): void { + if (root.toggle) + root.internalChecked = !root.internalChecked; + root.clicked(); + } + } + + MaterialIcon { + id: label + + anchors.centerIn: parent + color: root.disabled ? root.disabledOnColour : root.internalChecked ? root.activeOnColour : root.inactiveOnColour + fill: !root.toggle || root.internalChecked ? 1 : 0 + + Behavior on fill { + Anim {} + } + } + + Behavior on radius { + Anim { + id: radiusAnim + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/IconTextButton.qml b/.config/quickshell/caelestia/components/controls/IconTextButton.qml new file mode 100644 index 0000000..b2bb96c --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/IconTextButton.qml @@ -0,0 +1,88 @@ +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + enum Type { + Filled, + Tonal, + Text + } + + property alias icon: iconLabel.text + property alias text: label.text + property bool checked + property bool toggle + property real horizontalPadding: Appearance.padding.normal + property real verticalPadding: Appearance.padding.smaller + property alias font: label.font + property int type: IconTextButton.Filled + + property alias stateLayer: stateLayer + property alias iconLabel: iconLabel + property alias label: label + + property bool internalChecked + property color activeColour: type === IconTextButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary + property color inactiveColour: type === IconTextButton.Filled ? Colours.tPalette.m3surfaceContainer : Colours.palette.m3secondaryContainer + property color activeOnColour: type === IconTextButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondary + property color inactiveOnColour: type === IconTextButton.Filled ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + + signal clicked + + onCheckedChanged: internalChecked = checked + + radius: internalChecked ? Appearance.rounding.small : implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) + color: type === IconTextButton.Text ? "transparent" : internalChecked ? activeColour : inactiveColour + + implicitWidth: row.implicitWidth + horizontalPadding * 2 + implicitHeight: row.implicitHeight + verticalPadding * 2 + + StateLayer { + id: stateLayer + + color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour + + function onClicked(): void { + if (root.toggle) + root.internalChecked = !root.internalChecked; + root.clicked(); + } + } + + RowLayout { + id: row + + anchors.centerIn: parent + spacing: Appearance.spacing.small + + MaterialIcon { + id: iconLabel + + Layout.alignment: Qt.AlignVCenter + Layout.topMargin: Math.round(fontInfo.pointSize * 0.0575) + color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour + fill: root.internalChecked ? 1 : 0 + + Behavior on fill { + Anim {} + } + } + + StyledText { + id: label + + Layout.alignment: Qt.AlignVCenter + Layout.topMargin: -Math.round(iconLabel.fontInfo.pointSize * 0.0575) + color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour + } + } + + Behavior on radius { + Anim {} + } +} diff --git a/.config/quickshell/caelestia/components/controls/Menu.qml b/.config/quickshell/caelestia/components/controls/Menu.qml new file mode 100644 index 0000000..c763b54 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/Menu.qml @@ -0,0 +1,113 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../effects" +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +Elevation { + id: root + + property list items + property MenuItem active: items[0] ?? null + property bool expanded + + signal itemSelected(item: MenuItem) + + radius: Appearance.rounding.small / 2 + level: 2 + + implicitWidth: Math.max(200, column.implicitWidth) + implicitHeight: root.expanded ? column.implicitHeight : 0 + opacity: root.expanded ? 1 : 0 + + StyledClippingRect { + anchors.fill: parent + radius: parent.radius + color: Colours.palette.m3surfaceContainer + + ColumnLayout { + id: column + + anchors.left: parent.left + anchors.right: parent.right + spacing: 0 + + Repeater { + model: root.items + + StyledRect { + id: item + + required property int index + required property MenuItem modelData + readonly property bool active: modelData === root.active + + Layout.fillWidth: true + implicitWidth: menuOptionRow.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: menuOptionRow.implicitHeight + Appearance.padding.normal * 2 + + color: Qt.alpha(Colours.palette.m3secondaryContainer, active ? 1 : 0) + + StateLayer { + color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + disabled: !root.expanded + + function onClicked(): void { + root.itemSelected(item.modelData); + root.active = item.modelData; + root.expanded = false; + } + } + + RowLayout { + id: menuOptionRow + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + spacing: Appearance.spacing.small + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + text: item.modelData.icon + color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurfaceVariant + } + + StyledText { + Layout.alignment: Qt.AlignVCenter + Layout.fillWidth: true + text: item.modelData.text + color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + } + + Loader { + Layout.alignment: Qt.AlignVCenter + active: item.modelData.trailingIcon.length > 0 + visible: active + + sourceComponent: MaterialIcon { + text: item.modelData.trailingIcon + color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + } + } + } + } + } + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + } + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/MenuItem.qml b/.config/quickshell/caelestia/components/controls/MenuItem.qml new file mode 100644 index 0000000..5348bbe --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/MenuItem.qml @@ -0,0 +1,11 @@ +import QtQuick + +QtObject { + required property string text + property string icon + property string trailingIcon + property string activeIcon: icon + property string activeText: text + + signal clicked +} diff --git a/.config/quickshell/caelestia/components/controls/SpinBoxRow.qml b/.config/quickshell/caelestia/components/controls/SpinBoxRow.qml new file mode 100644 index 0000000..fe6a198 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/SpinBoxRow.qml @@ -0,0 +1,52 @@ +import ".." +import qs.components +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property string label + required property real value + required property real min + required property real max + property real step: 1 + property var onValueModified: function (value) {} + + Layout.fillWidth: true + implicitHeight: row.implicitHeight + Appearance.padding.large * 2 + radius: Appearance.rounding.normal + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + + Behavior on implicitHeight { + Anim {} + } + + RowLayout { + id: row + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: root.label + } + + CustomSpinBox { + min: root.min + max: root.max + step: root.step + value: root.value + onValueModified: value => { + root.onValueModified(value); + } + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/SplitButton.qml b/.config/quickshell/caelestia/components/controls/SplitButton.qml new file mode 100644 index 0000000..c91474e --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/SplitButton.qml @@ -0,0 +1,164 @@ +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +Row { + id: root + + enum Type { + Filled, + Tonal + } + + property real horizontalPadding: Appearance.padding.normal + property real verticalPadding: Appearance.padding.smaller + property int type: SplitButton.Filled + property bool disabled + property bool menuOnTop + property string fallbackIcon + property string fallbackText + + property alias menuItems: menu.items + property alias active: menu.active + property alias expanded: menu.expanded + property alias menu: menu + property alias iconLabel: iconLabel + property alias label: label + property alias stateLayer: stateLayer + + property color colour: type == SplitButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondaryContainer + property color textColour: type == SplitButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondaryContainer + property color disabledColour: Qt.alpha(Colours.palette.m3onSurface, 0.1) + property color disabledTextColour: Qt.alpha(Colours.palette.m3onSurface, 0.38) + + spacing: Math.floor(Appearance.spacing.small / 2) + + StyledRect { + radius: implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) + topRightRadius: Appearance.rounding.small / 2 + bottomRightRadius: Appearance.rounding.small / 2 + color: root.disabled ? root.disabledColour : root.colour + + implicitWidth: textRow.implicitWidth + root.horizontalPadding * 2 + implicitHeight: expandBtn.implicitHeight + + StateLayer { + id: stateLayer + + rect.topRightRadius: parent.topRightRadius + rect.bottomRightRadius: parent.bottomRightRadius + color: root.textColour + disabled: root.disabled + + function onClicked(): void { + root.active?.clicked(); + } + } + + RowLayout { + id: textRow + + anchors.centerIn: parent + anchors.horizontalCenterOffset: Math.floor(root.verticalPadding / 4) + spacing: Appearance.spacing.small + + MaterialIcon { + id: iconLabel + + Layout.alignment: Qt.AlignVCenter + animate: true + text: root.active?.activeIcon ?? root.fallbackIcon + color: root.disabled ? root.disabledTextColour : root.textColour + fill: 1 + } + + StyledText { + id: label + + Layout.alignment: Qt.AlignVCenter + Layout.preferredWidth: implicitWidth + animate: true + text: root.active?.activeText ?? root.fallbackText + color: root.disabled ? root.disabledTextColour : root.textColour + clip: true + + Behavior on Layout.preferredWidth { + Anim { + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + } + } + } + + StyledRect { + id: expandBtn + + property real rad: root.expanded ? implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) : Appearance.rounding.small / 2 + + radius: implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) + topLeftRadius: rad + bottomLeftRadius: rad + color: root.disabled ? root.disabledColour : root.colour + + implicitWidth: implicitHeight + implicitHeight: expandIcon.implicitHeight + root.verticalPadding * 2 + + StateLayer { + id: expandStateLayer + + rect.topLeftRadius: parent.topLeftRadius + rect.bottomLeftRadius: parent.bottomLeftRadius + color: root.textColour + disabled: root.disabled + + function onClicked(): void { + root.expanded = !root.expanded; + } + } + + MaterialIcon { + id: expandIcon + + anchors.centerIn: parent + anchors.horizontalCenterOffset: root.expanded ? 0 : -Math.floor(root.verticalPadding / 4) + + text: "expand_more" + color: root.disabled ? root.disabledTextColour : root.textColour + rotation: root.expanded ? 180 : 0 + + Behavior on anchors.horizontalCenterOffset { + Anim {} + } + + Behavior on rotation { + Anim {} + } + } + + Behavior on rad { + Anim {} + } + + Menu { + id: menu + + states: State { + when: root.menuOnTop + + AnchorChanges { + target: menu + anchors.top: undefined + anchors.bottom: expandBtn.top + } + } + + anchors.top: parent.bottom + anchors.right: parent.right + anchors.topMargin: Appearance.spacing.small + anchors.bottomMargin: Appearance.spacing.small + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/SplitButtonRow.qml b/.config/quickshell/caelestia/components/controls/SplitButtonRow.qml new file mode 100644 index 0000000..db9925f --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/SplitButtonRow.qml @@ -0,0 +1,62 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property string label + property int expandedZ: 100 + property bool enabled: true + + property alias menuItems: splitButton.menuItems + property alias active: splitButton.active + property alias expanded: splitButton.expanded + property alias type: splitButton.type + + signal selected(item: MenuItem) + + Layout.fillWidth: true + implicitHeight: row.implicitHeight + Appearance.padding.large * 2 + radius: Appearance.rounding.normal + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + + clip: false + z: splitButton.menu.implicitHeight > 0 ? expandedZ : 1 + opacity: enabled ? 1.0 : 0.5 + + RowLayout { + id: row + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: root.label + color: root.enabled ? Colours.palette.m3onSurface : Colours.palette.m3onSurfaceVariant + } + + SplitButton { + id: splitButton + enabled: root.enabled + type: SplitButton.Filled + + menu.z: 1 + + stateLayer.onClicked: { + splitButton.expanded = !splitButton.expanded; + } + + menu.onItemSelected: item => { + root.selected(item); + } + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/StyledInputField.qml b/.config/quickshell/caelestia/components/controls/StyledInputField.qml new file mode 100644 index 0000000..0d199c7 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/StyledInputField.qml @@ -0,0 +1,79 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.services +import qs.config +import QtQuick + +Item { + id: root + + property string text: "" + property var validator: null + property bool readOnly: false + property int horizontalAlignment: TextInput.AlignHCenter + property int implicitWidth: 70 + property bool enabled: true + + // Expose activeFocus through alias to avoid FINAL property override + readonly property alias hasFocus: inputField.activeFocus + + signal textEdited(string text) + signal editingFinished + + implicitHeight: inputField.implicitHeight + Appearance.padding.small * 2 + + StyledRect { + id: container + + anchors.fill: parent + color: inputHover.containsMouse || inputField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2) + radius: Appearance.rounding.small + border.width: 1 + border.color: inputField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3) + opacity: root.enabled ? 1 : 0.5 + + Behavior on color { + CAnim {} + } + Behavior on border.color { + CAnim {} + } + + MouseArea { + id: inputHover + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.IBeamCursor + acceptedButtons: Qt.NoButton + enabled: root.enabled + } + + StyledTextField { + id: inputField + anchors.centerIn: parent + width: parent.width - Appearance.padding.normal + horizontalAlignment: root.horizontalAlignment + validator: root.validator + readOnly: root.readOnly + enabled: root.enabled + + Binding { + target: inputField + property: "text" + value: root.text + when: !inputField.activeFocus + } + + onTextChanged: { + root.text = text; + root.textEdited(text); + } + + onEditingFinished: { + root.editingFinished(); + } + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/StyledRadioButton.qml b/.config/quickshell/caelestia/components/controls/StyledRadioButton.qml new file mode 100644 index 0000000..b72fc77 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/StyledRadioButton.qml @@ -0,0 +1,57 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Templates + +RadioButton { + id: root + + font.pointSize: Appearance.font.size.smaller + + implicitWidth: implicitIndicatorWidth + implicitContentWidth + contentItem.anchors.leftMargin + implicitHeight: Math.max(implicitIndicatorHeight, implicitContentHeight) + + indicator: Rectangle { + id: outerCircle + + implicitWidth: 20 + implicitHeight: 20 + radius: Appearance.rounding.full + color: "transparent" + border.color: root.checked ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant + border.width: 2 + anchors.verticalCenter: parent.verticalCenter + + StateLayer { + anchors.margins: -Appearance.padding.smaller + color: root.checked ? Colours.palette.m3onSurface : Colours.palette.m3primary + z: -1 + + function onClicked(): void { + root.click(); + } + } + + StyledRect { + anchors.centerIn: parent + implicitWidth: 8 + implicitHeight: 8 + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3primary, root.checked ? 1 : 0) + } + + Behavior on border.color { + CAnim {} + } + } + + contentItem: StyledText { + text: root.text + font.pointSize: root.font.pointSize + anchors.verticalCenter: parent.verticalCenter + anchors.left: outerCircle.right + anchors.leftMargin: Appearance.spacing.smaller + } +} diff --git a/.config/quickshell/caelestia/components/controls/StyledScrollBar.qml b/.config/quickshell/caelestia/components/controls/StyledScrollBar.qml new file mode 100644 index 0000000..de8b679 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/StyledScrollBar.qml @@ -0,0 +1,190 @@ +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Templates + +ScrollBar { + id: root + + required property Flickable flickable + property bool shouldBeActive + property real nonAnimPosition + property bool animating + + onHoveredChanged: { + if (hovered) + shouldBeActive = true; + else + shouldBeActive = flickable.moving; + } + + property bool _updatingFromFlickable: false + property bool _updatingFromUser: false + + // Sync nonAnimPosition with Qt's automatic position binding + onPositionChanged: { + if (_updatingFromUser) { + _updatingFromUser = false; + return; + } + if (position === nonAnimPosition) { + animating = false; + return; + } + if (!animating && !_updatingFromFlickable && !fullMouse.pressed) { + nonAnimPosition = position; + } + } + + // Sync nonAnimPosition with flickable when not animating + Connections { + target: flickable + function onContentYChanged() { + if (!animating && !fullMouse.pressed) { + _updatingFromFlickable = true; + const contentHeight = flickable.contentHeight; + const height = flickable.height; + if (contentHeight > height) { + nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height))); + } else { + nonAnimPosition = 0; + } + _updatingFromFlickable = false; + } + } + } + + Component.onCompleted: { + if (flickable) { + const contentHeight = flickable.contentHeight; + const height = flickable.height; + if (contentHeight > height) { + nonAnimPosition = Math.max(0, Math.min(1, flickable.contentY / (contentHeight - height))); + } + } + } + implicitWidth: Appearance.padding.small + + contentItem: StyledRect { + anchors.left: parent.left + anchors.right: parent.right + opacity: { + if (root.size === 1) + return 0; + if (fullMouse.pressed) + return 1; + if (mouse.containsMouse) + return 0.8; + if (root.policy === ScrollBar.AlwaysOn || root.shouldBeActive) + return 0.6; + return 0; + } + radius: Appearance.rounding.full + color: Colours.palette.m3secondary + + MouseArea { + id: mouse + + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + acceptedButtons: Qt.NoButton + } + + Behavior on opacity { + Anim {} + } + } + + Connections { + target: root.flickable + + function onMovingChanged(): void { + if (root.flickable.moving) + root.shouldBeActive = true; + else + hideDelay.restart(); + } + } + + Timer { + id: hideDelay + + interval: 600 + onTriggered: root.shouldBeActive = root.flickable.moving || root.hovered + } + + CustomMouseArea { + id: fullMouse + + anchors.fill: parent + preventStealing: true + + onPressed: event => { + root.animating = true; + root._updatingFromUser = true; + const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2)); + root.nonAnimPosition = newPos; + // Update flickable position + // Map scrollbar position [0, 1-size] to contentY [0, maxContentY] + if (root.flickable) { + const contentHeight = root.flickable.contentHeight; + const height = root.flickable.height; + if (contentHeight > height) { + const maxContentY = contentHeight - height; + const maxPos = 1 - root.size; + const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0; + root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY)); + } + } + } + + onPositionChanged: event => { + root._updatingFromUser = true; + const newPos = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2)); + root.nonAnimPosition = newPos; + // Update flickable position + // Map scrollbar position [0, 1-size] to contentY [0, maxContentY] + if (root.flickable) { + const contentHeight = root.flickable.contentHeight; + const height = root.flickable.height; + if (contentHeight > height) { + const maxContentY = contentHeight - height; + const maxPos = 1 - root.size; + const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0; + root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY)); + } + } + } + + function onWheel(event: WheelEvent): void { + root.animating = true; + root._updatingFromUser = true; + let newPos = root.nonAnimPosition; + if (event.angleDelta.y > 0) + newPos = Math.max(0, root.nonAnimPosition - 0.1); + else if (event.angleDelta.y < 0) + newPos = Math.min(1 - root.size, root.nonAnimPosition + 0.1); + root.nonAnimPosition = newPos; + // Update flickable position + // Map scrollbar position [0, 1-size] to contentY [0, maxContentY] + if (root.flickable) { + const contentHeight = root.flickable.contentHeight; + const height = root.flickable.height; + if (contentHeight > height) { + const maxContentY = contentHeight - height; + const maxPos = 1 - root.size; + const contentY = maxPos > 0 ? (newPos / maxPos) * maxContentY : 0; + root.flickable.contentY = Math.max(0, Math.min(maxContentY, contentY)); + } + } + } + } + + Behavior on position { + enabled: !fullMouse.pressed + + Anim {} + } +} diff --git a/.config/quickshell/caelestia/components/controls/StyledSlider.qml b/.config/quickshell/caelestia/components/controls/StyledSlider.qml new file mode 100644 index 0000000..0ef229d --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/StyledSlider.qml @@ -0,0 +1,57 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Templates + +Slider { + id: root + + background: Item { + StyledRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.topMargin: root.implicitHeight / 3 + anchors.bottomMargin: root.implicitHeight / 3 + + implicitWidth: root.handle.x - root.implicitHeight / 6 + + color: Colours.palette.m3primary + radius: Appearance.rounding.full + topRightRadius: root.implicitHeight / 15 + bottomRightRadius: root.implicitHeight / 15 + } + + StyledRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.topMargin: root.implicitHeight / 3 + anchors.bottomMargin: root.implicitHeight / 3 + + implicitWidth: parent.width - root.handle.x - root.handle.implicitWidth - root.implicitHeight / 6 + + color: Colours.palette.m3surfaceContainerHighest + radius: Appearance.rounding.full + topLeftRadius: root.implicitHeight / 15 + bottomLeftRadius: root.implicitHeight / 15 + } + } + + handle: StyledRect { + x: root.visualPosition * root.availableWidth - implicitWidth / 2 + + implicitWidth: root.implicitHeight / 4.5 + implicitHeight: root.implicitHeight + + color: Colours.palette.m3primary + radius: Appearance.rounding.full + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: Qt.PointingHandCursor + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/StyledSwitch.qml b/.config/quickshell/caelestia/components/controls/StyledSwitch.qml new file mode 100644 index 0000000..ce93cd5 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/StyledSwitch.qml @@ -0,0 +1,152 @@ +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Templates +import QtQuick.Shapes + +Switch { + id: root + + property int cLayer: 1 + + implicitWidth: implicitIndicatorWidth + implicitHeight: implicitIndicatorHeight + + indicator: StyledRect { + radius: Appearance.rounding.full + color: root.checked ? Colours.palette.m3primary : Colours.layer(Colours.palette.m3surfaceContainerHighest, root.cLayer) + + implicitWidth: implicitHeight * 1.7 + implicitHeight: Appearance.font.size.normal + Appearance.padding.smaller * 2 + + StyledRect { + readonly property real nonAnimWidth: root.pressed ? implicitHeight * 1.3 : implicitHeight + + radius: Appearance.rounding.full + color: root.checked ? Colours.palette.m3onPrimary : Colours.layer(Colours.palette.m3outline, root.cLayer + 1) + + x: root.checked ? parent.implicitWidth - nonAnimWidth - Appearance.padding.small / 2 : Appearance.padding.small / 2 + implicitWidth: nonAnimWidth + implicitHeight: parent.implicitHeight - Appearance.padding.small + anchors.verticalCenter: parent.verticalCenter + + StyledRect { + anchors.fill: parent + radius: parent.radius + + color: root.checked ? Colours.palette.m3primary : Colours.palette.m3onSurface + opacity: root.pressed ? 0.1 : root.hovered ? 0.08 : 0 + + Behavior on opacity { + Anim {} + } + } + + Shape { + id: icon + + property point start1: { + if (root.pressed) + return Qt.point(width * 0.2, height / 2); + if (root.checked) + return Qt.point(width * 0.15, height / 2); + return Qt.point(width * 0.15, height * 0.15); + } + property point end1: { + if (root.pressed) { + if (root.checked) + return Qt.point(width * 0.4, height / 2); + return Qt.point(width * 0.8, height / 2); + } + if (root.checked) + return Qt.point(width * 0.4, height * 0.7); + return Qt.point(width * 0.85, height * 0.85); + } + property point start2: { + if (root.pressed) { + if (root.checked) + return Qt.point(width * 0.4, height / 2); + return Qt.point(width * 0.2, height / 2); + } + if (root.checked) + return Qt.point(width * 0.4, height * 0.7); + return Qt.point(width * 0.15, height * 0.85); + } + property point end2: { + if (root.pressed) + return Qt.point(width * 0.8, height / 2); + if (root.checked) + return Qt.point(width * 0.85, height * 0.2); + return Qt.point(width * 0.85, height * 0.15); + } + + anchors.centerIn: parent + width: height + height: parent.implicitHeight - Appearance.padding.small * 2 + preferredRendererType: Shape.CurveRenderer + asynchronous: true + + ShapePath { + strokeWidth: Appearance.font.size.larger * 0.15 + strokeColor: root.checked ? Colours.palette.m3primary : Colours.palette.m3surfaceContainerHighest + fillColor: "transparent" + capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap + + startX: icon.start1.x + startY: icon.start1.y + + PathLine { + x: icon.end1.x + y: icon.end1.y + } + PathMove { + x: icon.start2.x + y: icon.start2.y + } + PathLine { + x: icon.end2.x + y: icon.end2.y + } + + Behavior on strokeColor { + CAnim {} + } + } + + Behavior on start1 { + PropAnim {} + } + Behavior on end1 { + PropAnim {} + } + Behavior on start2 { + PropAnim {} + } + Behavior on end2 { + PropAnim {} + } + } + + Behavior on x { + Anim {} + } + + Behavior on implicitWidth { + Anim {} + } + } + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + enabled: false + } + + component PropAnim: PropertyAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } +} diff --git a/.config/quickshell/caelestia/components/controls/StyledTextField.qml b/.config/quickshell/caelestia/components/controls/StyledTextField.qml new file mode 100644 index 0000000..60bcff2 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/StyledTextField.qml @@ -0,0 +1,76 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Controls + +TextField { + id: root + + color: Colours.palette.m3onSurface + placeholderTextColor: Colours.palette.m3outline + font.family: Appearance.font.family.sans + font.pointSize: Appearance.font.size.smaller + renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering + cursorVisible: !readOnly + + background: null + + cursorDelegate: StyledRect { + id: cursor + + property bool disableBlink + + implicitWidth: 2 + color: Colours.palette.m3primary + radius: Appearance.rounding.normal + + Connections { + target: root + + function onCursorPositionChanged(): void { + if (root.activeFocus && root.cursorVisible) { + cursor.opacity = 1; + cursor.disableBlink = true; + enableBlink.restart(); + } + } + } + + Timer { + id: enableBlink + + interval: 100 + onTriggered: cursor.disableBlink = false + } + + Timer { + running: root.activeFocus && root.cursorVisible && !cursor.disableBlink + repeat: true + triggeredOnStart: true + interval: 500 + onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1 + } + + Binding { + when: !root.activeFocus || !root.cursorVisible + cursor.opacity: 0 + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.small + } + } + } + + Behavior on color { + CAnim {} + } + + Behavior on placeholderTextColor { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/components/controls/SwitchRow.qml b/.config/quickshell/caelestia/components/controls/SwitchRow.qml new file mode 100644 index 0000000..6dda3f0 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/SwitchRow.qml @@ -0,0 +1,48 @@ +import ".." +import qs.components +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property string label + required property bool checked + property bool enabled: true + property var onToggled: function (checked) {} + + Layout.fillWidth: true + implicitHeight: row.implicitHeight + Appearance.padding.large * 2 + radius: Appearance.rounding.normal + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + + Behavior on implicitHeight { + Anim {} + } + + RowLayout { + id: row + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: root.label + } + + StyledSwitch { + checked: root.checked + enabled: root.enabled + onToggled: { + root.onToggled(checked); + } + } + } +} diff --git a/.config/quickshell/caelestia/components/controls/TextButton.qml b/.config/quickshell/caelestia/components/controls/TextButton.qml new file mode 100644 index 0000000..ecf7eb1 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/TextButton.qml @@ -0,0 +1,78 @@ +import ".." +import qs.services +import qs.config +import QtQuick + +StyledRect { + id: root + + enum Type { + Filled, + Tonal, + Text + } + + property alias text: label.text + property bool checked + property bool toggle + property real horizontalPadding: Appearance.padding.normal + property real verticalPadding: Appearance.padding.smaller + property alias font: label.font + property int type: TextButton.Filled + + property alias stateLayer: stateLayer + property alias label: label + + property bool internalChecked + property color activeColour: type === TextButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondary + property color inactiveColour: { + if (!toggle && type === TextButton.Filled) + return Colours.palette.m3primary; + return type === TextButton.Filled ? Colours.tPalette.m3surfaceContainer : Colours.palette.m3secondaryContainer; + } + property color activeOnColour: { + if (type === TextButton.Text) + return Colours.palette.m3primary; + return type === TextButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondary; + } + property color inactiveOnColour: { + if (!toggle && type === TextButton.Filled) + return Colours.palette.m3onPrimary; + if (type === TextButton.Text) + return Colours.palette.m3primary; + return type === TextButton.Filled ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer; + } + + signal clicked + + onCheckedChanged: internalChecked = checked + + radius: internalChecked ? Appearance.rounding.small : implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) + color: type === TextButton.Text ? "transparent" : internalChecked ? activeColour : inactiveColour + + implicitWidth: label.implicitWidth + horizontalPadding * 2 + implicitHeight: label.implicitHeight + verticalPadding * 2 + + StateLayer { + id: stateLayer + + color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour + + function onClicked(): void { + if (root.toggle) + root.internalChecked = !root.internalChecked; + root.clicked(); + } + } + + StyledText { + id: label + + anchors.centerIn: parent + color: root.internalChecked ? root.activeOnColour : root.inactiveOnColour + } + + Behavior on radius { + Anim {} + } +} diff --git a/.config/quickshell/caelestia/components/controls/ToggleButton.qml b/.config/quickshell/caelestia/components/controls/ToggleButton.qml new file mode 100644 index 0000000..98c7564 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/ToggleButton.qml @@ -0,0 +1,124 @@ +import ".." +import qs.components +import qs.components.controls +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property bool toggled + property string icon + property string label + property string accent: "Secondary" + property real iconSize: Appearance.font.size.large + property real horizontalPadding: Appearance.padding.large + property real verticalPadding: Appearance.padding.normal + property string tooltip: "" + + property bool hovered: false + signal clicked + + Component.onCompleted: { + hovered = toggleStateLayer.containsMouse; + } + + Connections { + target: toggleStateLayer + function onContainsMouseChanged() { + const newHovered = toggleStateLayer.containsMouse; + if (hovered !== newHovered) { + hovered = newHovered; + } + } + } + + Layout.preferredWidth: implicitWidth + (toggleStateLayer.pressed ? Appearance.padding.normal * 2 : toggled ? Appearance.padding.small * 2 : 0) + implicitWidth: toggleBtnInner.implicitWidth + horizontalPadding * 2 + implicitHeight: toggleBtnIcon.implicitHeight + verticalPadding * 2 + + radius: toggled || toggleStateLayer.pressed ? Appearance.rounding.small : Math.min(width, height) / 2 * Math.min(1, Appearance.rounding.scale) + color: toggled ? Colours.palette[`m3${accent.toLowerCase()}`] : Colours.palette[`m3${accent.toLowerCase()}Container`] + + StateLayer { + id: toggleStateLayer + + color: root.toggled ? Colours.palette[`m3on${root.accent}`] : Colours.palette[`m3on${root.accent}Container`] + + function onClicked(): void { + root.clicked(); + } + } + + RowLayout { + id: toggleBtnInner + + anchors.centerIn: parent + spacing: Appearance.spacing.normal + + MaterialIcon { + id: toggleBtnIcon + + visible: !!text + fill: root.toggled ? 1 : 0 + text: root.icon + color: root.toggled ? Colours.palette[`m3on${root.accent}`] : Colours.palette[`m3on${root.accent}Container`] + font.pointSize: root.iconSize + + Behavior on fill { + Anim {} + } + } + + Loader { + active: !!root.label + visible: active + + sourceComponent: StyledText { + text: root.label + color: root.toggled ? Colours.palette[`m3on${root.accent}`] : Colours.palette[`m3on${root.accent}Container`] + } + } + } + + Behavior on radius { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + Behavior on Layout.preferredWidth { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + // Tooltip - positioned absolutely, doesn't affect layout + Loader { + id: tooltipLoader + active: root.tooltip !== "" + z: 10000 + width: 0 + height: 0 + sourceComponent: Component { + Tooltip { + target: root + text: root.tooltip + } + } + // Completely remove from layout + Layout.fillWidth: false + Layout.fillHeight: false + Layout.preferredWidth: 0 + Layout.preferredHeight: 0 + Layout.maximumWidth: 0 + Layout.maximumHeight: 0 + Layout.minimumWidth: 0 + Layout.minimumHeight: 0 + } +} diff --git a/.config/quickshell/caelestia/components/controls/ToggleRow.qml b/.config/quickshell/caelestia/components/controls/ToggleRow.qml new file mode 100644 index 0000000..269d3d6 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/ToggleRow.qml @@ -0,0 +1,28 @@ +import qs.components +import qs.components.controls +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +RowLayout { + id: root + + required property string label + property alias checked: toggle.checked + property alias toggle: toggle + + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: root.label + } + + StyledSwitch { + id: toggle + + cLayer: 2 + } +} diff --git a/.config/quickshell/caelestia/components/controls/Tooltip.qml b/.config/quickshell/caelestia/components/controls/Tooltip.qml new file mode 100644 index 0000000..b129a37 --- /dev/null +++ b/.config/quickshell/caelestia/components/controls/Tooltip.qml @@ -0,0 +1,185 @@ +import ".." +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +Popup { + id: root + + required property Item target + required property string text + property int delay: 500 + property int timeout: 0 + + property bool tooltipVisible: false + property Timer showTimer: Timer { + interval: root.delay + onTriggered: root.tooltipVisible = true + } + property Timer hideTimer: Timer { + interval: root.timeout + onTriggered: root.tooltipVisible = false + } + + // Popup properties - doesn't affect layout + parent: { + let p = target; + // Walk up to find the root Item (usually has anchors.fill: parent) + while (p && p.parent) { + const parentItem = p.parent; + // Check if this looks like a root pane Item + if (parentItem && parentItem.anchors && parentItem.anchors.fill !== undefined) { + return parentItem; + } + p = parentItem; + } + // Fallback + return target.parent?.parent?.parent ?? target.parent?.parent ?? target.parent ?? target; + } + + visible: tooltipVisible + modal: false + closePolicy: Popup.NoAutoClose + padding: 0 + margins: 0 + background: Item {} + + // Update position when target moves or tooltip becomes visible + onTooltipVisibleChanged: { + if (tooltipVisible) { + Qt.callLater(updatePosition); + } + } + Connections { + target: root.target + function onXChanged() { + if (root.tooltipVisible) + root.updatePosition(); + } + function onYChanged() { + if (root.tooltipVisible) + root.updatePosition(); + } + function onWidthChanged() { + if (root.tooltipVisible) + root.updatePosition(); + } + function onHeightChanged() { + if (root.tooltipVisible) + root.updatePosition(); + } + } + + function updatePosition() { + if (!target || !parent) + return; + + // Wait for tooltipRect to have its size calculated + Qt.callLater(() => { + if (!target || !parent || !tooltipRect) + return; + + // Get target position in parent's coordinate system + const targetPos = target.mapToItem(parent, 0, 0); + const targetCenterX = targetPos.x + target.width / 2; + + // Get tooltip size (use width/height if available, otherwise implicit) + const tooltipWidth = tooltipRect.width > 0 ? tooltipRect.width : tooltipRect.implicitWidth; + const tooltipHeight = tooltipRect.height > 0 ? tooltipRect.height : tooltipRect.implicitHeight; + + // Center tooltip horizontally on target + let newX = targetCenterX - tooltipWidth / 2; + + // Position tooltip above target + let newY = targetPos.y - tooltipHeight - Appearance.spacing.small; + + // Keep within bounds + const padding = Appearance.padding.normal; + if (newX < padding) { + newX = padding; + } else if (newX + tooltipWidth > (parent.width - padding)) { + newX = parent.width - tooltipWidth - padding; + } + + // Update popup position + x = newX; + y = newY; + }); + } + + enter: Transition { + Anim { + property: "opacity" + from: 0 + to: 1 + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + exit: Transition { + Anim { + property: "opacity" + from: 1 + to: 0 + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + // Monitor hover state + Connections { + target: root.target + function onHoveredChanged() { + if (target.hovered) { + showTimer.start(); + if (timeout > 0) { + hideTimer.stop(); + hideTimer.start(); + } + } else { + showTimer.stop(); + hideTimer.stop(); + tooltipVisible = false; + } + } + } + + contentItem: StyledRect { + id: tooltipRect + + implicitWidth: tooltipText.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: tooltipText.implicitHeight + Appearance.padding.smaller * 2 + + color: Colours.palette.m3surfaceContainerHighest + radius: Appearance.rounding.small + antialiasing: true + + // Add elevation for depth + Elevation { + anchors.fill: parent + radius: parent.radius + z: -1 + level: 3 + } + + StyledText { + id: tooltipText + + anchors.centerIn: parent + + text: root.text + color: Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.small + } + } + + Component.onCompleted: { + if (tooltipVisible) { + updatePosition(); + } + } +} diff --git a/.config/quickshell/caelestia/components/effects/ColouredIcon.qml b/.config/quickshell/caelestia/components/effects/ColouredIcon.qml new file mode 100644 index 0000000..5ef4d4c --- /dev/null +++ b/.config/quickshell/caelestia/components/effects/ColouredIcon.qml @@ -0,0 +1,35 @@ +pragma ComponentBehavior: Bound + +import Caelestia +import Quickshell.Widgets +import QtQuick + +IconImage { + id: root + + required property color colour + + asynchronous: true + + layer.enabled: true + layer.effect: Colouriser { + sourceColor: analyser.dominantColour + colorizationColor: root.colour + } + + layer.onEnabledChanged: { + if (layer.enabled && status === Image.Ready) + analyser.requestUpdate(); + } + + onStatusChanged: { + if (layer.enabled && status === Image.Ready) + analyser.requestUpdate(); + } + + ImageAnalyser { + id: analyser + + sourceItem: root + } +} diff --git a/.config/quickshell/caelestia/components/effects/Colouriser.qml b/.config/quickshell/caelestia/components/effects/Colouriser.qml new file mode 100644 index 0000000..2948155 --- /dev/null +++ b/.config/quickshell/caelestia/components/effects/Colouriser.qml @@ -0,0 +1,14 @@ +import ".." +import QtQuick +import QtQuick.Effects + +MultiEffect { + property color sourceColor: "black" + + colorization: 1 + brightness: 1 - sourceColor.hslLightness + + Behavior on colorizationColor { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/components/effects/Elevation.qml b/.config/quickshell/caelestia/components/effects/Elevation.qml new file mode 100644 index 0000000..fb29f16 --- /dev/null +++ b/.config/quickshell/caelestia/components/effects/Elevation.qml @@ -0,0 +1,18 @@ +import ".." +import qs.services +import QtQuick +import QtQuick.Effects + +RectangularShadow { + property int level + property real dp: [0, 1, 3, 6, 8, 12][level] + + color: Qt.alpha(Colours.palette.m3shadow, 0.7) + blur: (dp * 5) ** 0.7 + spread: -dp * 0.3 + (dp * 0.1) ** 2 + offset.y: dp / 2 + + Behavior on dp { + Anim {} + } +} diff --git a/.config/quickshell/caelestia/components/effects/InnerBorder.qml b/.config/quickshell/caelestia/components/effects/InnerBorder.qml new file mode 100644 index 0000000..d4a751f --- /dev/null +++ b/.config/quickshell/caelestia/components/effects/InnerBorder.qml @@ -0,0 +1,44 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Effects + +StyledRect { + property alias innerRadius: maskInner.radius + property alias thickness: maskInner.anchors.margins + property alias leftThickness: maskInner.anchors.leftMargin + property alias topThickness: maskInner.anchors.topMargin + property alias rightThickness: maskInner.anchors.rightMargin + property alias bottomThickness: maskInner.anchors.bottomMargin + + anchors.fill: parent + color: Colours.tPalette.m3surfaceContainer + + layer.enabled: true + layer.effect: MultiEffect { + maskSource: mask + maskEnabled: true + maskInverted: true + maskThresholdMin: 0.5 + maskSpreadAtMin: 1 + } + + Item { + id: mask + + anchors.fill: parent + layer.enabled: true + visible: false + + Rectangle { + id: maskInner + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + radius: Appearance.rounding.small + } + } +} diff --git a/.config/quickshell/caelestia/components/effects/OpacityMask.qml b/.config/quickshell/caelestia/components/effects/OpacityMask.qml new file mode 100644 index 0000000..22e4249 --- /dev/null +++ b/.config/quickshell/caelestia/components/effects/OpacityMask.qml @@ -0,0 +1,9 @@ +import Quickshell +import QtQuick + +ShaderEffect { + required property Item source + required property Item maskSource + + fragmentShader: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/shaders/opacitymask.frag.qsb`) +} diff --git a/.config/quickshell/caelestia/components/filedialog/CurrentItem.qml b/.config/quickshell/caelestia/components/filedialog/CurrentItem.qml new file mode 100644 index 0000000..bb87133 --- /dev/null +++ b/.config/quickshell/caelestia/components/filedialog/CurrentItem.qml @@ -0,0 +1,102 @@ +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Shapes + +Item { + id: root + + required property var currentItem + + implicitWidth: content.implicitWidth + Appearance.padding.larger + content.anchors.rightMargin + implicitHeight: currentItem ? content.implicitHeight + Appearance.padding.normal + content.anchors.bottomMargin : 0 + + Shape { + preferredRendererType: Shape.CurveRenderer + + ShapePath { + id: path + + readonly property real rounding: Appearance.rounding.small + readonly property bool flatten: root.implicitHeight < rounding * 2 + readonly property real roundingY: flatten ? root.implicitHeight / 2 : rounding + + strokeWidth: -1 + fillColor: Colours.tPalette.m3surfaceContainer + + startX: root.implicitWidth + startY: root.implicitHeight + + PathLine { + relativeX: -(root.implicitWidth + path.rounding) + relativeY: 0 + } + PathArc { + relativeX: path.rounding + relativeY: -path.roundingY + radiusX: path.rounding + radiusY: Math.min(path.rounding, root.implicitHeight) + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: -(root.implicitHeight - path.roundingY * 2) + } + PathArc { + relativeX: path.rounding + relativeY: -path.roundingY + radiusX: path.rounding + radiusY: Math.min(path.rounding, root.implicitHeight) + } + PathLine { + relativeX: root.implicitHeight > 0 ? root.implicitWidth - path.rounding * 2 : root.implicitWidth + relativeY: 0 + } + PathArc { + relativeX: path.rounding + relativeY: -path.rounding + radiusX: path.rounding + radiusY: path.rounding + direction: PathArc.Counterclockwise + } + + Behavior on fillColor { + CAnim {} + } + } + } + + Item { + anchors.fill: parent + clip: true + + StyledText { + id: content + + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.rightMargin: Appearance.padding.larger - Appearance.padding.small + anchors.bottomMargin: Appearance.padding.normal - Appearance.padding.small + + Connections { + target: root + + function onCurrentItemChanged(): void { + if (root.currentItem) + content.text = qsTr(`"%1" selected`).arg(root.currentItem.modelData.name); + } + } + } + } + + Behavior on implicitWidth { + enabled: !!root.currentItem + + Anim {} + } + + Behavior on implicitHeight { + Anim {} + } +} diff --git a/.config/quickshell/caelestia/components/filedialog/DialogButtons.qml b/.config/quickshell/caelestia/components/filedialog/DialogButtons.qml new file mode 100644 index 0000000..bde9ac2 --- /dev/null +++ b/.config/quickshell/caelestia/components/filedialog/DialogButtons.qml @@ -0,0 +1,93 @@ +import ".." +import qs.services +import qs.config +import QtQuick.Layouts + +StyledRect { + id: root + + required property var dialog + required property FolderContents folder + + implicitHeight: inner.implicitHeight + Appearance.padding.normal * 2 + + color: Colours.tPalette.m3surfaceContainer + + RowLayout { + id: inner + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.small + + StyledText { + text: qsTr("Filter:") + } + + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.rightMargin: Appearance.spacing.normal + + color: Colours.tPalette.m3surfaceContainerHigh + radius: Appearance.rounding.small + + StyledText { + anchors.fill: parent + anchors.margins: Appearance.padding.normal + + text: `${root.dialog.filterLabel} (${root.dialog.filters.map(f => `*.${f}`).join(", ")})` + } + } + + StyledRect { + color: Colours.tPalette.m3surfaceContainerHigh + radius: Appearance.rounding.small + + implicitWidth: cancelText.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: cancelText.implicitHeight + Appearance.padding.normal * 2 + + StateLayer { + disabled: !root.dialog.selectionValid + + function onClicked(): void { + root.dialog.accepted(root.folder.currentItem.modelData.path); + } + } + + StyledText { + id: selectText + + anchors.centerIn: parent + anchors.margins: Appearance.padding.normal + + text: qsTr("Select") + color: root.dialog.selectionValid ? Colours.palette.m3onSurface : Colours.palette.m3outline + } + } + + StyledRect { + color: Colours.tPalette.m3surfaceContainerHigh + radius: Appearance.rounding.small + + implicitWidth: cancelText.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: cancelText.implicitHeight + Appearance.padding.normal * 2 + + StateLayer { + function onClicked(): void { + root.dialog.rejected(); + } + } + + StyledText { + id: cancelText + + anchors.centerIn: parent + anchors.margins: Appearance.padding.normal + + text: qsTr("Cancel") + } + } + } +} diff --git a/.config/quickshell/caelestia/components/filedialog/FileDialog.qml b/.config/quickshell/caelestia/components/filedialog/FileDialog.qml new file mode 100644 index 0000000..f3187a5 --- /dev/null +++ b/.config/quickshell/caelestia/components/filedialog/FileDialog.qml @@ -0,0 +1,102 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import Quickshell +import QtQuick +import QtQuick.Layouts + +LazyLoader { + id: loader + + property list cwd: ["Home"] + property string filterLabel: "All files" + property list filters: ["*"] + property string title: qsTr("Select a file") + + signal accepted(path: string) + signal rejected + + function open(): void { + activeAsync = true; + } + + function close(): void { + rejected(); + } + + onAccepted: activeAsync = false + onRejected: activeAsync = false + + FloatingWindow { + id: root + + property list cwd: loader.cwd + property string filterLabel: loader.filterLabel + property list filters: loader.filters + + readonly property bool selectionValid: { + const file = folderContents.currentItem?.modelData; + return (file && !file.isDir && (filters.includes("*") || filters.includes(file.suffix))) ?? false; + } + + function accepted(path: string): void { + loader.accepted(path); + } + + function rejected(): void { + loader.rejected(); + } + + implicitWidth: 1000 + implicitHeight: 600 + color: Colours.tPalette.m3surface + title: loader.title + + onVisibleChanged: { + if (!visible) + rejected(); + } + + RowLayout { + anchors.fill: parent + + spacing: 0 + + Sidebar { + Layout.fillHeight: true + dialog: root + } + + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + + spacing: 0 + + HeaderBar { + Layout.fillWidth: true + dialog: root + } + + FolderContents { + id: folderContents + + Layout.fillWidth: true + Layout.fillHeight: true + dialog: root + } + + DialogButtons { + Layout.fillWidth: true + dialog: root + folder: folderContents + } + } + } + + Behavior on color { + CAnim {} + } + } +} diff --git a/.config/quickshell/caelestia/components/filedialog/FolderContents.qml b/.config/quickshell/caelestia/components/filedialog/FolderContents.qml new file mode 100644 index 0000000..e16c7a1 --- /dev/null +++ b/.config/quickshell/caelestia/components/filedialog/FolderContents.qml @@ -0,0 +1,228 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../controls" +import "../images" +import qs.services +import qs.config +import qs.utils +import Caelestia.Models +import Quickshell +import QtQuick +import QtQuick.Layouts +import QtQuick.Effects + +Item { + id: root + + required property var dialog + property alias currentItem: view.currentItem + + StyledRect { + anchors.fill: parent + color: Colours.tPalette.m3surfaceContainer + + layer.enabled: true + layer.effect: MultiEffect { + maskSource: mask + maskEnabled: true + maskInverted: true + maskThresholdMin: 0.5 + maskSpreadAtMin: 1 + } + } + + Item { + id: mask + + anchors.fill: parent + layer.enabled: true + visible: false + + Rectangle { + anchors.fill: parent + anchors.margins: Appearance.padding.small + radius: Appearance.rounding.small + } + } + + Loader { + anchors.centerIn: parent + + opacity: view.count === 0 ? 1 : 0 + active: opacity > 0 + + sourceComponent: ColumnLayout { + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: "scan_delete" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.extraLarge * 2 + font.weight: 500 + } + + StyledText { + text: qsTr("This folder is empty") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + } + + Behavior on opacity { + Anim {} + } + } + + GridView { + id: view + + anchors.fill: parent + anchors.margins: Appearance.padding.small + Appearance.padding.normal + + cellWidth: Sizes.itemWidth + Appearance.spacing.small + cellHeight: Sizes.itemWidth + Appearance.spacing.small * 2 + Appearance.padding.normal * 2 + 1 + + clip: true + focus: true + currentIndex: -1 + Keys.onEscapePressed: currentIndex = -1 + + Keys.onReturnPressed: { + if (root.dialog.selectionValid) + root.dialog.accepted(currentItem.modelData.path); + } + Keys.onEnterPressed: { + if (root.dialog.selectionValid) + root.dialog.accepted(currentItem.modelData.path); + } + + StyledScrollBar.vertical: StyledScrollBar { + flickable: view + } + + model: FileSystemModel { + path: { + if (root.dialog.cwd[0] === "Home") + return `${Paths.home}/${root.dialog.cwd.slice(1).join("/")}`; + else + return root.dialog.cwd.join("/"); + } + onPathChanged: view.currentIndex = -1 + } + + delegate: StyledRect { + id: item + + required property int index + required property FileSystemEntry modelData + + readonly property real nonAnimHeight: icon.implicitHeight + name.anchors.topMargin + name.implicitHeight + Appearance.padding.normal * 2 + + implicitWidth: Sizes.itemWidth + implicitHeight: nonAnimHeight + + radius: Appearance.rounding.normal + color: Qt.alpha(Colours.tPalette.m3surfaceContainerHighest, GridView.isCurrentItem ? Colours.tPalette.m3surfaceContainerHighest.a : 0) + z: GridView.isCurrentItem || implicitHeight !== nonAnimHeight ? 1 : 0 + clip: true + + StateLayer { + onDoubleClicked: { + if (item.modelData.isDir) + root.dialog.cwd.push(item.modelData.name); + else if (root.dialog.selectionValid) + root.dialog.accepted(item.modelData.path); + } + + function onClicked(): void { + view.currentIndex = item.index; + } + } + + CachingIconImage { + id: icon + + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: Appearance.padding.normal + + implicitSize: Sizes.itemWidth - Appearance.padding.normal * 2 + + Component.onCompleted: { + const file = item.modelData; + if (file.isImage) + source = Qt.resolvedUrl(file.path); + else if (!file.isDir) + source = Quickshell.iconPath(file.mimeType.replace("/", "-"), "application-x-zerosize"); + else if (root.dialog.cwd.length === 1 && ["Desktop", "Documents", "Downloads", "Music", "Pictures", "Public", "Templates", "Videos"].includes(file.name)) + source = Quickshell.iconPath(`folder-${file.name.toLowerCase()}`); + else + source = Quickshell.iconPath("inode-directory"); + } + } + + StyledText { + id: name + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: icon.bottom + anchors.topMargin: Appearance.spacing.small + anchors.margins: Appearance.padding.normal + + horizontalAlignment: Text.AlignHCenter + elide: item.GridView.isCurrentItem ? Text.ElideNone : Text.ElideRight + wrapMode: item.GridView.isCurrentItem ? Text.WrapAtWordBoundaryOrAnywhere : Text.NoWrap + + Component.onCompleted: text = item.modelData.name + } + + Behavior on implicitHeight { + Anim {} + } + } + + add: Transition { + Anim { + properties: "opacity,scale" + from: 0 + to: 1 + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + remove: Transition { + Anim { + property: "opacity" + to: 0 + } + Anim { + property: "scale" + to: 0.5 + } + } + + displaced: Transition { + Anim { + properties: "opacity,scale" + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + properties: "x,y" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + + CurrentItem { + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: Appearance.padding.small + + currentItem: view.currentItem + } +} diff --git a/.config/quickshell/caelestia/components/filedialog/HeaderBar.qml b/.config/quickshell/caelestia/components/filedialog/HeaderBar.qml new file mode 100644 index 0000000..c9a3feb --- /dev/null +++ b/.config/quickshell/caelestia/components/filedialog/HeaderBar.qml @@ -0,0 +1,139 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property var dialog + + implicitWidth: inner.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: inner.implicitHeight + Appearance.padding.normal * 2 + + color: Colours.tPalette.m3surfaceContainer + + RowLayout { + id: inner + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + spacing: Appearance.spacing.small + + Item { + implicitWidth: implicitHeight + implicitHeight: upIcon.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + radius: Appearance.rounding.small + disabled: root.dialog.cwd.length === 1 + + function onClicked(): void { + root.dialog.cwd.pop(); + } + } + + MaterialIcon { + id: upIcon + + anchors.centerIn: parent + text: "drive_folder_upload" + color: root.dialog.cwd.length === 1 ? Colours.palette.m3outline : Colours.palette.m3onSurface + grade: 200 + } + } + + StyledRect { + Layout.fillWidth: true + + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainerHigh + + implicitHeight: pathComponents.implicitHeight + pathComponents.anchors.margins * 2 + + RowLayout { + id: pathComponents + + anchors.fill: parent + anchors.margins: Appearance.padding.small / 2 + anchors.leftMargin: 0 + + spacing: Appearance.spacing.small + + Repeater { + model: root.dialog.cwd + + RowLayout { + id: folder + + required property string modelData + required property int index + + spacing: 0 + + Loader { + Layout.rightMargin: Appearance.spacing.small + active: folder.index > 0 + sourceComponent: StyledText { + text: "/" + color: Colours.palette.m3onSurfaceVariant + font.bold: true + } + } + + Item { + implicitWidth: homeIcon.implicitWidth + (homeIcon.active ? Appearance.padding.small : 0) + folderName.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: folderName.implicitHeight + Appearance.padding.small * 2 + + Loader { + anchors.fill: parent + active: folder.index < root.dialog.cwd.length - 1 + sourceComponent: StateLayer { + radius: Appearance.rounding.small + + function onClicked(): void { + root.dialog.cwd = root.dialog.cwd.slice(0, folder.index + 1); + } + } + } + + Loader { + id: homeIcon + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.padding.normal + + active: folder.index === 0 && folder.modelData === "Home" + sourceComponent: MaterialIcon { + text: "home" + color: root.dialog.cwd.length === 1 ? Colours.palette.m3onSurface : Colours.palette.m3onSurfaceVariant + fill: 1 + } + } + + StyledText { + id: folderName + + anchors.left: homeIcon.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: homeIcon.active ? Appearance.padding.small : 0 + + text: folder.modelData + color: folder.index < root.dialog.cwd.length - 1 ? Colours.palette.m3onSurfaceVariant : Colours.palette.m3onSurface + font.bold: true + } + } + } + } + + Item { + Layout.fillWidth: true + } + } + } + } +} diff --git a/.config/quickshell/caelestia/components/filedialog/Sidebar.qml b/.config/quickshell/caelestia/components/filedialog/Sidebar.qml new file mode 100644 index 0000000..b55d7b3 --- /dev/null +++ b/.config/quickshell/caelestia/components/filedialog/Sidebar.qml @@ -0,0 +1,113 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property var dialog + + implicitWidth: Sizes.sidebarWidth + implicitHeight: inner.implicitHeight + Appearance.padding.normal * 2 + + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: inner + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: Appearance.padding.normal + spacing: Appearance.spacing.small / 2 + + StyledText { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Appearance.padding.small / 2 + Layout.bottomMargin: Appearance.spacing.normal + text: qsTr("Files") + color: Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.larger + font.bold: true + } + + Repeater { + model: ["Home", "Downloads", "Desktop", "Documents", "Music", "Pictures", "Videos"] + + StyledRect { + id: place + + required property string modelData + readonly property bool selected: modelData === root.dialog.cwd[root.dialog.cwd.length - 1] + + Layout.fillWidth: true + implicitHeight: placeInner.implicitHeight + Appearance.padding.normal * 2 + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3secondaryContainer, selected ? 1 : 0) + + StateLayer { + color: place.selected ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + + function onClicked(): void { + if (place.modelData === "Home") + root.dialog.cwd = ["Home"]; + else + root.dialog.cwd = ["Home", place.modelData]; + } + } + + RowLayout { + id: placeInner + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + anchors.leftMargin: Appearance.padding.large + anchors.rightMargin: Appearance.padding.large + + spacing: Appearance.spacing.normal + + MaterialIcon { + text: { + const p = place.modelData; + if (p === "Home") + return "home"; + if (p === "Downloads") + return "file_download"; + if (p === "Desktop") + return "desktop_windows"; + if (p === "Documents") + return "description"; + if (p === "Music") + return "music_note"; + if (p === "Pictures") + return "image"; + if (p === "Videos") + return "video_library"; + return "folder"; + } + color: place.selected ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.large + fill: place.selected ? 1 : 0 + + Behavior on fill { + Anim {} + } + } + + StyledText { + Layout.fillWidth: true + text: place.modelData + color: place.selected ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.normal + elide: Text.ElideRight + } + } + } + } + } +} diff --git a/.config/quickshell/caelestia/components/filedialog/Sizes.qml b/.config/quickshell/caelestia/components/filedialog/Sizes.qml new file mode 100644 index 0000000..2ad31f9 --- /dev/null +++ b/.config/quickshell/caelestia/components/filedialog/Sizes.qml @@ -0,0 +1,8 @@ +pragma Singleton + +import Quickshell + +Singleton { + property int itemWidth: 103 + property int sidebarWidth: 200 +} diff --git a/.config/quickshell/caelestia/components/images/CachingIconImage.qml b/.config/quickshell/caelestia/components/images/CachingIconImage.qml new file mode 100644 index 0000000..1acc6a1 --- /dev/null +++ b/.config/quickshell/caelestia/components/images/CachingIconImage.qml @@ -0,0 +1,42 @@ +pragma ComponentBehavior: Bound + +import qs.utils +import Quickshell.Widgets +import QtQuick + +Item { + id: root + + readonly property int status: loader.item?.status ?? Image.Null + readonly property real actualSize: Math.min(width, height) + property real implicitSize + property url source + + implicitWidth: implicitSize + implicitHeight: implicitSize + + Loader { + id: loader + + anchors.fill: parent + sourceComponent: root.source ? root.source.toString().startsWith("image://icon/") ? iconImage : cachingImage : null + } + + Component { + id: cachingImage + + CachingImage { + path: Paths.toLocalFile(root.source) + fillMode: Image.PreserveAspectFit + } + } + + Component { + id: iconImage + + IconImage { + source: root.source + asynchronous: true + } + } +} diff --git a/.config/quickshell/caelestia/components/images/CachingImage.qml b/.config/quickshell/caelestia/components/images/CachingImage.qml new file mode 100644 index 0000000..e8f957a --- /dev/null +++ b/.config/quickshell/caelestia/components/images/CachingImage.qml @@ -0,0 +1,28 @@ +import qs.utils +import Caelestia.Internal +import Quickshell +import QtQuick + +Image { + id: root + + property alias path: manager.path + + asynchronous: true + fillMode: Image.PreserveAspectCrop + + Connections { + target: QsWindow.window + + function onDevicePixelRatioChanged(): void { + manager.updateSource(); + } + } + + CachingImageManager { + id: manager + + item: root + cacheDir: Qt.resolvedUrl(Paths.imagecache) + } +} diff --git a/.config/quickshell/caelestia/components/misc/CustomShortcut.qml b/.config/quickshell/caelestia/components/misc/CustomShortcut.qml new file mode 100644 index 0000000..aa35ed8 --- /dev/null +++ b/.config/quickshell/caelestia/components/misc/CustomShortcut.qml @@ -0,0 +1,5 @@ +import Quickshell.Hyprland + +GlobalShortcut { + appid: "caelestia" +} diff --git a/.config/quickshell/caelestia/components/misc/Ref.qml b/.config/quickshell/caelestia/components/misc/Ref.qml new file mode 100644 index 0000000..0a694a4 --- /dev/null +++ b/.config/quickshell/caelestia/components/misc/Ref.qml @@ -0,0 +1,8 @@ +import QtQuick + +QtObject { + required property var service + + Component.onCompleted: service.refCount++ + Component.onDestruction: service.refCount-- +} diff --git a/.config/quickshell/caelestia/components/widgets/ExtraIndicator.qml b/.config/quickshell/caelestia/components/widgets/ExtraIndicator.qml new file mode 100644 index 0000000..db73ea0 --- /dev/null +++ b/.config/quickshell/caelestia/components/widgets/ExtraIndicator.qml @@ -0,0 +1,51 @@ +import ".." +import "../effects" +import qs.services +import qs.config +import QtQuick + +StyledRect { + required property int extra + + anchors.right: parent.right + anchors.margins: Appearance.padding.normal + + color: Colours.palette.m3tertiary + radius: Appearance.rounding.small + + implicitWidth: count.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: count.implicitHeight + Appearance.padding.small * 2 + + opacity: extra > 0 ? 1 : 0 + scale: extra > 0 ? 1 : 0.5 + + Elevation { + anchors.fill: parent + radius: parent.radius + opacity: parent.opacity + z: -1 + level: 2 + } + + StyledText { + id: count + + anchors.centerIn: parent + animate: parent.opacity > 0 + text: qsTr("+%1").arg(parent.extra) + color: Colours.palette.m3onTertiary + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + } + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } +} diff --git a/.config/quickshell/caelestia/config/Appearance.qml b/.config/quickshell/caelestia/config/Appearance.qml new file mode 100644 index 0000000..241c21a --- /dev/null +++ b/.config/quickshell/caelestia/config/Appearance.qml @@ -0,0 +1,14 @@ +pragma Singleton + +import Quickshell + +Singleton { + // Literally just here to shorten accessing stuff :woe: + // Also kinda so I can keep accessing it with `Appearance.xxx` instead of `Config.appearance.xxx` + readonly property AppearanceConfig.Rounding rounding: Config.appearance.rounding + readonly property AppearanceConfig.Spacing spacing: Config.appearance.spacing + readonly property AppearanceConfig.Padding padding: Config.appearance.padding + readonly property AppearanceConfig.FontStuff font: Config.appearance.font + readonly property AppearanceConfig.Anim anim: Config.appearance.anim + readonly property AppearanceConfig.Transparency transparency: Config.appearance.transparency +} diff --git a/.config/quickshell/caelestia/config/AppearanceConfig.qml b/.config/quickshell/caelestia/config/AppearanceConfig.qml new file mode 100644 index 0000000..3d590dc --- /dev/null +++ b/.config/quickshell/caelestia/config/AppearanceConfig.qml @@ -0,0 +1,94 @@ +import Quickshell.Io + +JsonObject { + property Rounding rounding: Rounding {} + property Spacing spacing: Spacing {} + property Padding padding: Padding {} + property FontStuff font: FontStuff {} + property Anim anim: Anim {} + property Transparency transparency: Transparency {} + + component Rounding: JsonObject { + property real scale: 1 + property int small: 12 * scale + property int normal: 17 * scale + property int large: 25 * scale + property int full: 1000 * scale + } + + component Spacing: JsonObject { + property real scale: 1 + property int small: 7 * scale + property int smaller: 10 * scale + property int normal: 12 * scale + property int larger: 15 * scale + property int large: 20 * scale + } + + component Padding: JsonObject { + property real scale: 1 + property int small: 5 * scale + property int smaller: 7 * scale + property int normal: 10 * scale + property int larger: 12 * scale + property int large: 15 * scale + } + + component FontFamily: JsonObject { + property string sans: "Rubik" + property string mono: "CaskaydiaCove NF" + property string material: "Material Symbols Rounded" + property string clock: "Rubik" + } + + component FontSize: JsonObject { + property real scale: 1 + property int small: 11 * scale + property int smaller: 12 * scale + property int normal: 13 * scale + property int larger: 15 * scale + property int large: 18 * scale + property int extraLarge: 28 * scale + } + + component FontStuff: JsonObject { + property FontFamily family: FontFamily {} + property FontSize size: FontSize {} + } + + component AnimCurves: JsonObject { + property list emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1] + property list emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1] + property list emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1] + property list standard: [0.2, 0, 0, 1, 1, 1] + property list standardAccel: [0.3, 0, 1, 1, 1, 1] + property list standardDecel: [0, 0, 0, 1, 1, 1] + property list expressiveFastSpatial: [0.42, 1.67, 0.21, 0.9, 1, 1] + property list expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1, 1, 1] + property list expressiveEffects: [0.34, 0.8, 0.34, 1, 1, 1] + } + + component AnimDurations: JsonObject { + property real scale: 1 + property int small: 200 * scale + property int normal: 400 * scale + property int large: 600 * scale + property int extraLarge: 1000 * scale + property int expressiveFastSpatial: 350 * scale + property int expressiveDefaultSpatial: 500 * scale + property int expressiveEffects: 200 * scale + } + + component Anim: JsonObject { + property real mediaGifSpeedAdjustment: 300 + property real sessionGifSpeed: 0.7 + property AnimCurves curves: AnimCurves {} + property AnimDurations durations: AnimDurations {} + } + + component Transparency: JsonObject { + property bool enabled: false + property real base: 0.85 + property real layers: 0.4 + } +} diff --git a/.config/quickshell/caelestia/config/BackgroundConfig.qml b/.config/quickshell/caelestia/config/BackgroundConfig.qml new file mode 100644 index 0000000..8383f52 --- /dev/null +++ b/.config/quickshell/caelestia/config/BackgroundConfig.qml @@ -0,0 +1,37 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: true + property bool wallpaperEnabled: true + property DesktopClock desktopClock: DesktopClock {} + property Visualiser visualiser: Visualiser {} + + component DesktopClock: JsonObject { + property bool enabled: false + property real scale: 1.0 + property string position: "bottom-right" + property bool invertColors: false + property DesktopClockBackground background: DesktopClockBackground {} + property DesktopClockShadow shadow: DesktopClockShadow {} + } + + component DesktopClockBackground: JsonObject { + property bool enabled: false + property real opacity: 0.7 + property bool blur: true + } + + component DesktopClockShadow: JsonObject { + property bool enabled: true + property real opacity: 0.7 + property real blur: 0.4 + } + + component Visualiser: JsonObject { + property bool enabled: false + property bool autoHide: true + property bool blur: false + property real rounding: 1 + property real spacing: 1 + } +} diff --git a/.config/quickshell/caelestia/config/BarConfig.qml b/.config/quickshell/caelestia/config/BarConfig.qml new file mode 100644 index 0000000..36a5f78 --- /dev/null +++ b/.config/quickshell/caelestia/config/BarConfig.qml @@ -0,0 +1,118 @@ +import Quickshell.Io + +JsonObject { + property bool persistent: true + property bool showOnHover: true + property int dragThreshold: 20 + property ScrollActions scrollActions: ScrollActions {} + property Popouts popouts: Popouts {} + property Workspaces workspaces: Workspaces {} + property ActiveWindow activeWindow: ActiveWindow {} + property Tray tray: Tray {} + property Status status: Status {} + property Clock clock: Clock {} + property Sizes sizes: Sizes {} + property list excludedScreens: [] + + property list entries: [ + { + id: "logo", + enabled: true + }, + { + id: "workspaces", + enabled: true + }, + { + id: "spacer", + enabled: true + }, + { + id: "activeWindow", + enabled: true + }, + { + id: "spacer", + enabled: true + }, + { + id: "tray", + enabled: true + }, + { + id: "clock", + enabled: true + }, + { + id: "statusIcons", + enabled: true + }, + { + id: "power", + enabled: true + } + ] + + component ScrollActions: JsonObject { + property bool workspaces: true + property bool volume: true + property bool brightness: true + } + + component Popouts: JsonObject { + property bool activeWindow: true + property bool tray: true + property bool statusIcons: true + } + + component Workspaces: JsonObject { + property int shown: 5 + property bool activeIndicator: true + property bool occupiedBg: false + property bool showWindows: true + property bool showWindowsOnSpecialWorkspaces: showWindows + property bool activeTrail: false + property bool perMonitorWorkspaces: true + property string label: " " // if empty, will show workspace name's first letter + property string occupiedLabel: "󰮯" + property string activeLabel: "󰮯" + property string capitalisation: "preserve" // upper, lower, or preserve - relevant only if label is empty + property list specialWorkspaceIcons: [] + } + + component ActiveWindow: JsonObject { + property bool inverted: false + } + + component Tray: JsonObject { + property bool background: false + property bool recolour: false + property bool compact: false + property list iconSubs: [] + property list hiddenIcons: [] + } + + component Status: JsonObject { + property bool showAudio: false + property bool showMicrophone: false + property bool showKbLayout: false + property bool showNetwork: true + property bool showWifi: true + property bool showBluetooth: true + property bool showBattery: true + property bool showLockStatus: true + } + + component Clock: JsonObject { + property bool showIcon: true + } + + component Sizes: JsonObject { + property int innerWidth: 40 + property int windowPreviewSize: 400 + property int trayMenuWidth: 300 + property int batteryWidth: 250 + property int networkWidth: 320 + property int kbLayoutWidth: 320 + } +} diff --git a/.config/quickshell/caelestia/config/BorderConfig.qml b/.config/quickshell/caelestia/config/BorderConfig.qml new file mode 100644 index 0000000..b15811f --- /dev/null +++ b/.config/quickshell/caelestia/config/BorderConfig.qml @@ -0,0 +1,6 @@ +import Quickshell.Io + +JsonObject { + property int thickness: Appearance.padding.normal + property int rounding: Appearance.rounding.large +} diff --git a/.config/quickshell/caelestia/config/Config.qml b/.config/quickshell/caelestia/config/Config.qml new file mode 100644 index 0000000..8c01014 --- /dev/null +++ b/.config/quickshell/caelestia/config/Config.qml @@ -0,0 +1,522 @@ +pragma Singleton + +import qs.utils +import Caelestia +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + property alias appearance: adapter.appearance + property alias general: adapter.general + property alias background: adapter.background + property alias bar: adapter.bar + property alias border: adapter.border + property alias dashboard: adapter.dashboard + property alias controlCenter: adapter.controlCenter + property alias launcher: adapter.launcher + property alias notifs: adapter.notifs + property alias osd: adapter.osd + property alias session: adapter.session + property alias winfo: adapter.winfo + property alias lock: adapter.lock + property alias utilities: adapter.utilities + property alias sidebar: adapter.sidebar + property alias services: adapter.services + property alias paths: adapter.paths + + // Public save function - call this to persist config changes + function save(): void { + saveTimer.restart(); + recentlySaved = true; + recentSaveCooldown.restart(); + } + + property bool recentlySaved: false + + ElapsedTimer { + id: timer + } + + Timer { + id: saveTimer + + interval: 500 + onTriggered: { + timer.restart(); + try { + // Parse current config to preserve structure and comments if possible + let config = {}; + try { + config = JSON.parse(fileView.text()); + } catch (e) { + // If parsing fails, start with empty object + config = {}; + } + + // Update config with current values + config = serializeConfig(); + + // Save to file with pretty printing + fileView.setText(JSON.stringify(config, null, 2)); + } catch (e) { + Toaster.toast(qsTr("Failed to serialize config"), e.message, "settings_alert", Toast.Error); + } + } + } + + Timer { + id: recentSaveCooldown + + interval: 2000 + onTriggered: { + recentlySaved = false; + } + } + + // Helper function to serialize the config object + function serializeConfig(): var { + return { + appearance: serializeAppearance(), + general: serializeGeneral(), + background: serializeBackground(), + bar: serializeBar(), + border: serializeBorder(), + dashboard: serializeDashboard(), + controlCenter: serializeControlCenter(), + launcher: serializeLauncher(), + notifs: serializeNotifs(), + osd: serializeOsd(), + session: serializeSession(), + winfo: serializeWinfo(), + lock: serializeLock(), + utilities: serializeUtilities(), + sidebar: serializeSidebar(), + services: serializeServices(), + paths: serializePaths() + }; + } + + function serializeAppearance(): var { + return { + rounding: { + scale: appearance.rounding.scale + }, + spacing: { + scale: appearance.spacing.scale + }, + padding: { + scale: appearance.padding.scale + }, + font: { + family: { + sans: appearance.font.family.sans, + mono: appearance.font.family.mono, + material: appearance.font.family.material, + clock: appearance.font.family.clock + }, + size: { + scale: appearance.font.size.scale + } + }, + anim: { + mediaGifSpeedAdjustment: 300, + sessionGifSpeed: 0.7, + durations: { + scale: appearance.anim.durations.scale + } + }, + transparency: { + enabled: appearance.transparency.enabled, + base: appearance.transparency.base, + layers: appearance.transparency.layers + } + }; + } + + function serializeGeneral(): var { + return { + logo: general.logo, + apps: { + terminal: general.apps.terminal, + audio: general.apps.audio, + playback: general.apps.playback, + explorer: general.apps.explorer + }, + idle: { + lockBeforeSleep: general.idle.lockBeforeSleep, + inhibitWhenAudio: general.idle.inhibitWhenAudio, + timeouts: general.idle.timeouts + }, + battery: { + warnLevels: general.battery.warnLevels, + criticalLevel: general.battery.criticalLevel + } + }; + } + + function serializeBackground(): var { + return { + enabled: background.enabled, + wallpaperEnabled: background.wallpaperEnabled, + desktopClock: { + enabled: background.desktopClock.enabled, + scale: background.desktopClock.scale, + position: background.desktopClock.position, + invertColors: background.desktopClock.invertColors, + background: { + enabled: background.desktopClock.background.enabled, + opacity: background.desktopClock.background.opacity, + blur: background.desktopClock.background.blur + }, + shadow: { + enabled: background.desktopClock.shadow.enabled, + opacity: background.desktopClock.shadow.opacity, + blur: background.desktopClock.shadow.blur + } + }, + visualiser: { + enabled: background.visualiser.enabled, + autoHide: background.visualiser.autoHide, + blur: background.visualiser.blur, + rounding: background.visualiser.rounding, + spacing: background.visualiser.spacing + } + }; + } + + function serializeBar(): var { + return { + persistent: bar.persistent, + showOnHover: bar.showOnHover, + dragThreshold: bar.dragThreshold, + scrollActions: { + workspaces: bar.scrollActions.workspaces, + volume: bar.scrollActions.volume, + brightness: bar.scrollActions.brightness + }, + popouts: { + activeWindow: bar.popouts.activeWindow, + tray: bar.popouts.tray, + statusIcons: bar.popouts.statusIcons + }, + workspaces: { + shown: bar.workspaces.shown, + activeIndicator: bar.workspaces.activeIndicator, + occupiedBg: bar.workspaces.occupiedBg, + showWindows: bar.workspaces.showWindows, + showWindowsOnSpecialWorkspaces: bar.workspaces.showWindowsOnSpecialWorkspaces, + activeTrail: bar.workspaces.activeTrail, + perMonitorWorkspaces: bar.workspaces.perMonitorWorkspaces, + label: bar.workspaces.label, + occupiedLabel: bar.workspaces.occupiedLabel, + activeLabel: bar.workspaces.activeLabel, + capitalisation: bar.workspaces.capitalisation, + specialWorkspaceIcons: bar.workspaces.specialWorkspaceIcons + }, + tray: { + background: bar.tray.background, + recolour: bar.tray.recolour, + compact: bar.tray.compact, + iconSubs: bar.tray.iconSubs + }, + status: { + showAudio: bar.status.showAudio, + showMicrophone: bar.status.showMicrophone, + showKbLayout: bar.status.showKbLayout, + showNetwork: bar.status.showNetwork, + showWifi: bar.status.showWifi, + showBluetooth: bar.status.showBluetooth, + showBattery: bar.status.showBattery, + showLockStatus: bar.status.showLockStatus + }, + clock: { + showIcon: bar.clock.showIcon + }, + sizes: { + innerWidth: bar.sizes.innerWidth, + windowPreviewSize: bar.sizes.windowPreviewSize, + trayMenuWidth: bar.sizes.trayMenuWidth, + batteryWidth: bar.sizes.batteryWidth, + networkWidth: bar.sizes.networkWidth + }, + entries: bar.entries, + excludedScreens: bar.excludedScreens + }; + } + + function serializeBorder(): var { + return { + thickness: border.thickness, + rounding: border.rounding + }; + } + + function serializeDashboard(): var { + return { + enabled: dashboard.enabled, + showOnHover: dashboard.showOnHover, + updateInterval: dashboard.updateInterval, + dragThreshold: dashboard.dragThreshold, + performance: { + showBattery: dashboard.performance.showBattery, + showGpu: dashboard.performance.showGpu, + showCpu: dashboard.performance.showCpu, + showMemory: dashboard.performance.showMemory, + showStorage: dashboard.performance.showStorage, + showNetwork: dashboard.performance.showNetwork + }, + sizes: { + tabIndicatorHeight: dashboard.sizes.tabIndicatorHeight, + tabIndicatorSpacing: dashboard.sizes.tabIndicatorSpacing, + infoWidth: dashboard.sizes.infoWidth, + infoIconSize: dashboard.sizes.infoIconSize, + dateTimeWidth: dashboard.sizes.dateTimeWidth, + mediaWidth: dashboard.sizes.mediaWidth, + mediaProgressSweep: dashboard.sizes.mediaProgressSweep, + mediaProgressThickness: dashboard.sizes.mediaProgressThickness, + resourceProgessThickness: dashboard.sizes.resourceProgessThickness, + weatherWidth: dashboard.sizes.weatherWidth, + mediaCoverArtSize: dashboard.sizes.mediaCoverArtSize, + mediaVisualiserSize: dashboard.sizes.mediaVisualiserSize, + resourceSize: dashboard.sizes.resourceSize + } + }; + } + + function serializeControlCenter(): var { + return { + sizes: { + heightMult: controlCenter.sizes.heightMult, + ratio: controlCenter.sizes.ratio + } + }; + } + + function serializeLauncher(): var { + return { + enabled: launcher.enabled, + showOnHover: launcher.showOnHover, + maxShown: launcher.maxShown, + maxWallpapers: launcher.maxWallpapers, + specialPrefix: launcher.specialPrefix, + actionPrefix: launcher.actionPrefix, + enableDangerousActions: launcher.enableDangerousActions, + dragThreshold: launcher.dragThreshold, + vimKeybinds: launcher.vimKeybinds, + favouriteApps: launcher.favouriteApps, + hiddenApps: launcher.hiddenApps, + useFuzzy: { + apps: launcher.useFuzzy.apps, + actions: launcher.useFuzzy.actions, + schemes: launcher.useFuzzy.schemes, + variants: launcher.useFuzzy.variants, + wallpapers: launcher.useFuzzy.wallpapers + }, + sizes: { + itemWidth: launcher.sizes.itemWidth, + itemHeight: launcher.sizes.itemHeight, + wallpaperWidth: launcher.sizes.wallpaperWidth, + wallpaperHeight: launcher.sizes.wallpaperHeight + }, + actions: launcher.actions + }; + } + + function serializeNotifs(): var { + return { + expire: notifs.expire, + defaultExpireTimeout: notifs.defaultExpireTimeout, + clearThreshold: notifs.clearThreshold, + expandThreshold: notifs.expandThreshold, + actionOnClick: notifs.actionOnClick, + groupPreviewNum: notifs.groupPreviewNum, + sizes: { + width: notifs.sizes.width, + image: notifs.sizes.image, + badge: notifs.sizes.badge + } + }; + } + + function serializeOsd(): var { + return { + enabled: osd.enabled, + hideDelay: osd.hideDelay, + enableBrightness: osd.enableBrightness, + enableMicrophone: osd.enableMicrophone, + sizes: { + sliderWidth: osd.sizes.sliderWidth, + sliderHeight: osd.sizes.sliderHeight + } + }; + } + + function serializeSession(): var { + return { + enabled: session.enabled, + dragThreshold: session.dragThreshold, + vimKeybinds: session.vimKeybinds, + icons: { + logout: session.icons.logout, + shutdown: session.icons.shutdown, + hibernate: session.icons.hibernate, + reboot: session.icons.reboot + }, + commands: { + logout: session.commands.logout, + shutdown: session.commands.shutdown, + hibernate: session.commands.hibernate, + reboot: session.commands.reboot + }, + sizes: { + button: session.sizes.button + } + }; + } + + function serializeWinfo(): var { + return { + sizes: { + heightMult: winfo.sizes.heightMult, + detailsWidth: winfo.sizes.detailsWidth + } + }; + } + + function serializeLock(): var { + return { + recolourLogo: lock.recolourLogo, + enableFprint: lock.enableFprint, + maxFprintTries: lock.maxFprintTries, + sizes: { + heightMult: lock.sizes.heightMult, + ratio: lock.sizes.ratio, + centerWidth: lock.sizes.centerWidth + } + }; + } + + function serializeUtilities(): var { + return { + enabled: utilities.enabled, + maxToasts: utilities.maxToasts, + sizes: { + width: utilities.sizes.width, + toastWidth: utilities.sizes.toastWidth + }, + toasts: { + configLoaded: utilities.toasts.configLoaded, + chargingChanged: utilities.toasts.chargingChanged, + gameModeChanged: utilities.toasts.gameModeChanged, + dndChanged: utilities.toasts.dndChanged, + audioOutputChanged: utilities.toasts.audioOutputChanged, + audioInputChanged: utilities.toasts.audioInputChanged, + capsLockChanged: utilities.toasts.capsLockChanged, + numLockChanged: utilities.toasts.numLockChanged, + kbLayoutChanged: utilities.toasts.kbLayoutChanged, + vpnChanged: utilities.toasts.vpnChanged, + nowPlaying: utilities.toasts.nowPlaying + }, + vpn: { + enabled: utilities.vpn.enabled, + provider: utilities.vpn.provider + } + }; + } + + function serializeSidebar(): var { + return { + enabled: sidebar.enabled, + dragThreshold: sidebar.dragThreshold, + sizes: { + width: sidebar.sizes.width + } + }; + } + + function serializeServices(): var { + return { + weatherLocation: services.weatherLocation, + useFahrenheit: services.useFahrenheit, + useFahrenheitPerformance: services.useFahrenheitPerformance, + useTwelveHourClock: services.useTwelveHourClock, + gpuType: services.gpuType, + visualiserBars: services.visualiserBars, + audioIncrement: services.audioIncrement, + brightnessIncrement: services.brightnessIncrement, + maxVolume: services.maxVolume, + smartScheme: services.smartScheme, + defaultPlayer: services.defaultPlayer, + playerAliases: services.playerAliases + }; + } + + function serializePaths(): var { + return { + wallpaperDir: paths.wallpaperDir, + sessionGif: paths.sessionGif, + mediaGif: paths.mediaGif + }; + } + + FileView { + id: fileView + + path: `${Paths.config}/shell.json` + watchChanges: true + onFileChanged: { + // Prevent reload loop - don't reload if we just saved + if (!recentlySaved) { + timer.restart(); + reload(); + } else { + // Self-initiated save - reload without toast + reload(); + } + } + onLoaded: { + try { + JSON.parse(text()); + const elapsed = timer.elapsedMs(); + // Only show toast for external changes (not our own saves) and when elapsed time is meaningful + if (adapter.utilities.toasts.configLoaded && !recentlySaved && elapsed > 0) { + Toaster.toast(qsTr("Config loaded"), qsTr("Config loaded in %1ms").arg(elapsed), "rule_settings"); + } else if (adapter.utilities.toasts.configLoaded && recentlySaved && elapsed > 0) { + Toaster.toast(qsTr("Config saved"), qsTr("Config reloaded in %1ms").arg(elapsed), "rule_settings"); + } + } catch (e) { + Toaster.toast(qsTr("Failed to load config"), e.message, "settings_alert", Toast.Error); + } + } + onLoadFailed: err => { + if (err !== FileViewError.FileNotFound) + Toaster.toast(qsTr("Failed to read config file"), FileViewError.toString(err), "settings_alert", Toast.Warning); + } + onSaveFailed: err => Toaster.toast(qsTr("Failed to save config"), FileViewError.toString(err), "settings_alert", Toast.Error) + + JsonAdapter { + id: adapter + + property AppearanceConfig appearance: AppearanceConfig {} + property GeneralConfig general: GeneralConfig {} + property BackgroundConfig background: BackgroundConfig {} + property BarConfig bar: BarConfig {} + property BorderConfig border: BorderConfig {} + property DashboardConfig dashboard: DashboardConfig {} + property ControlCenterConfig controlCenter: ControlCenterConfig {} + property LauncherConfig launcher: LauncherConfig {} + property NotifsConfig notifs: NotifsConfig {} + property OsdConfig osd: OsdConfig {} + property SessionConfig session: SessionConfig {} + property WInfoConfig winfo: WInfoConfig {} + property LockConfig lock: LockConfig {} + property UtilitiesConfig utilities: UtilitiesConfig {} + property SidebarConfig sidebar: SidebarConfig {} + property ServiceConfig services: ServiceConfig {} + property UserPaths paths: UserPaths {} + } + } +} diff --git a/.config/quickshell/caelestia/config/ControlCenterConfig.qml b/.config/quickshell/caelestia/config/ControlCenterConfig.qml new file mode 100644 index 0000000..a588949 --- /dev/null +++ b/.config/quickshell/caelestia/config/ControlCenterConfig.qml @@ -0,0 +1,10 @@ +import Quickshell.Io + +JsonObject { + property Sizes sizes: Sizes {} + + component Sizes: JsonObject { + property real heightMult: 0.7 + property real ratio: 16 / 9 + } +} diff --git a/.config/quickshell/caelestia/config/DashboardConfig.qml b/.config/quickshell/caelestia/config/DashboardConfig.qml new file mode 100644 index 0000000..e089550 --- /dev/null +++ b/.config/quickshell/caelestia/config/DashboardConfig.qml @@ -0,0 +1,36 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: true + property bool showOnHover: true + property int mediaUpdateInterval: 500 + property int resourceUpdateInterval: 1000 + property int dragThreshold: 50 + property Sizes sizes: Sizes {} + property Performance performance: Performance {} + + component Performance: JsonObject { + property bool showBattery: true + property bool showGpu: true + property bool showCpu: true + property bool showMemory: true + property bool showStorage: true + property bool showNetwork: true + } + + component Sizes: JsonObject { + readonly property int tabIndicatorHeight: 3 + readonly property int tabIndicatorSpacing: 5 + readonly property int infoWidth: 200 + readonly property int infoIconSize: 25 + readonly property int dateTimeWidth: 110 + readonly property int mediaWidth: 200 + readonly property int mediaProgressSweep: 180 + readonly property int mediaProgressThickness: 8 + readonly property int resourceProgessThickness: 10 + readonly property int weatherWidth: 250 + readonly property int mediaCoverArtSize: 150 + readonly property int mediaVisualiserSize: 80 + readonly property int resourceSize: 200 + } +} diff --git a/.config/quickshell/caelestia/config/GeneralConfig.qml b/.config/quickshell/caelestia/config/GeneralConfig.qml new file mode 100644 index 0000000..52ef0de --- /dev/null +++ b/.config/quickshell/caelestia/config/GeneralConfig.qml @@ -0,0 +1,60 @@ +import Quickshell.Io + +JsonObject { + property string logo: "" + property Apps apps: Apps {} + property Idle idle: Idle {} + property Battery battery: Battery {} + + component Apps: JsonObject { + property list terminal: ["foot"] + property list audio: ["pavucontrol"] + property list playback: ["mpv"] + property list explorer: ["thunar"] + } + + component Idle: JsonObject { + property bool lockBeforeSleep: true + property bool inhibitWhenAudio: true + property list timeouts: [ + { + timeout: 180, + idleAction: "lock" + }, + { + timeout: 300, + idleAction: "dpms off", + returnAction: "dpms on" + }, + { + timeout: 600, + idleAction: ["systemctl", "suspend-then-hibernate"] + } + ] + } + + component Battery: JsonObject { + property list warnLevels: [ + { + level: 20, + title: qsTr("Low battery"), + message: qsTr("You might want to plug in a charger"), + icon: "battery_android_frame_2" + }, + { + level: 10, + title: qsTr("Did you see the previous message?"), + message: qsTr("You should probably plug in a charger now"), + icon: "battery_android_frame_1" + }, + { + level: 5, + title: qsTr("Critical battery level"), + message: qsTr("PLUG THE CHARGER RIGHT NOW!!"), + icon: "battery_android_alert", + critical: true + }, + ] + property int criticalLevel: 3 + } +} diff --git a/.config/quickshell/caelestia/config/LauncherConfig.qml b/.config/quickshell/caelestia/config/LauncherConfig.qml new file mode 100644 index 0000000..d9e3a73 --- /dev/null +++ b/.config/quickshell/caelestia/config/LauncherConfig.qml @@ -0,0 +1,147 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: true + property bool showOnHover: false + property int maxShown: 7 + property int maxWallpapers: 9 // Warning: even numbers look bad + property string specialPrefix: "@" + property string actionPrefix: ">" + property bool enableDangerousActions: false // Allow actions that can cause losing data, like shutdown, reboot and logout + property int dragThreshold: 50 + property bool vimKeybinds: false + property list favouriteApps: [] + property list hiddenApps: [] + property UseFuzzy useFuzzy: UseFuzzy {} + property Sizes sizes: Sizes {} + + component UseFuzzy: JsonObject { + property bool apps: false + property bool actions: false + property bool schemes: false + property bool variants: false + property bool wallpapers: false + } + + component Sizes: JsonObject { + property int itemWidth: 600 + property int itemHeight: 57 + property int wallpaperWidth: 280 + property int wallpaperHeight: 200 + } + + property list actions: [ + { + name: "Calculator", + icon: "calculate", + description: "Do simple math equations (powered by Qalc)", + command: ["autocomplete", "calc"], + enabled: true, + dangerous: false + }, + { + name: "Scheme", + icon: "palette", + description: "Change the current colour scheme", + command: ["autocomplete", "scheme"], + enabled: true, + dangerous: false + }, + { + name: "Wallpaper", + icon: "image", + description: "Change the current wallpaper", + command: ["autocomplete", "wallpaper"], + enabled: true, + dangerous: false + }, + { + name: "Variant", + icon: "colors", + description: "Change the current scheme variant", + command: ["autocomplete", "variant"], + enabled: true, + dangerous: false + }, + { + name: "Transparency", + icon: "opacity", + description: "Change shell transparency", + command: ["autocomplete", "transparency"], + enabled: false, + dangerous: false + }, + { + name: "Random", + icon: "casino", + description: "Switch to a random wallpaper", + command: ["caelestia", "wallpaper", "-r"], + enabled: true, + dangerous: false + }, + { + name: "Light", + icon: "light_mode", + description: "Change the scheme to light mode", + command: ["setMode", "light"], + enabled: true, + dangerous: false + }, + { + name: "Dark", + icon: "dark_mode", + description: "Change the scheme to dark mode", + command: ["setMode", "dark"], + enabled: true, + dangerous: false + }, + { + name: "Shutdown", + icon: "power_settings_new", + description: "Shutdown the system", + command: ["systemctl", "poweroff"], + enabled: true, + dangerous: true + }, + { + name: "Reboot", + icon: "cached", + description: "Reboot the system", + command: ["systemctl", "reboot"], + enabled: true, + dangerous: true + }, + { + name: "Logout", + icon: "exit_to_app", + description: "Log out of the current session", + command: ["loginctl", "terminate-user", ""], + enabled: true, + dangerous: true + }, + { + name: "Lock", + icon: "lock", + description: "Lock the current session", + command: ["loginctl", "lock-session"], + enabled: true, + dangerous: false + }, + { + name: "Sleep", + icon: "bedtime", + description: "Suspend then hibernate", + command: ["systemctl", "suspend-then-hibernate"], + enabled: true, + dangerous: false + }, + { + name: "Settings", + icon: "settings", + description: "Configure the shell", + command: ["caelestia", "shell", "controlCenter", "open"], + enabled: true, + dangerous: false + } + ] +} diff --git a/.config/quickshell/caelestia/config/LockConfig.qml b/.config/quickshell/caelestia/config/LockConfig.qml new file mode 100644 index 0000000..2af4e2c --- /dev/null +++ b/.config/quickshell/caelestia/config/LockConfig.qml @@ -0,0 +1,14 @@ +import Quickshell.Io + +JsonObject { + property bool recolourLogo: false + property bool enableFprint: true + property int maxFprintTries: 3 + property Sizes sizes: Sizes {} + + component Sizes: JsonObject { + property real heightMult: 0.7 + property real ratio: 16 / 9 + property int centerWidth: 600 + } +} diff --git a/.config/quickshell/caelestia/config/NotifsConfig.qml b/.config/quickshell/caelestia/config/NotifsConfig.qml new file mode 100644 index 0000000..fa2db49 --- /dev/null +++ b/.config/quickshell/caelestia/config/NotifsConfig.qml @@ -0,0 +1,18 @@ +import Quickshell.Io + +JsonObject { + property bool expire: true + property int defaultExpireTimeout: 5000 + property real clearThreshold: 0.3 + property int expandThreshold: 20 + property bool actionOnClick: false + property int groupPreviewNum: 3 + property bool openExpanded: false // Show the notifichation in expanded state when opening + property Sizes sizes: Sizes {} + + component Sizes: JsonObject { + property int width: 400 + property int image: 41 + property int badge: 20 + } +} diff --git a/.config/quickshell/caelestia/config/OsdConfig.qml b/.config/quickshell/caelestia/config/OsdConfig.qml new file mode 100644 index 0000000..543fc41 --- /dev/null +++ b/.config/quickshell/caelestia/config/OsdConfig.qml @@ -0,0 +1,14 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: true + property int hideDelay: 2000 + property bool enableBrightness: true + property bool enableMicrophone: false + property Sizes sizes: Sizes {} + + component Sizes: JsonObject { + property int sliderWidth: 30 + property int sliderHeight: 150 + } +} diff --git a/.config/quickshell/caelestia/config/ServiceConfig.qml b/.config/quickshell/caelestia/config/ServiceConfig.qml new file mode 100644 index 0000000..29600cc --- /dev/null +++ b/.config/quickshell/caelestia/config/ServiceConfig.qml @@ -0,0 +1,22 @@ +import Quickshell.Io +import QtQuick + +JsonObject { + property string weatherLocation: "" // A lat,long pair or empty for autodetection, e.g. "37.8267,-122.4233" + property bool useFahrenheit: [Locale.ImperialUSSystem, Locale.ImperialSystem].includes(Qt.locale().measurementSystem) + property bool useFahrenheitPerformance: [Locale.ImperialUSSystem, Locale.ImperialSystem].includes(Qt.locale().measurementSystem) + property bool useTwelveHourClock: Qt.locale().timeFormat(Locale.ShortFormat).toLowerCase().includes("a") + property string gpuType: "" + property int visualiserBars: 45 + property real audioIncrement: 0.1 + property real brightnessIncrement: 0.1 + property real maxVolume: 1.0 + property bool smartScheme: true + property string defaultPlayer: "Spotify" + property list playerAliases: [ + { + "from": "com.github.th_ch.youtube_music", + "to": "YT Music" + } + ] +} diff --git a/.config/quickshell/caelestia/config/SessionConfig.qml b/.config/quickshell/caelestia/config/SessionConfig.qml new file mode 100644 index 0000000..414f821 --- /dev/null +++ b/.config/quickshell/caelestia/config/SessionConfig.qml @@ -0,0 +1,29 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: true + property int dragThreshold: 30 + property bool vimKeybinds: false + property Icons icons: Icons {} + property Commands commands: Commands {} + + property Sizes sizes: Sizes {} + + component Icons: JsonObject { + property string logout: "logout" + property string shutdown: "power_settings_new" + property string hibernate: "downloading" + property string reboot: "cached" + } + + component Commands: JsonObject { + property list logout: ["loginctl", "terminate-user", ""] + property list shutdown: ["systemctl", "poweroff"] + property list hibernate: ["systemctl", "hibernate"] + property list reboot: ["systemctl", "reboot"] + } + + component Sizes: JsonObject { + property int button: 80 + } +} diff --git a/.config/quickshell/caelestia/config/SidebarConfig.qml b/.config/quickshell/caelestia/config/SidebarConfig.qml new file mode 100644 index 0000000..a871562 --- /dev/null +++ b/.config/quickshell/caelestia/config/SidebarConfig.qml @@ -0,0 +1,11 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: true + property int dragThreshold: 80 + property Sizes sizes: Sizes {} + + component Sizes: JsonObject { + property int width: 430 + } +} diff --git a/.config/quickshell/caelestia/config/UserPaths.qml b/.config/quickshell/caelestia/config/UserPaths.qml new file mode 100644 index 0000000..f8de267 --- /dev/null +++ b/.config/quickshell/caelestia/config/UserPaths.qml @@ -0,0 +1,8 @@ +import qs.utils +import Quickshell.Io + +JsonObject { + property string wallpaperDir: `${Paths.pictures}/Wallpapers` + property string sessionGif: "root:/assets/kurukuru.gif" + property string mediaGif: "root:/assets/bongocat.gif" +} diff --git a/.config/quickshell/caelestia/config/UtilitiesConfig.qml b/.config/quickshell/caelestia/config/UtilitiesConfig.qml new file mode 100644 index 0000000..cf46446 --- /dev/null +++ b/.config/quickshell/caelestia/config/UtilitiesConfig.qml @@ -0,0 +1,35 @@ +import Quickshell.Io + +JsonObject { + property bool enabled: true + property int maxToasts: 4 + + property Sizes sizes: Sizes {} + property Toasts toasts: Toasts {} + property Vpn vpn: Vpn {} + + component Sizes: JsonObject { + property int width: 430 + property int toastWidth: 430 + } + + component Toasts: JsonObject { + property bool configLoaded: true + property bool chargingChanged: true + property bool gameModeChanged: true + property bool dndChanged: true + property bool audioOutputChanged: true + property bool audioInputChanged: true + property bool capsLockChanged: true + property bool numLockChanged: true + property bool kbLayoutChanged: true + property bool kbLimit: true + property bool vpnChanged: true + property bool nowPlaying: false + } + + component Vpn: JsonObject { + property bool enabled: false + property list provider: ["netbird"] + } +} diff --git a/.config/quickshell/caelestia/config/WInfoConfig.qml b/.config/quickshell/caelestia/config/WInfoConfig.qml new file mode 100644 index 0000000..5025780 --- /dev/null +++ b/.config/quickshell/caelestia/config/WInfoConfig.qml @@ -0,0 +1,10 @@ +import Quickshell.Io + +JsonObject { + property Sizes sizes: Sizes {} + + component Sizes: JsonObject { + property real heightMult: 0.7 + property real detailsWidth: 500 + } +} diff --git a/.config/quickshell/caelestia/extras/CMakeLists.txt b/.config/quickshell/caelestia/extras/CMakeLists.txt new file mode 100644 index 0000000..52fe17c --- /dev/null +++ b/.config/quickshell/caelestia/extras/CMakeLists.txt @@ -0,0 +1,9 @@ +# Version +add_executable(version version.cpp) +target_compile_definitions(version PRIVATE + PROJECT_NAME="${PROJECT_NAME}" + VERSION="${VERSION}" + GIT_REVISION="${GIT_REVISION}" + DISTRIBUTOR="${DISTRIBUTOR}" +) +install(TARGETS version DESTINATION ${INSTALL_LIBDIR}) diff --git a/.config/quickshell/caelestia/extras/version.cpp b/.config/quickshell/caelestia/extras/version.cpp new file mode 100644 index 0000000..e1a0cf3 --- /dev/null +++ b/.config/quickshell/caelestia/extras/version.cpp @@ -0,0 +1,26 @@ +#include + +int main(int argc, char* argv[]) { + if (argc > 1) { + std::string arg = argv[1]; + + if (arg == "-t" || arg == "--terse") { + std::cout << PROJECT_NAME << std::endl; + std::cout << VERSION << std::endl; + std::cout << GIT_REVISION << std::endl; + std::cout << DISTRIBUTOR << std::endl; + } else if (arg == "-s" || arg == "--short") { + std::cout << PROJECT_NAME << " " << VERSION << ", revision " << GIT_REVISION << ", distrubuted by: " << DISTRIBUTOR << std::endl; + } else { + std::cout << "Usage: " << argv[0] << " [-t | --terse] [-s | --short]" << std::endl; + return arg != "-h" && arg != "--help"; + } + } else { + std::cout << "Project: " << PROJECT_NAME << std::endl; + std::cout << "Version: " << VERSION << std::endl; + std::cout << "Git revision: " << GIT_REVISION << std::endl; + std::cout << "Distributor: " << DISTRIBUTOR << std::endl; + } + + return 0; +} diff --git a/.config/quickshell/caelestia/flake.lock b/.config/quickshell/caelestia/flake.lock new file mode 100644 index 0000000..9f1b2ea --- /dev/null +++ b/.config/quickshell/caelestia/flake.lock @@ -0,0 +1,70 @@ +{ + "nodes": { + "caelestia-cli": { + "inputs": { + "caelestia-shell": [], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1772764582, + "narHash": "sha256-hSwjmpXHFqzSXrndVekA0IheKrbC7wi0IbfZTYwlmXw=", + "owner": "caelestia-dots", + "repo": "cli", + "rev": "4bcd42f482d038b98145b0b03388244b68b7d35d", + "type": "github" + }, + "original": { + "owner": "caelestia-dots", + "repo": "cli", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1772773019, + "narHash": "sha256-E1bxHxNKfDoQUuvriG71+f+s/NT0qWkImXsYZNFFfCs=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "aca4d95fce4914b3892661bcb80b8087293536c6", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "quickshell": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1772925576, + "narHash": "sha256-mMoiXABDtkSJxCYDrkhJ/TrrJf5M46oUfIlJvv2gkZ0=", + "ref": "refs/heads/master", + "rev": "15a84097653593dd15fad59a56befc2b7bdc270d", + "revCount": 750, + "type": "git", + "url": "https://git.outfoxxed.me/outfoxxed/quickshell" + }, + "original": { + "type": "git", + "url": "https://git.outfoxxed.me/outfoxxed/quickshell" + } + }, + "root": { + "inputs": { + "caelestia-cli": "caelestia-cli", + "nixpkgs": "nixpkgs", + "quickshell": "quickshell" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/.config/quickshell/caelestia/flake.nix b/.config/quickshell/caelestia/flake.nix new file mode 100644 index 0000000..5c88411 --- /dev/null +++ b/.config/quickshell/caelestia/flake.nix @@ -0,0 +1,60 @@ +{ + description = "Desktop shell for Caelestia dots"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + quickshell = { + url = "git+https://git.outfoxxed.me/outfoxxed/quickshell"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + caelestia-cli = { + url = "github:caelestia-dots/cli"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.caelestia-shell.follows = ""; + }; + }; + + outputs = { + self, + nixpkgs, + ... + } @ inputs: let + forAllSystems = fn: + nixpkgs.lib.genAttrs nixpkgs.lib.platforms.linux ( + system: fn nixpkgs.legacyPackages.${system} + ); + in { + formatter = forAllSystems (pkgs: pkgs.alejandra); + + packages = forAllSystems (pkgs: rec { + caelestia-shell = pkgs.callPackage ./nix { + rev = self.rev or self.dirtyRev; + stdenv = pkgs.clangStdenv; + quickshell = inputs.quickshell.packages.${pkgs.stdenv.hostPlatform.system}.default.override { + withX11 = false; + withI3 = false; + }; + app2unit = pkgs.callPackage ./nix/app2unit.nix {inherit pkgs;}; + caelestia-cli = inputs.caelestia-cli.packages.${pkgs.stdenv.hostPlatform.system}.default; + }; + with-cli = caelestia-shell.override {withCli = true;}; + debug = caelestia-shell.override {debug = true;}; + default = caelestia-shell; + }); + + devShells = forAllSystems (pkgs: { + default = let + shell = self.packages.${pkgs.stdenv.hostPlatform.system}.caelestia-shell; + in + pkgs.mkShell.override {stdenv = shell.stdenv;} { + inputsFrom = [shell shell.plugin shell.extras]; + packages = with pkgs; [clazy material-symbols rubik nerd-fonts.caskaydia-cove]; + CAELESTIA_XKB_RULES_PATH = "${pkgs.xkeyboard-config}/share/xkeyboard-config-2/rules/base.lst"; + }; + }); + + homeManagerModules.default = import ./nix/hm-module.nix self; + }; +} diff --git a/.config/quickshell/caelestia/modules/BatteryMonitor.qml b/.config/quickshell/caelestia/modules/BatteryMonitor.qml new file mode 100644 index 0000000..d24cff2 --- /dev/null +++ b/.config/quickshell/caelestia/modules/BatteryMonitor.qml @@ -0,0 +1,56 @@ +import qs.config +import Caelestia +import Quickshell +import Quickshell.Services.UPower +import QtQuick + +Scope { + id: root + + readonly property list warnLevels: [...Config.general.battery.warnLevels].sort((a, b) => b.level - a.level) + + Connections { + target: UPower + + function onOnBatteryChanged(): void { + if (UPower.onBattery) { + if (Config.utilities.toasts.chargingChanged) + Toaster.toast(qsTr("Charger unplugged"), qsTr("Battery is discharging"), "power_off"); + } else { + if (Config.utilities.toasts.chargingChanged) + Toaster.toast(qsTr("Charger plugged in"), qsTr("Battery is charging"), "power"); + for (const level of root.warnLevels) + level.warned = false; + } + } + } + + Connections { + target: UPower.displayDevice + + function onPercentageChanged(): void { + if (!UPower.onBattery) + return; + + const p = UPower.displayDevice.percentage * 100; + for (const level of root.warnLevels) { + if (p <= level.level && !level.warned) { + level.warned = true; + Toaster.toast(level.title ?? qsTr("Battery warning"), level.message ?? qsTr("Battery level is low"), level.icon ?? "battery_android_alert", level.critical ? Toast.Error : Toast.Warning); + } + } + + if (!hibernateTimer.running && p <= Config.general.battery.criticalLevel) { + Toaster.toast(qsTr("Hibernating in 5 seconds"), qsTr("Hibernating to prevent data loss"), "battery_android_alert", Toast.Error); + hibernateTimer.start(); + } + } + } + + Timer { + id: hibernateTimer + + interval: 5000 + onTriggered: Quickshell.execDetached(["systemctl", "hibernate"]) + } +} diff --git a/.config/quickshell/caelestia/modules/IdleMonitors.qml b/.config/quickshell/caelestia/modules/IdleMonitors.qml new file mode 100644 index 0000000..b7ce058 --- /dev/null +++ b/.config/quickshell/caelestia/modules/IdleMonitors.qml @@ -0,0 +1,51 @@ +pragma ComponentBehavior: Bound + +import "lock" +import qs.config +import qs.services +import Caelestia.Internal +import Quickshell +import Quickshell.Wayland + +Scope { + id: root + + required property Lock lock + readonly property bool enabled: !Config.general.idle.inhibitWhenAudio || !Players.list.some(p => p.isPlaying) + + function handleIdleAction(action: var): void { + if (!action) + return; + + if (action === "lock") + lock.lock.locked = true; + else if (action === "unlock") + lock.lock.locked = false; + else if (typeof action === "string") + Hypr.dispatch(action); + else + Quickshell.execDetached(action); + } + + LogindManager { + onAboutToSleep: { + if (Config.general.idle.lockBeforeSleep) + root.lock.lock.locked = true; + } + onLockRequested: root.lock.lock.locked = true + onUnlockRequested: root.lock.lock.unlock() + } + + Variants { + model: Config.general.idle.timeouts + + IdleMonitor { + required property var modelData + + enabled: root.enabled && (modelData.enabled ?? true) + timeout: modelData.timeout + respectInhibitors: modelData.respectInhibitors ?? true + onIsIdleChanged: root.handleIdleAction(isIdle ? modelData.idleAction : modelData.returnAction) + } + } +} diff --git a/.config/quickshell/caelestia/modules/Shortcuts.qml b/.config/quickshell/caelestia/modules/Shortcuts.qml new file mode 100644 index 0000000..3bf20a4 --- /dev/null +++ b/.config/quickshell/caelestia/modules/Shortcuts.qml @@ -0,0 +1,142 @@ +import qs.components.misc +import qs.modules.controlcenter +import qs.services +import Caelestia +import Quickshell +import Quickshell.Io + +Scope { + id: root + + property bool launcherInterrupted + readonly property bool hasFullscreen: Hypr.focusedWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen === 2) ?? false + + CustomShortcut { + name: "controlCenter" + description: "Open control center" + onPressed: WindowFactory.create() + } + + CustomShortcut { + name: "showall" + description: "Toggle launcher, dashboard and osd" + onPressed: { + if (root.hasFullscreen) + return; + const v = Visibilities.getForActive(); + v.launcher = v.dashboard = v.osd = v.utilities = !(v.launcher || v.dashboard || v.osd || v.utilities); + } + } + + CustomShortcut { + name: "dashboard" + description: "Toggle dashboard" + onPressed: { + if (root.hasFullscreen) + return; + const visibilities = Visibilities.getForActive(); + visibilities.dashboard = !visibilities.dashboard; + } + } + + CustomShortcut { + name: "session" + description: "Toggle session menu" + onPressed: { + if (root.hasFullscreen) + return; + const visibilities = Visibilities.getForActive(); + visibilities.session = !visibilities.session; + } + } + + CustomShortcut { + name: "launcher" + description: "Toggle launcher" + onPressed: root.launcherInterrupted = false + onReleased: { + if (!root.launcherInterrupted && !root.hasFullscreen) { + const visibilities = Visibilities.getForActive(); + visibilities.launcher = !visibilities.launcher; + } + root.launcherInterrupted = false; + } + } + + CustomShortcut { + name: "launcherInterrupt" + description: "Interrupt launcher keybind" + onPressed: root.launcherInterrupted = true + } + + + CustomShortcut { + name: "sidebar" + description: "Toggle sidebar" + onPressed: { + if (root.hasFullscreen) + return; + const visibilities = Visibilities.getForActive(); + visibilities.sidebar = !visibilities.sidebar; + } + } + + CustomShortcut { + name: "utilities" + description: "Toggle utilities" + onPressed: { + if (root.hasFullscreen) + return; + const visibilities = Visibilities.getForActive(); + visibilities.utilities = !visibilities.utilities; + } + } + + IpcHandler { + target: "drawers" + + function toggle(drawer: string): void { + if (list().split("\n").includes(drawer)) { + if (root.hasFullscreen && ["launcher", "session", "dashboard"].includes(drawer)) + return; + const visibilities = Visibilities.getForActive(); + visibilities[drawer] = !visibilities[drawer]; + } else { + console.warn(`[IPC] Drawer "${drawer}" does not exist`); + } + } + + function list(): string { + const visibilities = Visibilities.getForActive(); + return Object.keys(visibilities).filter(k => typeof visibilities[k] === "boolean").join("\n"); + } + } + + IpcHandler { + target: "controlCenter" + + function open(): void { + WindowFactory.create(); + } + } + + IpcHandler { + target: "toaster" + + function info(title: string, message: string, icon: string): void { + Toaster.toast(title, message, icon, Toast.Info); + } + + function success(title: string, message: string, icon: string): void { + Toaster.toast(title, message, icon, Toast.Success); + } + + function warn(title: string, message: string, icon: string): void { + Toaster.toast(title, message, icon, Toast.Warning); + } + + function error(title: string, message: string, icon: string): void { + Toaster.toast(title, message, icon, Toast.Error); + } + } +} diff --git a/.config/quickshell/caelestia/modules/areapicker/AreaPicker.qml b/.config/quickshell/caelestia/modules/areapicker/AreaPicker.qml new file mode 100644 index 0000000..0d8b2fe --- /dev/null +++ b/.config/quickshell/caelestia/modules/areapicker/AreaPicker.qml @@ -0,0 +1,124 @@ +pragma ComponentBehavior: Bound + +import qs.components.containers +import qs.components.misc +import Quickshell +import Quickshell.Wayland +import Quickshell.Io + +Scope { + LazyLoader { + id: root + + property bool freeze + property bool closing + property bool clipboardOnly + + Variants { + model: Quickshell.screens + + StyledWindow { + id: win + + required property ShellScreen modelData + + screen: modelData + name: "area-picker" + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.layer: WlrLayer.Overlay + WlrLayershell.keyboardFocus: root.closing ? WlrKeyboardFocus.None : WlrKeyboardFocus.Exclusive + mask: root.closing ? empty : null + + anchors.top: true + anchors.bottom: true + anchors.left: true + anchors.right: true + + Region { + id: empty + } + + Picker { + loader: root + screen: win.modelData + } + } + } + } + + IpcHandler { + target: "picker" + + function open(): void { + root.freeze = false; + root.closing = false; + root.clipboardOnly = false; + root.activeAsync = true; + } + + function openFreeze(): void { + root.freeze = true; + root.closing = false; + root.clipboardOnly = false; + root.activeAsync = true; + } + + function openClip(): void { + root.freeze = false; + root.closing = false; + root.clipboardOnly = true; + root.activeAsync = true; + } + + function openFreezeClip(): void { + root.freeze = true; + root.closing = false; + root.clipboardOnly = true; + root.activeAsync = true; + } + } + + CustomShortcut { + name: "screenshot" + description: "Open screenshot tool" + onPressed: { + root.freeze = false; + root.closing = false; + root.clipboardOnly = false; + root.activeAsync = true; + } + } + + CustomShortcut { + name: "screenshotFreeze" + description: "Open screenshot tool (freeze mode)" + onPressed: { + root.freeze = true; + root.closing = false; + root.clipboardOnly = false; + root.activeAsync = true; + } + } + + CustomShortcut { + name: "screenshotClip" + description: "Open screenshot tool (clipboard)" + onPressed: { + root.freeze = false; + root.closing = false; + root.clipboardOnly = true; + root.activeAsync = true; + } + } + + CustomShortcut { + name: "screenshotFreezeClip" + description: "Open screenshot tool (freeze mode, clipboard)" + onPressed: { + root.freeze = true; + root.closing = false; + root.clipboardOnly = true; + root.activeAsync = true; + } + } +} diff --git a/.config/quickshell/caelestia/modules/areapicker/Picker.qml b/.config/quickshell/caelestia/modules/areapicker/Picker.qml new file mode 100644 index 0000000..08f46df --- /dev/null +++ b/.config/quickshell/caelestia/modules/areapicker/Picker.qml @@ -0,0 +1,300 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Caelestia +import Quickshell +import Quickshell.Wayland +import QtQuick +import QtQuick.Effects + +MouseArea { + id: root + + required property LazyLoader loader + required property ShellScreen screen + + property bool onClient + + property real realBorderWidth: onClient ? (Hypr.options["general:border_size"] ?? 1) : 2 + property real realRounding: onClient ? (Hypr.options["decoration:rounding"] ?? 0) : 0 + + property real ssx + property real ssy + + property real sx: 0 + property real sy: 0 + property real ex: screen.width + property real ey: screen.height + + property real rsx: Math.min(sx, ex) + property real rsy: Math.min(sy, ey) + property real sw: Math.abs(sx - ex) + property real sh: Math.abs(sy - ey) + + property list clients: { + const mon = Hypr.monitorFor(screen); + if (!mon) + return []; + + const special = mon.lastIpcObject.specialWorkspace; + const wsId = special.name ? special.id : mon.activeWorkspace.id; + + return Hypr.toplevels.values.filter(c => c.workspace?.id === wsId).sort((a, b) => { + // Pinned first, then fullscreen, then floating, then any other + const ac = a.lastIpcObject; + const bc = b.lastIpcObject; + return (bc.pinned - ac.pinned) || ((bc.fullscreen !== 0) - (ac.fullscreen !== 0)) || (bc.floating - ac.floating); + }); + } + + function checkClientRects(x: real, y: real): void { + for (const client of clients) { + if (!client) + continue; + + let { + at: [cx, cy], + size: [cw, ch] + } = client.lastIpcObject; + cx -= screen.x; + cy -= screen.y; + if (cx <= x && cy <= y && cx + cw >= x && cy + ch >= y) { + onClient = true; + sx = cx; + sy = cy; + ex = cx + cw; + ey = cy + ch; + break; + } + } + } + + function save(): void { + const tmpfile = Qt.resolvedUrl(`/tmp/caelestia-picker-${Quickshell.processId}-${Date.now()}.png`); + CUtils.saveItem(screencopy, tmpfile, Qt.rect(Math.ceil(rsx), Math.ceil(rsy), Math.floor(sw), Math.floor(sh)), path => { + if (root.loader.clipboardOnly) { + Quickshell.execDetached(["sh", "-c", "wl-copy --type image/png < " + path]); + Quickshell.execDetached(["notify-send", "-a", "caelestia-cli", "-i", path, "Screenshot taken", "Screenshot copied to clipboard"]); + } else { + Quickshell.execDetached(["swappy", "-f", path]); + } + closeAnim.start(); + }); + } + + onClientsChanged: checkClientRects(mouseX, mouseY) + + anchors.fill: parent + opacity: 0 + hoverEnabled: true + cursorShape: Qt.CrossCursor + + Component.onCompleted: { + Hypr.extras.refreshOptions(); + + // Break binding if frozen + if (loader.freeze) + clients = clients; + + opacity = 1; + + const c = clients[0]; + if (c) { + const cx = c.lastIpcObject.at[0] - screen.x; + const cy = c.lastIpcObject.at[1] - screen.y; + onClient = true; + sx = cx; + sy = cy; + ex = cx + c.lastIpcObject.size[0]; + ey = cy + c.lastIpcObject.size[1]; + } else { + sx = screen.width / 2 - 100; + sy = screen.height / 2 - 100; + ex = screen.width / 2 + 100; + ey = screen.height / 2 + 100; + } + } + + onPressed: event => { + ssx = event.x; + ssy = event.y; + } + + onReleased: { + if (closeAnim.running) + return; + + if (root.loader.freeze) { + save(); + } else { + overlay.visible = border.visible = false; + screencopy.visible = false; + screencopy.active = true; + } + } + + onPositionChanged: event => { + const x = event.x; + const y = event.y; + + if (pressed) { + onClient = false; + sx = ssx; + sy = ssy; + ex = x; + ey = y; + } else { + checkClientRects(x, y); + } + } + + focus: true + Keys.onEscapePressed: closeAnim.start() + + SequentialAnimation { + id: closeAnim + + PropertyAction { + target: root.loader + property: "closing" + value: true + } + ParallelAnimation { + Anim { + target: root + property: "opacity" + to: 0 + duration: Appearance.anim.durations.large + } + ExAnim { + target: root + properties: "rsx,rsy" + to: 0 + } + ExAnim { + target: root + property: "sw" + to: root.screen.width + } + ExAnim { + target: root + property: "sh" + to: root.screen.height + } + } + PropertyAction { + target: root.loader + property: "activeAsync" + value: false + } + } + + Loader { + id: screencopy + + anchors.fill: parent + + active: root.loader.freeze + + sourceComponent: ScreencopyView { + captureSource: root.screen + + onHasContentChanged: { + if (hasContent && !root.loader.freeze) { + overlay.visible = border.visible = true; + root.save(); + } + } + } + } + + StyledRect { + id: overlay + + anchors.fill: parent + color: Colours.palette.m3secondaryContainer + opacity: 0.3 + + layer.enabled: true + layer.effect: MultiEffect { + maskSource: selectionWrapper + maskEnabled: true + maskInverted: true + maskSpreadAtMin: 1 + maskThresholdMin: 0.5 + } + } + + Item { + id: selectionWrapper + + anchors.fill: parent + layer.enabled: true + visible: false + + Rectangle { + id: selectionRect + + radius: root.realRounding + x: root.rsx + y: root.rsy + implicitWidth: root.sw + implicitHeight: root.sh + } + } + + Rectangle { + id: border + + color: "transparent" + radius: root.realRounding > 0 ? root.realRounding + root.realBorderWidth : 0 + border.width: root.realBorderWidth + border.color: Colours.palette.m3primary + + x: selectionRect.x - root.realBorderWidth + y: selectionRect.y - root.realBorderWidth + implicitWidth: selectionRect.implicitWidth + root.realBorderWidth * 2 + implicitHeight: selectionRect.implicitHeight + root.realBorderWidth * 2 + + Behavior on border.color { + CAnim {} + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.large + } + } + + Behavior on rsx { + enabled: !root.pressed + + ExAnim {} + } + + Behavior on rsy { + enabled: !root.pressed + + ExAnim {} + } + + Behavior on sw { + enabled: !root.pressed + + ExAnim {} + } + + Behavior on sh { + enabled: !root.pressed + + ExAnim {} + } + + component ExAnim: Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } +} diff --git a/.config/quickshell/caelestia/modules/background/Background.qml b/.config/quickshell/caelestia/modules/background/Background.qml new file mode 100644 index 0000000..682da62 --- /dev/null +++ b/.config/quickshell/caelestia/modules/background/Background.qml @@ -0,0 +1,153 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.containers +import qs.services +import qs.config +import Quickshell +import Quickshell.Wayland +import QtQuick + +Loader { + active: Config.background.enabled + + sourceComponent: Variants { + model: Quickshell.screens + + StyledWindow { + id: win + + required property ShellScreen modelData + + screen: modelData + name: "background" + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.layer: Config.background.wallpaperEnabled ? WlrLayer.Background : WlrLayer.Bottom + color: Config.background.wallpaperEnabled ? "black" : "transparent" + surfaceFormat.opaque: false + + anchors.top: true + anchors.bottom: true + anchors.left: true + anchors.right: true + + Item { + id: behindClock + + anchors.fill: parent + + Loader { + id: wallpaper + + anchors.fill: parent + active: Config.background.wallpaperEnabled + + sourceComponent: Wallpaper {} + } + + Visualiser { + anchors.fill: parent + screen: win.modelData + wallpaper: wallpaper + } + } + + Loader { + id: clockLoader + active: Config.background.desktopClock.enabled + + anchors.margins: Appearance.padding.large * 2 + anchors.leftMargin: Appearance.padding.large * 2 + Config.bar.sizes.innerWidth + Math.max(Appearance.padding.smaller, Config.border.thickness) + + state: Config.background.desktopClock.position + states: [ + State { + name: "top-left" + AnchorChanges { + target: clockLoader + anchors.top: parent.top + anchors.left: parent.left + } + }, + State { + name: "top-center" + AnchorChanges { + target: clockLoader + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + } + }, + State { + name: "top-right" + AnchorChanges { + target: clockLoader + anchors.top: parent.top + anchors.right: parent.right + } + }, + State { + name: "middle-left" + AnchorChanges { + target: clockLoader + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + } + }, + State { + name: "middle-center" + AnchorChanges { + target: clockLoader + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } + }, + State { + name: "middle-right" + AnchorChanges { + target: clockLoader + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + } + }, + State { + name: "bottom-left" + AnchorChanges { + target: clockLoader + anchors.bottom: parent.bottom + anchors.left: parent.left + } + }, + State { + name: "bottom-center" + AnchorChanges { + target: clockLoader + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + } + }, + State { + name: "bottom-right" + AnchorChanges { + target: clockLoader + anchors.bottom: parent.bottom + anchors.right: parent.right + } + } + ] + + transitions: Transition { + AnchorAnimation { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + sourceComponent: DesktopClock { + wallpaper: behindClock + absX: clockLoader.x + absY: clockLoader.y + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/background/DesktopClock.qml b/.config/quickshell/caelestia/modules/background/DesktopClock.qml new file mode 100644 index 0000000..f9a06a2 --- /dev/null +++ b/.config/quickshell/caelestia/modules/background/DesktopClock.qml @@ -0,0 +1,169 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts +import QtQuick.Effects + +Item { + id: root + + required property Item wallpaper + required property real absX + required property real absY + + property real scale: Config.background.desktopClock.scale + readonly property bool bgEnabled: Config.background.desktopClock.background.enabled + readonly property bool blurEnabled: bgEnabled && Config.background.desktopClock.background.blur && !GameMode.enabled + readonly property bool invertColors: Config.background.desktopClock.invertColors + readonly property bool useLightSet: Colours.light ? !invertColors : invertColors + readonly property color safePrimary: useLightSet ? Colours.palette.m3primaryContainer : Colours.palette.m3primary + readonly property color safeSecondary: useLightSet ? Colours.palette.m3secondaryContainer : Colours.palette.m3secondary + readonly property color safeTertiary: useLightSet ? Colours.palette.m3tertiaryContainer : Colours.palette.m3tertiary + + implicitWidth: layout.implicitWidth + (Appearance.padding.large * 4 * root.scale) + implicitHeight: layout.implicitHeight + (Appearance.padding.large * 2 * root.scale) + + Item { + id: clockContainer + + anchors.fill: parent + + layer.enabled: Config.background.desktopClock.shadow.enabled + layer.effect: MultiEffect { + shadowEnabled: true + shadowColor: Colours.palette.m3shadow + shadowOpacity: Config.background.desktopClock.shadow.opacity + shadowBlur: Config.background.desktopClock.shadow.blur + } + + Loader { + anchors.fill: parent + active: root.blurEnabled + + sourceComponent: MultiEffect { + source: ShaderEffectSource { + sourceItem: root.wallpaper + sourceRect: Qt.rect(root.absX, root.absY, root.width, root.height) + } + maskSource: backgroundPlate + maskEnabled: true + blurEnabled: true + blur: 1 + blurMax: 64 + autoPaddingEnabled: false + } + } + + StyledRect { + id: backgroundPlate + + visible: root.bgEnabled + anchors.fill: parent + radius: Appearance.rounding.large * root.scale + opacity: Config.background.desktopClock.background.opacity + color: Colours.palette.m3surface + + layer.enabled: root.blurEnabled + } + + RowLayout { + id: layout + + anchors.centerIn: parent + spacing: Appearance.spacing.larger * root.scale + + RowLayout { + spacing: Appearance.spacing.small + + StyledText { + text: Time.hourStr + font.pointSize: Appearance.font.size.extraLarge * 3 * root.scale + font.weight: Font.Bold + color: root.safePrimary + } + + StyledText { + text: ":" + font.pointSize: Appearance.font.size.extraLarge * 3 * root.scale + color: root.safeTertiary + opacity: 0.8 + Layout.topMargin: -Appearance.padding.large * 1.5 * root.scale + } + + StyledText { + text: Time.minuteStr + font.pointSize: Appearance.font.size.extraLarge * 3 * root.scale + font.weight: Font.Bold + color: root.safeSecondary + } + + Loader { + Layout.alignment: Qt.AlignTop + Layout.topMargin: Appearance.padding.large * 1.4 * root.scale + + active: Config.services.useTwelveHourClock + visible: active + + sourceComponent: StyledText { + text: Time.amPmStr + font.pointSize: Appearance.font.size.large * root.scale + color: root.safeSecondary + } + } + } + + StyledRect { + Layout.fillHeight: true + Layout.preferredWidth: 4 * root.scale + Layout.topMargin: Appearance.spacing.larger * root.scale + Layout.bottomMargin: Appearance.spacing.larger * root.scale + radius: Appearance.rounding.full + color: root.safePrimary + opacity: 0.8 + } + + ColumnLayout { + spacing: 0 + + StyledText { + text: Time.format("MMMM").toUpperCase() + font.pointSize: Appearance.font.size.large * root.scale + font.letterSpacing: 4 + font.weight: Font.Bold + color: root.safeSecondary + } + + StyledText { + text: Time.format("dd") + font.pointSize: Appearance.font.size.extraLarge * root.scale + font.letterSpacing: 2 + font.weight: Font.Medium + color: root.safePrimary + } + + StyledText { + text: Time.format("dddd") + font.pointSize: Appearance.font.size.larger * root.scale + font.letterSpacing: 2 + color: root.safeSecondary + } + } + } + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + Behavior on implicitWidth { + Anim { + duration: Appearance.anim.durations.small + } + } +} diff --git a/.config/quickshell/caelestia/modules/background/Visualiser.qml b/.config/quickshell/caelestia/modules/background/Visualiser.qml new file mode 100644 index 0000000..35a086b --- /dev/null +++ b/.config/quickshell/caelestia/modules/background/Visualiser.qml @@ -0,0 +1,151 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Caelestia.Services +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Effects + +Item { + id: root + + required property ShellScreen screen + required property Item wallpaper + + readonly property bool shouldBeActive: Config.background.visualiser.enabled && (!Config.background.visualiser.autoHide || (Hypr.monitorFor(screen)?.activeWorkspace?.toplevels?.values.every(t => t.lastIpcObject?.floating) ?? true)) + property real offset: shouldBeActive ? 0 : screen.height * 0.2 + + opacity: shouldBeActive ? 1 : 0 + + Loader { + anchors.fill: parent + active: root.opacity > 0 && Config.background.visualiser.blur + + sourceComponent: MultiEffect { + source: root.wallpaper + maskSource: wrapper + maskEnabled: true + blurEnabled: true + blur: 1 + blurMax: 32 + autoPaddingEnabled: false + } + } + + Item { + id: wrapper + + anchors.fill: parent + layer.enabled: true + + Loader { + anchors.fill: parent + anchors.topMargin: root.offset + anchors.bottomMargin: -root.offset + + active: root.opacity > 0 + + sourceComponent: Item { + ServiceRef { + service: Audio.cava + } + + Item { + id: content + + anchors.fill: parent + anchors.margins: Config.border.thickness + anchors.leftMargin: Visibilities.bars.get(root.screen).exclusiveZone + Appearance.spacing.small * Config.background.visualiser.spacing + + Side { + content: content + } + Side { + content: content + isRight: true + } + + Behavior on anchors.leftMargin { + Anim {} + } + } + } + } + } + + Behavior on offset { + Anim {} + } + + Behavior on opacity { + Anim {} + } + + component Side: Repeater { + id: side + + required property Item content + property bool isRight + + model: Config.services.visualiserBars + + ClippingRectangle { + id: bar + + required property int modelData + property real value: Math.max(0, Math.min(1, Audio.cava.values[side.isRight ? modelData : side.count - modelData - 1])) + + clip: true + + x: modelData * ((side.content.width * 0.4) / Config.services.visualiserBars) + (side.isRight ? side.content.width * 0.6 : 0) + implicitWidth: (side.content.width * 0.4) / Config.services.visualiserBars - Appearance.spacing.small * Config.background.visualiser.spacing + + y: side.content.height - height + implicitHeight: bar.value * side.content.height * 0.4 + + color: "transparent" + topLeftRadius: Appearance.rounding.small * Config.background.visualiser.rounding + topRightRadius: Appearance.rounding.small * Config.background.visualiser.rounding + + Rectangle { + topLeftRadius: parent.topLeftRadius + topRightRadius: parent.topRightRadius + + gradient: Gradient { + orientation: Gradient.Vertical + + GradientStop { + position: 0 + color: Qt.alpha(Colours.palette.m3primary, 0.7) + + Behavior on color { + CAnim {} + } + } + GradientStop { + position: 1 + color: Qt.alpha(Colours.palette.m3inversePrimary, 0.7) + + Behavior on color { + CAnim {} + } + } + } + + anchors.left: parent.left + anchors.right: parent.right + y: parent.height - height + implicitHeight: side.content.height * 0.4 + } + + Behavior on value { + Anim { + duration: Appearance.anim.durations.small + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/background/Wallpaper.qml b/.config/quickshell/caelestia/modules/background/Wallpaper.qml new file mode 100644 index 0000000..39a48fc --- /dev/null +++ b/.config/quickshell/caelestia/modules/background/Wallpaper.qml @@ -0,0 +1,145 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.images +import qs.components.filedialog +import qs.services +import qs.config +import qs.utils +import QtQuick + +Item { + id: root + + property string source: Wallpapers.current + property Image current: one + + onSourceChanged: { + if (!source) + current = null; + else if (current === one) + two.update(); + else + one.update(); + } + + Component.onCompleted: { + if (source) + Qt.callLater(() => one.update()); + } + + Loader { + anchors.fill: parent + + active: !root.source + + sourceComponent: StyledRect { + color: Colours.palette.m3surfaceContainer + + Row { + anchors.centerIn: parent + spacing: Appearance.spacing.large + + MaterialIcon { + text: "sentiment_stressed" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.extraLarge * 5 + } + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: Appearance.spacing.small + + StyledText { + text: qsTr("Wallpaper missing?") + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.extraLarge * 2 + font.bold: true + } + + StyledRect { + implicitWidth: selectWallText.implicitWidth + Appearance.padding.large * 2 + implicitHeight: selectWallText.implicitHeight + Appearance.padding.small * 2 + + radius: Appearance.rounding.full + color: Colours.palette.m3primary + + FileDialog { + id: dialog + + title: qsTr("Select a wallpaper") + filterLabel: qsTr("Image files") + filters: Images.validImageExtensions + onAccepted: path => Wallpapers.setWallpaper(path) + } + + StateLayer { + radius: parent.radius + color: Colours.palette.m3onPrimary + + function onClicked(): void { + dialog.open(); + } + } + + StyledText { + id: selectWallText + + anchors.centerIn: parent + + text: qsTr("Set it now!") + color: Colours.palette.m3onPrimary + font.pointSize: Appearance.font.size.large + } + } + } + } + } + } + + Img { + id: one + } + + Img { + id: two + } + + component Img: CachingImage { + id: img + + function update(): void { + if (path === root.source) + root.current = this; + else + path = root.source; + } + + anchors.fill: parent + + opacity: 0 + scale: Wallpapers.showPreview ? 1 : 0.8 + + onStatusChanged: { + if (status === Image.Ready) + root.current = this; + } + + states: State { + name: "visible" + when: root.current === img + + PropertyChanges { + img.opacity: 1 + img.scale: 1 + } + } + + transitions: Transition { + Anim { + target: img + properties: "opacity,scale" + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/Bar.qml b/.config/quickshell/caelestia/modules/bar/Bar.qml new file mode 100644 index 0000000..cb384e3 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/Bar.qml @@ -0,0 +1,205 @@ +pragma ComponentBehavior: Bound + +import qs.services +import qs.config +import "popouts" as BarPopouts +import "components" +import "components/workspaces" +import Quickshell +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property ShellScreen screen + required property PersistentProperties visibilities + required property BarPopouts.Wrapper popouts + readonly property int vPadding: Appearance.padding.large + + function closeTray(): void { + if (!Config.bar.tray.compact) + return; + + for (let i = 0; i < repeater.count; i++) { + const item = repeater.itemAt(i); + if (item?.enabled && item.id === "tray") { + item.item.expanded = false; + } + } + } + + function checkPopout(y: real): void { + const ch = childAt(width / 2, y) as WrappedLoader; + + if (ch?.id !== "tray") + closeTray(); + + if (!ch) { + popouts.hasCurrent = false; + return; + } + + const id = ch.id; + const top = ch.y; + const item = ch.item; + const itemHeight = item.implicitHeight; + + if (id === "statusIcons" && Config.bar.popouts.statusIcons) { + const items = item.items; + const icon = items.childAt(items.width / 2, mapToItem(items, 0, y).y); + if (icon) { + popouts.currentName = icon.name; + popouts.currentCenter = Qt.binding(() => icon.mapToItem(root, 0, icon.implicitHeight / 2).y); + popouts.hasCurrent = true; + } + } else if (id === "tray" && Config.bar.popouts.tray) { + if (!Config.bar.tray.compact || (item.expanded && !item.expandIcon.contains(mapToItem(item.expandIcon, item.implicitWidth / 2, y)))) { + const index = Math.floor(((y - top - item.padding * 2 + item.spacing) / item.layout.implicitHeight) * item.items.count); + const trayItem = item.items.itemAt(index); + if (trayItem) { + popouts.currentName = `traymenu${index}`; + popouts.currentCenter = Qt.binding(() => trayItem.mapToItem(root, 0, trayItem.implicitHeight / 2).y); + popouts.hasCurrent = true; + } else { + popouts.hasCurrent = false; + } + } else { + popouts.hasCurrent = false; + item.expanded = true; + } + } else if (id === "activeWindow" && Config.bar.popouts.activeWindow) { + popouts.currentName = id.toLowerCase(); + popouts.currentCenter = item.mapToItem(root, 0, itemHeight / 2).y; + popouts.hasCurrent = true; + } + } + + function handleWheel(y: real, angleDelta: point): void { + const ch = childAt(width / 2, y) as WrappedLoader; + if (ch?.id === "workspaces" && Config.bar.scrollActions.workspaces) { + // Workspace scroll + const mon = (Config.bar.workspaces.perMonitorWorkspaces ? Hypr.monitorFor(screen) : Hypr.focusedMonitor); + const specialWs = mon?.lastIpcObject.specialWorkspace.name; + if (specialWs?.length > 0) + Hypr.dispatch(`togglespecialworkspace ${specialWs.slice(8)}`); + else if (angleDelta.y < 0 || (Config.bar.workspaces.perMonitorWorkspaces ? mon.activeWorkspace?.id : Hypr.activeWsId) > 1) + Hypr.dispatch(`workspace r${angleDelta.y > 0 ? "-" : "+"}1`); + } else if (y < screen.height / 2 && Config.bar.scrollActions.volume) { + // Volume scroll on top half + if (angleDelta.y > 0) + Audio.incrementVolume(); + else if (angleDelta.y < 0) + Audio.decrementVolume(); + } else if (Config.bar.scrollActions.brightness) { + // Brightness scroll on bottom half + const monitor = Brightness.getMonitorForScreen(screen); + if (angleDelta.y > 0) + monitor.setBrightness(monitor.brightness + Config.services.brightnessIncrement); + else if (angleDelta.y < 0) + monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement); + } + } + + spacing: Appearance.spacing.normal + + Repeater { + id: repeater + + model: Config.bar.entries + + DelegateChooser { + role: "id" + + DelegateChoice { + roleValue: "spacer" + delegate: WrappedLoader { + Layout.fillHeight: enabled + } + } + DelegateChoice { + roleValue: "logo" + delegate: WrappedLoader { + sourceComponent: OsIcon {} + } + } + DelegateChoice { + roleValue: "workspaces" + delegate: WrappedLoader { + sourceComponent: Workspaces { + screen: root.screen + } + } + } + DelegateChoice { + roleValue: "activeWindow" + delegate: WrappedLoader { + sourceComponent: ActiveWindow { + bar: root + monitor: Brightness.getMonitorForScreen(root.screen) + } + } + } + DelegateChoice { + roleValue: "tray" + delegate: WrappedLoader { + sourceComponent: Tray {} + } + } + DelegateChoice { + roleValue: "clock" + delegate: WrappedLoader { + sourceComponent: Clock {} + } + } + DelegateChoice { + roleValue: "statusIcons" + delegate: WrappedLoader { + sourceComponent: StatusIcons {} + } + } + DelegateChoice { + roleValue: "power" + delegate: WrappedLoader { + sourceComponent: Power { + visibilities: root.visibilities + } + } + } + } + } + + component WrappedLoader: Loader { + required property bool enabled + required property string id + required property int index + + function findFirstEnabled(): Item { + const count = repeater.count; + for (let i = 0; i < count; i++) { + const item = repeater.itemAt(i); + if (item?.enabled) + return item; + } + return null; + } + + function findLastEnabled(): Item { + for (let i = repeater.count - 1; i >= 0; i--) { + const item = repeater.itemAt(i); + if (item?.enabled) + return item; + } + return null; + } + + Layout.alignment: Qt.AlignHCenter + + // Cursed ahh thing to add padding to first and last enabled components + Layout.topMargin: findFirstEnabled() === this ? root.vPadding : 0 + Layout.bottomMargin: findLastEnabled() === this ? root.vPadding : 0 + + visible: enabled + active: enabled + } +} diff --git a/.config/quickshell/caelestia/modules/bar/BarWrapper.qml b/.config/quickshell/caelestia/modules/bar/BarWrapper.qml new file mode 100644 index 0000000..29961b6 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/BarWrapper.qml @@ -0,0 +1,87 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.config +import "popouts" as BarPopouts +import Quickshell +import QtQuick + +Item { + id: root + + required property ShellScreen screen + required property PersistentProperties visibilities + required property BarPopouts.Wrapper popouts + required property bool disabled + + readonly property int padding: Math.max(Appearance.padding.smaller, Config.border.thickness) + readonly property int contentWidth: Config.bar.sizes.innerWidth + padding * 2 + readonly property int exclusiveZone: !disabled && (Config.bar.persistent || visibilities.bar) ? contentWidth : Config.border.thickness + readonly property bool shouldBeVisible: !disabled && (Config.bar.persistent || visibilities.bar || isHovered) + property bool isHovered + + function closeTray(): void { + content.item?.closeTray(); + } + + function checkPopout(y: real): void { + content.item?.checkPopout(y); + } + + function handleWheel(y: real, angleDelta: point): void { + content.item?.handleWheel(y, angleDelta); + } + + visible: width > Config.border.thickness + implicitWidth: Config.border.thickness + + states: State { + name: "visible" + when: root.shouldBeVisible + + PropertyChanges { + root.implicitWidth: root.contentWidth + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + target: root + property: "implicitWidth" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + }, + Transition { + from: "visible" + to: "" + + Anim { + target: root + property: "implicitWidth" + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + ] + + Loader { + id: content + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + + active: root.shouldBeVisible || root.visible + + sourceComponent: Bar { + width: root.contentWidth + screen: root.screen + visibilities: root.visibilities + popouts: root.popouts + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/ActiveWindow.qml b/.config/quickshell/caelestia/modules/bar/components/ActiveWindow.qml new file mode 100644 index 0000000..0c9b21e --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/ActiveWindow.qml @@ -0,0 +1,100 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.utils +import qs.config +import QtQuick + +Item { + id: root + + required property var bar + required property Brightness.Monitor monitor + property color colour: Colours.palette.m3primary + + readonly property int maxHeight: { + const otherModules = bar.children.filter(c => c.id && c.item !== this && c.id !== "spacer"); + const otherHeight = otherModules.reduce((acc, curr) => acc + (curr.item.nonAnimHeight ?? curr.height), 0); + // Length - 2 cause repeater counts as a child + return bar.height - otherHeight - bar.spacing * (bar.children.length - 1) - bar.vPadding * 2; + } + property Title current: text1 + + clip: true + implicitWidth: Math.max(icon.implicitWidth, current.implicitHeight) + implicitHeight: icon.implicitHeight + current.implicitWidth + current.anchors.topMargin + + MaterialIcon { + id: icon + + anchors.horizontalCenter: parent.horizontalCenter + + animate: true + text: Icons.getAppCategoryIcon(Hypr.activeToplevel?.lastIpcObject.class, "desktop_windows") + color: root.colour + } + + Title { + id: text1 + } + + Title { + id: text2 + } + + TextMetrics { + id: metrics + + text: Hypr.activeToplevel?.title ?? qsTr("Desktop") + font.pointSize: Appearance.font.size.smaller + font.family: Appearance.font.family.mono + elide: Qt.ElideRight + elideWidth: root.maxHeight - icon.height + + onTextChanged: { + const next = root.current === text1 ? text2 : text1; + next.text = elidedText; + root.current = next; + } + onElideWidthChanged: root.current.text = elidedText + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + component Title: StyledText { + id: text + + anchors.horizontalCenter: icon.horizontalCenter + anchors.top: icon.bottom + anchors.topMargin: Appearance.spacing.small + + font.pointSize: metrics.font.pointSize + font.family: metrics.font.family + color: root.colour + opacity: root.current === this ? 1 : 0 + + transform: [ + Translate { + x: Config.bar.activeWindow.inverted ? -implicitWidth + text.implicitHeight : 0 + }, + Rotation { + angle: Config.bar.activeWindow.inverted ? 270 : 90 + origin.x: text.implicitHeight / 2 + origin.y: text.implicitHeight / 2 + } + ] + + width: implicitHeight + height: implicitWidth + + Behavior on opacity { + Anim {} + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/Clock.qml b/.config/quickshell/caelestia/modules/bar/components/Clock.qml new file mode 100644 index 0000000..801e93d --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/Clock.qml @@ -0,0 +1,38 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import QtQuick + +Column { + id: root + + property color colour: Colours.palette.m3tertiary + + spacing: Appearance.spacing.small + + Loader { + anchors.horizontalCenter: parent.horizontalCenter + + active: Config.bar.clock.showIcon + visible: active + + sourceComponent: MaterialIcon { + text: "calendar_month" + color: root.colour + } + } + + StyledText { + id: text + + anchors.horizontalCenter: parent.horizontalCenter + + horizontalAlignment: StyledText.AlignHCenter + text: Time.format(Config.services.useTwelveHourClock ? "hh\nmm\nA" : "hh\nmm") + font.pointSize: Appearance.font.size.smaller + font.family: Appearance.font.family.mono + color: root.colour + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/OsIcon.qml b/.config/quickshell/caelestia/modules/bar/components/OsIcon.qml new file mode 100644 index 0000000..a61500a --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/OsIcon.qml @@ -0,0 +1,46 @@ +import qs.components.effects +import qs.services +import qs.config +import qs.utils +import QtQuick +import qs.components + +Item { + id: root + + implicitWidth: Appearance.font.size.large * 1.2 + implicitHeight: Appearance.font.size.large * 1.2 + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: { + const visibilities = Visibilities.getForActive(); + visibilities.launcher = !visibilities.launcher; + } + } + + Loader { + anchors.centerIn: parent + sourceComponent: SysInfo.isDefaultLogo ? caelestiaLogo : distroIcon + } + + Component { + id: caelestiaLogo + + Logo { + implicitWidth: Appearance.font.size.large * 1.8 + implicitHeight: Appearance.font.size.large * 1.8 + } + } + + Component { + id: distroIcon + + ColouredIcon { + source: SysInfo.osLogo + implicitSize: Appearance.font.size.large * 1.2 + colour: Colours.palette.m3tertiary + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/Power.qml b/.config/quickshell/caelestia/modules/bar/components/Power.qml new file mode 100644 index 0000000..917bdf7 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/Power.qml @@ -0,0 +1,40 @@ +import qs.components +import qs.services +import qs.config +import Quickshell +import QtQuick + +Item { + id: root + + required property PersistentProperties visibilities + + implicitWidth: icon.implicitHeight + Appearance.padding.small * 2 + implicitHeight: icon.implicitHeight + + StateLayer { + // Cursed workaround to make the height larger than the parent + anchors.fill: undefined + anchors.centerIn: parent + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.small * 2 + + radius: Appearance.rounding.full + + function onClicked(): void { + root.visibilities.session = !root.visibilities.session; + } + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + anchors.horizontalCenterOffset: -1 + + text: "power_settings_new" + color: Colours.palette.m3error + font.bold: true + font.pointSize: Appearance.font.size.normal + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/Settings.qml b/.config/quickshell/caelestia/modules/bar/components/Settings.qml new file mode 100644 index 0000000..5d562ce --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/Settings.qml @@ -0,0 +1,41 @@ +import qs.components +import qs.modules.controlcenter +import qs.services +import qs.config +import Quickshell +import QtQuick + +Item { + id: root + + implicitWidth: icon.implicitHeight + Appearance.padding.small * 2 + implicitHeight: icon.implicitHeight + + StateLayer { + // Cursed workaround to make the height larger than the parent + anchors.fill: undefined + anchors.centerIn: parent + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.small * 2 + + radius: Appearance.rounding.full + + function onClicked(): void { + WindowFactory.create(null, { + active: "network" + }); + } + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + anchors.horizontalCenterOffset: -1 + + text: "settings" + color: Colours.palette.m3onSurface + font.bold: true + font.pointSize: Appearance.font.size.normal + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/SettingsIcon.qml b/.config/quickshell/caelestia/modules/bar/components/SettingsIcon.qml new file mode 100644 index 0000000..5d562ce --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/SettingsIcon.qml @@ -0,0 +1,41 @@ +import qs.components +import qs.modules.controlcenter +import qs.services +import qs.config +import Quickshell +import QtQuick + +Item { + id: root + + implicitWidth: icon.implicitHeight + Appearance.padding.small * 2 + implicitHeight: icon.implicitHeight + + StateLayer { + // Cursed workaround to make the height larger than the parent + anchors.fill: undefined + anchors.centerIn: parent + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.small * 2 + + radius: Appearance.rounding.full + + function onClicked(): void { + WindowFactory.create(null, { + active: "network" + }); + } + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + anchors.horizontalCenterOffset: -1 + + text: "settings" + color: Colours.palette.m3onSurface + font.bold: true + font.pointSize: Appearance.font.size.normal + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/StatusIcons.qml b/.config/quickshell/caelestia/modules/bar/components/StatusIcons.qml new file mode 100644 index 0000000..ca7dc2e --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/StatusIcons.qml @@ -0,0 +1,270 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.utils +import qs.config +import Quickshell +import Quickshell.Bluetooth +import Quickshell.Services.UPower +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + property color colour: Colours.palette.m3secondary + readonly property alias items: iconColumn + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.full + + clip: true + implicitWidth: Config.bar.sizes.innerWidth + implicitHeight: iconColumn.implicitHeight + Appearance.padding.normal * 2 - (Config.bar.status.showLockStatus && !Hypr.capsLock && !Hypr.numLock ? iconColumn.spacing : 0) + + ColumnLayout { + id: iconColumn + + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: Appearance.padding.normal + + spacing: Appearance.spacing.smaller / 2 + + // Lock keys status + WrappedLoader { + name: "lockstatus" + active: Config.bar.status.showLockStatus + + sourceComponent: ColumnLayout { + spacing: 0 + + Item { + implicitWidth: capslockIcon.implicitWidth + implicitHeight: Hypr.capsLock ? capslockIcon.implicitHeight : 0 + + MaterialIcon { + id: capslockIcon + + anchors.centerIn: parent + + scale: Hypr.capsLock ? 1 : 0.5 + opacity: Hypr.capsLock ? 1 : 0 + + text: "keyboard_capslock_badge" + color: root.colour + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + } + + Behavior on implicitHeight { + Anim {} + } + } + + Item { + Layout.topMargin: Hypr.capsLock && Hypr.numLock ? iconColumn.spacing : 0 + + implicitWidth: numlockIcon.implicitWidth + implicitHeight: Hypr.numLock ? numlockIcon.implicitHeight : 0 + + MaterialIcon { + id: numlockIcon + + anchors.centerIn: parent + + scale: Hypr.numLock ? 1 : 0.5 + opacity: Hypr.numLock ? 1 : 0 + + text: "looks_one" + color: root.colour + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + } + + Behavior on implicitHeight { + Anim {} + } + } + } + } + + // Audio icon + WrappedLoader { + name: "audio" + active: Config.bar.status.showAudio + + sourceComponent: MaterialIcon { + animate: true + text: Icons.getVolumeIcon(Audio.volume, Audio.muted) + color: root.colour + } + } + + // Microphone icon + WrappedLoader { + name: "audio" + active: Config.bar.status.showMicrophone + + sourceComponent: MaterialIcon { + animate: true + text: Icons.getMicVolumeIcon(Audio.sourceVolume, Audio.sourceMuted) + color: root.colour + } + } + + // Keyboard layout icon + WrappedLoader { + name: "kblayout" + active: Config.bar.status.showKbLayout + + sourceComponent: StyledText { + animate: true + text: Hypr.kbLayout + color: root.colour + font.family: Appearance.font.family.mono + } + } + + // Network icon + WrappedLoader { + name: "network" + active: Config.bar.status.showNetwork && (!Nmcli.activeEthernet || Config.bar.status.showWifi) + + sourceComponent: MaterialIcon { + animate: true + text: Nmcli.active ? Icons.getNetworkIcon(Nmcli.active.strength ?? 0) : "wifi_off" + color: root.colour + } + } + + // Ethernet icon + WrappedLoader { + name: "ethernet" + active: Config.bar.status.showNetwork && Nmcli.activeEthernet + + sourceComponent: MaterialIcon { + animate: true + text: "cable" + color: root.colour + } + } + + // Bluetooth section + WrappedLoader { + Layout.preferredHeight: implicitHeight + + name: "bluetooth" + active: Config.bar.status.showBluetooth + + sourceComponent: ColumnLayout { + spacing: Appearance.spacing.smaller / 2 + + // Bluetooth icon + MaterialIcon { + animate: true + text: { + if (!Bluetooth.defaultAdapter?.enabled) + return "bluetooth_disabled"; + if (Bluetooth.devices.values.some(d => d.connected)) + return "bluetooth_connected"; + return "bluetooth"; + } + color: root.colour + } + + // Connected bluetooth devices + Repeater { + model: ScriptModel { + values: Bluetooth.devices.values.filter(d => d.state !== BluetoothDeviceState.Disconnected) + } + + MaterialIcon { + id: device + + required property BluetoothDevice modelData + + animate: true + text: Icons.getBluetoothIcon(modelData?.icon) + color: root.colour + fill: 1 + + SequentialAnimation on opacity { + running: device.modelData?.state !== BluetoothDeviceState.Connected + alwaysRunToEnd: true + loops: Animation.Infinite + + Anim { + from: 1 + to: 0 + duration: Appearance.anim.durations.large + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + Anim { + from: 0 + to: 1 + duration: Appearance.anim.durations.large + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + } + } + } + + Behavior on Layout.preferredHeight { + Anim {} + } + } + + // Battery icon + WrappedLoader { + name: "battery" + active: Config.bar.status.showBattery + + sourceComponent: MaterialIcon { + animate: true + text: { + if (!UPower.displayDevice.isLaptopBattery) { + if (PowerProfiles.profile === PowerProfile.PowerSaver) + return "energy_savings_leaf"; + if (PowerProfiles.profile === PowerProfile.Performance) + return "rocket_launch"; + return "balance"; + } + + const perc = UPower.displayDevice.percentage; + const charging = [UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(UPower.displayDevice.state); + if (perc === 1) + return charging ? "battery_charging_full" : "battery_full"; + let level = Math.floor(perc * 7); + if (charging && (level === 4 || level === 1)) + level--; + return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`; + } + color: !UPower.onBattery || UPower.displayDevice.percentage > 0.2 ? root.colour : Colours.palette.m3error + fill: 1 + } + } + } + + component WrappedLoader: Loader { + required property string name + + Layout.alignment: Qt.AlignHCenter + visible: active + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/Tray.qml b/.config/quickshell/caelestia/modules/bar/components/Tray.qml new file mode 100644 index 0000000..7bafda1 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/Tray.qml @@ -0,0 +1,121 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Quickshell +import Quickshell.Services.SystemTray +import QtQuick + +StyledRect { + id: root + + readonly property alias layout: layout + readonly property alias items: items + readonly property alias expandIcon: expandIcon + + readonly property int padding: Config.bar.tray.background ? Appearance.padding.normal : Appearance.padding.small + readonly property int spacing: Config.bar.tray.background ? Appearance.spacing.small : 0 + + property bool expanded + + readonly property real nonAnimHeight: { + if (!Config.bar.tray.compact) + return layout.implicitHeight + padding * 2; + return (expanded ? expandIcon.implicitHeight + layout.implicitHeight + spacing : expandIcon.implicitHeight) + padding * 2; + } + + clip: true + visible: height > 0 + + implicitWidth: Config.bar.sizes.innerWidth + implicitHeight: nonAnimHeight + + color: Qt.alpha(Colours.tPalette.m3surfaceContainer, (Config.bar.tray.background && items.count > 0) ? Colours.tPalette.m3surfaceContainer.a : 0) + radius: Appearance.rounding.full + + Column { + id: layout + + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: root.padding + spacing: Appearance.spacing.small + + opacity: root.expanded || !Config.bar.tray.compact ? 1 : 0 + + add: Transition { + Anim { + properties: "scale" + from: 0 + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + + move: Transition { + Anim { + properties: "scale" + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + properties: "x,y" + } + } + + Repeater { + id: items + + model: ScriptModel { + values: SystemTray.items.values.filter(i => !Config.bar.tray.hiddenIcons.includes(i.id)) + } + + TrayItem {} + } + + Behavior on opacity { + Anim {} + } + } + + Loader { + id: expandIcon + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + active: Config.bar.tray.compact && items.count > 0 + + sourceComponent: Item { + implicitWidth: expandIconInner.implicitWidth + implicitHeight: expandIconInner.implicitHeight - Appearance.padding.small * 2 + + MaterialIcon { + id: expandIconInner + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: Config.bar.tray.background ? Appearance.padding.small : -Appearance.padding.small + text: "expand_less" + font.pointSize: Appearance.font.size.large + rotation: root.expanded ? 180 : 0 + + Behavior on rotation { + Anim {} + } + + Behavior on anchors.bottomMargin { + Anim {} + } + } + } + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/TrayItem.qml b/.config/quickshell/caelestia/modules/bar/components/TrayItem.qml new file mode 100644 index 0000000..9911907 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/TrayItem.qml @@ -0,0 +1,34 @@ +pragma ComponentBehavior: Bound + +import qs.components.effects +import qs.services +import qs.config +import qs.utils +import Quickshell.Services.SystemTray +import QtQuick + +MouseArea { + id: root + + required property SystemTrayItem modelData + + acceptedButtons: Qt.LeftButton | Qt.RightButton + implicitWidth: Appearance.font.size.small * 2 + implicitHeight: Appearance.font.size.small * 2 + + onClicked: event => { + if (event.button === Qt.LeftButton) + modelData.activate(); + else + modelData.secondaryActivate(); + } + + ColouredIcon { + id: icon + + anchors.fill: parent + source: Icons.getTrayIcon(root.modelData.id, root.modelData.icon) + colour: Colours.palette.m3secondary + layer.enabled: Config.bar.tray.recolour + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/workspaces/ActiveIndicator.qml b/.config/quickshell/caelestia/modules/bar/components/workspaces/ActiveIndicator.qml new file mode 100644 index 0000000..dae54b3 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/workspaces/ActiveIndicator.qml @@ -0,0 +1,98 @@ +import qs.components +import qs.components.effects +import qs.services +import qs.config +import QtQuick + +StyledRect { + id: root + + required property int activeWsId + required property Repeater workspaces + required property Item mask + + readonly property int currentWsIdx: { + let i = activeWsId - 1; + while (i < 0) + i += Config.bar.workspaces.shown; + return i % Config.bar.workspaces.shown; + } + + property real leading: workspaces.count > 0 ? workspaces.itemAt(currentWsIdx)?.y ?? 0 : 0 + property real trailing: workspaces.count > 0 ? workspaces.itemAt(currentWsIdx)?.y ?? 0 : 0 + property real currentSize: workspaces.count > 0 ? workspaces.itemAt(currentWsIdx)?.size ?? 0 : 0 + property real offset: Math.min(leading, trailing) + property real size: { + const s = Math.abs(leading - trailing) + currentSize; + if (Config.bar.workspaces.activeTrail && lastWs > currentWsIdx) { + const ws = workspaces.itemAt(lastWs); + // console.log(ws, lastWs); + return ws ? Math.min(ws.y + ws.size - offset, s) : 0; + } + return s; + } + + property int cWs + property int lastWs + + onCurrentWsIdxChanged: { + lastWs = cWs; + cWs = currentWsIdx; + } + + clip: true + y: offset + mask.y + implicitWidth: Config.bar.sizes.innerWidth - Appearance.padding.small * 2 + implicitHeight: size + radius: Appearance.rounding.full + color: Colours.palette.m3primary + + Colouriser { + source: root.mask + sourceColor: Colours.palette.m3onSurface + colorizationColor: Colours.palette.m3onPrimary + + x: 0 + y: -parent.offset + implicitWidth: root.mask.implicitWidth + implicitHeight: root.mask.implicitHeight + + anchors.horizontalCenter: parent.horizontalCenter + } + + Behavior on leading { + enabled: Config.bar.workspaces.activeTrail + + EAnim {} + } + + Behavior on trailing { + enabled: Config.bar.workspaces.activeTrail + + EAnim { + duration: Appearance.anim.durations.normal * 2 + } + } + + Behavior on currentSize { + enabled: Config.bar.workspaces.activeTrail + + EAnim {} + } + + Behavior on offset { + enabled: !Config.bar.workspaces.activeTrail + + EAnim {} + } + + Behavior on size { + enabled: !Config.bar.workspaces.activeTrail + + EAnim {} + } + + component EAnim: Anim { + easing.bezierCurve: Appearance.anim.curves.emphasized + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/workspaces/OccupiedBg.qml b/.config/quickshell/caelestia/modules/bar/components/workspaces/OccupiedBg.qml new file mode 100644 index 0000000..56b215e --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/workspaces/OccupiedBg.qml @@ -0,0 +1,103 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Quickshell +import QtQuick + +Item { + id: root + + required property Repeater workspaces + required property var occupied + required property int groupOffset + + property list pills: [] + + onOccupiedChanged: { + if (!occupied) + return; + let count = 0; + const start = groupOffset; + const end = start + Config.bar.workspaces.shown; + for (const [ws, occ] of Object.entries(occupied)) { + if (ws > start && ws <= end && occ) { + const isFirstInGroup = Number(ws) === start + 1; + const isLastInGroup = Number(ws) === end; + if (isFirstInGroup || !occupied[ws - 1]) { + if (pills[count]) + pills[count].start = ws; + else + pills.push(pillComp.createObject(root, { + start: ws + })); + count++; + } + if ((isLastInGroup || !occupied[ws + 1]) && pills[count - 1]) + pills[count - 1].end = ws; + } + } + if (pills.length > count) + pills.splice(count, pills.length - count).forEach(p => p.destroy()); + } + + Repeater { + model: ScriptModel { + values: root.pills.filter(p => p) + } + + StyledRect { + id: rect + + required property var modelData + + readonly property Workspace start: root.workspaces.count > 0 ? root.workspaces.itemAt(getWsIdx(modelData.start)) ?? null : null + readonly property Workspace end: root.workspaces.count > 0 ? root.workspaces.itemAt(getWsIdx(modelData.end)) ?? null : null + + function getWsIdx(ws: int): int { + let i = ws - 1; + while (i < 0) + i += Config.bar.workspaces.shown; + return i % Config.bar.workspaces.shown; + } + + anchors.horizontalCenter: root.horizontalCenter + + y: (start?.y ?? 0) - 1 + implicitWidth: Config.bar.sizes.innerWidth - Appearance.padding.small * 2 + 2 + implicitHeight: start && end ? end.y + end.size - start.y + 2 : 0 + + color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + radius: Appearance.rounding.full + + scale: 0 + Component.onCompleted: scale = 1 + + Behavior on scale { + Anim { + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + + Behavior on y { + Anim {} + } + + Behavior on implicitHeight { + Anim {} + } + } + } + + component Pill: QtObject { + property int start + property int end + } + + Component { + id: pillComp + + Pill {} + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/workspaces/SpecialWorkspaces.qml b/.config/quickshell/caelestia/modules/bar/components/workspaces/SpecialWorkspaces.qml new file mode 100644 index 0000000..ad85af8 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/workspaces/SpecialWorkspaces.qml @@ -0,0 +1,359 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.effects +import qs.services +import qs.utils +import qs.config +import Quickshell +import Quickshell.Hyprland +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property ShellScreen screen + readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen) + readonly property string activeSpecial: (Config.bar.workspaces.perMonitorWorkspaces ? monitor : Hypr.focusedMonitor)?.lastIpcObject?.specialWorkspace?.name ?? "" + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: mask + } + + Item { + id: mask + + anchors.fill: parent + layer.enabled: true + visible: false + + Rectangle { + anchors.fill: parent + radius: Appearance.rounding.full + + gradient: Gradient { + orientation: Gradient.Vertical + + GradientStop { + position: 0 + color: Qt.rgba(0, 0, 0, 0) + } + GradientStop { + position: 0.3 + color: Qt.rgba(0, 0, 0, 1) + } + GradientStop { + position: 0.7 + color: Qt.rgba(0, 0, 0, 1) + } + GradientStop { + position: 1 + color: Qt.rgba(0, 0, 0, 0) + } + } + } + + Rectangle { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + radius: Appearance.rounding.full + implicitHeight: parent.height / 2 + opacity: view.contentY > 0 ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + + Rectangle { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + radius: Appearance.rounding.full + implicitHeight: parent.height / 2 + opacity: view.contentY < view.contentHeight - parent.height + Appearance.padding.small ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + } + + ListView { + id: view + + anchors.fill: parent + spacing: Appearance.spacing.normal + interactive: false + + currentIndex: model.values.findIndex(w => w.name === root.activeSpecial) + onCurrentIndexChanged: currentIndex = Qt.binding(() => model.values.findIndex(w => w.name === root.activeSpecial)) + + model: ScriptModel { + values: Hypr.workspaces.values.filter(w => w.name.startsWith("special:") && (!Config.bar.workspaces.perMonitorWorkspaces || w.monitor === root.monitor)) + } + + preferredHighlightBegin: 0 + preferredHighlightEnd: height + highlightRangeMode: ListView.StrictlyEnforceRange + + highlightFollowsCurrentItem: false + highlight: Item { + y: view.currentItem?.y ?? 0 + implicitHeight: view.currentItem?.size ?? 0 + + Behavior on y { + Anim {} + } + } + + delegate: ColumnLayout { + id: ws + + required property HyprlandWorkspace modelData + readonly property int size: label.Layout.preferredHeight + (hasWindows ? windows.implicitHeight + Appearance.padding.small : 0) + property int wsId + property string icon + property bool hasWindows + + anchors.left: view.contentItem.left + anchors.right: view.contentItem.right + + spacing: 0 + + Component.onCompleted: { + wsId = modelData.id; + icon = Icons.getSpecialWsIcon(modelData.name); + hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && modelData.lastIpcObject.windows > 0; + } + + // Hacky thing cause modelData gets destroyed before the remove anim finishes + Connections { + target: ws.modelData + + function onIdChanged(): void { + if (ws.modelData) + ws.wsId = ws.modelData.id; + } + + function onNameChanged(): void { + if (ws.modelData) + ws.icon = Icons.getSpecialWsIcon(ws.modelData.name); + } + + function onLastIpcObjectChanged(): void { + if (ws.modelData) + ws.hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && ws.modelData.lastIpcObject.windows > 0; + } + } + + Connections { + target: Config.bar.workspaces + + function onShowWindowsOnSpecialWorkspacesChanged(): void { + if (ws.modelData) + ws.hasWindows = Config.bar.workspaces.showWindowsOnSpecialWorkspaces && ws.modelData.lastIpcObject.windows > 0; + } + } + + Loader { + id: label + + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.preferredHeight: Config.bar.sizes.innerWidth - Appearance.padding.small * 2 + + sourceComponent: ws.icon.length === 1 ? letterComp : iconComp + + Component { + id: iconComp + + MaterialIcon { + fill: 1 + text: ws.icon + verticalAlignment: Qt.AlignVCenter + } + } + + Component { + id: letterComp + + StyledText { + text: ws.icon + verticalAlignment: Qt.AlignVCenter + } + } + } + + Loader { + id: windows + + Layout.alignment: Qt.AlignHCenter + Layout.fillHeight: true + Layout.preferredHeight: implicitHeight + + visible: active + active: ws.hasWindows + + sourceComponent: Column { + spacing: 0 + + add: Transition { + Anim { + properties: "scale" + from: 0 + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + + move: Transition { + Anim { + properties: "scale" + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + properties: "x,y" + } + } + + Repeater { + model: ScriptModel { + values: Hypr.toplevels.values.filter(c => c.workspace?.id === ws.wsId) + } + + MaterialIcon { + required property var modelData + + grade: 0 + text: Icons.getAppCategoryIcon(modelData.lastIpcObject.class, "terminal") + color: Colours.palette.m3onSurfaceVariant + } + } + } + + Behavior on Layout.preferredHeight { + Anim {} + } + } + } + + add: Transition { + Anim { + properties: "scale" + from: 0 + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + + remove: Transition { + Anim { + property: "scale" + to: 0.5 + duration: Appearance.anim.durations.small + } + Anim { + property: "opacity" + to: 0 + duration: Appearance.anim.durations.small + } + } + + move: Transition { + Anim { + properties: "scale" + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + properties: "x,y" + } + } + + displaced: Transition { + Anim { + properties: "scale" + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + properties: "x,y" + } + } + } + + Loader { + active: Config.bar.workspaces.activeIndicator + anchors.fill: parent + + sourceComponent: Item { + StyledClippingRect { + id: indicator + + anchors.left: parent.left + anchors.right: parent.right + + y: (view.currentItem?.y ?? 0) - view.contentY + implicitHeight: view.currentItem?.size ?? 0 + + color: Colours.palette.m3tertiary + radius: Appearance.rounding.full + + Colouriser { + source: view + sourceColor: Colours.palette.m3onSurface + colorizationColor: Colours.palette.m3onTertiary + + anchors.horizontalCenter: parent.horizontalCenter + + x: 0 + y: -indicator.y + implicitWidth: view.width + implicitHeight: view.height + } + + Behavior on y { + Anim { + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + Behavior on implicitHeight { + Anim { + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + } + } + } + + MouseArea { + property real startY + + anchors.fill: view + + drag.target: view.contentItem + drag.axis: Drag.YAxis + drag.maximumY: 0 + drag.minimumY: Math.min(0, view.height - view.contentHeight - Appearance.padding.small) + + onPressed: event => startY = event.y + + onClicked: event => { + if (Math.abs(event.y - startY) > drag.threshold) + return; + + const ws = view.itemAt(event.x, event.y); + if (ws?.modelData) + Hypr.dispatch(`togglespecialworkspace ${ws.modelData.name.slice(8)}`); + else + Hypr.dispatch("togglespecialworkspace special"); + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/workspaces/Workspace.qml b/.config/quickshell/caelestia/modules/bar/components/workspaces/Workspace.qml new file mode 100644 index 0000000..3c8238b --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/workspaces/Workspace.qml @@ -0,0 +1,107 @@ +import qs.components +import qs.services +import qs.utils +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property int index + required property int activeWsId + required property var occupied + required property int groupOffset + + readonly property bool isWorkspace: true // Flag for finding workspace children + // Unanimated prop for others to use as reference + readonly property int size: implicitHeight + (hasWindows ? Appearance.padding.small : 0) + + readonly property int ws: groupOffset + index + 1 + readonly property bool isOccupied: occupied[ws] ?? false + readonly property bool hasWindows: isOccupied && Config.bar.workspaces.showWindows + + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: size + + spacing: 0 + + StyledText { + id: indicator + + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.preferredHeight: Config.bar.sizes.innerWidth - Appearance.padding.small * 2 + + animate: true + text: { + const ws = Hypr.workspaces.values.find(w => w.id === root.ws); + const wsName = !ws || ws.name == root.ws ? root.ws : ws.name[0]; + let displayName = wsName.toString(); + if (Config.bar.workspaces.capitalisation.toLowerCase() === "upper") { + displayName = displayName.toUpperCase(); + } else if (Config.bar.workspaces.capitalisation.toLowerCase() === "lower") { + displayName = displayName.toLowerCase(); + } + const label = Config.bar.workspaces.label || displayName; + const occupiedLabel = Config.bar.workspaces.occupiedLabel || label; + const activeLabel = Config.bar.workspaces.activeLabel || (root.isOccupied ? occupiedLabel : label); + return root.activeWsId === root.ws ? activeLabel : root.isOccupied ? occupiedLabel : label; + } + color: Config.bar.workspaces.occupiedBg || root.isOccupied || root.activeWsId === root.ws ? Colours.palette.m3onSurface : Colours.layer(Colours.palette.m3outlineVariant, 2) + verticalAlignment: Qt.AlignVCenter + } + + Loader { + id: windows + + Layout.alignment: Qt.AlignHCenter + Layout.fillHeight: true + Layout.topMargin: -Config.bar.sizes.innerWidth / 10 + + visible: active + active: root.hasWindows + + sourceComponent: Column { + spacing: 0 + + add: Transition { + Anim { + properties: "scale" + from: 0 + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + + move: Transition { + Anim { + properties: "scale" + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + properties: "x,y" + } + } + + Repeater { + model: ScriptModel { + values: Hypr.toplevels.values.filter(c => c.workspace?.id === root.ws) + } + + MaterialIcon { + required property var modelData + + grade: 0 + text: Icons.getAppCategoryIcon(modelData.lastIpcObject.class, "terminal") + color: Colours.palette.m3onSurfaceVariant + } + } + } + } + + Behavior on Layout.preferredHeight { + Anim {} + } +} diff --git a/.config/quickshell/caelestia/modules/bar/components/workspaces/Workspaces.qml b/.config/quickshell/caelestia/modules/bar/components/workspaces/Workspaces.qml new file mode 100644 index 0000000..bfa80ab --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/components/workspaces/Workspaces.qml @@ -0,0 +1,137 @@ +pragma ComponentBehavior: Bound + +import qs.services +import qs.config +import qs.components +import Quickshell +import QtQuick +import QtQuick.Layouts +import QtQuick.Effects + +StyledClippingRect { + id: root + + required property ShellScreen screen + + readonly property bool onSpecial: (Config.bar.workspaces.perMonitorWorkspaces ? Hypr.monitorFor(screen) : Hypr.focusedMonitor)?.lastIpcObject?.specialWorkspace?.name !== "" + readonly property int activeWsId: Config.bar.workspaces.perMonitorWorkspaces ? (Hypr.monitorFor(screen).activeWorkspace?.id ?? 1) : Hypr.activeWsId + + readonly property var occupied: Hypr.workspaces.values.reduce((acc, curr) => { + acc[curr.id] = curr.lastIpcObject.windows > 0; + return acc; + }, {}) + readonly property int groupOffset: Math.floor((activeWsId - 1) / Config.bar.workspaces.shown) * Config.bar.workspaces.shown + + property real blur: onSpecial ? 1 : 0 + + implicitWidth: Config.bar.sizes.innerWidth + implicitHeight: layout.implicitHeight + Appearance.padding.small * 2 + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.full + + Item { + anchors.fill: parent + scale: root.onSpecial ? 0.8 : 1 + opacity: root.onSpecial ? 0.5 : 1 + + layer.enabled: root.blur > 0 + layer.effect: MultiEffect { + blurEnabled: true + blur: root.blur + blurMax: 32 + } + + Loader { + active: Config.bar.workspaces.occupiedBg + + anchors.fill: parent + anchors.margins: Appearance.padding.small + + sourceComponent: OccupiedBg { + workspaces: workspaces + occupied: root.occupied + groupOffset: root.groupOffset + } + } + + ColumnLayout { + id: layout + + anchors.centerIn: parent + spacing: Math.floor(Appearance.spacing.small / 2) + + Repeater { + id: workspaces + + model: Config.bar.workspaces.shown + + Workspace { + activeWsId: root.activeWsId + occupied: root.occupied + groupOffset: root.groupOffset + } + } + } + + Loader { + anchors.horizontalCenter: parent.horizontalCenter + active: Config.bar.workspaces.activeIndicator + + sourceComponent: ActiveIndicator { + activeWsId: root.activeWsId + workspaces: workspaces + mask: layout + } + } + + MouseArea { + anchors.fill: layout + onClicked: event => { + const ws = layout.childAt(event.x, event.y).ws; + if (Hypr.activeWsId !== ws) + Hypr.dispatch(`workspace ${ws}`); + else + Hypr.dispatch("togglespecialworkspace special"); + } + } + + Behavior on scale { + Anim {} + } + + Behavior on opacity { + Anim {} + } + } + + Loader { + id: specialWs + + anchors.fill: parent + anchors.margins: Appearance.padding.small + + active: opacity > 0 + + scale: root.onSpecial ? 1 : 0.5 + opacity: root.onSpecial ? 1 : 0 + + sourceComponent: SpecialWorkspaces { + screen: root.screen + } + + Behavior on scale { + Anim {} + } + + Behavior on opacity { + Anim {} + } + } + + Behavior on blur { + Anim { + duration: Appearance.anim.durations.small + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/ActiveWindow.qml b/.config/quickshell/caelestia/modules/bar/popouts/ActiveWindow.qml new file mode 100644 index 0000000..adf7b77 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/ActiveWindow.qml @@ -0,0 +1,102 @@ +import qs.components +import qs.services +import qs.utils +import qs.config +import Quickshell.Widgets +import Quickshell.Wayland +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Item wrapper + + implicitWidth: Hypr.activeToplevel ? child.implicitWidth : -Appearance.padding.large * 2 + implicitHeight: child.implicitHeight + + Column { + id: child + + anchors.centerIn: parent + spacing: Appearance.spacing.normal + + RowLayout { + id: detailsRow + + anchors.left: parent.left + anchors.right: parent.right + spacing: Appearance.spacing.normal + + IconImage { + id: icon + + Layout.alignment: Qt.AlignVCenter + implicitSize: details.implicitHeight + source: Icons.getAppIcon(Hypr.activeToplevel?.lastIpcObject.class ?? "", "image-missing") + } + + ColumnLayout { + id: details + + spacing: 0 + Layout.fillWidth: true + + StyledText { + Layout.fillWidth: true + text: Hypr.activeToplevel?.title ?? "" + font.pointSize: Appearance.font.size.normal + elide: Text.ElideRight + } + + StyledText { + Layout.fillWidth: true + text: Hypr.activeToplevel?.lastIpcObject.class ?? "" + color: Colours.palette.m3onSurfaceVariant + elide: Text.ElideRight + } + } + + Item { + implicitWidth: expandIcon.implicitHeight + Appearance.padding.small * 2 + implicitHeight: expandIcon.implicitHeight + Appearance.padding.small * 2 + + Layout.alignment: Qt.AlignVCenter + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + root.wrapper.detach("winfo"); + } + } + + MaterialIcon { + id: expandIcon + + anchors.centerIn: parent + anchors.horizontalCenterOffset: font.pointSize * 0.05 + + text: "chevron_right" + + font.pointSize: Appearance.font.size.large + } + } + } + + ClippingWrapperRectangle { + color: "transparent" + radius: Appearance.rounding.small + + ScreencopyView { + id: preview + + captureSource: Hypr.activeToplevel?.wayland ?? null + live: visible + + constraintSize.width: Config.bar.sizes.windowPreviewSize + constraintSize.height: Config.bar.sizes.windowPreviewSize + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/Audio.qml b/.config/quickshell/caelestia/modules/bar/popouts/Audio.qml new file mode 100644 index 0000000..58b29ba --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/Audio.qml @@ -0,0 +1,120 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.services +import qs.config +import Quickshell +import Quickshell.Services.Pipewire +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import "../../controlcenter/network" + +Item { + id: root + + required property var wrapper + + implicitWidth: layout.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: layout.implicitHeight + Appearance.padding.normal * 2 + + ButtonGroup { + id: sinks + } + + ButtonGroup { + id: sources + } + + ColumnLayout { + id: layout + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + spacing: Appearance.spacing.normal + + StyledText { + text: qsTr("Output device") + font.weight: 500 + } + + Repeater { + model: Audio.sinks + + StyledRadioButton { + id: control + + required property PwNode modelData + + ButtonGroup.group: sinks + checked: Audio.sink?.id === modelData.id + onClicked: Audio.setAudioSink(modelData) + text: modelData.description + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.smaller + text: qsTr("Input device") + font.weight: 500 + } + + Repeater { + model: Audio.sources + + StyledRadioButton { + required property PwNode modelData + + ButtonGroup.group: sources + checked: Audio.source?.id === modelData.id + onClicked: Audio.setAudioSource(modelData) + text: modelData.description + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.smaller + Layout.bottomMargin: -Appearance.spacing.small / 2 + text: qsTr("Volume (%1)").arg(Audio.muted ? qsTr("Muted") : `${Math.round(Audio.volume * 100)}%`) + font.weight: 500 + } + + CustomMouseArea { + Layout.fillWidth: true + implicitHeight: Appearance.padding.normal * 3 + + onWheel: event => { + if (event.angleDelta.y > 0) + Audio.incrementVolume(); + else if (event.angleDelta.y < 0) + Audio.decrementVolume(); + } + + StyledSlider { + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: parent.implicitHeight + + value: Audio.volume + onMoved: Audio.setVolume(value) + + Behavior on value { + Anim {} + } + } + } + + IconTextButton { + Layout.fillWidth: true + Layout.topMargin: Appearance.spacing.normal + inactiveColour: Colours.palette.m3primaryContainer + inactiveOnColour: Colours.palette.m3onPrimaryContainer + verticalPadding: Appearance.padding.small + text: qsTr("Open settings") + icon: "settings" + + onClicked: root.wrapper.detach("audio") + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/Background.qml b/.config/quickshell/caelestia/modules/bar/popouts/Background.qml new file mode 100644 index 0000000..075b698 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/Background.qml @@ -0,0 +1,73 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + required property bool invertBottomRounding + readonly property real rounding: wrapper.isDetached ? Appearance.rounding.normal : Config.border.rounding + readonly property bool flatten: wrapper.width < rounding * 2 + readonly property real roundingX: flatten ? wrapper.width / 2 : rounding + property real ibr: invertBottomRounding ? -1 : 1 + + property real sideRounding: startX > 0 ? -1 : 1 + + strokeWidth: -1 + fillColor: Colours.palette.m3surface + + PathArc { + relativeX: root.roundingX + relativeY: root.rounding * root.sideRounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + direction: root.sideRounding < 0 ? PathArc.Clockwise : PathArc.Counterclockwise + } + PathLine { + relativeX: root.wrapper.width - root.roundingX * 2 + relativeY: 0 + } + PathArc { + relativeX: root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + } + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.rounding * 2 + } + PathArc { + relativeX: -root.roundingX * root.ibr + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + direction: root.ibr < 0 ? PathArc.Counterclockwise : PathArc.Clockwise + } + PathLine { + relativeX: -(root.wrapper.width - root.roundingX - root.roundingX * root.ibr) + relativeY: 0 + } + PathArc { + relativeX: -root.roundingX + relativeY: root.rounding * root.sideRounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + direction: root.sideRounding < 0 ? PathArc.Clockwise : PathArc.Counterclockwise + } + + Behavior on fillColor { + CAnim {} + } + + Behavior on ibr { + Anim {} + } + + Behavior on sideRounding { + Anim {} + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/Battery.qml b/.config/quickshell/caelestia/modules/bar/popouts/Battery.qml new file mode 100644 index 0000000..ac975e1 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/Battery.qml @@ -0,0 +1,230 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Quickshell.Services.UPower +import QtQuick + +Column { + id: root + + spacing: Appearance.spacing.normal + width: Config.bar.sizes.batteryWidth + + StyledText { + text: UPower.displayDevice.isLaptopBattery ? qsTr("Remaining: %1%").arg(Math.round(UPower.displayDevice.percentage * 100)) : qsTr("No battery detected") + } + + StyledText { + function formatSeconds(s: int, fallback: string): string { + const day = Math.floor(s / 86400); + const hr = Math.floor(s / 3600) % 60; + const min = Math.floor(s / 60) % 60; + + let comps = []; + if (day > 0) + comps.push(`${day} days`); + if (hr > 0) + comps.push(`${hr} hours`); + if (min > 0) + comps.push(`${min} mins`); + + return comps.join(", ") || fallback; + } + + text: UPower.displayDevice.isLaptopBattery ? qsTr("Time %1: %2").arg(UPower.onBattery ? "remaining" : "until charged").arg(UPower.onBattery ? formatSeconds(UPower.displayDevice.timeToEmpty, "Calculating...") : formatSeconds(UPower.displayDevice.timeToFull, "Fully charged!")) : qsTr("Power profile: %1").arg(PowerProfile.toString(PowerProfiles.profile)) + } + + Loader { + anchors.horizontalCenter: parent.horizontalCenter + + active: PowerProfiles.degradationReason !== PerformanceDegradationReason.None + + height: active ? (item?.implicitHeight ?? 0) : 0 + + sourceComponent: StyledRect { + implicitWidth: child.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: child.implicitHeight + Appearance.padding.smaller * 2 + + color: Colours.palette.m3error + radius: Appearance.rounding.normal + + Column { + id: child + + anchors.centerIn: parent + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: Appearance.spacing.small + + MaterialIcon { + anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: -font.pointSize / 10 + + text: "warning" + color: Colours.palette.m3onError + } + + StyledText { + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Performance Degraded") + color: Colours.palette.m3onError + font.family: Appearance.font.family.mono + font.weight: 500 + } + + MaterialIcon { + anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: -font.pointSize / 10 + + text: "warning" + color: Colours.palette.m3onError + } + } + + StyledText { + anchors.horizontalCenter: parent.horizontalCenter + + text: qsTr("Reason: %1").arg(PerformanceDegradationReason.toString(PowerProfiles.degradationReason)) + color: Colours.palette.m3onError + } + } + } + } + + StyledRect { + id: profiles + + property string current: { + const p = PowerProfiles.profile; + if (p === PowerProfile.PowerSaver) + return saver.icon; + if (p === PowerProfile.Performance) + return perf.icon; + return balance.icon; + } + + anchors.horizontalCenter: parent.horizontalCenter + + implicitWidth: saver.implicitHeight + balance.implicitHeight + perf.implicitHeight + Appearance.padding.normal * 2 + Appearance.spacing.large * 2 + implicitHeight: Math.max(saver.implicitHeight, balance.implicitHeight, perf.implicitHeight) + Appearance.padding.small * 2 + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.full + + StyledRect { + id: indicator + + color: Colours.palette.m3primary + radius: Appearance.rounding.full + state: profiles.current + + states: [ + State { + name: saver.icon + + Fill { + item: saver + } + }, + State { + name: balance.icon + + Fill { + item: balance + } + }, + State { + name: perf.icon + + Fill { + item: perf + } + } + ] + + transitions: Transition { + AnchorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + } + + Profile { + id: saver + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Appearance.padding.small + + profile: PowerProfile.PowerSaver + icon: "energy_savings_leaf" + } + + Profile { + id: balance + + anchors.centerIn: parent + + profile: PowerProfile.Balanced + icon: "balance" + } + + Profile { + id: perf + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: Appearance.padding.small + + profile: PowerProfile.Performance + icon: "rocket_launch" + } + } + + component Fill: AnchorChanges { + required property Item item + + target: indicator + anchors.left: item.left + anchors.right: item.right + anchors.top: item.top + anchors.bottom: item.bottom + } + + component Profile: Item { + required property string icon + required property int profile + + implicitWidth: icon.implicitHeight + Appearance.padding.small * 2 + implicitHeight: icon.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + radius: Appearance.rounding.full + color: profiles.current === parent.icon ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + + function onClicked(): void { + PowerProfiles.profile = parent.profile; + } + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + + text: parent.icon + font.pointSize: Appearance.font.size.large + color: profiles.current === text ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + fill: profiles.current === text ? 1 : 0 + + Behavior on fill { + Anim {} + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/Bluetooth.qml b/.config/quickshell/caelestia/modules/bar/popouts/Bluetooth.qml new file mode 100644 index 0000000..676da82 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/Bluetooth.qml @@ -0,0 +1,197 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.services +import qs.config +import qs.utils +import Quickshell +import Quickshell.Bluetooth +import QtQuick +import QtQuick.Layouts +import "../../controlcenter/network" + +ColumnLayout { + id: root + + required property Item wrapper + + spacing: Appearance.spacing.small + + StyledText { + Layout.topMargin: Appearance.padding.normal + Layout.rightMargin: Appearance.padding.small + text: qsTr("Bluetooth") + font.weight: 500 + } + + Toggle { + label: qsTr("Enabled") + checked: Bluetooth.defaultAdapter?.enabled ?? false + toggle.onToggled: { + const adapter = Bluetooth.defaultAdapter; + if (adapter) + adapter.enabled = checked; + } + } + + Toggle { + label: qsTr("Discovering") + checked: Bluetooth.defaultAdapter?.discovering ?? false + toggle.onToggled: { + const adapter = Bluetooth.defaultAdapter; + if (adapter) + adapter.discovering = checked; + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.small + Layout.rightMargin: Appearance.padding.small + text: { + const devices = Bluetooth.devices.values; + let available = qsTr("%1 device%2 available").arg(devices.length).arg(devices.length === 1 ? "" : "s"); + const connected = devices.filter(d => d.connected).length; + if (connected > 0) + available += qsTr(" (%1 connected)").arg(connected); + return available; + } + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + } + + Repeater { + model: ScriptModel { + values: [...Bluetooth.devices.values].sort((a, b) => (b.connected - a.connected) || (b.paired - a.paired) || a.name.localeCompare(b.name)).slice(0, 5) + } + + RowLayout { + id: device + + required property BluetoothDevice modelData + readonly property bool loading: modelData.state === BluetoothDeviceState.Connecting || modelData.state === BluetoothDeviceState.Disconnecting + + Layout.fillWidth: true + Layout.rightMargin: Appearance.padding.small + spacing: Appearance.spacing.small + + opacity: 0 + scale: 0.7 + + Component.onCompleted: { + opacity = 1; + scale = 1; + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + MaterialIcon { + text: Icons.getBluetoothIcon(device.modelData.icon) + } + + StyledText { + Layout.leftMargin: Appearance.spacing.small / 2 + Layout.rightMargin: Appearance.spacing.small / 2 + Layout.fillWidth: true + text: device.modelData.name + } + + StyledRect { + id: connectBtn + + implicitWidth: implicitHeight + implicitHeight: connectIcon.implicitHeight + Appearance.padding.small + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3primary, device.modelData.state === BluetoothDeviceState.Connected ? 1 : 0) + + CircularIndicator { + anchors.fill: parent + running: device.loading + } + + StateLayer { + color: device.modelData.state === BluetoothDeviceState.Connected ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + disabled: device.loading + + function onClicked(): void { + device.modelData.connected = !device.modelData.connected; + } + } + + MaterialIcon { + id: connectIcon + + anchors.centerIn: parent + animate: true + text: device.modelData.connected ? "link_off" : "link" + color: device.modelData.state === BluetoothDeviceState.Connected ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + + opacity: device.loading ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + } + + Loader { + active: device.modelData.bonded + sourceComponent: Item { + implicitWidth: connectBtn.implicitWidth + implicitHeight: connectBtn.implicitHeight + + StateLayer { + radius: Appearance.rounding.full + + function onClicked(): void { + device.modelData.forget(); + } + } + + MaterialIcon { + anchors.centerIn: parent + text: "delete" + } + } + } + } + } + + IconTextButton { + Layout.fillWidth: true + Layout.topMargin: Appearance.spacing.normal + inactiveColour: Colours.palette.m3primaryContainer + inactiveOnColour: Colours.palette.m3onPrimaryContainer + verticalPadding: Appearance.padding.small + text: qsTr("Open settings") + icon: "settings" + + onClicked: root.wrapper.detach("bluetooth") + } + + component Toggle: RowLayout { + required property string label + property alias checked: toggle.checked + property alias toggle: toggle + + Layout.fillWidth: true + Layout.rightMargin: Appearance.padding.small + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: parent.label + } + + StyledSwitch { + id: toggle + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/Content.qml b/.config/quickshell/caelestia/modules/bar/popouts/Content.qml new file mode 100644 index 0000000..6543e58 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/Content.qml @@ -0,0 +1,222 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.config +import Quickshell +import Quickshell.Services.SystemTray +import QtQuick + +import "./kblayout" + +Item { + id: root + + required property Item wrapper + readonly property Popout currentPopout: content.children.find(c => c.shouldBeActive) ?? null + readonly property Item current: currentPopout?.item ?? null + + anchors.centerIn: parent + + implicitWidth: (currentPopout?.implicitWidth ?? 0) + Appearance.padding.large * 2 + implicitHeight: (currentPopout?.implicitHeight ?? 0) + Appearance.padding.large * 2 + + Item { + id: content + + anchors.fill: parent + anchors.margins: Appearance.padding.large + + Popout { + name: "activewindow" + sourceComponent: ActiveWindow { + wrapper: root.wrapper + } + } + + Popout { + id: networkPopout + name: "network" + sourceComponent: Network { + wrapper: root.wrapper + view: "wireless" + } + } + + Popout { + name: "ethernet" + sourceComponent: Network { + wrapper: root.wrapper + view: "ethernet" + } + } + + Popout { + id: passwordPopout + name: "wirelesspassword" + sourceComponent: WirelessPassword { + id: passwordComponent + wrapper: root.wrapper + network: networkPopout.item?.passwordNetwork ?? null + } + + Connections { + target: root.wrapper + function onCurrentNameChanged() { + // Update network immediately when password popout becomes active + if (root.wrapper.currentName === "wirelesspassword") { + // Set network immediately if available + if (networkPopout.item && networkPopout.item.passwordNetwork) { + if (passwordPopout.item) { + passwordPopout.item.network = networkPopout.item.passwordNetwork; + } + } + // Also try after a short delay in case networkPopout.item wasn't ready + Qt.callLater(() => { + if (passwordPopout.item && networkPopout.item && networkPopout.item.passwordNetwork) { + passwordPopout.item.network = networkPopout.item.passwordNetwork; + } + }, 100); + } + } + } + + Connections { + target: networkPopout + function onItemChanged() { + // When network popout loads, update password popout if it's active + if (root.wrapper.currentName === "wirelesspassword" && passwordPopout.item) { + Qt.callLater(() => { + if (networkPopout.item && networkPopout.item.passwordNetwork) { + passwordPopout.item.network = networkPopout.item.passwordNetwork; + } + }); + } + } + } + } + + Popout { + name: "bluetooth" + sourceComponent: Bluetooth { + wrapper: root.wrapper + } + } + + Popout { + name: "battery" + sourceComponent: Battery {} + } + + Popout { + name: "audio" + sourceComponent: Audio { + wrapper: root.wrapper + } + } + + Popout { + name: "kblayout" + sourceComponent: KbLayout { + wrapper: root.wrapper + } + } + + Popout { + name: "lockstatus" + sourceComponent: LockStatus {} + } + + Repeater { + model: ScriptModel { + values: SystemTray.items.values.filter(i => !Config.bar.tray.hiddenIcons.includes(i.id)) + } + + Popout { + id: trayMenu + + required property SystemTrayItem modelData + required property int index + + name: `traymenu${index}` + sourceComponent: trayMenuComp + + Connections { + target: root.wrapper + + function onHasCurrentChanged(): void { + if (root.wrapper.hasCurrent && trayMenu.shouldBeActive) { + trayMenu.sourceComponent = null; + trayMenu.sourceComponent = trayMenuComp; + } + } + } + + Component { + id: trayMenuComp + + TrayMenu { + popouts: root.wrapper + trayItem: trayMenu.modelData.menu + } + } + } + } + } + + component Popout: Loader { + id: popout + + required property string name + readonly property bool shouldBeActive: root.wrapper.currentName === name + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + + opacity: 0 + scale: 0.8 + active: false + + states: State { + name: "active" + when: popout.shouldBeActive + + PropertyChanges { + popout.active: true + popout.opacity: 1 + popout.scale: 1 + } + } + + transitions: [ + Transition { + from: "active" + to: "" + + SequentialAnimation { + Anim { + properties: "opacity,scale" + duration: Appearance.anim.durations.small + } + PropertyAction { + target: popout + property: "active" + } + } + }, + Transition { + from: "" + to: "active" + + SequentialAnimation { + PropertyAction { + target: popout + property: "active" + } + Anim { + properties: "opacity,scale" + } + } + } + ] + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/LockStatus.qml b/.config/quickshell/caelestia/modules/bar/popouts/LockStatus.qml new file mode 100644 index 0000000..7d74530 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/LockStatus.qml @@ -0,0 +1,16 @@ +import qs.components +import qs.services +import qs.config +import QtQuick.Layouts + +ColumnLayout { + spacing: Appearance.spacing.small + + StyledText { + text: qsTr("Capslock: %1").arg(Hypr.capsLock ? "Enabled" : "Disabled") + } + + StyledText { + text: qsTr("Numlock: %1").arg(Hypr.numLock ? "Enabled" : "Disabled") + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/Network.qml b/.config/quickshell/caelestia/modules/bar/popouts/Network.qml new file mode 100644 index 0000000..5b32e4a --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/Network.qml @@ -0,0 +1,388 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.services +import qs.config +import qs.utils +import Quickshell +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property Item wrapper + + property string connectingToSsid: "" + property string view: "wireless" // "wireless" or "ethernet" + property var passwordNetwork: null + property bool showPasswordDialog: false + + spacing: Appearance.spacing.small + width: Config.bar.sizes.networkWidth + + // Wireless section + StyledText { + visible: root.view === "wireless" + Layout.preferredHeight: visible ? implicitHeight : 0 + Layout.topMargin: visible ? Appearance.padding.normal : 0 + Layout.rightMargin: Appearance.padding.small + text: qsTr("Wireless") + font.weight: 500 + } + + Toggle { + visible: root.view === "wireless" + Layout.preferredHeight: visible ? implicitHeight : 0 + label: qsTr("Enabled") + checked: Nmcli.wifiEnabled + toggle.onToggled: Nmcli.enableWifi(checked) + } + + StyledText { + visible: root.view === "wireless" + Layout.preferredHeight: visible ? implicitHeight : 0 + Layout.topMargin: visible ? Appearance.spacing.small : 0 + Layout.rightMargin: Appearance.padding.small + text: qsTr("%1 networks available").arg(Nmcli.networks.length) + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + } + + Repeater { + visible: root.view === "wireless" + model: ScriptModel { + values: [...Nmcli.networks].sort((a, b) => { + if (a.active !== b.active) + return b.active - a.active; + return b.strength - a.strength; + }).slice(0, 8) + } + + RowLayout { + id: networkItem + + required property Nmcli.AccessPoint modelData + readonly property bool isConnecting: root.connectingToSsid === modelData.ssid + readonly property bool loading: networkItem.isConnecting + + visible: root.view === "wireless" + Layout.preferredHeight: visible ? implicitHeight : 0 + Layout.fillWidth: true + Layout.rightMargin: Appearance.padding.small + spacing: Appearance.spacing.small + + opacity: 0 + scale: 0.7 + + Component.onCompleted: { + opacity = 1; + scale = 1; + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + MaterialIcon { + text: Icons.getNetworkIcon(networkItem.modelData.strength) + color: networkItem.modelData.active ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant + } + + MaterialIcon { + visible: networkItem.modelData.isSecure + text: "lock" + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.leftMargin: Appearance.spacing.small / 2 + Layout.rightMargin: Appearance.spacing.small / 2 + Layout.fillWidth: true + text: networkItem.modelData.ssid + elide: Text.ElideRight + font.weight: networkItem.modelData.active ? 500 : 400 + color: networkItem.modelData.active ? Colours.palette.m3primary : Colours.palette.m3onSurface + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: wirelessConnectIcon.implicitHeight + Appearance.padding.small + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3primary, networkItem.modelData.active ? 1 : 0) + + CircularIndicator { + anchors.fill: parent + running: networkItem.loading + } + + StateLayer { + color: networkItem.modelData.active ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + disabled: networkItem.loading || !Nmcli.wifiEnabled + + function onClicked(): void { + if (networkItem.modelData.active) { + Nmcli.disconnectFromNetwork(); + } else { + root.connectingToSsid = networkItem.modelData.ssid; + NetworkConnection.handleConnect(networkItem.modelData, null, network => { + // Password is required - show password dialog + root.passwordNetwork = network; + root.showPasswordDialog = true; + root.wrapper.currentName = "wirelesspassword"; + }); + + // Clear connecting state if connection succeeds immediately (saved profile) + // This is handled by the onActiveChanged connection below + } + } + } + + MaterialIcon { + id: wirelessConnectIcon + + anchors.centerIn: parent + animate: true + text: networkItem.modelData.active ? "link_off" : "link" + color: networkItem.modelData.active ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + + opacity: networkItem.loading ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + } + } + } + + StyledRect { + visible: root.view === "wireless" + Layout.preferredHeight: visible ? implicitHeight : 0 + Layout.topMargin: visible ? Appearance.spacing.small : 0 + Layout.fillWidth: true + implicitHeight: rescanBtn.implicitHeight + Appearance.padding.small * 2 + + radius: Appearance.rounding.full + color: Colours.palette.m3primaryContainer + + StateLayer { + color: Colours.palette.m3onPrimaryContainer + disabled: Nmcli.scanning || !Nmcli.wifiEnabled + + function onClicked(): void { + Nmcli.rescanWifi(); + } + } + + RowLayout { + id: rescanBtn + + anchors.centerIn: parent + spacing: Appearance.spacing.small + opacity: Nmcli.scanning ? 0 : 1 + + MaterialIcon { + id: scanIcon + + Layout.topMargin: Math.round(fontInfo.pointSize * 0.0575) + animate: true + text: "wifi_find" + color: Colours.palette.m3onPrimaryContainer + } + + StyledText { + Layout.topMargin: -Math.round(scanIcon.fontInfo.pointSize * 0.0575) + text: qsTr("Rescan networks") + color: Colours.palette.m3onPrimaryContainer + } + + Behavior on opacity { + Anim {} + } + } + + CircularIndicator { + anchors.centerIn: parent + strokeWidth: Appearance.padding.small / 2 + bgColour: "transparent" + implicitSize: parent.implicitHeight - Appearance.padding.smaller * 2 + running: Nmcli.scanning + } + } + + // Ethernet section + StyledText { + visible: root.view === "ethernet" + Layout.preferredHeight: visible ? implicitHeight : 0 + Layout.topMargin: visible ? Appearance.padding.normal : 0 + Layout.rightMargin: Appearance.padding.small + text: qsTr("Ethernet") + font.weight: 500 + } + + StyledText { + visible: root.view === "ethernet" + Layout.preferredHeight: visible ? implicitHeight : 0 + Layout.topMargin: visible ? Appearance.spacing.small : 0 + Layout.rightMargin: Appearance.padding.small + text: qsTr("%1 devices available").arg(Nmcli.ethernetDevices.length) + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + } + + Repeater { + visible: root.view === "ethernet" + model: ScriptModel { + values: [...Nmcli.ethernetDevices].sort((a, b) => { + if (a.connected !== b.connected) + return b.connected - a.connected; + return (a.interface || "").localeCompare(b.interface || ""); + }).slice(0, 8) + } + + RowLayout { + id: ethernetItem + + required property var modelData + readonly property bool loading: false + + visible: root.view === "ethernet" + Layout.preferredHeight: visible ? implicitHeight : 0 + Layout.fillWidth: true + Layout.rightMargin: Appearance.padding.small + spacing: Appearance.spacing.small + + opacity: 0 + scale: 0.7 + + Component.onCompleted: { + opacity = 1; + scale = 1; + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + MaterialIcon { + text: "cable" + color: ethernetItem.modelData.connected ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant + } + + StyledText { + Layout.leftMargin: Appearance.spacing.small / 2 + Layout.rightMargin: Appearance.spacing.small / 2 + Layout.fillWidth: true + text: ethernetItem.modelData.interface || qsTr("Unknown") + elide: Text.ElideRight + font.weight: ethernetItem.modelData.connected ? 500 : 400 + color: ethernetItem.modelData.connected ? Colours.palette.m3primary : Colours.palette.m3onSurface + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: connectIcon.implicitHeight + Appearance.padding.small + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3primary, ethernetItem.modelData.connected ? 1 : 0) + + CircularIndicator { + anchors.fill: parent + running: ethernetItem.loading + } + + StateLayer { + color: ethernetItem.modelData.connected ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + disabled: ethernetItem.loading + + function onClicked(): void { + if (ethernetItem.modelData.connected && ethernetItem.modelData.connection) { + Nmcli.disconnectEthernet(ethernetItem.modelData.connection, () => {}); + } else { + Nmcli.connectEthernet(ethernetItem.modelData.connection || "", ethernetItem.modelData.interface || "", () => {}); + } + } + } + + MaterialIcon { + id: connectIcon + + anchors.centerIn: parent + animate: true + text: ethernetItem.modelData.connected ? "link_off" : "link" + color: ethernetItem.modelData.connected ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + + opacity: ethernetItem.loading ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + } + } + } + + Connections { + target: Nmcli + + function onActiveChanged(): void { + if (Nmcli.active && root.connectingToSsid === Nmcli.active.ssid) { + root.connectingToSsid = ""; + // Close password dialog if we successfully connected + if (root.showPasswordDialog && root.passwordNetwork && Nmcli.active.ssid === root.passwordNetwork.ssid) { + root.showPasswordDialog = false; + root.passwordNetwork = null; + if (root.wrapper.currentName === "wirelesspassword") { + root.wrapper.currentName = "network"; + } + } + } + } + + function onScanningChanged(): void { + if (!Nmcli.scanning) + scanIcon.rotation = 0; + } + } + + Connections { + target: root.wrapper + function onCurrentNameChanged(): void { + // Clear password network when leaving password dialog + if (root.wrapper.currentName !== "wirelesspassword" && root.showPasswordDialog) { + root.showPasswordDialog = false; + root.passwordNetwork = null; + } + } + } + + component Toggle: RowLayout { + required property string label + property alias checked: toggle.checked + property alias toggle: toggle + + Layout.fillWidth: true + Layout.rightMargin: Appearance.padding.small + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: parent.label + } + + StyledSwitch { + id: toggle + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/TrayMenu.qml b/.config/quickshell/caelestia/modules/bar/popouts/TrayMenu.qml new file mode 100644 index 0000000..9b743db --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/TrayMenu.qml @@ -0,0 +1,225 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Controls + +StackView { + id: root + + required property Item popouts + required property QsMenuHandle trayItem + + implicitWidth: currentItem.implicitWidth + implicitHeight: currentItem.implicitHeight + + initialItem: SubMenu { + handle: root.trayItem + } + + pushEnter: NoAnim {} + pushExit: NoAnim {} + popEnter: NoAnim {} + popExit: NoAnim {} + + component NoAnim: Transition { + NumberAnimation { + duration: 0 + } + } + + component SubMenu: Column { + id: menu + + required property QsMenuHandle handle + property bool isSubMenu + property bool shown + + padding: Appearance.padding.smaller + spacing: Appearance.spacing.small + + opacity: shown ? 1 : 0 + scale: shown ? 1 : 0.8 + + Component.onCompleted: shown = true + StackView.onActivating: shown = true + StackView.onDeactivating: shown = false + StackView.onRemoved: destroy() + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + QsMenuOpener { + id: menuOpener + + menu: menu.handle + } + + Repeater { + model: menuOpener.children + + StyledRect { + id: item + + required property QsMenuEntry modelData + + implicitWidth: Config.bar.sizes.trayMenuWidth + implicitHeight: modelData.isSeparator ? 1 : children.implicitHeight + + radius: Appearance.rounding.full + color: modelData.isSeparator ? Colours.palette.m3outlineVariant : "transparent" + + Loader { + id: children + + anchors.left: parent.left + anchors.right: parent.right + + active: !item.modelData.isSeparator + + sourceComponent: Item { + implicitHeight: label.implicitHeight + + StateLayer { + anchors.margins: -Appearance.padding.small / 2 + anchors.leftMargin: -Appearance.padding.smaller + anchors.rightMargin: -Appearance.padding.smaller + + radius: item.radius + disabled: !item.modelData.enabled + + function onClicked(): void { + const entry = item.modelData; + if (entry.hasChildren) + root.push(subMenuComp.createObject(null, { + handle: entry, + isSubMenu: true + })); + else { + item.modelData.triggered(); + root.popouts.hasCurrent = false; + } + } + } + + Loader { + id: icon + + anchors.left: parent.left + + active: item.modelData.icon !== "" + + sourceComponent: IconImage { + implicitSize: label.implicitHeight + + source: item.modelData.icon + } + } + + StyledText { + id: label + + anchors.left: icon.right + anchors.leftMargin: icon.active ? Appearance.spacing.smaller : 0 + + text: labelMetrics.elidedText + color: item.modelData.enabled ? Colours.palette.m3onSurface : Colours.palette.m3outline + } + + TextMetrics { + id: labelMetrics + + text: item.modelData.text + font.pointSize: label.font.pointSize + font.family: label.font.family + + elide: Text.ElideRight + elideWidth: Config.bar.sizes.trayMenuWidth - (icon.active ? icon.implicitWidth + label.anchors.leftMargin : 0) - (expand.active ? expand.implicitWidth + Appearance.spacing.normal : 0) + } + + Loader { + id: expand + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + + active: item.modelData.hasChildren + + sourceComponent: MaterialIcon { + text: "chevron_right" + color: item.modelData.enabled ? Colours.palette.m3onSurface : Colours.palette.m3outline + } + } + } + } + } + } + + Loader { + active: menu.isSubMenu + + sourceComponent: Item { + implicitWidth: back.implicitWidth + implicitHeight: back.implicitHeight + Appearance.spacing.small / 2 + + Item { + anchors.bottom: parent.bottom + implicitWidth: back.implicitWidth + implicitHeight: back.implicitHeight + + StyledRect { + anchors.fill: parent + anchors.margins: -Appearance.padding.small / 2 + anchors.leftMargin: -Appearance.padding.smaller + anchors.rightMargin: -Appearance.padding.smaller * 2 + + radius: Appearance.rounding.full + color: Colours.palette.m3secondaryContainer + + StateLayer { + radius: parent.radius + color: Colours.palette.m3onSecondaryContainer + + function onClicked(): void { + root.pop(); + } + } + } + + Row { + id: back + + anchors.verticalCenter: parent.verticalCenter + + MaterialIcon { + anchors.verticalCenter: parent.verticalCenter + text: "chevron_left" + color: Colours.palette.m3onSecondaryContainer + } + + StyledText { + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Back") + color: Colours.palette.m3onSecondaryContainer + } + } + } + } + } + } + + Component { + id: subMenuComp + + SubMenu {} + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/WirelessPassword.qml b/.config/quickshell/caelestia/modules/bar/popouts/WirelessPassword.qml new file mode 100644 index 0000000..96639e7 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/WirelessPassword.qml @@ -0,0 +1,605 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.services +import qs.config +import qs.utils +import Quickshell +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property Item wrapper + property var network: null + property bool isClosing: false + + readonly property bool shouldBeVisible: root.wrapper.currentName === "wirelesspassword" + + Connections { + target: root.wrapper + function onCurrentNameChanged() { + if (root.wrapper.currentName === "wirelesspassword") { + // Update network when popout becomes active + Qt.callLater(() => { + // Try to get network from parent Content's networkPopout + const content = root.parent?.parent?.parent; + if (content) { + const networkPopout = content.children.find(c => c.name === "network"); + if (networkPopout && networkPopout.item) { + root.network = networkPopout.item.passwordNetwork; + } + } + // Force focus to password container when popout becomes active + // Use Timer for actual delay to ensure dialog is fully rendered + focusTimer.start(); + }); + } + } + } + + Timer { + id: focusTimer + interval: 150 + onTriggered: { + root.forceActiveFocus(); + passwordContainer.forceActiveFocus(); + } + } + + spacing: Appearance.spacing.normal + + implicitWidth: 400 + implicitHeight: content.implicitHeight + Appearance.padding.large * 2 + + visible: shouldBeVisible || isClosing + enabled: shouldBeVisible && !isClosing + focus: enabled + + Component.onCompleted: { + if (shouldBeVisible) { + // Use Timer for actual delay to ensure dialog is fully rendered + focusTimer.start(); + } + } + + onShouldBeVisibleChanged: { + if (shouldBeVisible) { + // Use Timer for actual delay to ensure dialog is fully rendered + focusTimer.start(); + } + } + + Keys.onEscapePressed: closeDialog() + + StyledRect { + Layout.fillWidth: true + Layout.preferredWidth: 400 + implicitHeight: content.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + visible: root.shouldBeVisible || root.isClosing + opacity: root.shouldBeVisible && !root.isClosing ? 1 : 0 + scale: root.shouldBeVisible && !root.isClosing ? 1 : 0.7 + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + ParallelAnimation { + running: root.isClosing + onFinished: { + if (root.isClosing) { + root.isClosing = false; + } + } + + Anim { + target: parent + property: "opacity" + to: 0 + } + Anim { + target: parent + property: "scale" + to: 0.7 + } + } + + Keys.onEscapePressed: root.closeDialog() + + ColumnLayout { + id: content + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.normal + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: "lock" + font.pointSize: Appearance.font.size.extraLarge * 2 + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("Enter password") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + StyledText { + id: networkNameText + Layout.alignment: Qt.AlignHCenter + text: { + if (root.network) { + const ssid = root.network.ssid; + if (ssid && ssid.length > 0) { + return qsTr("Network: %1").arg(ssid); + } + } + return qsTr("Network: Unknown"); + } + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + Timer { + interval: 50 + running: root.shouldBeVisible && (!root.network || !root.network.ssid) + repeat: true + property int attempts: 0 + onTriggered: { + attempts++; + // Keep trying to get network from Network component + const content = root.parent?.parent?.parent; + if (content) { + const networkPopout = content.children.find(c => c.name === "network"); + if (networkPopout && networkPopout.item && networkPopout.item.passwordNetwork) { + root.network = networkPopout.item.passwordNetwork; + } + } + // Stop if we got it or after 20 attempts (1 second) + if ((root.network && root.network.ssid) || attempts >= 20) { + stop(); + attempts = 0; + } + } + onRunningChanged: { + if (!running) { + attempts = 0; + } + } + } + + StyledText { + id: statusText + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Appearance.spacing.small + visible: connectButton.connecting || connectButton.hasError + text: { + if (connectButton.hasError) { + return qsTr("Connection failed. Please check your password and try again."); + } + if (connectButton.connecting) { + return qsTr("Connecting..."); + } + return ""; + } + color: connectButton.hasError ? Colours.palette.m3error : Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + font.weight: 400 + wrapMode: Text.WordWrap + Layout.maximumWidth: parent.width - Appearance.padding.large * 2 + } + + FocusScope { + id: passwordContainer + objectName: "passwordContainer" + Layout.topMargin: Appearance.spacing.large + Layout.fillWidth: true + implicitHeight: Math.max(48, charList.implicitHeight + Appearance.padding.normal * 2) + + focus: true + activeFocusOnTab: true + + property string passwordBuffer: "" + + Keys.onPressed: event => { + // Ensure we have focus when receiving keyboard input + if (!activeFocus) { + forceActiveFocus(); + } + + // Clear error when user starts typing + if (connectButton.hasError && event.text && event.text.length > 0) { + connectButton.hasError = false; + } + + if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { + if (connectButton.enabled) { + connectButton.clicked(); + } + event.accepted = true; + } else if (event.key === Qt.Key_Backspace) { + if (event.modifiers & Qt.ControlModifier) { + passwordBuffer = ""; + } else { + passwordBuffer = passwordBuffer.slice(0, -1); + } + event.accepted = true; + } else if (event.text && event.text.length > 0) { + passwordBuffer += event.text; + event.accepted = true; + } + } + + Connections { + target: root + function onShouldBeVisibleChanged(): void { + if (root.shouldBeVisible) { + // Use Timer for actual delay to ensure focus works correctly + passwordFocusTimer.start(); + passwordContainer.passwordBuffer = ""; + connectButton.hasError = false; + } + } + } + + Timer { + id: passwordFocusTimer + interval: 50 + onTriggered: { + passwordContainer.forceActiveFocus(); + } + } + + Component.onCompleted: { + if (root.shouldBeVisible) { + // Use Timer for actual delay to ensure focus works correctly + passwordFocusTimer.start(); + } + } + + StyledRect { + anchors.fill: parent + radius: Appearance.rounding.normal + color: passwordContainer.activeFocus ? Qt.lighter(Colours.tPalette.m3surfaceContainer, 1.05) : Colours.tPalette.m3surfaceContainer + border.width: passwordContainer.activeFocus || connectButton.hasError ? 4 : (root.shouldBeVisible ? 1 : 0) + border.color: { + if (connectButton.hasError) { + return Colours.palette.m3error; + } + if (passwordContainer.activeFocus) { + return Colours.palette.m3primary; + } + return root.shouldBeVisible ? Colours.palette.m3outline : "transparent"; + } + + Behavior on border.color { + CAnim {} + } + + Behavior on border.width { + CAnim {} + } + + Behavior on color { + CAnim {} + } + } + + StateLayer { + hoverEnabled: false + cursorShape: Qt.IBeamCursor + radius: Appearance.rounding.normal + + function onClicked(): void { + passwordContainer.forceActiveFocus(); + } + } + + StyledText { + id: placeholder + + anchors.centerIn: parent + text: qsTr("Password") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.normal + font.family: Appearance.font.family.mono + opacity: passwordContainer.passwordBuffer ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + + ListView { + id: charList + + readonly property int fullWidth: count * (implicitHeight + spacing) - spacing + + anchors.centerIn: parent + implicitWidth: fullWidth + implicitHeight: Appearance.font.size.normal + + orientation: Qt.Horizontal + spacing: Appearance.spacing.small / 2 + interactive: false + + model: ScriptModel { + values: passwordContainer.passwordBuffer.split("") + } + + delegate: StyledRect { + id: ch + + implicitWidth: implicitHeight + implicitHeight: charList.implicitHeight + + color: Colours.palette.m3onSurface + radius: Appearance.rounding.small / 2 + + opacity: 0 + scale: 0 + Component.onCompleted: { + opacity = 1; + scale = 1; + } + ListView.onRemove: removeAnim.start() + + SequentialAnimation { + id: removeAnim + + PropertyAction { + target: ch + property: "ListView.delayRemove" + value: true + } + ParallelAnimation { + Anim { + target: ch + property: "opacity" + to: 0 + } + Anim { + target: ch + property: "scale" + to: 0.5 + } + } + PropertyAction { + target: ch + property: "ListView.delayRemove" + value: false + } + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } + + Behavior on implicitWidth { + Anim {} + } + } + } + + RowLayout { + Layout.topMargin: Appearance.spacing.normal + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + TextButton { + id: cancelButton + + Layout.fillWidth: true + Layout.minimumHeight: Appearance.font.size.normal + Appearance.padding.normal * 2 + inactiveColour: Colours.palette.m3secondaryContainer + inactiveOnColour: Colours.palette.m3onSecondaryContainer + text: qsTr("Cancel") + + onClicked: root.closeDialog() + } + + TextButton { + id: connectButton + + property bool connecting: false + property bool hasError: false + + Layout.fillWidth: true + Layout.minimumHeight: Appearance.font.size.normal + Appearance.padding.normal * 2 + inactiveColour: Colours.palette.m3primary + inactiveOnColour: Colours.palette.m3onPrimary + text: qsTr("Connect") + enabled: passwordContainer.passwordBuffer.length > 0 && !connecting + + onClicked: { + if (!root.network || connecting) { + return; + } + + const password = passwordContainer.passwordBuffer; + if (!password || password.length === 0) { + return; + } + + // Clear any previous error + hasError = false; + + // Set connecting state + connecting = true; + enabled = false; + text = qsTr("Connecting..."); + + // Connect to network + NetworkConnection.connectWithPassword(root.network, password, result => { + if (result && result.success) + // Connection successful, monitor will handle the rest + {} else if (result && result.needsPassword) { + // Shouldn't happen since we provided password + connectionMonitor.stop(); + connecting = false; + hasError = true; + enabled = true; + text = qsTr("Connect"); + passwordContainer.passwordBuffer = ""; + // Delete the failed connection + if (root.network && root.network.ssid) { + Nmcli.forgetNetwork(root.network.ssid); + } + } else { + // Connection failed immediately - show error + connectionMonitor.stop(); + connecting = false; + hasError = true; + enabled = true; + text = qsTr("Connect"); + passwordContainer.passwordBuffer = ""; + // Delete the failed connection + if (root.network && root.network.ssid) { + Nmcli.forgetNetwork(root.network.ssid); + } + } + }); + + // Start monitoring connection + connectionMonitor.start(); + } + } + } + } + } + + function checkConnectionStatus(): void { + if (!root.shouldBeVisible || !connectButton.connecting) { + return; + } + + // Check if we're connected to the target network (case-insensitive SSID comparison) + const isConnected = root.network && Nmcli.active && Nmcli.active.ssid && Nmcli.active.ssid.toLowerCase().trim() === root.network.ssid.toLowerCase().trim(); + + if (isConnected) { + // Successfully connected - give it a moment for network list to update + // Use Timer for actual delay + connectionSuccessTimer.start(); + return; + } + + // Check for connection failures - if pending connection was cleared but we're not connected + if (Nmcli.pendingConnection === null && connectButton.connecting) { + // Wait a bit more before giving up (allow time for connection to establish) + if (connectionMonitor.repeatCount > 10) { + connectionMonitor.stop(); + connectButton.connecting = false; + connectButton.hasError = true; + connectButton.enabled = true; + connectButton.text = qsTr("Connect"); + passwordContainer.passwordBuffer = ""; + // Delete the failed connection + if (root.network && root.network.ssid) { + Nmcli.forgetNetwork(root.network.ssid); + } + } + } + } + + Timer { + id: connectionMonitor + interval: 1000 + repeat: true + triggeredOnStart: false + property int repeatCount: 0 + + onTriggered: { + repeatCount++; + root.checkConnectionStatus(); + } + + onRunningChanged: { + if (!running) { + repeatCount = 0; + } + } + } + + Timer { + id: connectionSuccessTimer + interval: 500 + onTriggered: { + // Double-check connection is still active + if (root.shouldBeVisible && Nmcli.active && Nmcli.active.ssid) { + const stillConnected = Nmcli.active.ssid.toLowerCase().trim() === root.network.ssid.toLowerCase().trim(); + if (stillConnected) { + connectionMonitor.stop(); + connectButton.connecting = false; + connectButton.text = qsTr("Connect"); + // Return to network popout on successful connection + if (root.wrapper.currentName === "wirelesspassword") { + root.wrapper.currentName = "network"; + } + closeDialog(); + } + } + } + } + + Connections { + target: Nmcli + function onActiveChanged() { + if (root.shouldBeVisible) { + root.checkConnectionStatus(); + } + } + function onConnectionFailed(ssid: string) { + if (root.shouldBeVisible && root.network && root.network.ssid === ssid && connectButton.connecting) { + connectionMonitor.stop(); + connectButton.connecting = false; + connectButton.hasError = true; + connectButton.enabled = true; + connectButton.text = qsTr("Connect"); + passwordContainer.passwordBuffer = ""; + // Delete the failed connection + Nmcli.forgetNetwork(ssid); + } + } + } + + function closeDialog(): void { + if (isClosing) { + return; + } + + isClosing = true; + passwordContainer.passwordBuffer = ""; + connectButton.connecting = false; + connectButton.hasError = false; + connectButton.text = qsTr("Connect"); + connectionMonitor.stop(); + + // Return to network popout + if (root.wrapper.currentName === "wirelesspassword") { + root.wrapper.currentName = "network"; + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/Wrapper.qml b/.config/quickshell/caelestia/modules/bar/popouts/Wrapper.qml new file mode 100644 index 0000000..05a1d3c --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/Wrapper.qml @@ -0,0 +1,215 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import qs.modules.windowinfo +import qs.modules.controlcenter +import Quickshell +import Quickshell.Wayland +import Quickshell.Hyprland +import QtQuick + +Item { + id: root + + required property ShellScreen screen + + readonly property real nonAnimWidth: x > 0 || hasCurrent ? children.find(c => c.shouldBeActive)?.implicitWidth ?? content.implicitWidth : 0 + readonly property real nonAnimHeight: children.find(c => c.shouldBeActive)?.implicitHeight ?? content.implicitHeight + readonly property Item current: content.item?.current ?? null + + property string currentName + property real currentCenter + property bool hasCurrent + + property string detachedMode + property string queuedMode + readonly property bool isDetached: detachedMode.length > 0 + + property int animLength: Appearance.anim.durations.normal + property list animCurve: Appearance.anim.curves.emphasized + + function detach(mode: string): void { + animLength = Appearance.anim.durations.large; + if (mode === "winfo") { + detachedMode = mode; + } else { + queuedMode = mode; + detachedMode = "any"; + } + focus = true; + } + + function close(): void { + hasCurrent = false; + animCurve = Appearance.anim.curves.emphasizedAccel; + animLength = Appearance.anim.durations.normal; + detachedMode = ""; + animCurve = Appearance.anim.curves.emphasized; + } + + visible: width > 0 && height > 0 + clip: true + + implicitWidth: nonAnimWidth + implicitHeight: nonAnimHeight + + focus: hasCurrent + Keys.onEscapePressed: { + // Forward escape to password popout if active, otherwise close + if (currentName === "wirelesspassword" && content.item) { + const passwordPopout = content.item.children.find(c => c.name === "wirelesspassword"); + if (passwordPopout && passwordPopout.item) { + passwordPopout.item.closeDialog(); + return; + } + } + close(); + } + + Keys.onPressed: event => { + // Don't intercept keys when password popout is active - let it handle them + if (currentName === "wirelesspassword") { + event.accepted = false; + } + } + + HyprlandFocusGrab { + active: root.isDetached + windows: [QsWindow.window] + onCleared: root.close() + } + + Binding { + when: root.isDetached + + target: QsWindow.window + property: "WlrLayershell.keyboardFocus" + value: WlrKeyboardFocus.OnDemand + } + + Binding { + when: root.hasCurrent && root.currentName === "wirelesspassword" + + target: QsWindow.window + property: "WlrLayershell.keyboardFocus" + value: WlrKeyboardFocus.OnDemand + } + + Comp { + id: content + + shouldBeActive: root.hasCurrent && !root.detachedMode + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + sourceComponent: Content { + wrapper: root + } + } + + Comp { + shouldBeActive: root.detachedMode === "winfo" + anchors.centerIn: parent + + sourceComponent: WindowInfo { + screen: root.screen + client: Hypr.activeToplevel + } + } + + Comp { + shouldBeActive: root.detachedMode === "any" + anchors.centerIn: parent + + sourceComponent: ControlCenter { + screen: root.screen + active: root.queuedMode + + function close(): void { + root.close(); + } + } + } + + Behavior on x { + Anim { + duration: root.animLength + easing.bezierCurve: root.animCurve + } + } + + Behavior on y { + enabled: root.implicitWidth > 0 + + Anim { + duration: root.animLength + easing.bezierCurve: root.animCurve + } + } + + Behavior on implicitWidth { + Anim { + duration: root.animLength + easing.bezierCurve: root.animCurve + } + } + + Behavior on implicitHeight { + enabled: root.implicitWidth > 0 + + Anim { + duration: root.animLength + easing.bezierCurve: root.animCurve + } + } + + component Comp: Loader { + id: comp + + property bool shouldBeActive + + active: false + opacity: 0 + + states: State { + name: "active" + when: comp.shouldBeActive + + PropertyChanges { + comp.opacity: 1 + comp.active: true + } + } + + transitions: [ + Transition { + from: "" + to: "active" + + SequentialAnimation { + PropertyAction { + property: "active" + } + Anim { + property: "opacity" + } + } + }, + Transition { + from: "active" + to: "" + + SequentialAnimation { + Anim { + property: "opacity" + } + PropertyAction { + property: "active" + } + } + } + ] + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/kblayout/KbLayout.qml b/.config/quickshell/caelestia/modules/bar/popouts/kblayout/KbLayout.qml new file mode 100644 index 0000000..94b6f7e --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/kblayout/KbLayout.qml @@ -0,0 +1,211 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.components +import qs.components.controls +import qs.services +import qs.config +import qs.utils + +import "." + +ColumnLayout { + id: root + + required property Item wrapper + + spacing: Appearance.spacing.small + width: Config.bar.sizes.kbLayoutWidth + + KbLayoutModel { + id: kb + } + + function refresh() { + kb.refresh(); + } + Component.onCompleted: kb.start() + + StyledText { + Layout.topMargin: Appearance.padding.normal + Layout.rightMargin: Appearance.padding.small + text: qsTr("Keyboard Layouts") + font.weight: 500 + } + + ListView { + id: list + model: kb.visibleModel + + Layout.fillWidth: true + Layout.rightMargin: Appearance.padding.small + Layout.topMargin: Appearance.spacing.small + + clip: true + interactive: true + implicitHeight: Math.min(contentHeight, 320) + visible: kb.visibleModel.count > 0 + spacing: Appearance.spacing.small + + add: Transition { + NumberAnimation { + properties: "opacity" + from: 0 + to: 1 + duration: 140 + } + NumberAnimation { + properties: "y" + duration: 180 + easing.type: Easing.OutCubic + } + } + remove: Transition { + NumberAnimation { + properties: "opacity" + to: 0 + duration: 100 + } + } + move: Transition { + NumberAnimation { + properties: "y" + duration: 180 + easing.type: Easing.OutCubic + } + } + displaced: Transition { + NumberAnimation { + properties: "y" + duration: 180 + easing.type: Easing.OutCubic + } + } + + delegate: Item { + required property int layoutIndex + required property string label + + width: list.width + height: Math.max(36, rowText.implicitHeight + Appearance.padding.small * 2) + + readonly property bool isDisabled: layoutIndex > 3 + + StateLayer { + id: layer + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + implicitHeight: parent.height - 4 + + radius: Appearance.rounding.full + enabled: !isDisabled + + function onClicked(): void { + if (!isDisabled) + kb.switchTo(layoutIndex); + } + } + + StyledText { + id: rowText + anchors.verticalCenter: layer.verticalCenter + anchors.left: layer.left + anchors.right: layer.right + anchors.leftMargin: Appearance.padding.small + anchors.rightMargin: Appearance.padding.small + text: label + elide: Text.ElideRight + opacity: isDisabled ? 0.4 : 1.0 + } + + ToolTip.visible: isDisabled && layer.containsMouse + ToolTip.text: "XKB limitation: maximum 4 layouts allowed" + } + } + + Rectangle { + visible: kb.activeLabel.length > 0 + Layout.fillWidth: true + Layout.rightMargin: Appearance.padding.small + Layout.topMargin: Appearance.spacing.small + + height: 1 + color: Colours.palette.m3onSurfaceVariant + opacity: 0.35 + } + + RowLayout { + id: activeRow + + visible: kb.activeLabel.length > 0 + Layout.fillWidth: true + Layout.rightMargin: Appearance.padding.small + Layout.topMargin: Appearance.spacing.small + spacing: Appearance.spacing.small + + opacity: 1 + scale: 1 + + MaterialIcon { + text: "keyboard" + color: Colours.palette.m3primary + } + + StyledText { + Layout.fillWidth: true + text: kb.activeLabel + elide: Text.ElideRight + font.weight: 500 + color: Colours.palette.m3primary + } + + Connections { + target: kb + function onActiveLabelChanged() { + if (!activeRow.visible) + return; + popIn.restart(); + } + } + + SequentialAnimation { + id: popIn + running: false + + ParallelAnimation { + NumberAnimation { + target: activeRow + property: "opacity" + to: 0.0 + duration: 70 + } + NumberAnimation { + target: activeRow + property: "scale" + to: 0.92 + duration: 70 + } + } + + ParallelAnimation { + NumberAnimation { + target: activeRow + property: "opacity" + to: 1.0 + duration: 160 + easing.type: Easing.OutCubic + } + NumberAnimation { + target: activeRow + property: "scale" + to: 1.0 + duration: 220 + easing.type: Easing.OutBack + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/bar/popouts/kblayout/KbLayoutModel.qml b/.config/quickshell/caelestia/modules/bar/popouts/kblayout/KbLayoutModel.qml new file mode 100644 index 0000000..4371095 --- /dev/null +++ b/.config/quickshell/caelestia/modules/bar/popouts/kblayout/KbLayoutModel.qml @@ -0,0 +1,216 @@ +pragma ComponentBehavior: Bound + +import QtQuick + +import Quickshell +import Quickshell.Io + +import qs.config +import Caelestia + +Item { + id: model + visible: false + + ListModel { + id: _visibleModel + } + property alias visibleModel: _visibleModel + + property string activeLabel: "" + property int activeIndex: -1 + + function start() { + _xkbXmlBase.running = true; + _getKbLayoutOpt.running = true; + } + + function refresh() { + _notifiedLimit = false; + _getKbLayoutOpt.running = true; + } + + function switchTo(idx) { + _switchProc.command = ["hyprctl", "switchxkblayout", "all", String(idx)]; + _switchProc.running = true; + } + + ListModel { + id: _layoutsModel + } + + property var _xkbMap: ({}) + property bool _notifiedLimit: false + + Process { + id: _xkbXmlBase + command: ["xmllint", "--xpath", "//layout/configItem[name and description]", "/usr/share/X11/xkb/rules/base.xml"] + stdout: StdioCollector { + onStreamFinished: _buildXmlMap(text) + } + onRunningChanged: if (!running && (typeof exitCode !== "undefined") && exitCode !== 0) + _xkbXmlEvdev.running = true + } + + Process { + id: _xkbXmlEvdev + command: ["xmllint", "--xpath", "//layout/configItem[name and description]", "/usr/share/X11/xkb/rules/evdev.xml"] + stdout: StdioCollector { + onStreamFinished: _buildXmlMap(text) + } + } + + function _buildXmlMap(xml) { + const map = {}; + + const re = /\s*([^<]+?)\s*<\/name>[\s\S]*?\s*([^<]+?)\s*<\/description>/g; + + let m; + while ((m = re.exec(xml)) !== null) { + const code = (m[1] || "").trim(); + const desc = (m[2] || "").trim(); + if (!code || !desc) + continue; + map[code] = _short(desc); + } + + if (Object.keys(map).length === 0) + return; + + _xkbMap = map; + + if (_layoutsModel.count > 0) { + const tmp = []; + for (let i = 0; i < _layoutsModel.count; i++) { + const it = _layoutsModel.get(i); + tmp.push({ + layoutIndex: it.layoutIndex, + token: it.token, + label: _pretty(it.token) + }); + } + _layoutsModel.clear(); + tmp.forEach(t => _layoutsModel.append(t)); + _fetchActiveLayouts.running = true; + } + } + + function _short(desc) { + const m = desc.match(/^(.*)\((.*)\)$/); + if (!m) + return desc; + const lang = m[1].trim(); + const region = m[2].trim(); + const code = (region.split(/[,\s-]/)[0] || region).slice(0, 2).toUpperCase(); + return `${lang} (${code})`; + } + + Process { + id: _getKbLayoutOpt + command: ["hyprctl", "-j", "getoption", "input:kb_layout"] + stdout: StdioCollector { + onStreamFinished: { + try { + const j = JSON.parse(text); + const raw = (j?.str || j?.value || "").toString().trim(); + if (raw.length) { + _setLayouts(raw); + _fetchActiveLayouts.running = true; + return; + } + } catch (e) {} + _fetchLayoutsFromDevices.running = true; + } + } + } + + Process { + id: _fetchLayoutsFromDevices + command: ["hyprctl", "-j", "devices"] + stdout: StdioCollector { + onStreamFinished: { + try { + const dev = JSON.parse(text); + const kb = dev?.keyboards?.find(k => k.main) || dev?.keyboards?.[0]; + const raw = (kb?.layout || "").trim(); + if (raw.length) + _setLayouts(raw); + } catch (e) {} + _fetchActiveLayouts.running = true; + } + } + } + + Process { + id: _fetchActiveLayouts + command: ["hyprctl", "-j", "devices"] + stdout: StdioCollector { + onStreamFinished: { + try { + const dev = JSON.parse(text); + const kb = dev?.keyboards?.find(k => k.main) || dev?.keyboards?.[0]; + const idx = kb?.active_layout_index ?? -1; + + activeIndex = idx >= 0 ? idx : -1; + activeLabel = (idx >= 0 && idx < _layoutsModel.count) ? _layoutsModel.get(idx).label : ""; + } catch (e) { + activeIndex = -1; + activeLabel = ""; + } + + _rebuildVisible(); + } + } + } + + Process { + id: _switchProc + onRunningChanged: if (!running) + _fetchActiveLayouts.running = true + } + + function _setLayouts(raw) { + const parts = raw.split(",").map(s => s.trim()).filter(Boolean); + _layoutsModel.clear(); + + const seen = new Set(); + let idx = 0; + + for (const p of parts) { + if (seen.has(p)) + continue; + seen.add(p); + _layoutsModel.append({ + layoutIndex: idx, + token: p, + label: _pretty(p) + }); + idx++; + } + } + + function _rebuildVisible() { + _visibleModel.clear(); + + let arr = []; + for (let i = 0; i < _layoutsModel.count; i++) + arr.push(_layoutsModel.get(i)); + + arr = arr.filter(i => i.layoutIndex !== activeIndex); + arr.forEach(i => _visibleModel.append(i)); + + if (!Config.utilities.toasts.kbLimit) + return; + + if (_layoutsModel.count > 4) { + Toaster.toast(qsTr("Keyboard layout limit"), qsTr("XKB supports only 4 layouts at a time"), "warning"); + } + } + + function _pretty(token) { + const code = token.replace(/\(.*\)$/, "").trim(); + if (_xkbMap[code]) + return code.toUpperCase() + " - " + _xkbMap[code]; + return code.toUpperCase() + " - " + code; + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/ControlCenter.qml b/.config/quickshell/caelestia/modules/controlcenter/ControlCenter.qml new file mode 100644 index 0000000..4aacfad --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/ControlCenter.qml @@ -0,0 +1,100 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property ShellScreen screen + readonly property int rounding: floating ? 0 : Appearance.rounding.normal + + property alias floating: session.floating + property alias active: session.active + property alias navExpanded: session.navExpanded + + readonly property Session session: Session { + id: session + + root: root + } + + function close(): void { + } + + implicitWidth: implicitHeight * Config.controlCenter.sizes.ratio + implicitHeight: screen.height * Config.controlCenter.sizes.heightMult + + GridLayout { + anchors.fill: parent + + rowSpacing: 0 + columnSpacing: 0 + rows: root.floating ? 2 : 1 + columns: 2 + + Loader { + Layout.fillWidth: true + Layout.columnSpan: 2 + + active: root.floating + visible: active + + sourceComponent: WindowTitle { + screen: root.screen + session: root.session + } + } + + StyledRect { + Layout.fillHeight: true + + topLeftRadius: root.rounding + bottomLeftRadius: root.rounding + implicitWidth: navRail.implicitWidth + color: Colours.tPalette.m3surfaceContainer + + CustomMouseArea { + anchors.fill: parent + + function onWheel(event: WheelEvent): void { + // Prevent tab switching during initial opening animation to avoid blank pages + if (!panes.initialOpeningComplete) { + return; + } + + if (event.angleDelta.y < 0) + root.session.activeIndex = Math.min(root.session.activeIndex + 1, root.session.panes.length - 1); + else if (event.angleDelta.y > 0) + root.session.activeIndex = Math.max(root.session.activeIndex - 1, 0); + } + } + + NavRail { + id: navRail + + screen: root.screen + session: root.session + initialOpeningComplete: root.initialOpeningComplete + } + } + + Panes { + id: panes + + Layout.fillWidth: true + Layout.fillHeight: true + + topRightRadius: root.rounding + bottomRightRadius: root.rounding + session: root.session + } + } + + readonly property bool initialOpeningComplete: panes.initialOpeningComplete +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/NavRail.qml b/.config/quickshell/caelestia/modules/controlcenter/NavRail.qml new file mode 100644 index 0000000..e61a741 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/NavRail.qml @@ -0,0 +1,231 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import qs.modules.controlcenter +import Quickshell +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property ShellScreen screen + required property Session session + required property bool initialOpeningComplete + + implicitWidth: layout.implicitWidth + Appearance.padding.larger * 4 + implicitHeight: layout.implicitHeight + Appearance.padding.large * 2 + + ColumnLayout { + id: layout + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.padding.larger * 2 + spacing: Appearance.spacing.normal + + states: State { + name: "expanded" + when: root.session.navExpanded + + PropertyChanges { + layout.spacing: Appearance.spacing.small + } + } + + transitions: Transition { + Anim { + properties: "spacing" + } + } + + Loader { + Layout.topMargin: Appearance.spacing.large + active: !root.session.floating + visible: active + + sourceComponent: StyledRect { + readonly property int nonAnimWidth: normalWinIcon.implicitWidth + (root.session.navExpanded ? normalWinLabel.anchors.leftMargin + normalWinLabel.implicitWidth : 0) + normalWinIcon.anchors.leftMargin * 2 + + implicitWidth: nonAnimWidth + implicitHeight: root.session.navExpanded ? normalWinIcon.implicitHeight + Appearance.padding.normal * 2 : nonAnimWidth + + color: Colours.palette.m3primaryContainer + radius: Appearance.rounding.small + + StateLayer { + id: normalWinState + + color: Colours.palette.m3onPrimaryContainer + + function onClicked(): void { + root.session.root.close(); + WindowFactory.create(null, { + active: root.session.active, + navExpanded: root.session.navExpanded + }); + } + } + + MaterialIcon { + id: normalWinIcon + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.padding.large + + text: "select_window" + color: Colours.palette.m3onPrimaryContainer + font.pointSize: Appearance.font.size.large + fill: 1 + } + + StyledText { + id: normalWinLabel + + anchors.left: normalWinIcon.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.spacing.normal + + text: qsTr("Float window") + color: Colours.palette.m3onPrimaryContainer + opacity: root.session.navExpanded ? 1 : 0 + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.small + } + } + } + + Behavior on implicitWidth { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } + + Repeater { + model: PaneRegistry.count + + NavItem { + required property int index + Layout.topMargin: index === 0 ? Appearance.spacing.large * 2 : 0 + icon: PaneRegistry.getByIndex(index).icon + label: PaneRegistry.getByIndex(index).label + } + } + } + + component NavItem: Item { + id: item + + required property string icon + required property string label + readonly property bool active: root.session.active === label + + implicitWidth: background.implicitWidth + implicitHeight: background.implicitHeight + smallLabel.implicitHeight + smallLabel.anchors.topMargin + + states: State { + name: "expanded" + when: root.session.navExpanded + + PropertyChanges { + expandedLabel.opacity: 1 + smallLabel.opacity: 0 + background.implicitWidth: icon.implicitWidth + icon.anchors.leftMargin * 2 + expandedLabel.anchors.leftMargin + expandedLabel.implicitWidth + background.implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2 + item.implicitHeight: background.implicitHeight + } + } + + transitions: Transition { + Anim { + property: "opacity" + duration: Appearance.anim.durations.small + } + + Anim { + properties: "implicitWidth,implicitHeight" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + StyledRect { + id: background + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3secondaryContainer, item.active ? 1 : 0) + + implicitWidth: icon.implicitWidth + icon.anchors.leftMargin * 2 + implicitHeight: icon.implicitHeight + Appearance.padding.small + + StateLayer { + color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + + function onClicked(): void { + // Prevent tab switching during initial opening animation to avoid blank pages + if (!root.initialOpeningComplete) { + return; + } + root.session.active = item.label; + } + } + + MaterialIcon { + id: icon + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.padding.large + + text: item.icon + color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.large + fill: item.active ? 1 : 0 + + Behavior on fill { + Anim {} + } + } + + StyledText { + id: expandedLabel + + anchors.left: icon.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.spacing.normal + + opacity: 0 + text: item.label + color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + font.capitalization: Font.Capitalize + } + + StyledText { + id: smallLabel + + anchors.horizontalCenter: icon.horizontalCenter + anchors.top: icon.bottom + anchors.topMargin: Appearance.spacing.small / 2 + + text: item.label + font.pointSize: Appearance.font.size.small + font.capitalization: Font.Capitalize + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/PaneRegistry.qml b/.config/quickshell/caelestia/modules/controlcenter/PaneRegistry.qml new file mode 100644 index 0000000..ca48551 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/PaneRegistry.qml @@ -0,0 +1,92 @@ +pragma Singleton + +import QtQuick + +QtObject { + id: root + + readonly property list panes: [ + QtObject { + readonly property string id: "network" + readonly property string label: "network" + readonly property string icon: "router" + readonly property string component: "network/NetworkingPane.qml" + }, + QtObject { + readonly property string id: "bluetooth" + readonly property string label: "bluetooth" + readonly property string icon: "settings_bluetooth" + readonly property string component: "bluetooth/BtPane.qml" + }, + QtObject { + readonly property string id: "audio" + readonly property string label: "audio" + readonly property string icon: "volume_up" + readonly property string component: "audio/AudioPane.qml" + }, + QtObject { + readonly property string id: "appearance" + readonly property string label: "appearance" + readonly property string icon: "palette" + readonly property string component: "appearance/AppearancePane.qml" + }, + QtObject { + readonly property string id: "taskbar" + readonly property string label: "taskbar" + readonly property string icon: "task_alt" + readonly property string component: "taskbar/TaskbarPane.qml" + }, + QtObject { + readonly property string id: "launcher" + readonly property string label: "launcher" + readonly property string icon: "apps" + readonly property string component: "launcher/LauncherPane.qml" + }, + QtObject { + readonly property string id: "dashboard" + readonly property string label: "dashboard" + readonly property string icon: "dashboard" + readonly property string component: "dashboard/DashboardPane.qml" + } + ] + + readonly property int count: panes.length + + readonly property var labels: { + const result = []; + for (let i = 0; i < panes.length; i++) { + result.push(panes[i].label); + } + return result; + } + + function getByIndex(index: int): QtObject { + if (index >= 0 && index < panes.length) { + return panes[index]; + } + return null; + } + + function getIndexByLabel(label: string): int { + for (let i = 0; i < panes.length; i++) { + if (panes[i].label === label) { + return i; + } + } + return -1; + } + + function getByLabel(label: string): QtObject { + const index = getIndexByLabel(label); + return getByIndex(index); + } + + function getById(id: string): QtObject { + for (let i = 0; i < panes.length; i++) { + if (panes[i].id === id) { + return panes[i]; + } + } + return null; + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/Panes.qml b/.config/quickshell/caelestia/modules/controlcenter/Panes.qml new file mode 100644 index 0000000..ab2f808 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/Panes.qml @@ -0,0 +1,175 @@ +pragma ComponentBehavior: Bound + +import "bluetooth" +import "network" +import "audio" +import "appearance" +import "taskbar" +import "launcher" +import "dashboard" +import qs.components +import qs.services +import qs.config +import qs.modules.controlcenter +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +ClippingRectangle { + id: root + + required property Session session + + readonly property bool initialOpeningComplete: layout.initialOpeningComplete + + color: "transparent" + clip: true + focus: false + activeFocusOnTab: false + + MouseArea { + anchors.fill: parent + z: -1 + onPressed: function (mouse) { + root.focus = true; + mouse.accepted = false; + } + } + + Connections { + target: root.session + + function onActiveIndexChanged(): void { + root.focus = true; + } + } + + ColumnLayout { + id: layout + + spacing: 0 + y: -root.session.activeIndex * root.height + clip: true + + property bool animationComplete: true + property bool initialOpeningComplete: false + + Timer { + id: animationDelayTimer + interval: Appearance.anim.durations.normal + onTriggered: { + layout.animationComplete = true; + } + } + + Timer { + id: initialOpeningTimer + interval: Appearance.anim.durations.large + running: true + onTriggered: { + layout.initialOpeningComplete = true; + } + } + + Repeater { + model: PaneRegistry.count + + Pane { + required property int index + paneIndex: index + componentPath: PaneRegistry.getByIndex(index).component + } + } + + Behavior on y { + Anim {} + } + + Connections { + target: root.session + function onActiveIndexChanged(): void { + layout.animationComplete = false; + animationDelayTimer.restart(); + } + } + } + + component Pane: Item { + id: pane + + required property int paneIndex + required property string componentPath + + implicitWidth: root.width + implicitHeight: root.height + + property bool hasBeenLoaded: false + + function updateActive(): void { + const diff = Math.abs(root.session.activeIndex - pane.paneIndex); + const isActivePane = diff === 0; + let shouldBeActive = false; + + if (!layout.initialOpeningComplete) { + shouldBeActive = isActivePane; + } else { + if (diff <= 1) { + shouldBeActive = true; + } else if (pane.hasBeenLoaded) { + shouldBeActive = true; + } else { + shouldBeActive = layout.animationComplete; + } + } + + loader.active = shouldBeActive; + } + + Loader { + id: loader + + anchors.fill: parent + clip: false + active: false + + Component.onCompleted: { + Qt.callLater(pane.updateActive); + } + + onActiveChanged: { + if (active && !pane.hasBeenLoaded) { + pane.hasBeenLoaded = true; + } + + if (active && !item) { + loader.setSource(pane.componentPath, { + "session": root.session + }); + } + } + + onItemChanged: { + if (item) { + pane.hasBeenLoaded = true; + } + } + } + + Connections { + target: root.session + function onActiveIndexChanged(): void { + pane.updateActive(); + } + } + + Connections { + target: layout + function onInitialOpeningCompleteChanged(): void { + pane.updateActive(); + } + function onAnimationCompleteChanged(): void { + pane.updateActive(); + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/Session.qml b/.config/quickshell/caelestia/modules/controlcenter/Session.qml new file mode 100644 index 0000000..8a8545f --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/Session.qml @@ -0,0 +1,23 @@ +import QtQuick +import "./state" +import qs.modules.controlcenter + +QtObject { + readonly property list panes: PaneRegistry.labels + + required property var root + property bool floating: false + property string active: "network" + property int activeIndex: 0 + property bool navExpanded: false + + readonly property BluetoothState bt: BluetoothState {} + readonly property NetworkState network: NetworkState {} + readonly property EthernetState ethernet: EthernetState {} + readonly property LauncherState launcher: LauncherState {} + readonly property VpnState vpn: VpnState {} + + onActiveChanged: activeIndex = Math.max(0, panes.indexOf(active)) + onActiveIndexChanged: if (panes[activeIndex]) + active = panes[activeIndex] +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/WindowFactory.qml b/.config/quickshell/caelestia/modules/controlcenter/WindowFactory.qml new file mode 100644 index 0000000..abcf5df --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/WindowFactory.qml @@ -0,0 +1,62 @@ +pragma Singleton + +import qs.components +import qs.services +import Quickshell +import QtQuick + +Singleton { + id: root + + function create(parent: Item, props: var): void { + controlCenter.createObject(parent ?? dummy, props); + } + + QtObject { + id: dummy + } + + Component { + id: controlCenter + + FloatingWindow { + id: win + + property alias active: cc.active + property alias navExpanded: cc.navExpanded + + color: Colours.tPalette.m3surface + + onVisibleChanged: { + if (!visible) + destroy(); + } + + implicitWidth: cc.implicitWidth + implicitHeight: cc.implicitHeight + + minimumSize.width: implicitWidth + minimumSize.height: implicitHeight + maximumSize.width: implicitWidth + maximumSize.height: implicitHeight + + title: qsTr("Caelestia Settings - %1").arg(cc.active.slice(0, 1).toUpperCase() + cc.active.slice(1)) + + ControlCenter { + id: cc + + anchors.fill: parent + screen: win.screen + floating: true + + function close(): void { + win.destroy(); + } + } + + Behavior on color { + CAnim {} + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/WindowTitle.qml b/.config/quickshell/caelestia/modules/controlcenter/WindowTitle.qml new file mode 100644 index 0000000..fb71608 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/WindowTitle.qml @@ -0,0 +1,51 @@ +import qs.components +import qs.services +import qs.config +import Quickshell +import QtQuick + +StyledRect { + id: root + + required property ShellScreen screen + required property Session session + + implicitHeight: text.implicitHeight + Appearance.padding.normal + color: Colours.tPalette.m3surfaceContainer + + StyledText { + id: text + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + text: qsTr("Caelestia Settings - %1").arg(root.session.active) + font.capitalization: Font.Capitalize + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + Item { + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: Appearance.padding.normal + + implicitWidth: implicitHeight + implicitHeight: closeIcon.implicitHeight + Appearance.padding.small + + StateLayer { + radius: Appearance.rounding.full + + function onClicked(): void { + QsWindow.window.destroy(); + } + } + + MaterialIcon { + id: closeIcon + + anchors.centerIn: parent + text: "close" + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/appearance/AppearancePane.qml b/.config/quickshell/caelestia/modules/controlcenter/appearance/AppearancePane.qml new file mode 100644 index 0000000..f29f7ab --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/appearance/AppearancePane.qml @@ -0,0 +1,254 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import "./sections" +import "../../launcher/services" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.components.images +import qs.services +import qs.config +import qs.utils +import Caelestia.Models +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Session session + + property real animDurationsScale: Config.appearance.anim.durations.scale ?? 1 + property string fontFamilyMaterial: Config.appearance.font.family.material ?? "Material Symbols Rounded" + property string fontFamilyMono: Config.appearance.font.family.mono ?? "CaskaydiaCove NF" + property string fontFamilySans: Config.appearance.font.family.sans ?? "Rubik" + property real fontSizeScale: Config.appearance.font.size.scale ?? 1 + property real paddingScale: Config.appearance.padding.scale ?? 1 + property real roundingScale: Config.appearance.rounding.scale ?? 1 + property real spacingScale: Config.appearance.spacing.scale ?? 1 + property bool transparencyEnabled: Config.appearance.transparency.enabled ?? false + property real transparencyBase: Config.appearance.transparency.base ?? 0.85 + property real transparencyLayers: Config.appearance.transparency.layers ?? 0.4 + property real borderRounding: Config.border.rounding ?? 1 + property real borderThickness: Config.border.thickness ?? 1 + + property bool desktopClockEnabled: Config.background.desktopClock.enabled ?? false + property real desktopClockScale: Config.background.desktopClock.scale ?? 1 + property string desktopClockPosition: Config.background.desktopClock.position ?? "bottom-right" + property bool desktopClockShadowEnabled: Config.background.desktopClock.shadow.enabled ?? true + property real desktopClockShadowOpacity: Config.background.desktopClock.shadow.opacity ?? 0.7 + property real desktopClockShadowBlur: Config.background.desktopClock.shadow.blur ?? 0.4 + property bool desktopClockBackgroundEnabled: Config.background.desktopClock.background.enabled ?? false + property real desktopClockBackgroundOpacity: Config.background.desktopClock.background.opacity ?? 0.7 + property bool desktopClockBackgroundBlur: Config.background.desktopClock.background.blur ?? false + property bool desktopClockInvertColors: Config.background.desktopClock.invertColors ?? false + property bool backgroundEnabled: Config.background.enabled ?? true + property bool wallpaperEnabled: Config.background.wallpaperEnabled ?? true + property bool visualiserEnabled: Config.background.visualiser.enabled ?? false + property bool visualiserAutoHide: Config.background.visualiser.autoHide ?? true + property real visualiserRounding: Config.background.visualiser.rounding ?? 1 + property real visualiserSpacing: Config.background.visualiser.spacing ?? 1 + + anchors.fill: parent + + function saveConfig() { + Config.appearance.anim.durations.scale = root.animDurationsScale; + + Config.appearance.font.family.material = root.fontFamilyMaterial; + Config.appearance.font.family.mono = root.fontFamilyMono; + Config.appearance.font.family.sans = root.fontFamilySans; + Config.appearance.font.size.scale = root.fontSizeScale; + + Config.appearance.padding.scale = root.paddingScale; + Config.appearance.rounding.scale = root.roundingScale; + Config.appearance.spacing.scale = root.spacingScale; + + Config.appearance.transparency.enabled = root.transparencyEnabled; + Config.appearance.transparency.base = root.transparencyBase; + Config.appearance.transparency.layers = root.transparencyLayers; + + Config.background.desktopClock.enabled = root.desktopClockEnabled; + Config.background.enabled = root.backgroundEnabled; + Config.background.desktopClock.scale = root.desktopClockScale; + Config.background.desktopClock.position = root.desktopClockPosition; + Config.background.desktopClock.shadow.enabled = root.desktopClockShadowEnabled; + Config.background.desktopClock.shadow.opacity = root.desktopClockShadowOpacity; + Config.background.desktopClock.shadow.blur = root.desktopClockShadowBlur; + Config.background.desktopClock.background.enabled = root.desktopClockBackgroundEnabled; + Config.background.desktopClock.background.opacity = root.desktopClockBackgroundOpacity; + Config.background.desktopClock.background.blur = root.desktopClockBackgroundBlur; + Config.background.desktopClock.invertColors = root.desktopClockInvertColors; + + Config.background.wallpaperEnabled = root.wallpaperEnabled; + + Config.background.visualiser.enabled = root.visualiserEnabled; + Config.background.visualiser.autoHide = root.visualiserAutoHide; + Config.background.visualiser.rounding = root.visualiserRounding; + Config.background.visualiser.spacing = root.visualiserSpacing; + + Config.border.rounding = root.borderRounding; + Config.border.thickness = root.borderThickness; + + Config.save(); + } + + Component { + id: appearanceRightContentComponent + + Item { + id: rightAppearanceFlickable + + ColumnLayout { + id: contentLayout + + anchors.fill: parent + spacing: 0 + + StyledText { + Layout.alignment: Qt.AlignHCenter + Layout.bottomMargin: Appearance.spacing.normal + text: qsTr("Wallpaper") + font.pointSize: Appearance.font.size.extraLarge + font.weight: 600 + } + + Loader { + id: wallpaperLoader + + Layout.fillWidth: true + Layout.fillHeight: true + Layout.bottomMargin: -Appearance.padding.large * 2 + + active: { + const isActive = root.session.activeIndex === 3; + const isAdjacent = Math.abs(root.session.activeIndex - 3) === 1; + const splitLayout = root.children[0]; + const loader = splitLayout && splitLayout.rightLoader ? splitLayout.rightLoader : null; + const shouldActivate = loader && loader.item !== null && (isActive || isAdjacent); + return shouldActivate; + } + + onStatusChanged: { + if (status === Loader.Error) { + console.error("[AppearancePane] Wallpaper loader error!"); + } + } + + sourceComponent: WallpaperGrid { + session: root.session + } + } + } + } + } + + SplitPaneLayout { + anchors.fill: parent + + leftContent: Component { + + StyledFlickable { + id: sidebarFlickable + readonly property var rootPane: root + flickableDirection: Flickable.VerticalFlick + contentHeight: sidebarLayout.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: sidebarFlickable + } + + ColumnLayout { + id: sidebarLayout + anchors.left: parent.left + anchors.right: parent.right + spacing: Appearance.spacing.small + + readonly property var rootPane: sidebarFlickable.rootPane + + readonly property bool allSectionsExpanded: themeModeSection.expanded && colorVariantSection.expanded && colorSchemeSection.expanded && animationsSection.expanded && fontsSection.expanded && scalesSection.expanded && transparencySection.expanded && borderSection.expanded && backgroundSection.expanded + + RowLayout { + spacing: Appearance.spacing.smaller + + StyledText { + text: qsTr("Appearance") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + + IconButton { + icon: sidebarLayout.allSectionsExpanded ? "unfold_less" : "unfold_more" + type: IconButton.Text + label.animate: true + onClicked: { + const shouldExpand = !sidebarLayout.allSectionsExpanded; + themeModeSection.expanded = shouldExpand; + colorVariantSection.expanded = shouldExpand; + colorSchemeSection.expanded = shouldExpand; + animationsSection.expanded = shouldExpand; + fontsSection.expanded = shouldExpand; + scalesSection.expanded = shouldExpand; + transparencySection.expanded = shouldExpand; + borderSection.expanded = shouldExpand; + backgroundSection.expanded = shouldExpand; + } + } + } + + ThemeModeSection { + id: themeModeSection + } + + ColorVariantSection { + id: colorVariantSection + } + + ColorSchemeSection { + id: colorSchemeSection + } + + AnimationsSection { + id: animationsSection + rootPane: sidebarFlickable.rootPane + } + + FontsSection { + id: fontsSection + rootPane: sidebarFlickable.rootPane + } + + ScalesSection { + id: scalesSection + rootPane: sidebarFlickable.rootPane + } + + TransparencySection { + id: transparencySection + rootPane: sidebarFlickable.rootPane + } + + BorderSection { + id: borderSection + rootPane: sidebarFlickable.rootPane + } + + BackgroundSection { + id: backgroundSection + rootPane: sidebarFlickable.rootPane + } + } + } + } + + rightContent: appearanceRightContentComponent + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/AnimationsSection.qml b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/AnimationsSection.qml new file mode 100644 index 0000000..0cba5ce --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/AnimationsSection.qml @@ -0,0 +1,44 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../../components" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +CollapsibleSection { + id: root + + required property var rootPane + + title: qsTr("Animations") + showBackground: true + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Animation duration scale") + value: rootPane.animDurationsScale + from: 0.1 + to: 5.0 + decimals: 1 + suffix: "×" + validator: DoubleValidator { + bottom: 0.1 + top: 5.0 + } + + onValueModified: newValue => { + rootPane.animDurationsScale = newValue; + rootPane.saveConfig(); + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/BackgroundSection.qml b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/BackgroundSection.qml new file mode 100644 index 0000000..9d6bc6e --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/BackgroundSection.qml @@ -0,0 +1,345 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../../components" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +CollapsibleSection { + id: root + + required property var rootPane + + title: qsTr("Background") + showBackground: true + + SwitchRow { + label: qsTr("Background enabled") + checked: rootPane.backgroundEnabled + onToggled: checked => { + rootPane.backgroundEnabled = checked; + rootPane.saveConfig(); + } + } + + SwitchRow { + label: qsTr("Wallpaper enabled") + checked: rootPane.wallpaperEnabled + onToggled: checked => { + rootPane.wallpaperEnabled = checked; + rootPane.saveConfig(); + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Desktop Clock") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + SwitchRow { + label: qsTr("Desktop Clock enabled") + checked: rootPane.desktopClockEnabled + onToggled: checked => { + rootPane.desktopClockEnabled = checked; + rootPane.saveConfig(); + } + } + + SectionContainer { + id: posContainer + + contentSpacing: Appearance.spacing.small + z: 1 + + readonly property var pos: (rootPane.desktopClockPosition || "top-left").split('-') + readonly property string currentV: pos[0] + readonly property string currentH: pos[1] + + function updateClockPos(v, h) { + rootPane.desktopClockPosition = v + "-" + h; + rootPane.saveConfig(); + } + + StyledText { + text: qsTr("Positioning") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + SplitButtonRow { + label: qsTr("Vertical Position") + enabled: rootPane.desktopClockEnabled + + menuItems: [ + MenuItem { + text: qsTr("Top") + icon: "vertical_align_top" + property string val: "top" + }, + MenuItem { + text: qsTr("Middle") + icon: "vertical_align_center" + property string val: "middle" + }, + MenuItem { + text: qsTr("Bottom") + icon: "vertical_align_bottom" + property string val: "bottom" + } + ] + + Component.onCompleted: { + for (let i = 0; i < menuItems.length; i++) { + if (menuItems[i].val === posContainer.currentV) + active = menuItems[i]; + } + } + + // The signal from SplitButtonRow + onSelected: item => posContainer.updateClockPos(item.val, posContainer.currentH) + } + + SplitButtonRow { + label: qsTr("Horizontal Position") + enabled: rootPane.desktopClockEnabled + expandedZ: 99 + + menuItems: [ + MenuItem { + text: qsTr("Left") + icon: "align_horizontal_left" + property string val: "left" + }, + MenuItem { + text: qsTr("Center") + icon: "align_horizontal_center" + property string val: "center" + }, + MenuItem { + text: qsTr("Right") + icon: "align_horizontal_right" + property string val: "right" + } + ] + + Component.onCompleted: { + for (let i = 0; i < menuItems.length; i++) { + if (menuItems[i].val === posContainer.currentH) + active = menuItems[i]; + } + } + + onSelected: item => posContainer.updateClockPos(posContainer.currentV, item.val) + } + } + + SwitchRow { + label: qsTr("Invert colors") + checked: rootPane.desktopClockInvertColors + onToggled: checked => { + rootPane.desktopClockInvertColors = checked; + rootPane.saveConfig(); + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.small + + StyledText { + text: qsTr("Shadow") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + SwitchRow { + label: qsTr("Enabled") + checked: rootPane.desktopClockShadowEnabled + onToggled: checked => { + rootPane.desktopClockShadowEnabled = checked; + rootPane.saveConfig(); + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Opacity") + value: rootPane.desktopClockShadowOpacity * 100 + from: 0 + to: 100 + suffix: "%" + validator: IntValidator { + bottom: 0 + top: 100 + } + formatValueFunction: val => Math.round(val).toString() + parseValueFunction: text => parseInt(text) + + onValueModified: newValue => { + rootPane.desktopClockShadowOpacity = newValue / 100; + rootPane.saveConfig(); + } + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Blur") + value: rootPane.desktopClockShadowBlur * 100 + from: 0 + to: 100 + suffix: "%" + validator: IntValidator { + bottom: 0 + top: 100 + } + formatValueFunction: val => Math.round(val).toString() + parseValueFunction: text => parseInt(text) + + onValueModified: newValue => { + rootPane.desktopClockShadowBlur = newValue / 100; + rootPane.saveConfig(); + } + } + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.small + + StyledText { + text: qsTr("Background") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + SwitchRow { + label: qsTr("Enabled") + checked: rootPane.desktopClockBackgroundEnabled + onToggled: checked => { + rootPane.desktopClockBackgroundEnabled = checked; + rootPane.saveConfig(); + } + } + + SwitchRow { + label: qsTr("Blur enabled") + checked: rootPane.desktopClockBackgroundBlur + onToggled: checked => { + rootPane.desktopClockBackgroundBlur = checked; + rootPane.saveConfig(); + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Opacity") + value: rootPane.desktopClockBackgroundOpacity * 100 + from: 0 + to: 100 + suffix: "%" + validator: IntValidator { + bottom: 0 + top: 100 + } + formatValueFunction: val => Math.round(val).toString() + parseValueFunction: text => parseInt(text) + + onValueModified: newValue => { + rootPane.desktopClockBackgroundOpacity = newValue / 100; + rootPane.saveConfig(); + } + } + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Visualiser") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + SwitchRow { + label: qsTr("Visualiser enabled") + checked: rootPane.visualiserEnabled + onToggled: checked => { + rootPane.visualiserEnabled = checked; + rootPane.saveConfig(); + } + } + + SwitchRow { + label: qsTr("Visualiser auto hide") + checked: rootPane.visualiserAutoHide + onToggled: checked => { + rootPane.visualiserAutoHide = checked; + rootPane.saveConfig(); + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Visualiser rounding") + value: rootPane.visualiserRounding + from: 0 + to: 10 + stepSize: 1 + validator: IntValidator { + bottom: 0 + top: 10 + } + formatValueFunction: val => Math.round(val).toString() + parseValueFunction: text => parseInt(text) + + onValueModified: newValue => { + rootPane.visualiserRounding = Math.round(newValue); + rootPane.saveConfig(); + } + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Visualiser spacing") + value: rootPane.visualiserSpacing + from: 0 + to: 2 + validator: DoubleValidator { + bottom: 0 + top: 2 + } + + onValueModified: newValue => { + rootPane.visualiserSpacing = newValue; + rootPane.saveConfig(); + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/BorderSection.qml b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/BorderSection.qml new file mode 100644 index 0000000..9532d70 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/BorderSection.qml @@ -0,0 +1,68 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../../components" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +CollapsibleSection { + id: root + + required property var rootPane + + title: qsTr("Border") + showBackground: true + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Border rounding") + value: rootPane.borderRounding + from: 0.1 + to: 100 + decimals: 1 + suffix: "px" + validator: DoubleValidator { + bottom: 0.1 + top: 100 + } + + onValueModified: newValue => { + rootPane.borderRounding = newValue; + rootPane.saveConfig(); + } + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Border thickness") + value: rootPane.borderThickness + from: 0.1 + to: 100 + decimals: 1 + suffix: "px" + validator: DoubleValidator { + bottom: 0.1 + top: 100 + } + + onValueModified: newValue => { + rootPane.borderThickness = newValue; + rootPane.saveConfig(); + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ColorSchemeSection.qml b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ColorSchemeSection.qml new file mode 100644 index 0000000..95cb4b7 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ColorSchemeSection.qml @@ -0,0 +1,145 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../../../launcher/services" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +CollapsibleSection { + title: qsTr("Color scheme") + description: qsTr("Available color schemes") + showBackground: true + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small / 2 + + Repeater { + model: Schemes.list + + delegate: StyledRect { + required property var modelData + + Layout.fillWidth: true + + readonly property string schemeKey: `${modelData.name} ${modelData.flavour}` + readonly property bool isCurrent: schemeKey === Schemes.currentScheme + + color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0) + radius: Appearance.rounding.normal + border.width: isCurrent ? 1 : 0 + border.color: Colours.palette.m3primary + + StateLayer { + function onClicked(): void { + const name = modelData.name; + const flavour = modelData.flavour; + const schemeKey = `${name} ${flavour}`; + + Schemes.currentScheme = schemeKey; + Quickshell.execDetached(["caelestia", "scheme", "set", "-n", name, "-f", flavour]); + + Qt.callLater(() => { + reloadTimer.restart(); + }); + } + } + + Timer { + id: reloadTimer + interval: 300 + onTriggered: { + Schemes.reload(); + } + } + + RowLayout { + id: schemeRow + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + StyledRect { + id: preview + + Layout.alignment: Qt.AlignVCenter + + border.width: 1 + border.color: Qt.alpha(`#${modelData.colours?.outline}`, 0.5) + + color: `#${modelData.colours?.surface}` + radius: Appearance.rounding.full + implicitWidth: iconPlaceholder.implicitWidth + implicitHeight: iconPlaceholder.implicitWidth + + MaterialIcon { + id: iconPlaceholder + visible: false + text: "circle" + font.pointSize: Appearance.font.size.large + } + + Item { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + + implicitWidth: parent.implicitWidth / 2 + clip: true + + StyledRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + + implicitWidth: preview.implicitWidth + color: `#${modelData.colours?.primary}` + radius: Appearance.rounding.full + } + } + } + + Column { + Layout.fillWidth: true + spacing: 0 + + StyledText { + text: modelData.flavour ?? "" + font.pointSize: Appearance.font.size.normal + } + + StyledText { + text: modelData.name ?? "" + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3outline + + elide: Text.ElideRight + anchors.left: parent.left + anchors.right: parent.right + } + } + + Loader { + active: isCurrent + + sourceComponent: MaterialIcon { + text: "check" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.large + } + } + } + + implicitHeight: schemeRow.implicitHeight + Appearance.padding.normal * 2 + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ColorVariantSection.qml b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ColorVariantSection.qml new file mode 100644 index 0000000..3aa17dd --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ColorVariantSection.qml @@ -0,0 +1,91 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../../../launcher/services" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +CollapsibleSection { + title: qsTr("Color variant") + description: qsTr("Material theme variant") + showBackground: true + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small / 2 + + Repeater { + model: M3Variants.list + + delegate: StyledRect { + required property var modelData + + Layout.fillWidth: true + + color: Qt.alpha(Colours.tPalette.m3surfaceContainer, modelData.variant === Schemes.currentVariant ? Colours.tPalette.m3surfaceContainer.a : 0) + radius: Appearance.rounding.normal + border.width: modelData.variant === Schemes.currentVariant ? 1 : 0 + border.color: Colours.palette.m3primary + + StateLayer { + function onClicked(): void { + const variant = modelData.variant; + + Schemes.currentVariant = variant; + Quickshell.execDetached(["caelestia", "scheme", "set", "-v", variant]); + + Qt.callLater(() => { + reloadTimer.restart(); + }); + } + } + + Timer { + id: reloadTimer + interval: 300 + onTriggered: { + Schemes.reload(); + } + } + + RowLayout { + id: variantRow + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + MaterialIcon { + text: modelData.icon + font.pointSize: Appearance.font.size.large + fill: modelData.variant === Schemes.currentVariant ? 1 : 0 + } + + StyledText { + Layout.fillWidth: true + text: modelData.name + font.weight: modelData.variant === Schemes.currentVariant ? 500 : 400 + } + + MaterialIcon { + visible: modelData.variant === Schemes.currentVariant + text: "check" + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.large + } + } + + implicitHeight: variantRow.implicitHeight + Appearance.padding.normal * 2 + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/FontsSection.qml b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/FontsSection.qml new file mode 100644 index 0000000..3988863 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/FontsSection.qml @@ -0,0 +1,282 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../../components" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +CollapsibleSection { + id: root + + required property var rootPane + + title: qsTr("Fonts") + showBackground: true + + CollapsibleSection { + id: materialFontSection + title: qsTr("Material font family") + expanded: true + showBackground: true + nested: true + + Loader { + id: materialFontLoader + Layout.fillWidth: true + Layout.preferredHeight: item ? Math.min(item.contentHeight, 300) : 0 + active: materialFontSection.expanded + + sourceComponent: StyledListView { + id: materialFontList + property alias contentHeight: materialFontList.contentHeight + + clip: true + spacing: Appearance.spacing.small / 2 + model: Qt.fontFamilies() + + StyledScrollBar.vertical: StyledScrollBar { + flickable: materialFontList + } + + delegate: StyledRect { + required property string modelData + required property int index + + width: ListView.view.width + + readonly property bool isCurrent: modelData === rootPane.fontFamilyMaterial + color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0) + radius: Appearance.rounding.normal + border.width: isCurrent ? 1 : 0 + border.color: Colours.palette.m3primary + + StateLayer { + function onClicked(): void { + rootPane.fontFamilyMaterial = modelData; + rootPane.saveConfig(); + } + } + + RowLayout { + id: fontFamilyMaterialRow + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + StyledText { + text: modelData + font.pointSize: Appearance.font.size.normal + } + + Item { + Layout.fillWidth: true + } + + Loader { + active: isCurrent + + sourceComponent: MaterialIcon { + text: "check" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.large + } + } + } + + implicitHeight: fontFamilyMaterialRow.implicitHeight + Appearance.padding.normal * 2 + } + } + } + } + + CollapsibleSection { + id: monoFontSection + title: qsTr("Monospace font family") + expanded: false + showBackground: true + nested: true + + Loader { + Layout.fillWidth: true + Layout.preferredHeight: item ? Math.min(item.contentHeight, 300) : 0 + active: monoFontSection.expanded + + sourceComponent: StyledListView { + id: monoFontList + property alias contentHeight: monoFontList.contentHeight + + clip: true + spacing: Appearance.spacing.small / 2 + model: Qt.fontFamilies() + + StyledScrollBar.vertical: StyledScrollBar { + flickable: monoFontList + } + + delegate: StyledRect { + required property string modelData + required property int index + + width: ListView.view.width + + readonly property bool isCurrent: modelData === rootPane.fontFamilyMono + color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0) + radius: Appearance.rounding.normal + border.width: isCurrent ? 1 : 0 + border.color: Colours.palette.m3primary + + StateLayer { + function onClicked(): void { + rootPane.fontFamilyMono = modelData; + rootPane.saveConfig(); + } + } + + RowLayout { + id: fontFamilyMonoRow + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + StyledText { + text: modelData + font.pointSize: Appearance.font.size.normal + } + + Item { + Layout.fillWidth: true + } + + Loader { + active: isCurrent + + sourceComponent: MaterialIcon { + text: "check" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.large + } + } + } + + implicitHeight: fontFamilyMonoRow.implicitHeight + Appearance.padding.normal * 2 + } + } + } + } + + CollapsibleSection { + id: sansFontSection + title: qsTr("Sans-serif font family") + expanded: false + showBackground: true + nested: true + + Loader { + Layout.fillWidth: true + Layout.preferredHeight: item ? Math.min(item.contentHeight, 300) : 0 + active: sansFontSection.expanded + + sourceComponent: StyledListView { + id: sansFontList + property alias contentHeight: sansFontList.contentHeight + + clip: true + spacing: Appearance.spacing.small / 2 + model: Qt.fontFamilies() + + StyledScrollBar.vertical: StyledScrollBar { + flickable: sansFontList + } + + delegate: StyledRect { + required property string modelData + required property int index + + width: ListView.view.width + + readonly property bool isCurrent: modelData === rootPane.fontFamilySans + color: Qt.alpha(Colours.tPalette.m3surfaceContainer, isCurrent ? Colours.tPalette.m3surfaceContainer.a : 0) + radius: Appearance.rounding.normal + border.width: isCurrent ? 1 : 0 + border.color: Colours.palette.m3primary + + StateLayer { + function onClicked(): void { + rootPane.fontFamilySans = modelData; + rootPane.saveConfig(); + } + } + + RowLayout { + id: fontFamilySansRow + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + StyledText { + text: modelData + font.pointSize: Appearance.font.size.normal + } + + Item { + Layout.fillWidth: true + } + + Loader { + active: isCurrent + + sourceComponent: MaterialIcon { + text: "check" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.large + } + } + } + + implicitHeight: fontFamilySansRow.implicitHeight + Appearance.padding.normal * 2 + } + } + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Font size scale") + value: rootPane.fontSizeScale + from: 0.7 + to: 1.5 + decimals: 2 + suffix: "×" + validator: DoubleValidator { + bottom: 0.7 + top: 1.5 + } + + onValueModified: newValue => { + rootPane.fontSizeScale = newValue; + rootPane.saveConfig(); + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ScalesSection.qml b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ScalesSection.qml new file mode 100644 index 0000000..b0e6e38 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ScalesSection.qml @@ -0,0 +1,92 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../../components" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +CollapsibleSection { + id: root + + required property var rootPane + + title: qsTr("Scales") + showBackground: true + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Padding scale") + value: rootPane.paddingScale + from: 0.5 + to: 2.0 + decimals: 1 + suffix: "×" + validator: DoubleValidator { + bottom: 0.5 + top: 2.0 + } + + onValueModified: newValue => { + rootPane.paddingScale = newValue; + rootPane.saveConfig(); + } + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Rounding scale") + value: rootPane.roundingScale + from: 0.1 + to: 5.0 + decimals: 1 + suffix: "×" + validator: DoubleValidator { + bottom: 0.1 + top: 5.0 + } + + onValueModified: newValue => { + rootPane.roundingScale = newValue; + rootPane.saveConfig(); + } + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Spacing scale") + value: rootPane.spacingScale + from: 0.1 + to: 2.0 + decimals: 1 + suffix: "×" + validator: DoubleValidator { + bottom: 0.1 + top: 2.0 + } + + onValueModified: newValue => { + rootPane.spacingScale = newValue; + rootPane.saveConfig(); + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ThemeModeSection.qml b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ThemeModeSection.qml new file mode 100644 index 0000000..04eed91 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/ThemeModeSection.qml @@ -0,0 +1,23 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import QtQuick + +CollapsibleSection { + title: qsTr("Theme mode") + description: qsTr("Light or dark theme") + showBackground: true + + SwitchRow { + label: qsTr("Dark mode") + checked: !Colours.currentLight + onToggled: checked => { + Colours.setMode(checked ? "dark" : "light"); + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/TransparencySection.qml b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/TransparencySection.qml new file mode 100644 index 0000000..9a48629 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/appearance/sections/TransparencySection.qml @@ -0,0 +1,79 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../../components" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +CollapsibleSection { + id: root + + required property var rootPane + + title: qsTr("Transparency") + showBackground: true + + SwitchRow { + label: qsTr("Transparency enabled") + checked: rootPane.transparencyEnabled + onToggled: checked => { + rootPane.transparencyEnabled = checked; + rootPane.saveConfig(); + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Transparency base") + value: rootPane.transparencyBase * 100 + from: 0 + to: 100 + suffix: "%" + validator: IntValidator { + bottom: 0 + top: 100 + } + formatValueFunction: val => Math.round(val).toString() + parseValueFunction: text => parseInt(text) + + onValueModified: newValue => { + rootPane.transparencyBase = newValue / 100; + rootPane.saveConfig(); + } + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Transparency layers") + value: rootPane.transparencyLayers * 100 + from: 0 + to: 100 + suffix: "%" + validator: IntValidator { + bottom: 0 + top: 100 + } + formatValueFunction: val => Math.round(val).toString() + parseValueFunction: text => parseInt(text) + + onValueModified: newValue => { + rootPane.transparencyLayers = newValue / 100; + rootPane.saveConfig(); + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/audio/AudioPane.qml b/.config/quickshell/caelestia/modules/controlcenter/audio/AudioPane.qml new file mode 100644 index 0000000..01d90be --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/audio/AudioPane.qml @@ -0,0 +1,621 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Session session + + anchors.fill: parent + + SplitPaneLayout { + anchors.fill: parent + + leftContent: Component { + + StyledFlickable { + id: leftAudioFlickable + flickableDirection: Flickable.VerticalFlick + contentHeight: leftContent.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: leftAudioFlickable + } + + ColumnLayout { + id: leftContent + + anchors.left: parent.left + anchors.right: parent.right + spacing: Appearance.spacing.normal + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.smaller + + StyledText { + text: qsTr("Audio") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + } + + CollapsibleSection { + id: outputDevicesSection + + Layout.fillWidth: true + title: qsTr("Output devices") + expanded: true + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + StyledText { + text: qsTr("Devices (%1)").arg(Audio.sinks.length) + font.pointSize: Appearance.font.size.normal + font.weight: 500 + } + } + + StyledText { + Layout.fillWidth: true + text: qsTr("All available output devices") + color: Colours.palette.m3outline + } + + Repeater { + Layout.fillWidth: true + model: Audio.sinks + + delegate: StyledRect { + required property var modelData + + Layout.fillWidth: true + + color: Audio.sink?.id === modelData.id ? Colours.layer(Colours.palette.m3surfaceContainer, 2) : "transparent" + radius: Appearance.rounding.normal + + StateLayer { + function onClicked(): void { + Audio.setAudioSink(modelData); + } + } + + RowLayout { + id: outputRowLayout + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + MaterialIcon { + text: Audio.sink?.id === modelData.id ? "speaker" : "speaker_group" + font.pointSize: Appearance.font.size.large + fill: Audio.sink?.id === modelData.id ? 1 : 0 + } + + StyledText { + Layout.fillWidth: true + elide: Text.ElideRight + maximumLineCount: 1 + + text: modelData.description || qsTr("Unknown") + font.weight: Audio.sink?.id === modelData.id ? 500 : 400 + } + } + + implicitHeight: outputRowLayout.implicitHeight + Appearance.padding.normal * 2 + } + } + } + } + + CollapsibleSection { + id: inputDevicesSection + + Layout.fillWidth: true + title: qsTr("Input devices") + expanded: true + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + StyledText { + text: qsTr("Devices (%1)").arg(Audio.sources.length) + font.pointSize: Appearance.font.size.normal + font.weight: 500 + } + } + + StyledText { + Layout.fillWidth: true + text: qsTr("All available input devices") + color: Colours.palette.m3outline + } + + Repeater { + Layout.fillWidth: true + model: Audio.sources + + delegate: StyledRect { + required property var modelData + + Layout.fillWidth: true + + color: Audio.source?.id === modelData.id ? Colours.layer(Colours.palette.m3surfaceContainer, 2) : "transparent" + radius: Appearance.rounding.normal + + StateLayer { + function onClicked(): void { + Audio.setAudioSource(modelData); + } + } + + RowLayout { + id: inputRowLayout + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + MaterialIcon { + text: "mic" + font.pointSize: Appearance.font.size.large + fill: Audio.source?.id === modelData.id ? 1 : 0 + } + + StyledText { + Layout.fillWidth: true + elide: Text.ElideRight + maximumLineCount: 1 + + text: modelData.description || qsTr("Unknown") + font.weight: Audio.source?.id === modelData.id ? 500 : 400 + } + } + + implicitHeight: inputRowLayout.implicitHeight + Appearance.padding.normal * 2 + } + } + } + } + } + } + } + + rightContent: Component { + StyledFlickable { + id: rightAudioFlickable + flickableDirection: Flickable.VerticalFlick + contentHeight: contentLayout.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: rightAudioFlickable + } + + ColumnLayout { + id: contentLayout + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + spacing: Appearance.spacing.normal + + SettingsHeader { + icon: "volume_up" + title: qsTr("Audio Settings") + } + + SectionHeader { + title: qsTr("Output volume") + description: qsTr("Control the volume of your output device") + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledText { + text: qsTr("Volume") + font.pointSize: Appearance.font.size.normal + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + + StyledInputField { + id: outputVolumeInput + Layout.preferredWidth: 70 + validator: IntValidator { + bottom: 0 + top: 100 + } + enabled: !Audio.muted + + Component.onCompleted: { + text = Math.round(Audio.volume * 100).toString(); + } + + Connections { + target: Audio + function onVolumeChanged() { + if (!outputVolumeInput.hasFocus) { + outputVolumeInput.text = Math.round(Audio.volume * 100).toString(); + } + } + } + + onTextEdited: text => { + if (hasFocus) { + const val = parseInt(text); + if (!isNaN(val) && val >= 0 && val <= 100) { + Audio.setVolume(val / 100); + } + } + } + + onEditingFinished: { + const val = parseInt(text); + if (isNaN(val) || val < 0 || val > 100) { + text = Math.round(Audio.volume * 100).toString(); + } + } + } + + StyledText { + text: "%" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.normal + opacity: Audio.muted ? 0.5 : 1 + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: muteIcon.implicitHeight + Appearance.padding.normal * 2 + + radius: Appearance.rounding.normal + color: Audio.muted ? Colours.palette.m3secondary : Colours.palette.m3secondaryContainer + + StateLayer { + function onClicked(): void { + if (Audio.sink?.audio) { + Audio.sink.audio.muted = !Audio.sink.audio.muted; + } + } + } + + MaterialIcon { + id: muteIcon + + anchors.centerIn: parent + text: Audio.muted ? "volume_off" : "volume_up" + color: Audio.muted ? Colours.palette.m3onSecondary : Colours.palette.m3onSecondaryContainer + } + } + } + + StyledSlider { + id: outputVolumeSlider + Layout.fillWidth: true + implicitHeight: Appearance.padding.normal * 3 + + value: Audio.volume + enabled: !Audio.muted + opacity: enabled ? 1 : 0.5 + onMoved: { + Audio.setVolume(value); + if (!outputVolumeInput.hasFocus) { + outputVolumeInput.text = Math.round(value * 100).toString(); + } + } + } + } + } + + SectionHeader { + title: qsTr("Input volume") + description: qsTr("Control the volume of your input device") + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledText { + text: qsTr("Volume") + font.pointSize: Appearance.font.size.normal + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + + StyledInputField { + id: inputVolumeInput + Layout.preferredWidth: 70 + validator: IntValidator { + bottom: 0 + top: 100 + } + enabled: !Audio.sourceMuted + + Component.onCompleted: { + text = Math.round(Audio.sourceVolume * 100).toString(); + } + + Connections { + target: Audio + function onSourceVolumeChanged() { + if (!inputVolumeInput.hasFocus) { + inputVolumeInput.text = Math.round(Audio.sourceVolume * 100).toString(); + } + } + } + + onTextEdited: text => { + if (hasFocus) { + const val = parseInt(text); + if (!isNaN(val) && val >= 0 && val <= 100) { + Audio.setSourceVolume(val / 100); + } + } + } + + onEditingFinished: { + const val = parseInt(text); + if (isNaN(val) || val < 0 || val > 100) { + text = Math.round(Audio.sourceVolume * 100).toString(); + } + } + } + + StyledText { + text: "%" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.normal + opacity: Audio.sourceMuted ? 0.5 : 1 + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: muteInputIcon.implicitHeight + Appearance.padding.normal * 2 + + radius: Appearance.rounding.normal + color: Audio.sourceMuted ? Colours.palette.m3secondary : Colours.palette.m3secondaryContainer + + StateLayer { + function onClicked(): void { + if (Audio.source?.audio) { + Audio.source.audio.muted = !Audio.source.audio.muted; + } + } + } + + MaterialIcon { + id: muteInputIcon + + anchors.centerIn: parent + text: "mic_off" + color: Audio.sourceMuted ? Colours.palette.m3onSecondary : Colours.palette.m3onSecondaryContainer + } + } + } + + StyledSlider { + id: inputVolumeSlider + Layout.fillWidth: true + implicitHeight: Appearance.padding.normal * 3 + + value: Audio.sourceVolume + enabled: !Audio.sourceMuted + opacity: enabled ? 1 : 0.5 + onMoved: { + Audio.setSourceVolume(value); + if (!inputVolumeInput.hasFocus) { + inputVolumeInput.text = Math.round(value * 100).toString(); + } + } + } + } + } + + SectionHeader { + title: qsTr("Applications") + description: qsTr("Control volume for individual applications") + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + Repeater { + model: Audio.streams + Layout.fillWidth: true + + delegate: ColumnLayout { + required property var modelData + required property int index + + Layout.fillWidth: true + spacing: Appearance.spacing.smaller + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + MaterialIcon { + text: "apps" + font.pointSize: Appearance.font.size.normal + fill: 0 + } + + StyledText { + Layout.fillWidth: true + elide: Text.ElideRight + maximumLineCount: 1 + text: Audio.getStreamName(modelData) + font.pointSize: Appearance.font.size.normal + font.weight: 500 + } + + StyledInputField { + id: streamVolumeInput + Layout.preferredWidth: 70 + validator: IntValidator { + bottom: 0 + top: 100 + } + enabled: !Audio.getStreamMuted(modelData) + + Component.onCompleted: { + text = Math.round(Audio.getStreamVolume(modelData) * 100).toString(); + } + + Connections { + target: modelData + function onAudioChanged() { + if (!streamVolumeInput.hasFocus && modelData?.audio) { + streamVolumeInput.text = Math.round(modelData.audio.volume * 100).toString(); + } + } + } + + onTextEdited: text => { + if (hasFocus) { + const val = parseInt(text); + if (!isNaN(val) && val >= 0 && val <= 100) { + Audio.setStreamVolume(modelData, val / 100); + } + } + } + + onEditingFinished: { + const val = parseInt(text); + if (isNaN(val) || val < 0 || val > 100) { + text = Math.round(Audio.getStreamVolume(modelData) * 100).toString(); + } + } + } + + StyledText { + text: "%" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.normal + opacity: Audio.getStreamMuted(modelData) ? 0.5 : 1 + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: streamMuteIcon.implicitHeight + Appearance.padding.normal * 2 + + radius: Appearance.rounding.normal + color: Audio.getStreamMuted(modelData) ? Colours.palette.m3secondary : Colours.palette.m3secondaryContainer + + StateLayer { + function onClicked(): void { + Audio.setStreamMuted(modelData, !Audio.getStreamMuted(modelData)); + } + } + + MaterialIcon { + id: streamMuteIcon + + anchors.centerIn: parent + text: Audio.getStreamMuted(modelData) ? "volume_off" : "volume_up" + color: Audio.getStreamMuted(modelData) ? Colours.palette.m3onSecondary : Colours.palette.m3onSecondaryContainer + } + } + } + + StyledSlider { + Layout.fillWidth: true + implicitHeight: Appearance.padding.normal * 3 + + value: Audio.getStreamVolume(modelData) + enabled: !Audio.getStreamMuted(modelData) + opacity: enabled ? 1 : 0.5 + onMoved: { + Audio.setStreamVolume(modelData, value); + if (!streamVolumeInput.hasFocus) { + streamVolumeInput.text = Math.round(value * 100).toString(); + } + } + + Connections { + target: modelData + function onAudioChanged() { + if (modelData?.audio) { + value = modelData.audio.volume; + } + } + } + } + } + } + + StyledText { + Layout.fillWidth: true + visible: Audio.streams.length === 0 + text: qsTr("No applications currently playing audio") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + horizontalAlignment: Text.AlignHCenter + } + } + } + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/bluetooth/BtPane.qml b/.config/quickshell/caelestia/modules/controlcenter/bluetooth/BtPane.qml new file mode 100644 index 0000000..7d3b9ca --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/bluetooth/BtPane.qml @@ -0,0 +1,73 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import "." +import qs.components +import qs.components.controls +import qs.components.containers +import qs.config +import Quickshell.Widgets +import Quickshell.Bluetooth +import QtQuick + +SplitPaneWithDetails { + id: root + + required property Session session + + anchors.fill: parent + + activeItem: session.bt.active + paneIdGenerator: function (item) { + return item ? (item.address || "") : ""; + } + + leftContent: Component { + StyledFlickable { + id: leftFlickable + + flickableDirection: Flickable.VerticalFlick + contentHeight: deviceList.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: leftFlickable + } + + DeviceList { + id: deviceList + + anchors.left: parent.left + anchors.right: parent.right + session: root.session + } + } + } + + rightDetailsComponent: Component { + Details { + session: root.session + } + } + + rightSettingsComponent: Component { + StyledFlickable { + id: settingsFlickable + flickableDirection: Flickable.VerticalFlick + contentHeight: settingsInner.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: settingsFlickable + } + + Settings { + id: settingsInner + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + session: root.session + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/bluetooth/Details.qml b/.config/quickshell/caelestia/modules/controlcenter/bluetooth/Details.qml new file mode 100644 index 0000000..bc276e0 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/bluetooth/Details.qml @@ -0,0 +1,671 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import Quickshell.Bluetooth +import QtQuick +import QtQuick.Layouts + +StyledFlickable { + id: root + + required property Session session + readonly property BluetoothDevice device: session.bt.active + + flickableDirection: Flickable.VerticalFlick + contentHeight: detailsWrapper.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: root + } + + Item { + id: detailsWrapper + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + implicitHeight: details.implicitHeight + + DeviceDetails { + id: details + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + + session: root.session + device: root.device + + headerComponent: Component { + SettingsHeader { + icon: Icons.getBluetoothIcon(root.device?.icon ?? "") + title: root.device?.name ?? "" + } + } + + sections: [ + Component { + ColumnLayout { + spacing: Appearance.spacing.normal + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Connection status") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("Connection settings for this device") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: deviceStatus.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: deviceStatus + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.larger + + Toggle { + label: qsTr("Connected") + checked: root.device?.connected ?? false + toggle.onToggled: root.device.connected = checked + } + + Toggle { + label: qsTr("Paired") + checked: root.device?.paired ?? false + toggle.onToggled: { + if (root.device.paired) + root.device.forget(); + else + root.device.pair(); + } + } + + Toggle { + label: qsTr("Blocked") + checked: root.device?.blocked ?? false + toggle.onToggled: root.device.blocked = checked + } + } + } + } + }, + Component { + ColumnLayout { + spacing: Appearance.spacing.normal + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Device properties") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("Additional settings") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: deviceProps.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: deviceProps + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.larger + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + Item { + id: renameDevice + + Layout.fillWidth: true + Layout.rightMargin: Appearance.spacing.small + + implicitHeight: renameLabel.implicitHeight + deviceNameEdit.implicitHeight + + states: State { + name: "editingDeviceName" + when: root.session.bt.editingDeviceName + + AnchorChanges { + target: deviceNameEdit + anchors.top: renameDevice.top + } + PropertyChanges { + renameDevice.implicitHeight: deviceNameEdit.implicitHeight + renameLabel.opacity: 0 + deviceNameEdit.padding: Appearance.padding.normal + } + } + + transitions: Transition { + AnchorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + Anim { + properties: "implicitHeight,opacity,padding" + } + } + + StyledText { + id: renameLabel + + anchors.left: parent.left + + text: qsTr("Device name") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledTextField { + id: deviceNameEdit + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: renameLabel.bottom + anchors.leftMargin: root.session.bt.editingDeviceName ? 0 : -Appearance.padding.normal + + text: root.device?.name ?? "" + readOnly: !root.session.bt.editingDeviceName + onAccepted: { + root.session.bt.editingDeviceName = false; + root.device.name = text; + } + + leftPadding: Appearance.padding.normal + rightPadding: Appearance.padding.normal + + background: StyledRect { + radius: Appearance.rounding.small + border.width: 2 + border.color: Colours.palette.m3primary + opacity: root.session.bt.editingDeviceName ? 1 : 0 + + Behavior on border.color { + CAnim {} + } + + Behavior on opacity { + Anim {} + } + } + + Behavior on anchors.leftMargin { + Anim {} + } + } + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: cancelEditIcon.implicitHeight + Appearance.padding.smaller * 2 + + radius: Appearance.rounding.small + color: Colours.palette.m3secondaryContainer + opacity: root.session.bt.editingDeviceName ? 1 : 0 + scale: root.session.bt.editingDeviceName ? 1 : 0.5 + + StateLayer { + color: Colours.palette.m3onSecondaryContainer + disabled: !root.session.bt.editingDeviceName + + function onClicked(): void { + root.session.bt.editingDeviceName = false; + deviceNameEdit.text = Qt.binding(() => root.device?.name ?? ""); + } + } + + MaterialIcon { + id: cancelEditIcon + + anchors.centerIn: parent + animate: true + text: "cancel" + color: Colours.palette.m3onSecondaryContainer + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: editIcon.implicitHeight + Appearance.padding.smaller * 2 + + radius: root.session.bt.editingDeviceName ? Appearance.rounding.small : implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) + color: Qt.alpha(Colours.palette.m3primary, root.session.bt.editingDeviceName ? 1 : 0) + + StateLayer { + color: root.session.bt.editingDeviceName ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + + function onClicked(): void { + root.session.bt.editingDeviceName = !root.session.bt.editingDeviceName; + if (root.session.bt.editingDeviceName) + deviceNameEdit.forceActiveFocus(); + else + deviceNameEdit.accepted(); + } + } + + MaterialIcon { + id: editIcon + + anchors.centerIn: parent + animate: true + text: root.session.bt.editingDeviceName ? "check_circle" : "edit" + color: root.session.bt.editingDeviceName ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + } + + Behavior on radius { + Anim {} + } + } + } + + Toggle { + label: qsTr("Trusted") + checked: root.device?.trusted ?? false + toggle.onToggled: root.device.trusted = checked + } + + Toggle { + label: qsTr("Wake allowed") + checked: root.device?.wakeAllowed ?? false + toggle.onToggled: root.device.wakeAllowed = checked + } + } + } + } + }, + Component { + ColumnLayout { + spacing: Appearance.spacing.normal + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Device information") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("Information about this device") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: deviceInfo.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: deviceInfo + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.small / 2 + + StyledText { + text: root.device?.batteryAvailable ? qsTr("Device battery (%1%)").arg(root.device.battery * 100) : qsTr("Battery unavailable") + } + + RowLayout { + id: batteryPercent + Layout.topMargin: Appearance.spacing.small / 2 + Layout.fillWidth: true + Layout.preferredHeight: Appearance.padding.smaller + spacing: Appearance.spacing.small / 2 + + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true + radius: Appearance.rounding.full + color: Colours.palette.m3secondaryContainer + + StyledRect { + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: parent.height * 0.25 + + implicitWidth: root.device?.batteryAvailable ? batteryPercent.width * root.device.battery : 0 + radius: Appearance.rounding.full + color: Colours.palette.m3primary + } + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Dbus path") + } + + StyledText { + text: root.device?.dbusPath ?? "" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("MAC address") + } + + StyledText { + text: root.device?.address ?? "" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Bonded") + } + + StyledText { + text: root.device?.bonded ? qsTr("Yes") : qsTr("No") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("System name") + } + + StyledText { + text: root.device?.deviceName ?? "" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + } + } + } + } + ] + } + } + + ColumnLayout { + anchors.right: fabRoot.right + anchors.bottom: fabRoot.top + anchors.bottomMargin: Appearance.padding.normal + + Repeater { + id: fabMenu + + model: ListModel { + ListElement { + name: "trust" + icon: "handshake" + } + ListElement { + name: "block" + icon: "block" + } + ListElement { + name: "pair" + icon: "missing_controller" + } + ListElement { + name: "connect" + icon: "bluetooth_connected" + } + } + + StyledClippingRect { + id: fabMenuItem + + required property var modelData + required property int index + + Layout.alignment: Qt.AlignRight + + implicitHeight: fabMenuItemInner.implicitHeight + Appearance.padding.larger * 2 + + radius: Appearance.rounding.full + color: Colours.palette.m3primaryContainer + + opacity: 0 + + states: State { + name: "visible" + when: root.session.bt.fabMenuOpen + + PropertyChanges { + fabMenuItem.implicitWidth: fabMenuItemInner.implicitWidth + Appearance.padding.large * 2 + fabMenuItem.opacity: 1 + fabMenuItemInner.opacity: 1 + } + } + + transitions: [ + Transition { + to: "visible" + + SequentialAnimation { + PauseAnimation { + duration: (fabMenu.count - 1 - fabMenuItem.index) * Appearance.anim.durations.small / 8 + } + ParallelAnimation { + Anim { + property: "implicitWidth" + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + Anim { + property: "opacity" + duration: Appearance.anim.durations.small + } + } + } + }, + Transition { + from: "visible" + + SequentialAnimation { + PauseAnimation { + duration: fabMenuItem.index * Appearance.anim.durations.small / 8 + } + ParallelAnimation { + Anim { + property: "implicitWidth" + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + Anim { + property: "opacity" + duration: Appearance.anim.durations.small + } + } + } + } + ] + + StateLayer { + function onClicked(): void { + root.session.bt.fabMenuOpen = false; + + const name = fabMenuItem.modelData.name; + if (fabMenuItem.modelData.name !== "pair") + root.device[`${name}ed`] = !root.device[`${name}ed`]; + else if (root.device.paired) + root.device.forget(); + else + root.device.pair(); + } + } + + RowLayout { + id: fabMenuItemInner + + anchors.centerIn: parent + spacing: Appearance.spacing.normal + opacity: 0 + + MaterialIcon { + text: fabMenuItem.modelData.icon + color: Colours.palette.m3onPrimaryContainer + fill: 1 + } + + StyledText { + animate: true + text: (root.device && root.device[`${fabMenuItem.modelData.name}ed`] ? fabMenuItem.modelData.name === "connect" ? "dis" : "un" : "") + fabMenuItem.modelData.name + color: Colours.palette.m3onPrimaryContainer + font.capitalization: Font.Capitalize + Layout.preferredWidth: implicitWidth + + Behavior on Layout.preferredWidth { + Anim { + duration: Appearance.anim.durations.small + } + } + } + } + } + } + } + + Item { + id: fabRoot + + x: root.contentX + root.width - width + y: root.contentY + root.height - height + width: 64 + height: 64 + z: 10000 + + StyledRect { + id: fabBg + + anchors.right: parent.right + anchors.top: parent.top + + implicitWidth: 64 + implicitHeight: 64 + + radius: Appearance.rounding.normal + color: root.session.bt.fabMenuOpen ? Colours.palette.m3primary : Colours.palette.m3primaryContainer + + states: State { + name: "expanded" + when: root.session.bt.fabMenuOpen + + PropertyChanges { + fabBg.implicitWidth: 48 + fabBg.implicitHeight: 48 + fabBg.radius: 48 / 2 + fab.font.pointSize: Appearance.font.size.larger + } + } + + transitions: Transition { + Anim { + properties: "implicitWidth,implicitHeight" + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + Anim { + properties: "radius,font.pointSize" + } + } + + Elevation { + anchors.fill: parent + radius: parent.radius + z: -1 + level: fabState.containsMouse && !fabState.pressed ? 4 : 3 + } + + StateLayer { + id: fabState + + color: root.session.bt.fabMenuOpen ? Colours.palette.m3onPrimary : Colours.palette.m3onPrimaryContainer + + function onClicked(): void { + root.session.bt.fabMenuOpen = !root.session.bt.fabMenuOpen; + } + } + + MaterialIcon { + id: fab + + anchors.centerIn: parent + animate: true + text: root.session.bt.fabMenuOpen ? "close" : "settings" + color: root.session.bt.fabMenuOpen ? Colours.palette.m3onPrimary : Colours.palette.m3onPrimaryContainer + font.pointSize: Appearance.font.size.large + fill: 1 + } + } + } + + component Toggle: RowLayout { + required property string label + property alias checked: toggle.checked + property alias toggle: toggle + + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: parent.label + } + + StyledSwitch { + id: toggle + + cLayer: 2 + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/bluetooth/DeviceList.qml b/.config/quickshell/caelestia/modules/controlcenter/bluetooth/DeviceList.qml new file mode 100644 index 0000000..2a2bde9 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/bluetooth/DeviceList.qml @@ -0,0 +1,264 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import Quickshell +import Quickshell.Bluetooth +import QtQuick +import QtQuick.Layouts + +DeviceList { + id: root + + required property Session session + readonly property bool smallDiscoverable: width <= 540 + readonly property bool smallPairable: width <= 480 + + title: qsTr("Devices (%1)").arg(Bluetooth.devices.values.length) + description: qsTr("All available bluetooth devices") + activeItem: session.bt.active + + model: ScriptModel { + id: deviceModel + + values: [...Bluetooth.devices.values].sort((a, b) => (b.connected - a.connected) || (b.paired - a.paired) || a.name.localeCompare(b.name)) + } + + headerComponent: Component { + RowLayout { + spacing: Appearance.spacing.smaller + + StyledText { + text: qsTr("Bluetooth") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + + ToggleButton { + toggled: Bluetooth.defaultAdapter?.enabled ?? false + icon: "power" + accent: "Tertiary" + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + tooltip: qsTr("Toggle Bluetooth") + + onClicked: { + const adapter = Bluetooth.defaultAdapter; + if (adapter) + adapter.enabled = !adapter.enabled; + } + } + + ToggleButton { + toggled: Bluetooth.defaultAdapter?.discoverable ?? false + icon: root.smallDiscoverable ? "group_search" : "" + label: root.smallDiscoverable ? "" : qsTr("Discoverable") + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + tooltip: qsTr("Make discoverable") + + onClicked: { + const adapter = Bluetooth.defaultAdapter; + if (adapter) + adapter.discoverable = !adapter.discoverable; + } + } + + ToggleButton { + toggled: Bluetooth.defaultAdapter?.pairable ?? false + icon: "missing_controller" + label: root.smallPairable ? "" : qsTr("Pairable") + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + tooltip: qsTr("Make pairable") + + onClicked: { + const adapter = Bluetooth.defaultAdapter; + if (adapter) + adapter.pairable = !adapter.pairable; + } + } + + ToggleButton { + toggled: Bluetooth.defaultAdapter?.discovering ?? false + icon: "bluetooth_searching" + accent: "Secondary" + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + tooltip: qsTr("Scan for devices") + + onClicked: { + const adapter = Bluetooth.defaultAdapter; + if (adapter) + adapter.discovering = !adapter.discovering; + } + } + + ToggleButton { + toggled: !root.session.bt.active + icon: "settings" + accent: "Primary" + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + tooltip: qsTr("Bluetooth settings") + + onClicked: { + if (root.session.bt.active) + root.session.bt.active = null; + else { + root.session.bt.active = root.model.values[0] ?? null; + } + } + } + } + } + + delegate: Component { + StyledRect { + id: device + + required property BluetoothDevice modelData + readonly property bool loading: modelData && (modelData.state === BluetoothDeviceState.Connecting || modelData.state === BluetoothDeviceState.Disconnecting) + readonly property bool connected: modelData && modelData.state === BluetoothDeviceState.Connected + + width: ListView.view ? ListView.view.width : undefined + implicitHeight: deviceInner.implicitHeight + Appearance.padding.normal * 2 + + color: Qt.alpha(Colours.tPalette.m3surfaceContainer, root.activeItem === modelData ? Colours.tPalette.m3surfaceContainer.a : 0) + radius: Appearance.rounding.normal + + StateLayer { + id: stateLayer + + function onClicked(): void { + if (device.modelData) + root.session.bt.active = device.modelData; + } + } + + RowLayout { + id: deviceInner + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2 + + radius: Appearance.rounding.normal + color: device.connected ? Colours.palette.m3primaryContainer : (device.modelData && device.modelData.bonded) ? Colours.palette.m3secondaryContainer : Colours.tPalette.m3surfaceContainerHigh + + StyledRect { + anchors.fill: parent + radius: parent.radius + color: Qt.alpha(device.connected ? Colours.palette.m3onPrimaryContainer : (device.modelData && device.modelData.bonded) ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface, stateLayer.pressed ? 0.1 : stateLayer.containsMouse ? 0.08 : 0) + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + text: Icons.getBluetoothIcon(device.modelData ? device.modelData.icon : "") + color: device.connected ? Colours.palette.m3onPrimaryContainer : (device.modelData && device.modelData.bonded) ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.large + fill: device.connected ? 1 : 0 + + Behavior on fill { + Anim {} + } + } + } + + ColumnLayout { + Layout.fillWidth: true + + spacing: 0 + + StyledText { + Layout.fillWidth: true + text: device.modelData ? device.modelData.name : qsTr("Unknown") + elide: Text.ElideRight + } + + StyledText { + Layout.fillWidth: true + text: (device.modelData ? device.modelData.address : "") + (device.connected ? qsTr(" (Connected)") : (device.modelData && device.modelData.bonded) ? qsTr(" (Paired)") : "") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + elide: Text.ElideRight + } + } + + StyledRect { + id: connectBtn + + implicitWidth: implicitHeight + implicitHeight: connectIcon.implicitHeight + Appearance.padding.smaller * 2 + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3primaryContainer, device.connected ? 1 : 0) + + CircularIndicator { + anchors.fill: parent + running: device.loading + } + + StateLayer { + color: device.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface + disabled: device.loading + + function onClicked(): void { + if (device.loading) + return; + + if (device.connected) { + device.modelData.connected = false; + } else { + if (device.modelData.bonded) { + device.modelData.connected = true; + } else { + device.modelData.pair(); + } + } + } + } + + MaterialIcon { + id: connectIcon + + anchors.centerIn: parent + animate: true + text: device.connected ? "link_off" : "link" + color: device.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface + + opacity: device.loading ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + } + } + } + } + + onItemSelected: item => session.bt.active = item +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/bluetooth/Settings.qml b/.config/quickshell/caelestia/modules/controlcenter/bluetooth/Settings.qml new file mode 100644 index 0000000..c547240 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/bluetooth/Settings.qml @@ -0,0 +1,532 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.services +import qs.config +import Quickshell.Bluetooth +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property Session session + + spacing: Appearance.spacing.normal + + SettingsHeader { + icon: "bluetooth" + title: qsTr("Bluetooth Settings") + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Adapter status") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("General adapter settings") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: adapterStatus.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: adapterStatus + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.larger + + Toggle { + label: qsTr("Powered") + checked: Bluetooth.defaultAdapter?.enabled ?? false + toggle.onToggled: { + const adapter = Bluetooth.defaultAdapter; + if (adapter) + adapter.enabled = checked; + } + } + + Toggle { + label: qsTr("Discoverable") + checked: Bluetooth.defaultAdapter?.discoverable ?? false + toggle.onToggled: { + const adapter = Bluetooth.defaultAdapter; + if (adapter) + adapter.discoverable = checked; + } + } + + Toggle { + label: qsTr("Pairable") + checked: Bluetooth.defaultAdapter?.pairable ?? false + toggle.onToggled: { + const adapter = Bluetooth.defaultAdapter; + if (adapter) + adapter.pairable = checked; + } + } + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Adapter properties") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("Per-adapter settings") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: adapterSettings.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: adapterSettings + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.larger + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: qsTr("Current adapter") + } + + Item { + id: adapterPickerButton + + property bool expanded + + implicitWidth: adapterPicker.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: adapterPicker.implicitHeight + Appearance.padding.smaller * 2 + + StateLayer { + radius: Appearance.rounding.small + + function onClicked(): void { + adapterPickerButton.expanded = !adapterPickerButton.expanded; + } + } + + RowLayout { + id: adapterPicker + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + anchors.topMargin: Appearance.padding.smaller + anchors.bottomMargin: Appearance.padding.smaller + spacing: Appearance.spacing.normal + + StyledText { + Layout.leftMargin: Appearance.padding.small + text: Bluetooth.defaultAdapter?.name ?? qsTr("None") + } + + MaterialIcon { + text: "expand_more" + } + } + + Elevation { + anchors.fill: adapterListBg + radius: adapterListBg.radius + opacity: adapterPickerButton.expanded ? 1 : 0 + scale: adapterPickerButton.expanded ? 1 : 0.7 + level: 2 + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } + + StyledClippingRect { + id: adapterListBg + + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + implicitHeight: adapterPickerButton.expanded ? adapterList.implicitHeight : adapterPickerButton.implicitHeight + + color: Colours.palette.m3secondaryContainer + radius: Appearance.rounding.small + opacity: adapterPickerButton.expanded ? 1 : 0 + scale: adapterPickerButton.expanded ? 1 : 0.7 + + ColumnLayout { + id: adapterList + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + spacing: 0 + + Repeater { + model: Bluetooth.adapters + + Item { + id: adapter + + required property BluetoothAdapter modelData + + Layout.fillWidth: true + implicitHeight: adapterInner.implicitHeight + Appearance.padding.normal * 2 + + StateLayer { + disabled: !adapterPickerButton.expanded + + function onClicked(): void { + adapterPickerButton.expanded = false; + root.session.bt.currentAdapter = adapter.modelData; + } + } + + RowLayout { + id: adapterInner + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + Layout.leftMargin: Appearance.padding.small + text: adapter.modelData.name + color: Colours.palette.m3onSecondaryContainer + } + + MaterialIcon { + text: "check" + color: Colours.palette.m3onSecondaryContainer + visible: adapter.modelData === root.session.bt.currentAdapter + } + } + } + } + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: qsTr("Discoverable timeout") + } + + CustomSpinBox { + min: 0 + value: root.session.bt.currentAdapter?.discoverableTimeout ?? 0 + onValueModified: value => { + if (root.session.bt.currentAdapter) { + root.session.bt.currentAdapter.discoverableTimeout = value; + } + } + } + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + Item { + id: renameAdapter + + Layout.fillWidth: true + Layout.rightMargin: Appearance.spacing.small + + implicitHeight: renameLabel.implicitHeight + adapterNameEdit.implicitHeight + + states: State { + name: "editingAdapterName" + when: root.session.bt.editingAdapterName + + AnchorChanges { + target: adapterNameEdit + anchors.top: renameAdapter.top + } + PropertyChanges { + renameAdapter.implicitHeight: adapterNameEdit.implicitHeight + renameLabel.opacity: 0 + adapterNameEdit.padding: Appearance.padding.normal + } + } + + transitions: Transition { + AnchorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + Anim { + properties: "implicitHeight,opacity,padding" + } + } + + StyledText { + id: renameLabel + + anchors.left: parent.left + + text: qsTr("Rename adapter (currently does not work)") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledTextField { + id: adapterNameEdit + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: renameLabel.bottom + anchors.leftMargin: root.session.bt.editingAdapterName ? 0 : -Appearance.padding.normal + + text: root.session.bt.currentAdapter?.name ?? "" + readOnly: !root.session.bt.editingAdapterName + onAccepted: { + root.session.bt.editingAdapterName = false; + } + + leftPadding: Appearance.padding.normal + rightPadding: Appearance.padding.normal + + background: StyledRect { + radius: Appearance.rounding.small + border.width: 2 + border.color: Colours.palette.m3primary + opacity: root.session.bt.editingAdapterName ? 1 : 0 + + Behavior on border.color { + CAnim {} + } + + Behavior on opacity { + Anim {} + } + } + + Behavior on anchors.leftMargin { + Anim {} + } + } + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: cancelEditIcon.implicitHeight + Appearance.padding.smaller * 2 + + radius: Appearance.rounding.small + color: Colours.palette.m3secondaryContainer + opacity: root.session.bt.editingAdapterName ? 1 : 0 + scale: root.session.bt.editingAdapterName ? 1 : 0.5 + + StateLayer { + color: Colours.palette.m3onSecondaryContainer + disabled: !root.session.bt.editingAdapterName + + function onClicked(): void { + root.session.bt.editingAdapterName = false; + adapterNameEdit.text = Qt.binding(() => root.session.bt.currentAdapter?.name ?? ""); + } + } + + MaterialIcon { + id: cancelEditIcon + + anchors.centerIn: parent + animate: true + text: "cancel" + color: Colours.palette.m3onSecondaryContainer + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: editIcon.implicitHeight + Appearance.padding.smaller * 2 + + radius: root.session.bt.editingAdapterName ? Appearance.rounding.small : implicitHeight / 2 * Math.min(1, Appearance.rounding.scale) + color: Qt.alpha(Colours.palette.m3primary, root.session.bt.editingAdapterName ? 1 : 0) + + StateLayer { + color: root.session.bt.editingAdapterName ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + + function onClicked(): void { + root.session.bt.editingAdapterName = !root.session.bt.editingAdapterName; + if (root.session.bt.editingAdapterName) + adapterNameEdit.forceActiveFocus(); + else + adapterNameEdit.accepted(); + } + } + + MaterialIcon { + id: editIcon + + anchors.centerIn: parent + animate: true + text: root.session.bt.editingAdapterName ? "check_circle" : "edit" + color: root.session.bt.editingAdapterName ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + } + + Behavior on radius { + Anim {} + } + } + } + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Adapter information") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("Information about the default adapter") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: adapterInfo.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: adapterInfo + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.small / 2 + + StyledText { + text: qsTr("Adapter state") + } + + StyledText { + text: Bluetooth.defaultAdapter ? BluetoothAdapterState.toString(Bluetooth.defaultAdapter.state) : qsTr("Unknown") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Dbus path") + } + + StyledText { + text: Bluetooth.defaultAdapter?.dbusPath ?? "" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Adapter id") + } + + StyledText { + text: Bluetooth.defaultAdapter?.adapterId ?? "" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + } + } + + component Toggle: RowLayout { + required property string label + property alias checked: toggle.checked + property alias toggle: toggle + + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: parent.label + } + + StyledSwitch { + id: toggle + + cLayer: 2 + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/components/ConnectedButtonGroup.qml b/.config/quickshell/caelestia/modules/controlcenter/components/ConnectedButtonGroup.qml new file mode 100644 index 0000000..01cd612 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/components/ConnectedButtonGroup.qml @@ -0,0 +1,108 @@ +import ".." +import qs.components +import qs.components.controls +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + property var options: [] // Array of {label: string, propertyName: string, onToggled: function} + property var rootItem: null // The root item that contains the properties we want to bind to + property string title: "" // Optional title text + + Layout.fillWidth: true + implicitHeight: layout.implicitHeight + Appearance.padding.large * 2 + radius: Appearance.rounding.normal + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + clip: true + + Behavior on implicitHeight { + Anim {} + } + + ColumnLayout { + id: layout + + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + visible: root.title !== "" + text: root.title + font.pointSize: Appearance.font.size.normal + } + + RowLayout { + id: buttonRow + Layout.alignment: Qt.AlignHCenter + spacing: Appearance.spacing.small + + Repeater { + id: repeater + model: root.options + + delegate: TextButton { + id: button + required property int index + required property var modelData + + Layout.fillWidth: true + text: modelData.label + + property bool _checked: false + + checked: _checked + toggle: false + type: TextButton.Tonal + + // Create binding in Component.onCompleted + Component.onCompleted: { + if (root.rootItem && modelData.propertyName) { + const propName = modelData.propertyName; + const rootItem = root.rootItem; + _checked = Qt.binding(function () { + return rootItem[propName] ?? false; + }); + } + } + + // Match utilities Toggles radius styling + // Each button has full rounding (not connected) since they have spacing + radius: stateLayer.pressed ? Appearance.rounding.small / 2 : internalChecked ? Appearance.rounding.small : Appearance.rounding.normal + + // Match utilities Toggles inactive color + inactiveColour: Colours.layer(Colours.palette.m3surfaceContainerHighest, 2) + + // Adjust width similar to utilities toggles + Layout.preferredWidth: implicitWidth + (stateLayer.pressed ? Appearance.padding.large : internalChecked ? Appearance.padding.smaller : 0) + + onClicked: { + if (modelData.onToggled && root.rootItem && modelData.propertyName) { + const currentValue = root.rootItem[modelData.propertyName] ?? false; + modelData.onToggled(!currentValue); + } + } + + Behavior on Layout.preferredWidth { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + Behavior on radius { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/components/DeviceDetails.qml b/.config/quickshell/caelestia/modules/controlcenter/components/DeviceDetails.qml new file mode 100644 index 0000000..a5d0647 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/components/DeviceDetails.qml @@ -0,0 +1,70 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.config +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + property Session session + property var device: null + + property Component headerComponent: null + property list sections: [] + + property Component topContent: null + property Component bottomContent: null + + implicitWidth: layout.implicitWidth + implicitHeight: layout.implicitHeight + + ColumnLayout { + id: layout + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + spacing: Appearance.spacing.normal + + Loader { + id: headerLoader + + Layout.fillWidth: true + sourceComponent: root.headerComponent + visible: root.headerComponent !== null + } + + Loader { + id: topContentLoader + + Layout.fillWidth: true + sourceComponent: root.topContent + visible: root.topContent !== null + } + + Repeater { + model: root.sections + + Loader { + required property Component modelData + + Layout.fillWidth: true + sourceComponent: modelData + } + } + + Loader { + id: bottomContentLoader + + Layout.fillWidth: true + sourceComponent: root.bottomContent + visible: root.bottomContent !== null + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/components/DeviceList.qml b/.config/quickshell/caelestia/modules/controlcenter/components/DeviceList.qml new file mode 100644 index 0000000..722f9a1 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/components/DeviceList.qml @@ -0,0 +1,84 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + property Session session: null + property var model: null + property Component delegate: null + + property string title: "" + property string description: "" + property var activeItem: null + property Component headerComponent: null + property Component titleSuffix: null + property bool showHeader: true + + signal itemSelected(var item) + + spacing: Appearance.spacing.small + + Loader { + id: headerLoader + + Layout.fillWidth: true + sourceComponent: root.headerComponent + visible: root.headerComponent !== null && root.showHeader + } + + RowLayout { + Layout.fillWidth: true + Layout.topMargin: root.headerComponent ? 0 : 0 + spacing: Appearance.spacing.small + visible: root.title !== "" || root.description !== "" + + StyledText { + visible: root.title !== "" + text: root.title + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + Loader { + sourceComponent: root.titleSuffix + visible: root.titleSuffix !== null + } + + Item { + Layout.fillWidth: true + } + } + + property alias view: view + + StyledText { + visible: root.description !== "" + Layout.fillWidth: true + text: root.description + color: Colours.palette.m3outline + } + + StyledListView { + id: view + + Layout.fillWidth: true + implicitHeight: contentHeight + + model: root.model + delegate: root.delegate + + spacing: Appearance.spacing.small / 2 + interactive: false + clip: false + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/components/PaneTransition.qml b/.config/quickshell/caelestia/modules/controlcenter/components/PaneTransition.qml new file mode 100644 index 0000000..5d80dbe --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/components/PaneTransition.qml @@ -0,0 +1,71 @@ +pragma ComponentBehavior: Bound + +import qs.config +import QtQuick + +SequentialAnimation { + id: root + + required property Item target + property list propertyActions + + property real scaleFrom: 1.0 + property real scaleTo: 0.8 + property real opacityFrom: 1.0 + property real opacityTo: 0.0 + + ParallelAnimation { + NumberAnimation { + target: root.target + property: "opacity" + from: root.opacityFrom + to: root.opacityTo + duration: Appearance.anim.durations.normal / 2 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + + NumberAnimation { + target: root.target + property: "scale" + from: root.scaleFrom + to: root.scaleTo + duration: Appearance.anim.durations.normal / 2 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + } + + ScriptAction { + script: { + for (let i = 0; i < root.propertyActions.length; i++) { + const action = root.propertyActions[i]; + if (action.target && action.property !== undefined) { + action.target[action.property] = action.value; + } + } + } + } + + ParallelAnimation { + NumberAnimation { + target: root.target + property: "opacity" + from: root.opacityTo + to: root.opacityFrom + duration: Appearance.anim.durations.normal / 2 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + + NumberAnimation { + target: root.target + property: "scale" + from: root.scaleTo + to: root.scaleFrom + duration: Appearance.anim.durations.normal / 2 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/components/ReadonlySlider.qml b/.config/quickshell/caelestia/modules/controlcenter/components/ReadonlySlider.qml new file mode 100644 index 0000000..169d636 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/components/ReadonlySlider.qml @@ -0,0 +1,67 @@ +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + property string label: "" + property real value: 0 + property real from: 0 + property real to: 100 + property string suffix: "" + property bool readonly: false + + spacing: Appearance.spacing.small + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledText { + visible: root.label !== "" + text: root.label + font.pointSize: Appearance.font.size.normal + color: root.readonly ? Colours.palette.m3outline : Colours.palette.m3onSurface + } + + Item { + Layout.fillWidth: true + } + + MaterialIcon { + visible: root.readonly + text: "lock" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + text: Math.round(root.value) + (root.suffix !== "" ? " " + root.suffix : "") + font.pointSize: Appearance.font.size.normal + color: root.readonly ? Colours.palette.m3outline : Colours.palette.m3onSurface + } + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: Appearance.padding.normal + radius: Appearance.rounding.full + color: Colours.layer(Colours.palette.m3surfaceContainerHighest, 1) + opacity: root.readonly ? 0.5 : 1.0 + + StyledRect { + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + width: parent.width * ((root.value - root.from) / (root.to - root.from)) + radius: parent.radius + color: root.readonly ? Colours.palette.m3outline : Colours.palette.m3primary + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/components/SettingsHeader.qml b/.config/quickshell/caelestia/modules/controlcenter/components/SettingsHeader.qml new file mode 100644 index 0000000..0dc190c --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/components/SettingsHeader.qml @@ -0,0 +1,37 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.config +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property string icon + required property string title + + Layout.fillWidth: true + implicitHeight: column.implicitHeight + + ColumnLayout { + id: column + + anchors.centerIn: parent + spacing: Appearance.spacing.normal + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: root.icon + font.pointSize: Appearance.font.size.extraLarge * 3 + font.bold: true + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: root.title + font.pointSize: Appearance.font.size.large + font.bold: true + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/components/SliderInput.qml b/.config/quickshell/caelestia/modules/controlcenter/components/SliderInput.qml new file mode 100644 index 0000000..11b3f70 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/components/SliderInput.qml @@ -0,0 +1,180 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + property string label: "" + property real value: 0 + property real from: 0 + property real to: 100 + property real stepSize: 0 + property var validator: null + property string suffix: "" // Optional suffix text (e.g., "×", "px") + property int decimals: 1 // Number of decimal places to show (default: 1) + property var formatValueFunction: null // Optional custom format function + property var parseValueFunction: null // Optional custom parse function + + function formatValue(val: real): string { + if (formatValueFunction) { + return formatValueFunction(val); + } + // Default format function + // Check if it's an IntValidator (IntValidator doesn't have a 'decimals' property) + if (validator && validator.bottom !== undefined && validator.decimals === undefined) { + return Math.round(val).toString(); + } + // For DoubleValidator or no validator, use the decimals property + return val.toFixed(root.decimals); + } + + function parseValue(text: string): real { + if (parseValueFunction) { + return parseValueFunction(text); + } + // Default parse function + if (validator && validator.bottom !== undefined) { + // Check if it's an integer validator + if (validator.top !== undefined && validator.top === Math.floor(validator.top)) { + return parseInt(text); + } + } + return parseFloat(text); + } + + signal valueModified(real newValue) + + property bool _initialized: false + + spacing: Appearance.spacing.small + + Component.onCompleted: { + // Set initialized flag after a brief delay to allow component to fully load + Qt.callLater(() => { + _initialized = true; + }); + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledText { + visible: root.label !== "" + text: root.label + font.pointSize: Appearance.font.size.normal + } + + Item { + Layout.fillWidth: true + } + + StyledInputField { + id: inputField + Layout.preferredWidth: 70 + validator: root.validator + + Component.onCompleted: { + // Initialize text without triggering valueModified signal + text = root.formatValue(root.value); + } + + onTextEdited: text => { + if (hasFocus) { + const val = root.parseValue(text); + if (!isNaN(val)) { + // Validate against validator bounds if available + let isValid = true; + if (root.validator) { + if (root.validator.bottom !== undefined && val < root.validator.bottom) { + isValid = false; + } + if (root.validator.top !== undefined && val > root.validator.top) { + isValid = false; + } + } + + if (isValid) { + root.valueModified(val); + } + } + } + } + + onEditingFinished: { + const val = root.parseValue(text); + let isValid = true; + if (root.validator) { + if (root.validator.bottom !== undefined && val < root.validator.bottom) { + isValid = false; + } + if (root.validator.top !== undefined && val > root.validator.top) { + isValid = false; + } + } + + if (isNaN(val) || !isValid) { + text = root.formatValue(root.value); + } + } + } + + StyledText { + visible: root.suffix !== "" + text: root.suffix + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.normal + } + } + + StyledSlider { + id: slider + + Layout.fillWidth: true + implicitHeight: Appearance.padding.normal * 3 + + from: root.from + to: root.to + stepSize: root.stepSize + + // Use Binding to allow slider to move freely during dragging + Binding { + target: slider + property: "value" + value: root.value + when: !slider.pressed + } + + onValueChanged: { + // Update input field text in real-time as slider moves during dragging + // Always update when slider value changes (during dragging or external updates) + if (!inputField.hasFocus) { + const newValue = root.stepSize > 0 ? Math.round(value / root.stepSize) * root.stepSize : value; + inputField.text = root.formatValue(newValue); + } + } + + onMoved: { + const newValue = root.stepSize > 0 ? Math.round(value / root.stepSize) * root.stepSize : value; + root.valueModified(newValue); + if (!inputField.hasFocus) { + inputField.text = root.formatValue(newValue); + } + } + } + + // Update input field when value changes externally (slider is already bound) + onValueChanged: { + // Only update if component is initialized to avoid issues during creation + if (root._initialized && !inputField.hasFocus) { + inputField.text = root.formatValue(root.value); + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/components/SplitPaneLayout.qml b/.config/quickshell/caelestia/modules/controlcenter/components/SplitPaneLayout.qml new file mode 100644 index 0000000..89504a0 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/components/SplitPaneLayout.qml @@ -0,0 +1,109 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.effects +import qs.config +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +RowLayout { + id: root + + spacing: 0 + + property Component leftContent: null + property Component rightContent: null + + property real leftWidthRatio: 0.4 + property int leftMinimumWidth: 420 + property var leftLoaderProperties: ({}) + property var rightLoaderProperties: ({}) + + property alias leftLoader: leftLoader + property alias rightLoader: rightLoader + + Item { + id: leftPane + + Layout.preferredWidth: Math.floor(parent.width * root.leftWidthRatio) + Layout.minimumWidth: root.leftMinimumWidth + Layout.fillHeight: true + + ClippingRectangle { + id: leftClippingRect + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + anchors.leftMargin: 0 + anchors.rightMargin: Appearance.padding.normal / 2 + + radius: leftBorder.innerRadius + color: "transparent" + + Loader { + id: leftLoader + + anchors.fill: parent + anchors.margins: Appearance.padding.large + Appearance.padding.normal + anchors.leftMargin: Appearance.padding.large + anchors.rightMargin: Appearance.padding.large + Appearance.padding.normal / 2 + + sourceComponent: root.leftContent + + Component.onCompleted: { + for (const key in root.leftLoaderProperties) { + leftLoader[key] = root.leftLoaderProperties[key]; + } + } + } + } + + InnerBorder { + id: leftBorder + + leftThickness: 0 + rightThickness: Appearance.padding.normal / 2 + } + } + + Item { + id: rightPane + + Layout.fillWidth: true + Layout.fillHeight: true + + ClippingRectangle { + id: rightClippingRect + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + anchors.leftMargin: 0 + anchors.rightMargin: Appearance.padding.normal / 2 + + radius: rightBorder.innerRadius + color: "transparent" + + Loader { + id: rightLoader + + anchors.fill: parent + anchors.margins: Appearance.padding.large * 2 + + sourceComponent: root.rightContent + + Component.onCompleted: { + for (const key in root.rightLoaderProperties) { + rightLoader[key] = root.rightLoaderProperties[key]; + } + } + } + } + + InnerBorder { + id: rightBorder + + leftThickness: Appearance.padding.normal / 2 + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/components/SplitPaneWithDetails.qml b/.config/quickshell/caelestia/modules/controlcenter/components/SplitPaneWithDetails.qml new file mode 100644 index 0000000..ce8c9d0 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/components/SplitPaneWithDetails.qml @@ -0,0 +1,93 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.effects +import qs.components.containers +import qs.config +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Component leftContent + required property Component rightDetailsComponent + required property Component rightSettingsComponent + + property var activeItem: null + property var paneIdGenerator: function (item) { + return item ? String(item) : ""; + } + + property Component overlayComponent: null + + SplitPaneLayout { + id: splitLayout + + anchors.fill: parent + + leftContent: root.leftContent + + rightContent: Component { + Item { + id: rightPaneItem + + property var pane: root.activeItem + property string paneId: root.paneIdGenerator(pane) + property Component targetComponent: root.rightSettingsComponent + property Component nextComponent: root.rightSettingsComponent + + function getComponentForPane() { + return pane ? root.rightDetailsComponent : root.rightSettingsComponent; + } + + Component.onCompleted: { + targetComponent = getComponentForPane(); + nextComponent = targetComponent; + } + + Loader { + id: rightLoader + + anchors.fill: parent + + opacity: 1 + scale: 1 + transformOrigin: Item.Center + + clip: false + sourceComponent: rightPaneItem.targetComponent + } + + Behavior on paneId { + PaneTransition { + target: rightLoader + propertyActions: [ + PropertyAction { + target: rightPaneItem + property: "targetComponent" + value: rightPaneItem.nextComponent + } + ] + } + } + + onPaneChanged: { + nextComponent = getComponentForPane(); + paneId = root.paneIdGenerator(pane); + } + } + } + } + + Loader { + id: overlayLoader + + anchors.fill: parent + z: 1000 + sourceComponent: root.overlayComponent + active: root.overlayComponent !== null + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/components/WallpaperGrid.qml b/.config/quickshell/caelestia/modules/controlcenter/components/WallpaperGrid.qml new file mode 100644 index 0000000..ed6bb40 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/components/WallpaperGrid.qml @@ -0,0 +1,233 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.images +import qs.services +import qs.config +import Caelestia.Models +import QtQuick + +GridView { + id: root + + required property Session session + + readonly property int minCellWidth: 200 + Appearance.spacing.normal + readonly property int columnsCount: Math.max(1, Math.floor(width / minCellWidth)) + + cellWidth: width / columnsCount + cellHeight: 140 + Appearance.spacing.normal + + model: Wallpapers.list + + clip: true + + StyledScrollBar.vertical: StyledScrollBar { + flickable: root + } + + delegate: Item { + required property var modelData + required property int index + + width: root.cellWidth + height: root.cellHeight + + readonly property bool isCurrent: modelData && modelData.path === Wallpapers.actualCurrent + readonly property real itemMargin: Appearance.spacing.normal / 2 + readonly property real itemRadius: Appearance.rounding.normal + + StateLayer { + anchors.fill: parent + anchors.leftMargin: itemMargin + anchors.rightMargin: itemMargin + anchors.topMargin: itemMargin + anchors.bottomMargin: itemMargin + radius: itemRadius + + function onClicked(): void { + Wallpapers.setWallpaper(modelData.path); + } + } + + StyledClippingRect { + id: image + + anchors.fill: parent + anchors.leftMargin: itemMargin + anchors.rightMargin: itemMargin + anchors.topMargin: itemMargin + anchors.bottomMargin: itemMargin + color: Colours.tPalette.m3surfaceContainer + radius: itemRadius + antialiasing: true + layer.enabled: true + layer.smooth: true + + CachingImage { + id: cachingImage + + path: modelData.path + anchors.fill: parent + fillMode: Image.PreserveAspectCrop + cache: true + visible: opacity > 0 + antialiasing: true + smooth: true + sourceSize: Qt.size(width, height) + + opacity: status === Image.Ready ? 1 : 0 + + Behavior on opacity { + NumberAnimation { + duration: 1000 + easing.type: Easing.OutQuad + } + } + } + + // Fallback if CachingImage fails to load + Image { + id: fallbackImage + + anchors.fill: parent + source: fallbackTimer.triggered && cachingImage.status !== Image.Ready ? modelData.path : "" + asynchronous: true + fillMode: Image.PreserveAspectCrop + cache: true + visible: opacity > 0 + antialiasing: true + smooth: true + sourceSize: Qt.size(width, height) + + opacity: status === Image.Ready && cachingImage.status !== Image.Ready ? 1 : 0 + + Behavior on opacity { + NumberAnimation { + duration: 1000 + easing.type: Easing.OutQuad + } + } + } + + Timer { + id: fallbackTimer + + property bool triggered: false + interval: 800 + running: cachingImage.status === Image.Loading || cachingImage.status === Image.Null + onTriggered: triggered = true + } + + // Gradient overlay for filename + Rectangle { + id: filenameOverlay + + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + implicitHeight: filenameText.implicitHeight + Appearance.padding.normal * 1.5 + radius: 0 + + gradient: Gradient { + GradientStop { + position: 0.0 + color: Qt.rgba(Colours.palette.m3surface.r, Colours.palette.m3surface.g, Colours.palette.m3surface.b, 0) + } + GradientStop { + position: 0.3 + color: Qt.rgba(Colours.palette.m3surface.r, Colours.palette.m3surface.g, Colours.palette.m3surface.b, 0.7) + } + GradientStop { + position: 0.6 + color: Qt.rgba(Colours.palette.m3surface.r, Colours.palette.m3surface.g, Colours.palette.m3surface.b, 0.9) + } + GradientStop { + position: 1.0 + color: Qt.rgba(Colours.palette.m3surface.r, Colours.palette.m3surface.g, Colours.palette.m3surface.b, 0.95) + } + } + + opacity: 0 + + Behavior on opacity { + NumberAnimation { + duration: 1000 + easing.type: Easing.OutCubic + } + } + + Component.onCompleted: { + opacity = 1; + } + } + } + + Rectangle { + anchors.fill: parent + anchors.leftMargin: itemMargin + anchors.rightMargin: itemMargin + anchors.topMargin: itemMargin + anchors.bottomMargin: itemMargin + color: "transparent" + radius: itemRadius + border.width + border.width: isCurrent ? 2 : 0 + border.color: Colours.palette.m3primary + antialiasing: true + smooth: true + + Behavior on border.width { + NumberAnimation { + duration: 150 + easing.type: Easing.OutQuad + } + } + + MaterialIcon { + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: Appearance.padding.small + + visible: isCurrent + text: "check_circle" + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.large + } + } + + StyledText { + id: filenameText + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.leftMargin: Appearance.padding.normal + Appearance.spacing.normal / 2 + anchors.rightMargin: Appearance.padding.normal + Appearance.spacing.normal / 2 + anchors.bottomMargin: Appearance.padding.normal + + text: modelData.name + font.pointSize: Appearance.font.size.smaller + font.weight: 500 + color: isCurrent ? Colours.palette.m3primary : Colours.palette.m3onSurface + elide: Text.ElideMiddle + maximumLineCount: 1 + horizontalAlignment: Text.AlignHCenter + + opacity: 0 + + Behavior on opacity { + NumberAnimation { + duration: 1000 + easing.type: Easing.OutCubic + } + } + + Component.onCompleted: { + opacity = 1; + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/dashboard/DashboardPane.qml b/.config/quickshell/caelestia/modules/controlcenter/dashboard/DashboardPane.qml new file mode 100644 index 0000000..72e3e6e --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/dashboard/DashboardPane.qml @@ -0,0 +1,123 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Session session + + // General Settings + property bool enabled: Config.dashboard.enabled ?? true + property bool showOnHover: Config.dashboard.showOnHover ?? true + property int updateInterval: Config.dashboard.updateInterval ?? 1000 + property int dragThreshold: Config.dashboard.dragThreshold ?? 50 + + // Performance Resources + property bool showBattery: Config.dashboard.performance.showBattery ?? false + property bool showGpu: Config.dashboard.performance.showGpu ?? true + property bool showCpu: Config.dashboard.performance.showCpu ?? true + property bool showMemory: Config.dashboard.performance.showMemory ?? true + property bool showStorage: Config.dashboard.performance.showStorage ?? true + property bool showNetwork: Config.dashboard.performance.showNetwork ?? true + + anchors.fill: parent + + function saveConfig() { + Config.dashboard.enabled = root.enabled; + Config.dashboard.showOnHover = root.showOnHover; + Config.dashboard.updateInterval = root.updateInterval; + Config.dashboard.dragThreshold = root.dragThreshold; + Config.dashboard.performance.showBattery = root.showBattery; + Config.dashboard.performance.showGpu = root.showGpu; + Config.dashboard.performance.showCpu = root.showCpu; + Config.dashboard.performance.showMemory = root.showMemory; + Config.dashboard.performance.showStorage = root.showStorage; + Config.dashboard.performance.showNetwork = root.showNetwork; + // Note: sizes properties are readonly and cannot be modified + Config.save(); + } + + ClippingRectangle { + id: dashboardClippingRect + anchors.fill: parent + anchors.margins: Appearance.padding.normal + anchors.leftMargin: 0 + anchors.rightMargin: Appearance.padding.normal + + radius: dashboardBorder.innerRadius + color: "transparent" + + Loader { + id: dashboardLoader + + anchors.fill: parent + anchors.margins: Appearance.padding.large + Appearance.padding.normal + anchors.leftMargin: Appearance.padding.large + anchors.rightMargin: Appearance.padding.large + + sourceComponent: dashboardContentComponent + } + } + + InnerBorder { + id: dashboardBorder + leftThickness: 0 + rightThickness: Appearance.padding.normal + } + + Component { + id: dashboardContentComponent + + StyledFlickable { + id: dashboardFlickable + flickableDirection: Flickable.VerticalFlick + contentHeight: dashboardLayout.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: dashboardFlickable + } + + ColumnLayout { + id: dashboardLayout + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + + spacing: Appearance.spacing.normal + + RowLayout { + spacing: Appearance.spacing.smaller + + StyledText { + text: qsTr("Dashboard") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + } + + // General Settings Section + GeneralSection { + rootItem: root + } + + // Performance Resources Section + PerformanceSection { + rootItem: root + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/dashboard/GeneralSection.qml b/.config/quickshell/caelestia/modules/controlcenter/dashboard/GeneralSection.qml new file mode 100644 index 0000000..bf54e97 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/dashboard/GeneralSection.qml @@ -0,0 +1,81 @@ +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +SectionContainer { + id: root + + required property var rootItem + + Layout.fillWidth: true + alignTop: true + + StyledText { + text: qsTr("General Settings") + font.pointSize: Appearance.font.size.normal + } + + SwitchRow { + label: qsTr("Enabled") + checked: root.rootItem.enabled + onToggled: checked => { + root.rootItem.enabled = checked; + root.rootItem.saveConfig(); + } + } + + SwitchRow { + label: qsTr("Show on hover") + checked: root.rootItem.showOnHover + onToggled: checked => { + root.rootItem.showOnHover = checked; + root.rootItem.saveConfig(); + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Update interval") + value: root.rootItem.updateInterval + from: 100 + to: 10000 + stepSize: 100 + suffix: "ms" + validator: IntValidator { bottom: 100; top: 10000 } + formatValueFunction: (val) => Math.round(val).toString() + parseValueFunction: (text) => parseInt(text) + + onValueModified: (newValue) => { + root.rootItem.updateInterval = Math.round(newValue); + root.rootItem.saveConfig(); + } + } + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Drag threshold") + value: root.rootItem.dragThreshold + from: 0 + to: 100 + suffix: "px" + validator: IntValidator { bottom: 0; top: 100 } + formatValueFunction: (val) => Math.round(val).toString() + parseValueFunction: (text) => parseInt(text) + + onValueModified: (newValue) => { + root.rootItem.dragThreshold = Math.round(newValue); + root.rootItem.saveConfig(); + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/dashboard/PerformanceSection.qml b/.config/quickshell/caelestia/modules/controlcenter/dashboard/PerformanceSection.qml new file mode 100644 index 0000000..7e72782 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/dashboard/PerformanceSection.qml @@ -0,0 +1,85 @@ +import ".." +import "../components" +import QtQuick +import QtQuick.Layouts +import Quickshell.Services.UPower +import qs.components +import qs.components.controls +import qs.config +import qs.services + +SectionContainer { + id: root + + required property var rootItem + // GPU toggle is hidden when gpuType is "NONE" (no GPU data available) + readonly property bool gpuAvailable: SystemUsage.gpuType !== "NONE" + // Battery toggle is hidden when no laptop battery is present + readonly property bool batteryAvailable: UPower.displayDevice.isLaptopBattery + + Layout.fillWidth: true + alignTop: true + + StyledText { + text: qsTr("Performance Resources") + font.pointSize: Appearance.font.size.normal + } + + ConnectedButtonGroup { + rootItem: root.rootItem + options: { + let opts = []; + if (root.batteryAvailable) + opts.push({ + "label": qsTr("Battery"), + "propertyName": "showBattery", + "onToggled": function(checked) { + root.rootItem.showBattery = checked; + root.rootItem.saveConfig(); + } + }); + + if (root.gpuAvailable) + opts.push({ + "label": qsTr("GPU"), + "propertyName": "showGpu", + "onToggled": function(checked) { + root.rootItem.showGpu = checked; + root.rootItem.saveConfig(); + } + }); + + opts.push({ + "label": qsTr("CPU"), + "propertyName": "showCpu", + "onToggled": function(checked) { + root.rootItem.showCpu = checked; + root.rootItem.saveConfig(); + } + }, { + "label": qsTr("Memory"), + "propertyName": "showMemory", + "onToggled": function(checked) { + root.rootItem.showMemory = checked; + root.rootItem.saveConfig(); + } + }, { + "label": qsTr("Storage"), + "propertyName": "showStorage", + "onToggled": function(checked) { + root.rootItem.showStorage = checked; + root.rootItem.saveConfig(); + } + }, { + "label": qsTr("Network"), + "propertyName": "showNetwork", + "onToggled": function(checked) { + root.rootItem.showNetwork = checked; + root.rootItem.saveConfig(); + } + }); + return opts; + } + } + +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/launcher/LauncherPane.qml b/.config/quickshell/caelestia/modules/controlcenter/launcher/LauncherPane.qml new file mode 100644 index 0000000..b236cf9 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/launcher/LauncherPane.qml @@ -0,0 +1,658 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import "../../launcher/services" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import Caelestia +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts +import "../../../utils/scripts/fuzzysort.js" as Fuzzy + +Item { + id: root + + required property Session session + + property var selectedApp: root.session.launcher.active + property bool hideFromLauncherChecked: false + property bool favouriteChecked: false + + anchors.fill: parent + + onSelectedAppChanged: { + root.session.launcher.active = root.selectedApp; + updateToggleState(); + } + + Connections { + target: root.session.launcher + function onActiveChanged() { + root.selectedApp = root.session.launcher.active; + updateToggleState(); + } + } + + function updateToggleState() { + if (!root.selectedApp) { + root.hideFromLauncherChecked = false; + root.favouriteChecked = false; + return; + } + + const appId = root.selectedApp.id || root.selectedApp.entry?.id; + + root.hideFromLauncherChecked = Config.launcher.hiddenApps && Config.launcher.hiddenApps.length > 0 && Strings.testRegexList(Config.launcher.hiddenApps, appId); + root.favouriteChecked = Config.launcher.favouriteApps && Config.launcher.favouriteApps.length > 0 && Strings.testRegexList(Config.launcher.favouriteApps, appId); + } + + function saveHiddenApps(isHidden) { + if (!root.selectedApp) { + return; + } + + const appId = root.selectedApp.id || root.selectedApp.entry?.id; + + const hiddenApps = Config.launcher.hiddenApps ? [...Config.launcher.hiddenApps] : []; + + if (isHidden) { + if (!hiddenApps.includes(appId)) { + hiddenApps.push(appId); + } + } else { + const index = hiddenApps.indexOf(appId); + if (index !== -1) { + hiddenApps.splice(index, 1); + } + } + + Config.launcher.hiddenApps = hiddenApps; + Config.save(); + } + + AppDb { + id: allAppsDb + + path: `${Paths.state}/apps.sqlite` + favouriteApps: Config.launcher.favouriteApps + entries: DesktopEntries.applications.values + } + + property string searchText: "" + + function filterApps(search: string): list { + if (!search || search.trim() === "") { + const apps = []; + for (let i = 0; i < allAppsDb.apps.length; i++) { + apps.push(allAppsDb.apps[i]); + } + return apps; + } + + if (!allAppsDb.apps || allAppsDb.apps.length === 0) { + return []; + } + + const preparedApps = []; + for (let i = 0; i < allAppsDb.apps.length; i++) { + const app = allAppsDb.apps[i]; + const name = app.name || app.entry?.name || ""; + preparedApps.push({ + _item: app, + name: Fuzzy.prepare(name) + }); + } + + const results = Fuzzy.go(search, preparedApps, { + all: true, + keys: ["name"], + scoreFn: r => r[0].score + }); + + return results.sort((a, b) => b._score - a._score).map(r => r.obj._item); + } + + property list filteredApps: [] + + function updateFilteredApps() { + filteredApps = filterApps(searchText); + } + + onSearchTextChanged: { + updateFilteredApps(); + } + + Component.onCompleted: { + updateFilteredApps(); + } + + Connections { + target: allAppsDb + function onAppsChanged() { + updateFilteredApps(); + } + } + + SplitPaneLayout { + anchors.fill: parent + + leftContent: Component { + + ColumnLayout { + id: leftLauncherLayout + anchors.fill: parent + + spacing: Appearance.spacing.small + + RowLayout { + spacing: Appearance.spacing.smaller + + StyledText { + text: qsTr("Launcher") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + + ToggleButton { + toggled: !root.session.launcher.active + icon: "settings" + accent: "Primary" + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + tooltip: qsTr("Launcher settings") + + onClicked: { + if (root.session.launcher.active) { + root.session.launcher.active = null; + } else { + if (root.filteredApps.length > 0) { + root.session.launcher.active = root.filteredApps[0]; + } + } + } + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Applications (%1)").arg(root.searchText ? root.filteredApps.length : allAppsDb.apps.length) + font.pointSize: Appearance.font.size.normal + font.weight: 500 + } + + StyledText { + text: qsTr("All applications available in the launcher") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + Layout.topMargin: Appearance.spacing.normal + Layout.bottomMargin: Appearance.spacing.small + + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + radius: Appearance.rounding.full + + implicitHeight: Math.max(searchIcon.implicitHeight, searchField.implicitHeight, clearIcon.implicitHeight) + + MaterialIcon { + id: searchIcon + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Appearance.padding.normal + + text: "search" + color: Colours.palette.m3onSurfaceVariant + } + + StyledTextField { + id: searchField + + anchors.left: searchIcon.right + anchors.right: clearIcon.left + anchors.leftMargin: Appearance.spacing.small + anchors.rightMargin: Appearance.spacing.small + + topPadding: Appearance.padding.normal + bottomPadding: Appearance.padding.normal + + placeholderText: qsTr("Search applications...") + + onTextChanged: { + root.searchText = text; + } + } + + MaterialIcon { + id: clearIcon + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: Appearance.padding.normal + + width: searchField.text ? implicitWidth : implicitWidth / 2 + opacity: { + if (!searchField.text) + return 0; + if (clearMouse.pressed) + return 0.7; + if (clearMouse.containsMouse) + return 0.8; + return 1; + } + + text: "close" + color: Colours.palette.m3onSurfaceVariant + + MouseArea { + id: clearMouse + + anchors.fill: parent + hoverEnabled: true + cursorShape: searchField.text ? Qt.PointingHandCursor : undefined + + onClicked: searchField.text = "" + } + + Behavior on width { + Anim { + duration: Appearance.anim.durations.small + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.small + } + } + } + } + + Loader { + id: appsListLoader + Layout.fillWidth: true + Layout.fillHeight: true + asynchronous: true + active: true + + sourceComponent: StyledListView { + id: appsListView + + Layout.fillWidth: true + Layout.fillHeight: true + + model: root.filteredApps + spacing: Appearance.spacing.small / 2 + clip: true + + StyledScrollBar.vertical: StyledScrollBar { + flickable: parent + } + + delegate: StyledRect { + required property var modelData + + width: parent ? parent.width : 0 + implicitHeight: 40 + + readonly property bool isSelected: root.selectedApp === modelData + + color: isSelected ? Colours.layer(Colours.palette.m3surfaceContainer, 2) : "transparent" + radius: Appearance.rounding.normal + + opacity: 0 + + Behavior on opacity { + NumberAnimation { + duration: 1000 + easing.type: Easing.OutCubic + } + } + + Component.onCompleted: { + opacity = 1; + } + + StateLayer { + function onClicked(): void { + root.session.launcher.active = modelData; + } + } + + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + IconImage { + Layout.alignment: Qt.AlignVCenter + implicitSize: 32 + source: { + const entry = modelData.entry; + return entry ? Quickshell.iconPath(entry.icon, "image-missing") : "image-missing"; + } + } + + StyledText { + Layout.fillWidth: true + text: modelData.name || modelData.entry?.name || qsTr("Unknown") + font.pointSize: Appearance.font.size.normal + } + + Loader { + Layout.alignment: Qt.AlignVCenter + readonly property bool isHidden: modelData ? Strings.testRegexList(Config.launcher.hiddenApps, modelData.id) : false + readonly property bool isFav: modelData ? Strings.testRegexList(Config.launcher.favouriteApps, modelData.id) : false + active: isHidden || isFav + + sourceComponent: isHidden ? hiddenIcon : (isFav ? favouriteIcon : null) + } + + Component { + id: hiddenIcon + MaterialIcon { + text: "visibility_off" + fill: 1 + color: Colours.palette.m3primary + } + } + + Component { + id: favouriteIcon + MaterialIcon { + text: "favorite" + fill: 1 + color: Colours.palette.m3primary + } + } + } + } + } + } + } + } + + rightContent: Component { + Item { + id: rightLauncherPane + + property var pane: root.session.launcher.active + property string paneId: pane ? (pane.id || pane.entry?.id || "") : "" + property Component targetComponent: settings + property Component nextComponent: settings + property var displayedApp: null + + function getComponentForPane() { + return pane ? appDetails : settings; + } + + Component.onCompleted: { + displayedApp = pane; + targetComponent = getComponentForPane(); + nextComponent = targetComponent; + } + + Loader { + id: rightLauncherLoader + + anchors.fill: parent + + opacity: 1 + scale: 1 + transformOrigin: Item.Center + clip: false + + sourceComponent: rightLauncherPane.targetComponent + active: true + + property var displayedApp: rightLauncherPane.displayedApp + + onItemChanged: { + if (item && rightLauncherPane.pane && rightLauncherPane.displayedApp !== rightLauncherPane.pane) { + rightLauncherPane.displayedApp = rightLauncherPane.pane; + } + } + } + + Behavior on paneId { + PaneTransition { + target: rightLauncherLoader + propertyActions: [ + PropertyAction { + target: rightLauncherPane + property: "displayedApp" + value: rightLauncherPane.pane + }, + PropertyAction { + target: rightLauncherLoader + property: "active" + value: false + }, + PropertyAction { + target: rightLauncherPane + property: "targetComponent" + value: rightLauncherPane.nextComponent + }, + PropertyAction { + target: rightLauncherLoader + property: "active" + value: true + } + ] + } + } + + onPaneChanged: { + nextComponent = getComponentForPane(); + paneId = pane ? (pane.id || pane.entry?.id || "") : ""; + } + + onDisplayedAppChanged: { + if (displayedApp) { + const appId = displayedApp.id || displayedApp.entry?.id; + root.hideFromLauncherChecked = Config.launcher.hiddenApps && Config.launcher.hiddenApps.length > 0 && Strings.testRegexList(Config.launcher.hiddenApps, appId); + root.favouriteChecked = Config.launcher.favouriteApps && Config.launcher.favouriteApps.length > 0 && Strings.testRegexList(Config.launcher.favouriteApps, appId); + } else { + root.hideFromLauncherChecked = false; + root.favouriteChecked = false; + } + } + } + } + } + + Component { + id: settings + + StyledFlickable { + id: settingsFlickable + flickableDirection: Flickable.VerticalFlick + contentHeight: settingsInner.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: settingsFlickable + } + + Settings { + id: settingsInner + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + session: root.session + } + } + } + + Component { + id: appDetails + + ColumnLayout { + id: appDetailsLayout + anchors.fill: parent + + readonly property var displayedApp: parent && parent.displayedApp !== undefined ? parent.displayedApp : null + + spacing: Appearance.spacing.normal + + SettingsHeader { + Layout.leftMargin: Appearance.padding.large * 2 + Layout.rightMargin: Appearance.padding.large * 2 + Layout.topMargin: Appearance.padding.large * 2 + visible: displayedApp === null + icon: "apps" + title: qsTr("Launcher Applications") + } + + Item { + Layout.alignment: Qt.AlignHCenter + Layout.leftMargin: Appearance.padding.large * 2 + Layout.rightMargin: Appearance.padding.large * 2 + Layout.topMargin: Appearance.padding.large * 2 + visible: displayedApp !== null + implicitWidth: Math.max(appIconImage.implicitWidth, appTitleText.implicitWidth) + implicitHeight: appIconImage.implicitHeight + Appearance.spacing.normal + appTitleText.implicitHeight + + ColumnLayout { + anchors.centerIn: parent + spacing: Appearance.spacing.normal + + IconImage { + id: appIconImage + Layout.alignment: Qt.AlignHCenter + implicitSize: Appearance.font.size.extraLarge * 3 * 2 + source: { + const app = appDetailsLayout.displayedApp; + if (!app) + return "image-missing"; + const entry = app.entry; + if (entry && entry.icon) { + return Quickshell.iconPath(entry.icon, "image-missing"); + } + return "image-missing"; + } + } + + StyledText { + id: appTitleText + Layout.alignment: Qt.AlignHCenter + text: displayedApp ? (displayedApp.name || displayedApp.entry?.name || qsTr("Application Details")) : "" + font.pointSize: Appearance.font.size.large + font.bold: true + } + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.topMargin: Appearance.spacing.large + Layout.leftMargin: Appearance.padding.large * 2 + Layout.rightMargin: Appearance.padding.large * 2 + + StyledFlickable { + id: detailsFlickable + anchors.fill: parent + flickableDirection: Flickable.VerticalFlick + contentHeight: debugLayout.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: parent + } + + ColumnLayout { + id: debugLayout + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + spacing: Appearance.spacing.normal + + SwitchRow { + Layout.topMargin: Appearance.spacing.normal + visible: appDetailsLayout.displayedApp !== null + label: qsTr("Mark as favourite") + checked: root.favouriteChecked + // disabled if: + // * app is hidden + // * app isn't in favouriteApps array but marked as favourite anyway + // ^^^ This means that this app is favourited because of a regex check + // this button can not toggle regexed apps + enabled: appDetailsLayout.displayedApp !== null && !root.hideFromLauncherChecked && (Config.launcher.favouriteApps.indexOf(appDetailsLayout.displayedApp.id || appDetailsLayout.displayedApp.entry?.id) !== -1 || !root.favouriteChecked) + opacity: enabled ? 1 : 0.6 + onToggled: checked => { + root.favouriteChecked = checked; + const app = appDetailsLayout.displayedApp; + if (app) { + const appId = app.id || app.entry?.id; + const favouriteApps = Config.launcher.favouriteApps ? [...Config.launcher.favouriteApps] : []; + if (checked) { + if (!favouriteApps.includes(appId)) { + favouriteApps.push(appId); + } + } else { + const index = favouriteApps.indexOf(appId); + if (index !== -1) { + favouriteApps.splice(index, 1); + } + } + Config.launcher.favouriteApps = favouriteApps; + Config.save(); + } + } + } + SwitchRow { + Layout.topMargin: Appearance.spacing.normal + visible: appDetailsLayout.displayedApp !== null + label: qsTr("Hide from launcher") + checked: root.hideFromLauncherChecked + // disabled if: + // * app is favourited + // * app isn't in hiddenApps array but marked as hidden anyway + // ^^^ This means that this app is hidden because of a regex check + // this button can not toggle regexed apps + enabled: appDetailsLayout.displayedApp !== null && !root.favouriteChecked && (Config.launcher.hiddenApps.indexOf(appDetailsLayout.displayedApp.id || appDetailsLayout.displayedApp.entry?.id) !== -1 || !root.hideFromLauncherChecked) + opacity: enabled ? 1 : 0.6 + onToggled: checked => { + root.hideFromLauncherChecked = checked; + const app = appDetailsLayout.displayedApp; + if (app) { + const appId = app.id || app.entry?.id; + const hiddenApps = Config.launcher.hiddenApps ? [...Config.launcher.hiddenApps] : []; + if (checked) { + if (!hiddenApps.includes(appId)) { + hiddenApps.push(appId); + } + } else { + const index = hiddenApps.indexOf(appId); + if (index !== -1) { + hiddenApps.splice(index, 1); + } + } + Config.launcher.hiddenApps = hiddenApps; + Config.save(); + } + } + } + } + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/launcher/Settings.qml b/.config/quickshell/caelestia/modules/controlcenter/launcher/Settings.qml new file mode 100644 index 0000000..5eaf6e0 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/launcher/Settings.qml @@ -0,0 +1,217 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property Session session + + spacing: Appearance.spacing.normal + + SettingsHeader { + icon: "apps" + title: qsTr("Launcher Settings") + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("General") + description: qsTr("General launcher settings") + } + + SectionContainer { + ToggleRow { + label: qsTr("Enabled") + checked: Config.launcher.enabled + toggle.onToggled: { + Config.launcher.enabled = checked; + Config.save(); + } + } + + ToggleRow { + label: qsTr("Show on hover") + checked: Config.launcher.showOnHover + toggle.onToggled: { + Config.launcher.showOnHover = checked; + Config.save(); + } + } + + ToggleRow { + label: qsTr("Vim keybinds") + checked: Config.launcher.vimKeybinds + toggle.onToggled: { + Config.launcher.vimKeybinds = checked; + Config.save(); + } + } + + ToggleRow { + label: qsTr("Enable dangerous actions") + checked: Config.launcher.enableDangerousActions + toggle.onToggled: { + Config.launcher.enableDangerousActions = checked; + Config.save(); + } + } + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("Display") + description: qsTr("Display and appearance settings") + } + + SectionContainer { + contentSpacing: Appearance.spacing.small / 2 + + PropertyRow { + label: qsTr("Max shown items") + value: qsTr("%1").arg(Config.launcher.maxShown) + } + + PropertyRow { + showTopMargin: true + label: qsTr("Max wallpapers") + value: qsTr("%1").arg(Config.launcher.maxWallpapers) + } + + PropertyRow { + showTopMargin: true + label: qsTr("Drag threshold") + value: qsTr("%1 px").arg(Config.launcher.dragThreshold) + } + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("Prefixes") + description: qsTr("Command prefix settings") + } + + SectionContainer { + contentSpacing: Appearance.spacing.small / 2 + + PropertyRow { + label: qsTr("Special prefix") + value: Config.launcher.specialPrefix || qsTr("None") + } + + PropertyRow { + showTopMargin: true + label: qsTr("Action prefix") + value: Config.launcher.actionPrefix || qsTr("None") + } + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("Fuzzy search") + description: qsTr("Fuzzy search settings") + } + + SectionContainer { + ToggleRow { + label: qsTr("Apps") + checked: Config.launcher.useFuzzy.apps + toggle.onToggled: { + Config.launcher.useFuzzy.apps = checked; + Config.save(); + } + } + + ToggleRow { + label: qsTr("Actions") + checked: Config.launcher.useFuzzy.actions + toggle.onToggled: { + Config.launcher.useFuzzy.actions = checked; + Config.save(); + } + } + + ToggleRow { + label: qsTr("Schemes") + checked: Config.launcher.useFuzzy.schemes + toggle.onToggled: { + Config.launcher.useFuzzy.schemes = checked; + Config.save(); + } + } + + ToggleRow { + label: qsTr("Variants") + checked: Config.launcher.useFuzzy.variants + toggle.onToggled: { + Config.launcher.useFuzzy.variants = checked; + Config.save(); + } + } + + ToggleRow { + label: qsTr("Wallpapers") + checked: Config.launcher.useFuzzy.wallpapers + toggle.onToggled: { + Config.launcher.useFuzzy.wallpapers = checked; + Config.save(); + } + } + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("Sizes") + description: qsTr("Size settings for launcher items") + } + + SectionContainer { + contentSpacing: Appearance.spacing.small / 2 + + PropertyRow { + label: qsTr("Item width") + value: qsTr("%1 px").arg(Config.launcher.sizes.itemWidth) + } + + PropertyRow { + showTopMargin: true + label: qsTr("Item height") + value: qsTr("%1 px").arg(Config.launcher.sizes.itemHeight) + } + + PropertyRow { + showTopMargin: true + label: qsTr("Wallpaper width") + value: qsTr("%1 px").arg(Config.launcher.sizes.wallpaperWidth) + } + + PropertyRow { + showTopMargin: true + label: qsTr("Wallpaper height") + value: qsTr("%1 px").arg(Config.launcher.sizes.wallpaperHeight) + } + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("Hidden apps") + description: qsTr("Applications hidden from launcher") + } + + SectionContainer { + contentSpacing: Appearance.spacing.small / 2 + + PropertyRow { + label: qsTr("Total hidden") + value: qsTr("%1").arg(Config.launcher.hiddenApps ? Config.launcher.hiddenApps.length : 0) + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/EthernetDetails.qml b/.config/quickshell/caelestia/modules/controlcenter/network/EthernetDetails.qml new file mode 100644 index 0000000..4e60b3d --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/EthernetDetails.qml @@ -0,0 +1,118 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +DeviceDetails { + id: root + + required property Session session + readonly property var ethernetDevice: root.session.ethernet.active + + device: ethernetDevice + + Component.onCompleted: { + if (ethernetDevice && ethernetDevice.interface) { + Nmcli.getEthernetDeviceDetails(ethernetDevice.interface, () => {}); + } + } + + onEthernetDeviceChanged: { + if (ethernetDevice && ethernetDevice.interface) { + Nmcli.getEthernetDeviceDetails(ethernetDevice.interface, () => {}); + } else { + Nmcli.ethernetDeviceDetails = null; + } + } + + headerComponent: Component { + ConnectionHeader { + icon: "cable" + title: root.ethernetDevice?.interface ?? qsTr("Unknown") + } + } + + sections: [ + Component { + ColumnLayout { + spacing: Appearance.spacing.normal + + SectionHeader { + title: qsTr("Connection status") + description: qsTr("Connection settings for this device") + } + + SectionContainer { + ToggleRow { + label: qsTr("Connected") + checked: root.ethernetDevice?.connected ?? false + toggle.onToggled: { + if (checked) { + Nmcli.connectEthernet(root.ethernetDevice?.connection || "", root.ethernetDevice?.interface || "", () => {}); + } else { + if (root.ethernetDevice?.connection) { + Nmcli.disconnectEthernet(root.ethernetDevice.connection, () => {}); + } + } + } + } + } + } + }, + Component { + ColumnLayout { + spacing: Appearance.spacing.normal + + SectionHeader { + title: qsTr("Device properties") + description: qsTr("Additional information") + } + + SectionContainer { + contentSpacing: Appearance.spacing.small / 2 + + PropertyRow { + label: qsTr("Interface") + value: root.ethernetDevice?.interface ?? qsTr("Unknown") + } + + PropertyRow { + showTopMargin: true + label: qsTr("Connection") + value: root.ethernetDevice?.connection || qsTr("Not connected") + } + + PropertyRow { + showTopMargin: true + label: qsTr("State") + value: root.ethernetDevice?.state ?? qsTr("Unknown") + } + } + } + }, + Component { + ColumnLayout { + spacing: Appearance.spacing.normal + + SectionHeader { + title: qsTr("Connection information") + description: qsTr("Network connection details") + } + + SectionContainer { + ConnectionInfoSection { + deviceDetails: Nmcli.ethernetDeviceDetails + } + } + } + } + ] +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/EthernetList.qml b/.config/quickshell/caelestia/modules/controlcenter/network/EthernetList.qml new file mode 100644 index 0000000..d1eb957 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/EthernetList.qml @@ -0,0 +1,177 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +DeviceList { + id: root + + required property Session session + + title: qsTr("Devices (%1)").arg(Nmcli.ethernetDevices.length) + description: qsTr("All available ethernet devices") + activeItem: session.ethernet.active + + model: Nmcli.ethernetDevices + + headerComponent: Component { + RowLayout { + spacing: Appearance.spacing.smaller + + StyledText { + text: qsTr("Settings") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + + ToggleButton { + toggled: !root.session.ethernet.active + icon: "settings" + accent: "Primary" + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + + onClicked: { + if (root.session.ethernet.active) + root.session.ethernet.active = null; + else { + root.session.ethernet.active = root.view.model.get(0)?.modelData ?? null; + } + } + } + } + } + + delegate: Component { + StyledRect { + id: ethernetItem + + required property var modelData + readonly property bool isActive: root.activeItem && modelData && root.activeItem.interface === modelData.interface + + width: ListView.view ? ListView.view.width : undefined + implicitHeight: rowLayout.implicitHeight + Appearance.padding.normal * 2 + + color: Qt.alpha(Colours.tPalette.m3surfaceContainer, ethernetItem.isActive ? Colours.tPalette.m3surfaceContainer.a : 0) + radius: Appearance.rounding.normal + + StateLayer { + id: stateLayer + + function onClicked(): void { + root.session.ethernet.active = modelData; + } + } + + RowLayout { + id: rowLayout + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2 + + radius: Appearance.rounding.normal + color: modelData.connected ? Colours.palette.m3primaryContainer : Colours.tPalette.m3surfaceContainerHigh + + StyledRect { + anchors.fill: parent + radius: parent.radius + color: Qt.alpha(modelData.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface, stateLayer.pressed ? 0.1 : stateLayer.containsMouse ? 0.08 : 0) + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + text: "cable" + font.pointSize: Appearance.font.size.large + fill: modelData.connected ? 1 : 0 + color: modelData.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface + + Behavior on fill { + Anim {} + } + } + } + + ColumnLayout { + Layout.fillWidth: true + + spacing: 0 + + StyledText { + Layout.fillWidth: true + text: modelData.interface || qsTr("Unknown") + elide: Text.ElideRight + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.smaller + + StyledText { + Layout.fillWidth: true + text: modelData.connected ? qsTr("Connected") : qsTr("Disconnected") + color: modelData.connected ? Colours.palette.m3primary : Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + font.weight: modelData.connected ? 500 : 400 + elide: Text.ElideRight + } + } + } + + StyledRect { + id: connectBtn + + implicitWidth: implicitHeight + implicitHeight: connectIcon.implicitHeight + Appearance.padding.smaller * 2 + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3primaryContainer, modelData.connected ? 1 : 0) + + StateLayer { + color: modelData.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface + + function onClicked(): void { + if (modelData.connected && modelData.connection) { + Nmcli.disconnectEthernet(modelData.connection, () => {}); + } else { + Nmcli.connectEthernet(modelData.connection || "", modelData.interface || "", () => {}); + } + } + } + + MaterialIcon { + id: connectIcon + + anchors.centerIn: parent + animate: true + text: modelData.connected ? "link_off" : "link" + color: modelData.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface + } + } + } + } + } + + onItemSelected: function (item) { + session.ethernet.active = item; + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/EthernetPane.qml b/.config/quickshell/caelestia/modules/controlcenter/network/EthernetPane.qml new file mode 100644 index 0000000..59d82bb --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/EthernetPane.qml @@ -0,0 +1,50 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.containers +import qs.config +import Quickshell.Widgets +import QtQuick + +SplitPaneWithDetails { + id: root + + required property Session session + + anchors.fill: parent + + activeItem: session.ethernet.active + paneIdGenerator: function (item) { + return item ? (item.interface || "") : ""; + } + + leftContent: Component { + EthernetList { + session: root.session + } + } + + rightDetailsComponent: Component { + EthernetDetails { + session: root.session + } + } + + rightSettingsComponent: Component { + StyledFlickable { + flickableDirection: Flickable.VerticalFlick + contentHeight: settingsInner.height + clip: true + + EthernetSettings { + id: settingsInner + + anchors.left: parent.left + anchors.right: parent.right + session: root.session + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/EthernetSettings.qml b/.config/quickshell/caelestia/modules/controlcenter/network/EthernetSettings.qml new file mode 100644 index 0000000..90bfcf4 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/EthernetSettings.qml @@ -0,0 +1,76 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property Session session + + spacing: Appearance.spacing.normal + + SettingsHeader { + icon: "cable" + title: qsTr("Ethernet settings") + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Ethernet devices") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("Available ethernet devices") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: ethernetInfo.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: ethernetInfo + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.small / 2 + + StyledText { + text: qsTr("Total devices") + } + + StyledText { + text: qsTr("%1").arg(Nmcli.ethernetDevices.length) + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Connected devices") + } + + StyledText { + text: qsTr("%1").arg(Nmcli.ethernetDevices.filter(d => d.connected).length) + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/NetworkSettings.qml b/.config/quickshell/caelestia/modules/controlcenter/network/NetworkSettings.qml new file mode 100644 index 0000000..bda7cb1 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/NetworkSettings.qml @@ -0,0 +1,171 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property Session session + + spacing: Appearance.spacing.normal + + SettingsHeader { + icon: "router" + title: qsTr("Network Settings") + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("Ethernet") + description: qsTr("Ethernet device information") + } + + SectionContainer { + contentSpacing: Appearance.spacing.small / 2 + + PropertyRow { + label: qsTr("Total devices") + value: qsTr("%1").arg(Nmcli.ethernetDevices.length) + } + + PropertyRow { + showTopMargin: true + label: qsTr("Connected devices") + value: qsTr("%1").arg(Nmcli.ethernetDevices.filter(d => d.connected).length) + } + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("Wireless") + description: qsTr("WiFi network settings") + } + + SectionContainer { + ToggleRow { + label: qsTr("WiFi enabled") + checked: Nmcli.wifiEnabled + toggle.onToggled: { + Nmcli.enableWifi(checked); + } + } + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("VPN") + description: qsTr("VPN provider settings") + visible: Config.utilities.vpn.enabled || Config.utilities.vpn.provider.length > 0 + } + + SectionContainer { + visible: Config.utilities.vpn.enabled || Config.utilities.vpn.provider.length > 0 + + ToggleRow { + label: qsTr("VPN enabled") + checked: Config.utilities.vpn.enabled + toggle.onToggled: { + Config.utilities.vpn.enabled = checked; + Config.save(); + } + } + + PropertyRow { + showTopMargin: true + label: qsTr("Providers") + value: qsTr("%1").arg(Config.utilities.vpn.provider.length) + } + + TextButton { + Layout.fillWidth: true + Layout.topMargin: Appearance.spacing.normal + Layout.minimumHeight: Appearance.font.size.normal + Appearance.padding.normal * 2 + text: qsTr("⚙ Manage VPN Providers") + inactiveColour: Colours.palette.m3secondaryContainer + inactiveOnColour: Colours.palette.m3onSecondaryContainer + + onClicked: { + vpnSettingsDialog.open(); + } + } + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("Current connection") + description: qsTr("Active network connection information") + } + + SectionContainer { + contentSpacing: Appearance.spacing.small / 2 + + PropertyRow { + label: qsTr("Network") + value: Nmcli.active ? Nmcli.active.ssid : (Nmcli.activeEthernet ? Nmcli.activeEthernet.interface : qsTr("Not connected")) + } + + PropertyRow { + showTopMargin: true + visible: Nmcli.active !== null + label: qsTr("Signal strength") + value: Nmcli.active ? qsTr("%1%").arg(Nmcli.active.strength) : qsTr("N/A") + } + + PropertyRow { + showTopMargin: true + visible: Nmcli.active !== null + label: qsTr("Security") + value: Nmcli.active ? (Nmcli.active.isSecure ? qsTr("Secured") : qsTr("Open")) : qsTr("N/A") + } + + PropertyRow { + showTopMargin: true + visible: Nmcli.active !== null + label: qsTr("Frequency") + value: Nmcli.active ? qsTr("%1 MHz").arg(Nmcli.active.frequency) : qsTr("N/A") + } + } + + Popup { + id: vpnSettingsDialog + + parent: Overlay.overlay + anchors.centerIn: parent + width: Math.min(600, parent.width - Appearance.padding.large * 2) + height: Math.min(700, parent.height - Appearance.padding.large * 2) + + modal: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + + background: StyledRect { + color: Colours.palette.m3surface + radius: Appearance.rounding.large + } + + StyledFlickable { + anchors.fill: parent + anchors.margins: Appearance.padding.large * 1.5 + flickableDirection: Flickable.VerticalFlick + contentHeight: vpnSettingsContent.height + clip: true + + VpnSettings { + id: vpnSettingsContent + + anchors.left: parent.left + anchors.right: parent.right + session: root.session + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/NetworkingPane.qml b/.config/quickshell/caelestia/modules/controlcenter/network/NetworkingPane.qml new file mode 100644 index 0000000..26cdbfa --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/NetworkingPane.qml @@ -0,0 +1,373 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import "." +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Session session + + anchors.fill: parent + + SplitPaneLayout { + id: splitLayout + + anchors.fill: parent + + leftContent: Component { + StyledFlickable { + id: leftFlickable + + flickableDirection: Flickable.VerticalFlick + contentHeight: leftContent.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: leftFlickable + } + + ColumnLayout { + id: leftContent + + anchors.left: parent.left + anchors.right: parent.right + spacing: Appearance.spacing.normal + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.smaller + + StyledText { + text: qsTr("Network") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + + ToggleButton { + toggled: Nmcli.wifiEnabled + icon: "wifi" + accent: "Tertiary" + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + tooltip: qsTr("Toggle WiFi") + + onClicked: { + Nmcli.toggleWifi(null); + } + } + + ToggleButton { + toggled: Nmcli.scanning + icon: "wifi_find" + accent: "Secondary" + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + tooltip: qsTr("Scan for networks") + + onClicked: { + Nmcli.rescanWifi(); + } + } + + ToggleButton { + toggled: !root.session.ethernet.active && !root.session.network.active + icon: "settings" + accent: "Primary" + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + tooltip: qsTr("Network settings") + + onClicked: { + if (root.session.ethernet.active || root.session.network.active) { + root.session.ethernet.active = null; + root.session.network.active = null; + } else { + if (Nmcli.ethernetDevices.length > 0) { + root.session.ethernet.active = Nmcli.ethernetDevices[0]; + } else if (Nmcli.networks.length > 0) { + root.session.network.active = Nmcli.networks[0]; + } + } + } + } + } + + CollapsibleSection { + id: vpnListSection + + Layout.fillWidth: true + title: qsTr("VPN") + expanded: true + + Loader { + Layout.fillWidth: true + sourceComponent: Component { + VpnList { + session: root.session + showHeader: false + } + } + } + } + + CollapsibleSection { + id: ethernetListSection + + Layout.fillWidth: true + title: qsTr("Ethernet") + expanded: true + + Loader { + Layout.fillWidth: true + sourceComponent: Component { + EthernetList { + session: root.session + showHeader: false + } + } + } + } + + CollapsibleSection { + id: wirelessListSection + + Layout.fillWidth: true + title: qsTr("Wireless") + expanded: true + + Loader { + Layout.fillWidth: true + sourceComponent: Component { + WirelessList { + session: root.session + showHeader: false + } + } + } + } + } + } + } + + rightContent: Component { + Item { + id: rightPaneItem + + property var vpnPane: root.session && root.session.vpn ? root.session.vpn.active : null + property var ethernetPane: root.session && root.session.ethernet ? root.session.ethernet.active : null + property var wirelessPane: root.session && root.session.network ? root.session.network.active : null + property var pane: vpnPane || ethernetPane || wirelessPane + property string paneId: vpnPane ? ("vpn:" + (vpnPane.name || "")) : (ethernetPane ? ("eth:" + (ethernetPane.interface || "")) : (wirelessPane ? ("wifi:" + (wirelessPane.ssid || wirelessPane.bssid || "")) : "settings")) + property Component targetComponent: settingsComponent + property Component nextComponent: settingsComponent + + function getComponentForPane() { + if (vpnPane) + return vpnDetailsComponent; + if (ethernetPane) + return ethernetDetailsComponent; + if (wirelessPane) + return wirelessDetailsComponent; + return settingsComponent; + } + + Component.onCompleted: { + targetComponent = getComponentForPane(); + nextComponent = targetComponent; + } + + Connections { + target: root.session && root.session.vpn ? root.session.vpn : null + enabled: target !== null + + function onActiveChanged() { + // Clear others when VPN is selected + if (root.session && root.session.vpn && root.session.vpn.active) { + if (root.session.ethernet && root.session.ethernet.active) + root.session.ethernet.active = null; + if (root.session.network && root.session.network.active) + root.session.network.active = null; + } + rightPaneItem.nextComponent = rightPaneItem.getComponentForPane(); + } + } + + Connections { + target: root.session && root.session.ethernet ? root.session.ethernet : null + enabled: target !== null + + function onActiveChanged() { + // Clear others when ethernet is selected + if (root.session && root.session.ethernet && root.session.ethernet.active) { + if (root.session.vpn && root.session.vpn.active) + root.session.vpn.active = null; + if (root.session.network && root.session.network.active) + root.session.network.active = null; + } + rightPaneItem.nextComponent = rightPaneItem.getComponentForPane(); + } + } + + Connections { + target: root.session && root.session.network ? root.session.network : null + enabled: target !== null + + function onActiveChanged() { + // Clear others when wireless is selected + if (root.session && root.session.network && root.session.network.active) { + if (root.session.vpn && root.session.vpn.active) + root.session.vpn.active = null; + if (root.session.ethernet && root.session.ethernet.active) + root.session.ethernet.active = null; + } + rightPaneItem.nextComponent = rightPaneItem.getComponentForPane(); + } + } + + Loader { + id: rightLoader + + anchors.fill: parent + + opacity: 1 + scale: 1 + transformOrigin: Item.Center + clip: false + + asynchronous: true + sourceComponent: rightPaneItem.targetComponent + } + + Behavior on paneId { + PaneTransition { + target: rightLoader + propertyActions: [ + PropertyAction { + target: rightPaneItem + property: "targetComponent" + value: rightPaneItem.nextComponent + } + ] + } + } + } + } + } + + Component { + id: settingsComponent + + StyledFlickable { + id: settingsFlickable + flickableDirection: Flickable.VerticalFlick + contentHeight: settingsInner.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: settingsFlickable + } + + NetworkSettings { + id: settingsInner + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + session: root.session + } + } + } + + Component { + id: ethernetDetailsComponent + + StyledFlickable { + id: ethernetFlickable + flickableDirection: Flickable.VerticalFlick + contentHeight: ethernetDetailsInner.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: ethernetFlickable + } + + EthernetDetails { + id: ethernetDetailsInner + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + session: root.session + } + } + } + + Component { + id: wirelessDetailsComponent + + StyledFlickable { + id: wirelessFlickable + flickableDirection: Flickable.VerticalFlick + contentHeight: wirelessDetailsInner.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: wirelessFlickable + } + + WirelessDetails { + id: wirelessDetailsInner + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + session: root.session + } + } + } + + Component { + id: vpnDetailsComponent + + StyledFlickable { + id: vpnFlickable + flickableDirection: Flickable.VerticalFlick + contentHeight: vpnDetailsInner.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: vpnFlickable + } + + VpnDetails { + id: vpnDetailsInner + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + session: root.session + } + } + } + + WirelessPasswordDialog { + anchors.fill: parent + session: root.session + z: 1000 + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/VpnDetails.qml b/.config/quickshell/caelestia/modules/controlcenter/network/VpnDetails.qml new file mode 100644 index 0000000..1c71cd7 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/VpnDetails.qml @@ -0,0 +1,396 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +DeviceDetails { + id: root + + required property Session session + readonly property var vpnProvider: root.session.vpn.active + readonly property bool providerEnabled: { + if (!vpnProvider || vpnProvider.index === undefined) + return false; + const provider = Config.utilities.vpn.provider[vpnProvider.index]; + return provider && typeof provider === "object" && provider.enabled === true; + } + + device: vpnProvider + + headerComponent: Component { + ConnectionHeader { + icon: "vpn_key" + title: root.vpnProvider?.displayName ?? qsTr("Unknown") + } + } + + sections: [ + Component { + ColumnLayout { + spacing: Appearance.spacing.normal + + SectionHeader { + title: qsTr("Connection status") + description: qsTr("VPN connection settings") + } + + SectionContainer { + ToggleRow { + label: qsTr("Enable this provider") + checked: root.providerEnabled + toggle.onToggled: { + if (!root.vpnProvider) + return; + const providers = []; + const index = root.vpnProvider.index; + + // Copy providers and update enabled state + for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { + const p = Config.utilities.vpn.provider[i]; + if (typeof p === "object") { + const newProvider = { + name: p.name, + displayName: p.displayName, + interface: p.interface + }; + + if (checked) { + // Enable this one, disable others + newProvider.enabled = (i === index); + } else { + // Just disable this one + newProvider.enabled = (i === index) ? false : (p.enabled !== false); + } + + providers.push(newProvider); + } else { + providers.push(p); + } + } + + Config.utilities.vpn.provider = providers; + Config.save(); + } + } + + RowLayout { + Layout.fillWidth: true + Layout.topMargin: Appearance.spacing.normal + spacing: Appearance.spacing.normal + + TextButton { + Layout.fillWidth: true + Layout.minimumHeight: Appearance.font.size.normal + Appearance.padding.normal * 2 + visible: root.providerEnabled + enabled: !VPN.connecting + inactiveColour: Colours.palette.m3primaryContainer + inactiveOnColour: Colours.palette.m3onPrimaryContainer + text: VPN.connected ? qsTr("Disconnect") : qsTr("Connect") + + onClicked: { + VPN.toggle(); + } + } + + TextButton { + Layout.fillWidth: true + text: qsTr("Edit Provider") + inactiveColour: Colours.palette.m3secondaryContainer + inactiveOnColour: Colours.palette.m3onSecondaryContainer + + onClicked: { + editVpnDialog.editIndex = root.vpnProvider.index; + editVpnDialog.providerName = root.vpnProvider.name; + editVpnDialog.displayName = root.vpnProvider.displayName; + editVpnDialog.interfaceName = root.vpnProvider.interface; + editVpnDialog.open(); + } + } + + TextButton { + Layout.fillWidth: true + text: qsTr("Delete Provider") + inactiveColour: Colours.palette.m3errorContainer + inactiveOnColour: Colours.palette.m3onErrorContainer + + onClicked: { + const providers = []; + for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { + if (i !== root.vpnProvider.index) { + providers.push(Config.utilities.vpn.provider[i]); + } + } + Config.utilities.vpn.provider = providers; + Config.save(); + root.session.vpn.active = null; + } + } + } + } + } + }, + Component { + ColumnLayout { + spacing: Appearance.spacing.normal + + SectionHeader { + title: qsTr("Provider details") + description: qsTr("VPN provider information") + } + + SectionContainer { + contentSpacing: Appearance.spacing.small / 2 + + PropertyRow { + label: qsTr("Provider") + value: root.vpnProvider?.name ?? qsTr("Unknown") + } + + PropertyRow { + showTopMargin: true + label: qsTr("Display name") + value: root.vpnProvider?.displayName ?? qsTr("Unknown") + } + + PropertyRow { + showTopMargin: true + label: qsTr("Interface") + value: root.vpnProvider?.interface || qsTr("N/A") + } + + PropertyRow { + showTopMargin: true + label: qsTr("Status") + value: { + if (!root.providerEnabled) + return qsTr("Disabled"); + if (VPN.connecting) + return qsTr("Connecting..."); + if (VPN.connected) + return qsTr("Connected"); + return qsTr("Enabled (Not connected)"); + } + } + + PropertyRow { + showTopMargin: true + label: qsTr("Enabled") + value: root.providerEnabled ? qsTr("Yes") : qsTr("No") + } + } + } + } + ] + + // Edit VPN Dialog + Popup { + id: editVpnDialog + + property int editIndex: -1 + property string providerName: "" + property string displayName: "" + property string interfaceName: "" + + parent: Overlay.overlay + anchors.centerIn: parent + width: Math.min(400, parent.width - Appearance.padding.large * 2) + padding: Appearance.padding.large * 1.5 + + modal: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + + opacity: 0 + scale: 0.7 + + enter: Transition { + Anim { + property: "opacity" + from: 0 + to: 1 + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + Anim { + property: "scale" + from: 0.7 + to: 1 + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + exit: Transition { + Anim { + property: "opacity" + from: 1 + to: 0 + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + Anim { + property: "scale" + from: 1 + to: 0.7 + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + function closeWithAnimation(): void { + close(); + } + + Overlay.modal: Rectangle { + color: Qt.rgba(0, 0, 0, 0.4 * editVpnDialog.opacity) + } + + background: StyledRect { + color: Colours.palette.m3surfaceContainerHigh + radius: Appearance.rounding.large + + Elevation { + anchors.fill: parent + radius: parent.radius + level: 3 + z: -1 + } + } + + contentItem: ColumnLayout { + spacing: Appearance.spacing.normal + + StyledText { + text: qsTr("Edit VPN Provider") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.smaller / 2 + + StyledText { + text: qsTr("Display Name") + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: 40 + color: displayNameField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2) + radius: Appearance.rounding.small + border.width: 1 + border.color: displayNameField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3) + + Behavior on color { + CAnim {} + } + Behavior on border.color { + CAnim {} + } + + StyledTextField { + id: displayNameField + anchors.centerIn: parent + width: parent.width - Appearance.padding.normal + horizontalAlignment: TextInput.AlignLeft + text: editVpnDialog.displayName + onTextChanged: editVpnDialog.displayName = text + } + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.smaller / 2 + + StyledText { + text: qsTr("Interface (e.g., wg0, torguard)") + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: 40 + color: interfaceNameField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2) + radius: Appearance.rounding.small + border.width: 1 + border.color: interfaceNameField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3) + + Behavior on color { + CAnim {} + } + Behavior on border.color { + CAnim {} + } + + StyledTextField { + id: interfaceNameField + anchors.centerIn: parent + width: parent.width - Appearance.padding.normal + horizontalAlignment: TextInput.AlignLeft + text: editVpnDialog.interfaceName + onTextChanged: editVpnDialog.interfaceName = text + } + } + } + + RowLayout { + Layout.topMargin: Appearance.spacing.normal + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + TextButton { + Layout.fillWidth: true + text: qsTr("Cancel") + inactiveColour: Colours.tPalette.m3surfaceContainerHigh + inactiveOnColour: Colours.palette.m3onSurface + onClicked: editVpnDialog.closeWithAnimation() + } + + TextButton { + Layout.fillWidth: true + text: qsTr("Save") + enabled: editVpnDialog.interfaceName.length > 0 + inactiveColour: Colours.palette.m3primaryContainer + inactiveOnColour: Colours.palette.m3onPrimaryContainer + + onClicked: { + const providers = []; + const oldProvider = Config.utilities.vpn.provider[editVpnDialog.editIndex]; + const wasEnabled = typeof oldProvider === "object" ? (oldProvider.enabled !== false) : true; + + for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { + if (i === editVpnDialog.editIndex) { + providers.push({ + name: editVpnDialog.providerName, + displayName: editVpnDialog.displayName || editVpnDialog.interfaceName, + interface: editVpnDialog.interfaceName, + enabled: wasEnabled + }); + } else { + providers.push(Config.utilities.vpn.provider[i]); + } + } + + Config.utilities.vpn.provider = providers; + Config.save(); + editVpnDialog.closeWithAnimation(); + } + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/VpnList.qml b/.config/quickshell/caelestia/modules/controlcenter/network/VpnList.qml new file mode 100644 index 0000000..81f4a45 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/VpnList.qml @@ -0,0 +1,686 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.controls +import qs.components.effects +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property Session session + property bool showHeader: true + property int pendingSwitchIndex: -1 + + spacing: Appearance.spacing.normal + + Connections { + target: VPN + function onConnectedChanged() { + if (!VPN.connected && root.pendingSwitchIndex >= 0) { + const targetIndex = root.pendingSwitchIndex; + root.pendingSwitchIndex = -1; + + const providers = []; + for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { + const p = Config.utilities.vpn.provider[i]; + if (typeof p === "object") { + const newProvider = { + name: p.name, + displayName: p.displayName, + interface: p.interface, + enabled: (i === targetIndex) + }; + providers.push(newProvider); + } else { + providers.push(p); + } + } + Config.utilities.vpn.provider = providers; + Config.save(); + + Qt.callLater(function () { + VPN.toggle(); + }); + } + } + } + + TextButton { + Layout.fillWidth: true + text: qsTr("+ Add VPN Provider") + inactiveColour: Colours.palette.m3primaryContainer + inactiveOnColour: Colours.palette.m3onPrimaryContainer + + onClicked: { + vpnDialog.showProviderSelection(); + } + } + + ListView { + id: listView + + Layout.fillWidth: true + Layout.preferredHeight: contentHeight + + interactive: false + spacing: Appearance.spacing.smaller + + model: ScriptModel { + values: Config.utilities.vpn.provider.map((provider, index) => { + const isObject = typeof provider === "object"; + const name = isObject ? (provider.name || "custom") : String(provider); + const displayName = isObject ? (provider.displayName || name) : name; + const iface = isObject ? (provider.interface || "") : ""; + const enabled = isObject ? (provider.enabled === true) : false; + + return { + index: index, + name: name, + displayName: displayName, + interface: iface, + provider: provider, + enabled: enabled + }; + }) + } + + delegate: Component { + StyledRect { + required property var modelData + required property int index + + width: ListView.view ? ListView.view.width : undefined + + color: Qt.alpha(Colours.tPalette.m3surfaceContainer, (root.session && root.session.vpn && root.session.vpn.active === modelData) ? Colours.tPalette.m3surfaceContainer.a : 0) + radius: Appearance.rounding.normal + + StateLayer { + function onClicked(): void { + if (root.session && root.session.vpn) { + root.session.vpn.active = modelData; + } + } + } + + RowLayout { + id: rowLayout + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2 + + radius: Appearance.rounding.normal + color: modelData.enabled && VPN.connected ? Colours.palette.m3primaryContainer : Colours.tPalette.m3surfaceContainerHigh + + MaterialIcon { + id: icon + + anchors.centerIn: parent + text: modelData.enabled && VPN.connected ? "vpn_key" : "vpn_key_off" + font.pointSize: Appearance.font.size.large + fill: modelData.enabled && VPN.connected ? 1 : 0 + color: modelData.enabled && VPN.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface + } + } + + ColumnLayout { + Layout.fillWidth: true + + spacing: 0 + + StyledText { + Layout.fillWidth: true + elide: Text.ElideRight + maximumLineCount: 1 + + text: modelData.displayName || qsTr("Unknown") + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.smaller + + StyledText { + Layout.fillWidth: true + text: { + if (modelData.enabled && VPN.connected) + return qsTr("Connected"); + if (modelData.enabled && VPN.connecting) + return qsTr("Connecting..."); + if (modelData.enabled) + return qsTr("Enabled"); + return qsTr("Disabled"); + } + color: modelData.enabled ? (VPN.connected ? Colours.palette.m3primary : Colours.palette.m3onSurface) : Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + font.weight: modelData.enabled && VPN.connected ? 500 : 400 + elide: Text.ElideRight + } + } + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: connectIcon.implicitHeight + Appearance.padding.smaller * 2 + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3primaryContainer, VPN.connected && modelData.enabled ? 1 : 0) + + StateLayer { + enabled: !VPN.connecting + function onClicked(): void { + const clickedIndex = modelData.index; + + if (modelData.enabled) { + VPN.toggle(); + } else { + if (VPN.connected) { + root.pendingSwitchIndex = clickedIndex; + VPN.toggle(); + } else { + const providers = []; + for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { + const p = Config.utilities.vpn.provider[i]; + if (typeof p === "object") { + const newProvider = { + name: p.name, + displayName: p.displayName, + interface: p.interface, + enabled: (i === clickedIndex) + }; + providers.push(newProvider); + } else { + providers.push(p); + } + } + Config.utilities.vpn.provider = providers; + Config.save(); + + Qt.callLater(function () { + VPN.toggle(); + }); + } + } + } + } + + MaterialIcon { + id: connectIcon + + anchors.centerIn: parent + text: VPN.connected && modelData.enabled ? "link_off" : "link" + color: VPN.connected && modelData.enabled ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface + } + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: deleteIcon.implicitHeight + Appearance.padding.smaller * 2 + + radius: Appearance.rounding.full + color: "transparent" + + StateLayer { + function onClicked(): void { + const providers = []; + for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { + if (i !== modelData.index) { + providers.push(Config.utilities.vpn.provider[i]); + } + } + Config.utilities.vpn.provider = providers; + Config.save(); + } + } + + MaterialIcon { + id: deleteIcon + + anchors.centerIn: parent + text: "delete" + color: Colours.palette.m3onSurface + } + } + } + + implicitHeight: rowLayout.implicitHeight + Appearance.padding.normal * 2 + } + } + } + + Popup { + id: vpnDialog + + property string currentState: "selection" + property int editIndex: -1 + property string providerName: "" + property string displayName: "" + property string interfaceName: "" + + parent: Overlay.overlay + x: Math.round((parent.width - width) / 2) + y: Math.round((parent.height - height) / 2) + implicitWidth: Math.min(400, parent.width - Appearance.padding.large * 2) + padding: Appearance.padding.large * 1.5 + + modal: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + + opacity: 0 + scale: 0.7 + + enter: Transition { + ParallelAnimation { + Anim { + property: "opacity" + from: 0 + to: 1 + duration: Appearance.anim.durations.normal + easing.bezierCurve: Appearance.anim.curves.emphasized + } + Anim { + property: "scale" + from: 0.7 + to: 1 + duration: Appearance.anim.durations.normal + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + } + + exit: Transition { + ParallelAnimation { + Anim { + property: "opacity" + from: 1 + to: 0 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.emphasized + } + Anim { + property: "scale" + from: 1 + to: 0.7 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + } + + function showProviderSelection(): void { + currentState = "selection"; + open(); + } + + function closeWithAnimation(): void { + close(); + } + + function showAddForm(providerType: string, defaultDisplayName: string): void { + editIndex = -1; + providerName = providerType; + displayName = defaultDisplayName; + interfaceName = ""; + + if (currentState === "selection") { + transitionToForm.start(); + } else { + currentState = "form"; + isClosing = false; + open(); + } + } + + function showEditForm(index: int): void { + const provider = Config.utilities.vpn.provider[index]; + const isObject = typeof provider === "object"; + + editIndex = index; + providerName = isObject ? (provider.name || "custom") : String(provider); + displayName = isObject ? (provider.displayName || providerName) : providerName; + interfaceName = isObject ? (provider.interface || "") : ""; + + currentState = "form"; + open(); + } + + Overlay.modal: Rectangle { + color: Qt.rgba(0, 0, 0, 0.4 * vpnDialog.opacity) + } + + onClosed: { + currentState = "selection"; + } + + SequentialAnimation { + id: transitionToForm + + ParallelAnimation { + Anim { + target: selectionContent + property: "opacity" + to: 0 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + ScriptAction { + script: { + vpnDialog.currentState = "form"; + } + } + + ParallelAnimation { + Anim { + target: formContent + property: "opacity" + to: 1 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + } + + background: StyledRect { + color: Colours.palette.m3surfaceContainerHigh + radius: Appearance.rounding.large + + Elevation { + anchors.fill: parent + radius: parent.radius + level: 3 + z: -1 + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.normal + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + } + + contentItem: Item { + implicitHeight: vpnDialog.currentState === "selection" ? selectionContent.implicitHeight : formContent.implicitHeight + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.normal + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + ColumnLayout { + id: selectionContent + + anchors.fill: parent + spacing: Appearance.spacing.normal + visible: vpnDialog.currentState === "selection" + opacity: vpnDialog.currentState === "selection" ? 1 : 0 + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + StyledText { + text: qsTr("Add VPN Provider") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + StyledText { + Layout.fillWidth: true + text: qsTr("Choose a provider to add") + wrapMode: Text.WordWrap + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + TextButton { + Layout.topMargin: Appearance.spacing.normal + Layout.fillWidth: true + text: qsTr("NetBird") + inactiveColour: Colours.tPalette.m3surfaceContainerHigh + inactiveOnColour: Colours.palette.m3onSurface + onClicked: { + const providers = []; + for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { + providers.push(Config.utilities.vpn.provider[i]); + } + providers.push({ + name: "netbird", + displayName: "NetBird", + interface: "wt0" + }); + Config.utilities.vpn.provider = providers; + Config.save(); + vpnDialog.closeWithAnimation(); + } + } + + TextButton { + Layout.fillWidth: true + text: qsTr("Tailscale") + inactiveColour: Colours.tPalette.m3surfaceContainerHigh + inactiveOnColour: Colours.palette.m3onSurface + onClicked: { + const providers = []; + for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { + providers.push(Config.utilities.vpn.provider[i]); + } + providers.push({ + name: "tailscale", + displayName: "Tailscale", + interface: "tailscale0" + }); + Config.utilities.vpn.provider = providers; + Config.save(); + vpnDialog.closeWithAnimation(); + } + } + + TextButton { + Layout.fillWidth: true + text: qsTr("Cloudflare WARP") + inactiveColour: Colours.tPalette.m3surfaceContainerHigh + inactiveOnColour: Colours.palette.m3onSurface + onClicked: { + const providers = []; + for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { + providers.push(Config.utilities.vpn.provider[i]); + } + providers.push({ + name: "warp", + displayName: "Cloudflare WARP", + interface: "CloudflareWARP" + }); + Config.utilities.vpn.provider = providers; + Config.save(); + vpnDialog.closeWithAnimation(); + } + } + + TextButton { + Layout.fillWidth: true + text: qsTr("WireGuard (Custom)") + inactiveColour: Colours.tPalette.m3surfaceContainerHigh + inactiveOnColour: Colours.palette.m3onSurface + onClicked: { + vpnDialog.showAddForm("wireguard", "WireGuard"); + } + } + + TextButton { + Layout.topMargin: Appearance.spacing.normal + Layout.fillWidth: true + text: qsTr("Cancel") + inactiveColour: Colours.palette.m3secondaryContainer + inactiveOnColour: Colours.palette.m3onSecondaryContainer + onClicked: vpnDialog.closeWithAnimation() + } + } + + ColumnLayout { + id: formContent + + anchors.fill: parent + spacing: Appearance.spacing.normal + visible: vpnDialog.currentState === "form" + opacity: vpnDialog.currentState === "form" ? 1 : 0 + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + StyledText { + text: vpnDialog.editIndex >= 0 ? qsTr("Edit VPN Provider") : qsTr("Add %1 VPN").arg(vpnDialog.displayName) + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.smaller / 2 + + StyledText { + text: qsTr("Display Name") + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: 40 + color: displayNameField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2) + radius: Appearance.rounding.small + border.width: 1 + border.color: displayNameField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3) + + Behavior on color { + CAnim {} + } + Behavior on border.color { + CAnim {} + } + + StyledTextField { + id: displayNameField + anchors.centerIn: parent + width: parent.width - Appearance.padding.normal + horizontalAlignment: TextInput.AlignLeft + text: vpnDialog.displayName + onTextChanged: vpnDialog.displayName = text + } + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.smaller / 2 + + StyledText { + text: qsTr("Interface (e.g., wg0, torguard)") + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: 40 + color: interfaceNameField.activeFocus ? Colours.layer(Colours.palette.m3surfaceContainer, 3) : Colours.layer(Colours.palette.m3surfaceContainer, 2) + radius: Appearance.rounding.small + border.width: 1 + border.color: interfaceNameField.activeFocus ? Colours.palette.m3primary : Qt.alpha(Colours.palette.m3outline, 0.3) + + Behavior on color { + CAnim {} + } + Behavior on border.color { + CAnim {} + } + + StyledTextField { + id: interfaceNameField + anchors.centerIn: parent + width: parent.width - Appearance.padding.normal + horizontalAlignment: TextInput.AlignLeft + text: vpnDialog.interfaceName + onTextChanged: vpnDialog.interfaceName = text + } + } + } + + RowLayout { + Layout.topMargin: Appearance.spacing.normal + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + TextButton { + Layout.fillWidth: true + text: qsTr("Cancel") + inactiveColour: Colours.tPalette.m3surfaceContainerHigh + inactiveOnColour: Colours.palette.m3onSurface + onClicked: vpnDialog.closeWithAnimation() + } + + TextButton { + Layout.fillWidth: true + text: qsTr("Save") + enabled: vpnDialog.interfaceName.length > 0 + inactiveColour: Colours.palette.m3primaryContainer + inactiveOnColour: Colours.palette.m3onPrimaryContainer + + onClicked: { + const providers = []; + const newProvider = { + name: vpnDialog.providerName, + displayName: vpnDialog.displayName || vpnDialog.interfaceName, + interface: vpnDialog.interfaceName + }; + + if (vpnDialog.editIndex >= 0) { + for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { + if (i === vpnDialog.editIndex) { + providers.push(newProvider); + } else { + providers.push(Config.utilities.vpn.provider[i]); + } + } + } else { + for (let i = 0; i < Config.utilities.vpn.provider.length; i++) { + providers.push(Config.utilities.vpn.provider[i]); + } + providers.push(newProvider); + } + + Config.utilities.vpn.provider = providers; + Config.save(); + vpnDialog.closeWithAnimation(); + } + } + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/VpnSettings.qml b/.config/quickshell/caelestia/modules/controlcenter/network/VpnSettings.qml new file mode 100644 index 0000000..49d801d --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/VpnSettings.qml @@ -0,0 +1,232 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.components.effects +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property Session session + + spacing: Appearance.spacing.normal + + SettingsHeader { + icon: "vpn_key" + title: qsTr("VPN Settings") + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("General") + description: qsTr("VPN configuration") + } + + SectionContainer { + ToggleRow { + label: qsTr("VPN enabled") + checked: Config.utilities.vpn.enabled + toggle.onToggled: { + Config.utilities.vpn.enabled = checked; + Config.save(); + } + } + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("Providers") + description: qsTr("Manage VPN providers") + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + ListView { + Layout.fillWidth: true + Layout.preferredHeight: contentHeight + + interactive: false + spacing: Appearance.spacing.smaller + + model: ScriptModel { + values: Config.utilities.vpn.provider.map((provider, index) => { + const isObject = typeof provider === "object"; + const name = isObject ? (provider.name || "custom") : String(provider); + const displayName = isObject ? (provider.displayName || name) : name; + const iface = isObject ? (provider.interface || "") : ""; + + return { + index: index, + name: name, + displayName: displayName, + interface: iface, + provider: provider, + isActive: index === 0 + }; + }) + } + + delegate: Component { + StyledRect { + required property var modelData + required property int index + + width: ListView.view ? ListView.view.width : undefined + color: Colours.tPalette.m3surfaceContainerHigh + radius: Appearance.rounding.normal + + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + spacing: Appearance.spacing.normal + + MaterialIcon { + text: modelData.isActive ? "vpn_key" : "vpn_key_off" + font.pointSize: Appearance.font.size.large + color: modelData.isActive ? Colours.palette.m3primary : Colours.palette.m3outline + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + + StyledText { + text: modelData.displayName + font.weight: modelData.isActive ? 500 : 400 + } + + StyledText { + text: qsTr("%1 • %2").arg(modelData.name).arg(modelData.interface || qsTr("No interface")) + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3outline + } + } + + IconButton { + icon: modelData.isActive ? "arrow_downward" : "arrow_upward" + visible: !modelData.isActive || Config.utilities.vpn.provider.length > 1 + onClicked: { + if (modelData.isActive && index < Config.utilities.vpn.provider.length - 1) { + // Move down + const providers = [...Config.utilities.vpn.provider]; + const temp = providers[index]; + providers[index] = providers[index + 1]; + providers[index + 1] = temp; + Config.utilities.vpn.provider = providers; + Config.save(); + } else if (!modelData.isActive) { + // Make active (move to top) + const providers = [...Config.utilities.vpn.provider]; + const provider = providers.splice(index, 1)[0]; + providers.unshift(provider); + Config.utilities.vpn.provider = providers; + Config.save(); + } + } + } + + IconButton { + icon: "delete" + onClicked: { + const providers = [...Config.utilities.vpn.provider]; + providers.splice(index, 1); + Config.utilities.vpn.provider = providers; + Config.save(); + } + } + } + + implicitHeight: 60 + } + } + } + + TextButton { + Layout.fillWidth: true + Layout.topMargin: Appearance.spacing.normal + text: qsTr("+ Add Provider") + inactiveColour: Colours.palette.m3primaryContainer + inactiveOnColour: Colours.palette.m3onPrimaryContainer + + onClicked: { + addProviderDialog.open(); + } + } + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("Quick Add") + description: qsTr("Add common VPN providers") + } + + SectionContainer { + contentSpacing: Appearance.spacing.smaller + + TextButton { + Layout.fillWidth: true + text: qsTr("+ Add NetBird") + inactiveColour: Colours.tPalette.m3surfaceContainerHigh + inactiveOnColour: Colours.palette.m3onSurface + + onClicked: { + const providers = [...Config.utilities.vpn.provider]; + providers.push({ + name: "netbird", + displayName: "NetBird", + interface: "wt0" + }); + Config.utilities.vpn.provider = providers; + Config.save(); + } + } + + TextButton { + Layout.fillWidth: true + text: qsTr("+ Add Tailscale") + inactiveColour: Colours.tPalette.m3surfaceContainerHigh + inactiveOnColour: Colours.palette.m3onSurface + + onClicked: { + const providers = [...Config.utilities.vpn.provider]; + providers.push({ + name: "tailscale", + displayName: "Tailscale", + interface: "tailscale0" + }); + Config.utilities.vpn.provider = providers; + Config.save(); + } + } + + TextButton { + Layout.fillWidth: true + text: qsTr("+ Add Cloudflare WARP") + inactiveColour: Colours.tPalette.m3surfaceContainerHigh + inactiveOnColour: Colours.palette.m3onSurface + + onClicked: { + const providers = [...Config.utilities.vpn.provider]; + providers.push({ + name: "warp", + displayName: "Cloudflare WARP", + interface: "CloudflareWARP" + }); + Config.utilities.vpn.provider = providers; + Config.save(); + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/WirelessDetails.qml b/.config/quickshell/caelestia/modules/controlcenter/network/WirelessDetails.qml new file mode 100644 index 0000000..e8777cd --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/WirelessDetails.qml @@ -0,0 +1,211 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import "." +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import QtQuick +import QtQuick.Layouts + +DeviceDetails { + id: root + + required property Session session + readonly property var network: root.session.network.active + + device: network + + Component.onCompleted: { + updateDeviceDetails(); + checkSavedProfile(); + } + + onNetworkChanged: { + connectionUpdateTimer.stop(); + if (network && network.ssid) { + connectionUpdateTimer.start(); + } + updateDeviceDetails(); + checkSavedProfile(); + } + + function checkSavedProfile(): void { + if (network && network.ssid) { + Nmcli.loadSavedConnections(() => {}); + } + } + + Connections { + target: Nmcli + function onActiveChanged() { + updateDeviceDetails(); + } + function onWirelessDeviceDetailsChanged() { + if (network && network.ssid) { + const isActive = network.active || (Nmcli.active && Nmcli.active.ssid === network.ssid); + if (isActive && Nmcli.wirelessDeviceDetails && Nmcli.wirelessDeviceDetails !== null) { + connectionUpdateTimer.stop(); + } + } + } + } + + Timer { + id: connectionUpdateTimer + interval: 500 + repeat: true + running: network && network.ssid + onTriggered: { + if (network) { + const isActive = network.active || (Nmcli.active && Nmcli.active.ssid === network.ssid); + if (isActive) { + if (!Nmcli.wirelessDeviceDetails || Nmcli.wirelessDeviceDetails === null) { + Nmcli.getWirelessDeviceDetails("", () => {}); + } else { + connectionUpdateTimer.stop(); + } + } else { + if (Nmcli.wirelessDeviceDetails !== null) { + Nmcli.wirelessDeviceDetails = null; + } + } + } + } + } + + function updateDeviceDetails(): void { + if (network && network.ssid) { + const isActive = network.active || (Nmcli.active && Nmcli.active.ssid === network.ssid); + if (isActive) { + Nmcli.getWirelessDeviceDetails(""); + } else { + Nmcli.wirelessDeviceDetails = null; + } + } else { + Nmcli.wirelessDeviceDetails = null; + } + } + + headerComponent: Component { + ConnectionHeader { + icon: root.network?.isSecure ? "lock" : "wifi" + title: root.network?.ssid ?? qsTr("Unknown") + } + } + + sections: [ + Component { + ColumnLayout { + spacing: Appearance.spacing.normal + + SectionHeader { + title: qsTr("Connection status") + description: qsTr("Connection settings for this network") + } + + SectionContainer { + ToggleRow { + label: qsTr("Connected") + checked: root.network?.active ?? false + toggle.onToggled: { + if (checked) { + NetworkConnection.handleConnect(root.network, root.session, null); + } else { + Nmcli.disconnectFromNetwork(); + } + } + } + + TextButton { + Layout.fillWidth: true + Layout.topMargin: Appearance.spacing.normal + Layout.minimumHeight: Appearance.font.size.normal + Appearance.padding.normal * 2 + visible: { + if (!root.network || !root.network.ssid) { + return false; + } + return Nmcli.hasSavedProfile(root.network.ssid); + } + inactiveColour: Colours.palette.m3secondaryContainer + inactiveOnColour: Colours.palette.m3onSecondaryContainer + text: qsTr("Forget Network") + + onClicked: { + if (root.network && root.network.ssid) { + if (root.network.active) { + Nmcli.disconnectFromNetwork(); + } + Nmcli.forgetNetwork(root.network.ssid); + } + } + } + } + } + }, + Component { + ColumnLayout { + spacing: Appearance.spacing.normal + + SectionHeader { + title: qsTr("Network properties") + description: qsTr("Additional information") + } + + SectionContainer { + contentSpacing: Appearance.spacing.small / 2 + + PropertyRow { + label: qsTr("SSID") + value: root.network?.ssid ?? qsTr("Unknown") + } + + PropertyRow { + showTopMargin: true + label: qsTr("BSSID") + value: root.network?.bssid ?? qsTr("Unknown") + } + + PropertyRow { + showTopMargin: true + label: qsTr("Signal strength") + value: root.network ? qsTr("%1%").arg(root.network.strength) : qsTr("N/A") + } + + PropertyRow { + showTopMargin: true + label: qsTr("Frequency") + value: root.network ? qsTr("%1 MHz").arg(root.network.frequency) : qsTr("N/A") + } + + PropertyRow { + showTopMargin: true + label: qsTr("Security") + value: root.network ? (root.network.isSecure ? root.network.security : qsTr("Open")) : qsTr("N/A") + } + } + } + }, + Component { + ColumnLayout { + spacing: Appearance.spacing.normal + + SectionHeader { + title: qsTr("Connection information") + description: qsTr("Network connection details") + } + + SectionContainer { + ConnectionInfoSection { + deviceDetails: Nmcli.wirelessDeviceDetails + } + } + } + } + ] +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/WirelessList.qml b/.config/quickshell/caelestia/modules/controlcenter/network/WirelessList.qml new file mode 100644 index 0000000..57a155f --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/WirelessList.qml @@ -0,0 +1,228 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import "." +import qs.components +import qs.components.controls +import qs.components.containers +import qs.components.effects +import qs.services +import qs.config +import qs.utils +import Quickshell +import QtQuick +import QtQuick.Layouts + +DeviceList { + id: root + + required property Session session + + title: qsTr("Networks (%1)").arg(Nmcli.networks.length) + description: qsTr("All available WiFi networks") + activeItem: session.network.active + + titleSuffix: Component { + StyledText { + visible: Nmcli.scanning + text: qsTr("Scanning...") + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.small + } + } + + model: ScriptModel { + values: [...Nmcli.networks].sort((a, b) => { + if (a.active !== b.active) + return b.active - a.active; + return b.strength - a.strength; + }) + } + + headerComponent: Component { + RowLayout { + spacing: Appearance.spacing.smaller + + StyledText { + text: qsTr("Settings") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + + ToggleButton { + toggled: Nmcli.wifiEnabled + icon: "wifi" + accent: "Tertiary" + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + + onClicked: { + Nmcli.toggleWifi(null); + } + } + + ToggleButton { + toggled: Nmcli.scanning + icon: "wifi_find" + accent: "Secondary" + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + + onClicked: { + Nmcli.rescanWifi(); + } + } + + ToggleButton { + toggled: !root.session.network.active + icon: "settings" + accent: "Primary" + iconSize: Appearance.font.size.normal + horizontalPadding: Appearance.padding.normal + verticalPadding: Appearance.padding.smaller + + onClicked: { + if (root.session.network.active) + root.session.network.active = null; + else { + root.session.network.active = root.view.model.get(0)?.modelData ?? null; + } + } + } + } + } + + delegate: Component { + StyledRect { + required property var modelData + + width: ListView.view ? ListView.view.width : undefined + + color: Qt.alpha(Colours.tPalette.m3surfaceContainer, root.activeItem === modelData ? Colours.tPalette.m3surfaceContainer.a : 0) + radius: Appearance.rounding.normal + + StateLayer { + function onClicked(): void { + root.session.network.active = modelData; + if (modelData && modelData.ssid) { + root.checkSavedProfileForNetwork(modelData.ssid); + } + } + } + + RowLayout { + id: rowLayout + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2 + + radius: Appearance.rounding.normal + color: modelData.active ? Colours.palette.m3primaryContainer : Colours.tPalette.m3surfaceContainerHigh + + MaterialIcon { + id: icon + + anchors.centerIn: parent + text: Icons.getNetworkIcon(modelData.strength, modelData.isSecure) + font.pointSize: Appearance.font.size.large + fill: modelData.active ? 1 : 0 + color: modelData.active ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface + } + } + + ColumnLayout { + Layout.fillWidth: true + + spacing: 0 + + StyledText { + Layout.fillWidth: true + elide: Text.ElideRight + maximumLineCount: 1 + + text: modelData.ssid || qsTr("Unknown") + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.smaller + + StyledText { + Layout.fillWidth: true + text: { + if (modelData.active) + return qsTr("Connected"); + if (modelData.isSecure && modelData.security && modelData.security.length > 0) { + return modelData.security; + } + if (modelData.isSecure) + return qsTr("Secured"); + return qsTr("Open"); + } + color: modelData.active ? Colours.palette.m3primary : Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + font.weight: modelData.active ? 500 : 400 + elide: Text.ElideRight + } + } + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: connectIcon.implicitHeight + Appearance.padding.smaller * 2 + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3primaryContainer, modelData.active ? 1 : 0) + + StateLayer { + function onClicked(): void { + if (modelData.active) { + Nmcli.disconnectFromNetwork(); + } else { + NetworkConnection.handleConnect(modelData, root.session, null); + } + } + } + + MaterialIcon { + id: connectIcon + + anchors.centerIn: parent + text: modelData.active ? "link_off" : "link" + color: modelData.active ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface + } + } + } + + implicitHeight: rowLayout.implicitHeight + Appearance.padding.normal * 2 + } + } + + onItemSelected: function (item) { + session.network.active = item; + if (item && item.ssid) { + checkSavedProfileForNetwork(item.ssid); + } + } + + function checkSavedProfileForNetwork(ssid: string): void { + if (ssid && ssid.length > 0) { + Nmcli.loadSavedConnections(() => {}); + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/WirelessPane.qml b/.config/quickshell/caelestia/modules/controlcenter/network/WirelessPane.qml new file mode 100644 index 0000000..8150af9 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/WirelessPane.qml @@ -0,0 +1,57 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.containers +import qs.config +import Quickshell.Widgets +import QtQuick + +SplitPaneWithDetails { + id: root + + required property Session session + + anchors.fill: parent + + activeItem: session.network.active + paneIdGenerator: function (item) { + return item ? (item.ssid || item.bssid || "") : ""; + } + + leftContent: Component { + WirelessList { + session: root.session + } + } + + rightDetailsComponent: Component { + WirelessDetails { + session: root.session + } + } + + rightSettingsComponent: Component { + StyledFlickable { + flickableDirection: Flickable.VerticalFlick + contentHeight: settingsInner.height + clip: true + + WirelessSettings { + id: settingsInner + + anchors.left: parent.left + anchors.right: parent.right + session: root.session + } + } + } + + overlayComponent: Component { + WirelessPasswordDialog { + anchors.fill: parent + session: root.session + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/WirelessPasswordDialog.qml b/.config/quickshell/caelestia/modules/controlcenter/network/WirelessPasswordDialog.qml new file mode 100644 index 0000000..7ad5204 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/WirelessPasswordDialog.qml @@ -0,0 +1,511 @@ +pragma ComponentBehavior: Bound + +import ".." +import "." +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import Quickshell +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Session session + + readonly property var network: { + if (session.network.pendingNetwork) { + return session.network.pendingNetwork; + } + if (session.network.active) { + return session.network.active; + } + return null; + } + + property bool isClosing: false + visible: session.network.showPasswordDialog || isClosing + enabled: session.network.showPasswordDialog && !isClosing + focus: enabled + + Keys.onEscapePressed: { + closeDialog(); + } + + Rectangle { + anchors.fill: parent + color: Qt.rgba(0, 0, 0, 0.5) + opacity: root.session.network.showPasswordDialog && !root.isClosing ? 1 : 0 + + Behavior on opacity { + Anim {} + } + + MouseArea { + anchors.fill: parent + onClicked: closeDialog() + } + } + + StyledRect { + id: dialog + + anchors.centerIn: parent + + implicitWidth: 400 + implicitHeight: content.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surface + opacity: root.session.network.showPasswordDialog && !root.isClosing ? 1 : 0 + scale: root.session.network.showPasswordDialog && !root.isClosing ? 1 : 0.7 + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + ParallelAnimation { + running: root.isClosing + onFinished: { + if (root.isClosing) { + root.session.network.showPasswordDialog = false; + root.isClosing = false; + } + } + + Anim { + target: dialog + property: "opacity" + to: 0 + } + Anim { + target: dialog + property: "scale" + to: 0.7 + } + } + + Keys.onEscapePressed: closeDialog() + + ColumnLayout { + id: content + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.normal + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: "lock" + font.pointSize: Appearance.font.size.extraLarge * 2 + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("Enter password") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: root.network ? qsTr("Network: %1").arg(root.network.ssid) : "" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + id: statusText + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Appearance.spacing.small + visible: connectButton.connecting || connectButton.hasError + text: { + if (connectButton.hasError) { + return qsTr("Connection failed. Please check your password and try again."); + } + if (connectButton.connecting) { + return qsTr("Connecting..."); + } + return ""; + } + color: connectButton.hasError ? Colours.palette.m3error : Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + font.weight: 400 + wrapMode: Text.WordWrap + Layout.maximumWidth: parent.width - Appearance.padding.large * 2 + } + + Item { + id: passwordContainer + Layout.topMargin: Appearance.spacing.large + Layout.fillWidth: true + implicitHeight: Math.max(48, charList.implicitHeight + Appearance.padding.normal * 2) + + focus: true + Keys.onPressed: event => { + if (!activeFocus) { + forceActiveFocus(); + } + + if (connectButton.hasError && event.text && event.text.length > 0) { + connectButton.hasError = false; + } + + if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { + if (connectButton.enabled) { + connectButton.clicked(); + } + event.accepted = true; + } else if (event.key === Qt.Key_Backspace) { + if (event.modifiers & Qt.ControlModifier) { + passwordBuffer = ""; + } else { + passwordBuffer = passwordBuffer.slice(0, -1); + } + event.accepted = true; + } else if (event.text && event.text.length > 0) { + passwordBuffer += event.text; + event.accepted = true; + } + } + + property string passwordBuffer: "" + + Connections { + target: root.session.network + function onShowPasswordDialogChanged(): void { + if (root.session.network.showPasswordDialog) { + Qt.callLater(() => { + passwordContainer.forceActiveFocus(); + passwordContainer.passwordBuffer = ""; + connectButton.hasError = false; + }); + } + } + } + + Connections { + target: root + function onVisibleChanged(): void { + if (root.visible) { + Qt.callLater(() => { + passwordContainer.forceActiveFocus(); + }); + } + } + } + + StyledRect { + anchors.fill: parent + radius: Appearance.rounding.normal + color: passwordContainer.activeFocus ? Qt.lighter(Colours.tPalette.m3surfaceContainer, 1.05) : Colours.tPalette.m3surfaceContainer + border.width: passwordContainer.activeFocus || connectButton.hasError ? 4 : (root.visible ? 1 : 0) + border.color: { + if (connectButton.hasError) { + return Colours.palette.m3error; + } + if (passwordContainer.activeFocus) { + return Colours.palette.m3primary; + } + return root.visible ? Colours.palette.m3outline : "transparent"; + } + + Behavior on border.color { + CAnim {} + } + + Behavior on border.width { + CAnim {} + } + + Behavior on color { + CAnim {} + } + } + + StateLayer { + hoverEnabled: false + cursorShape: Qt.IBeamCursor + + function onClicked(): void { + passwordContainer.forceActiveFocus(); + } + } + + StyledText { + id: placeholder + anchors.centerIn: parent + text: qsTr("Password") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.normal + font.family: Appearance.font.family.mono + opacity: passwordContainer.passwordBuffer ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + + ListView { + id: charList + + readonly property int fullWidth: count * (implicitHeight + spacing) - spacing + + anchors.centerIn: parent + implicitWidth: fullWidth + implicitHeight: Appearance.font.size.normal + + orientation: Qt.Horizontal + spacing: Appearance.spacing.small / 2 + interactive: false + + model: ScriptModel { + values: passwordContainer.passwordBuffer.split("") + } + + delegate: StyledRect { + id: ch + + implicitWidth: implicitHeight + implicitHeight: charList.implicitHeight + + color: Colours.palette.m3onSurface + radius: Appearance.rounding.small / 2 + + opacity: 0 + scale: 0 + Component.onCompleted: { + opacity = 1; + scale = 1; + } + ListView.onRemove: removeAnim.start() + + SequentialAnimation { + id: removeAnim + + PropertyAction { + target: ch + property: "ListView.delayRemove" + value: true + } + ParallelAnimation { + Anim { + target: ch + property: "opacity" + to: 0 + } + Anim { + target: ch + property: "scale" + to: 0.5 + } + } + PropertyAction { + target: ch + property: "ListView.delayRemove" + value: false + } + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } + + Behavior on implicitWidth { + Anim {} + } + } + } + + RowLayout { + Layout.topMargin: Appearance.spacing.normal + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + TextButton { + id: cancelButton + + Layout.fillWidth: true + Layout.minimumHeight: Appearance.font.size.normal + Appearance.padding.normal * 2 + inactiveColour: Colours.palette.m3secondaryContainer + inactiveOnColour: Colours.palette.m3onSecondaryContainer + text: qsTr("Cancel") + + onClicked: root.closeDialog() + } + + TextButton { + id: connectButton + + property bool connecting: false + property bool hasError: false + + Layout.fillWidth: true + Layout.minimumHeight: Appearance.font.size.normal + Appearance.padding.normal * 2 + inactiveColour: Colours.palette.m3primary + inactiveOnColour: Colours.palette.m3onPrimary + text: qsTr("Connect") + enabled: passwordContainer.passwordBuffer.length > 0 && !connecting + + onClicked: { + if (!root.network || connecting) { + return; + } + + const password = passwordContainer.passwordBuffer; + if (!password || password.length === 0) { + return; + } + + hasError = false; + connecting = true; + enabled = false; + text = qsTr("Connecting..."); + + NetworkConnection.connectWithPassword(root.network, password, result => { + if (result && result.success) {} else if (result && result.needsPassword) { + connectionMonitor.stop(); + connecting = false; + hasError = true; + enabled = true; + text = qsTr("Connect"); + passwordContainer.passwordBuffer = ""; + if (root.network && root.network.ssid) { + Nmcli.forgetNetwork(root.network.ssid); + } + } else { + connectionMonitor.stop(); + connecting = false; + hasError = true; + enabled = true; + text = qsTr("Connect"); + passwordContainer.passwordBuffer = ""; + if (root.network && root.network.ssid) { + Nmcli.forgetNetwork(root.network.ssid); + } + } + }); + + connectionMonitor.start(); + } + } + } + } + } + + function checkConnectionStatus(): void { + if (!root.visible || !connectButton.connecting) { + return; + } + + const isConnected = root.network && Nmcli.active && Nmcli.active.ssid && Nmcli.active.ssid.toLowerCase().trim() === root.network.ssid.toLowerCase().trim(); + + if (isConnected) { + connectionSuccessTimer.start(); + return; + } + + if (Nmcli.pendingConnection === null && connectButton.connecting) { + if (connectionMonitor.repeatCount > 10) { + connectionMonitor.stop(); + connectButton.connecting = false; + connectButton.hasError = true; + connectButton.enabled = true; + connectButton.text = qsTr("Connect"); + passwordContainer.passwordBuffer = ""; + if (root.network && root.network.ssid) { + Nmcli.forgetNetwork(root.network.ssid); + } + } + } + } + + Timer { + id: connectionMonitor + interval: 1000 + repeat: true + triggeredOnStart: false + property int repeatCount: 0 + + onTriggered: { + repeatCount++; + checkConnectionStatus(); + } + + onRunningChanged: { + if (!running) { + repeatCount = 0; + } + } + } + + Timer { + id: connectionSuccessTimer + interval: 500 + onTriggered: { + if (root.visible && Nmcli.active && Nmcli.active.ssid) { + const stillConnected = Nmcli.active.ssid.toLowerCase().trim() === root.network.ssid.toLowerCase().trim(); + if (stillConnected) { + connectionMonitor.stop(); + connectButton.connecting = false; + connectButton.text = qsTr("Connect"); + closeDialog(); + } + } + } + } + + Connections { + target: Nmcli + function onActiveChanged() { + if (root.visible) { + checkConnectionStatus(); + } + } + function onConnectionFailed(ssid: string) { + if (root.visible && root.network && root.network.ssid === ssid && connectButton.connecting) { + connectionMonitor.stop(); + connectButton.connecting = false; + connectButton.hasError = true; + connectButton.enabled = true; + connectButton.text = qsTr("Connect"); + passwordContainer.passwordBuffer = ""; + Nmcli.forgetNetwork(ssid); + } + } + } + + function closeDialog(): void { + if (isClosing) { + return; + } + + isClosing = true; + passwordContainer.passwordBuffer = ""; + connectButton.connecting = false; + connectButton.hasError = false; + connectButton.text = qsTr("Connect"); + connectionMonitor.stop(); + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/network/WirelessSettings.qml b/.config/quickshell/caelestia/modules/controlcenter/network/WirelessSettings.qml new file mode 100644 index 0000000..b4eb391 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/network/WirelessSettings.qml @@ -0,0 +1,73 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property Session session + + spacing: Appearance.spacing.normal + + SettingsHeader { + icon: "wifi" + title: qsTr("Network settings") + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("WiFi status") + description: qsTr("General WiFi settings") + } + + SectionContainer { + ToggleRow { + label: qsTr("WiFi enabled") + checked: Nmcli.wifiEnabled + toggle.onToggled: { + Nmcli.enableWifi(checked); + } + } + } + + SectionHeader { + Layout.topMargin: Appearance.spacing.large + title: qsTr("Network information") + description: qsTr("Current network connection") + } + + SectionContainer { + contentSpacing: Appearance.spacing.small / 2 + + PropertyRow { + label: qsTr("Connected network") + value: Nmcli.active ? Nmcli.active.ssid : qsTr("Not connected") + } + + PropertyRow { + showTopMargin: true + label: qsTr("Signal strength") + value: Nmcli.active ? qsTr("%1%").arg(Nmcli.active.strength) : qsTr("N/A") + } + + PropertyRow { + showTopMargin: true + label: qsTr("Security") + value: Nmcli.active ? (Nmcli.active.isSecure ? qsTr("Secured") : qsTr("Open")) : qsTr("N/A") + } + + PropertyRow { + showTopMargin: true + label: qsTr("Frequency") + value: Nmcli.active ? qsTr("%1 MHz").arg(Nmcli.active.frequency) : qsTr("N/A") + } + } +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/state/BluetoothState.qml b/.config/quickshell/caelestia/modules/controlcenter/state/BluetoothState.qml new file mode 100644 index 0000000..8678672 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/state/BluetoothState.qml @@ -0,0 +1,12 @@ +import Quickshell.Bluetooth +import QtQuick + +QtObject { + id: root + + property BluetoothDevice active: null + property BluetoothAdapter currentAdapter: Bluetooth.defaultAdapter + property bool editingAdapterName: false + property bool fabMenuOpen: false + property bool editingDeviceName: false +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/state/EthernetState.qml b/.config/quickshell/caelestia/modules/controlcenter/state/EthernetState.qml new file mode 100644 index 0000000..58f5fc8 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/state/EthernetState.qml @@ -0,0 +1,7 @@ +import QtQuick + +QtObject { + id: root + + property var active: null +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/state/LauncherState.qml b/.config/quickshell/caelestia/modules/controlcenter/state/LauncherState.qml new file mode 100644 index 0000000..58f5fc8 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/state/LauncherState.qml @@ -0,0 +1,7 @@ +import QtQuick + +QtObject { + id: root + + property var active: null +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/state/NetworkState.qml b/.config/quickshell/caelestia/modules/controlcenter/state/NetworkState.qml new file mode 100644 index 0000000..f9324c8 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/state/NetworkState.qml @@ -0,0 +1,9 @@ +import QtQuick + +QtObject { + id: root + + property var active: null + property bool showPasswordDialog: false + property var pendingNetwork: null +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/state/VpnState.qml b/.config/quickshell/caelestia/modules/controlcenter/state/VpnState.qml new file mode 100644 index 0000000..aa911f1 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/state/VpnState.qml @@ -0,0 +1,5 @@ +import QtQuick + +QtObject { + property var active: null +} diff --git a/.config/quickshell/caelestia/modules/controlcenter/taskbar/TaskbarPane.qml b/.config/quickshell/caelestia/modules/controlcenter/taskbar/TaskbarPane.qml new file mode 100644 index 0000000..d12d174 --- /dev/null +++ b/.config/quickshell/caelestia/modules/controlcenter/taskbar/TaskbarPane.qml @@ -0,0 +1,648 @@ +pragma ComponentBehavior: Bound + +import ".." +import "../components" +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Session session + + property bool clockShowIcon: Config.bar.clock.showIcon ?? true + property bool persistent: Config.bar.persistent ?? true + property bool showOnHover: Config.bar.showOnHover ?? true + property int dragThreshold: Config.bar.dragThreshold ?? 20 + property bool showAudio: Config.bar.status.showAudio ?? true + property bool showMicrophone: Config.bar.status.showMicrophone ?? true + property bool showKbLayout: Config.bar.status.showKbLayout ?? false + property bool showNetwork: Config.bar.status.showNetwork ?? true + property bool showWifi: Config.bar.status.showWifi ?? true + property bool showBluetooth: Config.bar.status.showBluetooth ?? true + property bool showBattery: Config.bar.status.showBattery ?? true + property bool showLockStatus: Config.bar.status.showLockStatus ?? true + property bool trayBackground: Config.bar.tray.background ?? false + property bool trayCompact: Config.bar.tray.compact ?? false + property bool trayRecolour: Config.bar.tray.recolour ?? false + property int workspacesShown: Config.bar.workspaces.shown ?? 5 + property bool workspacesActiveIndicator: Config.bar.workspaces.activeIndicator ?? true + property bool workspacesOccupiedBg: Config.bar.workspaces.occupiedBg ?? false + property bool workspacesShowWindows: Config.bar.workspaces.showWindows ?? false + property bool workspacesPerMonitor: Config.bar.workspaces.perMonitorWorkspaces ?? true + property bool scrollWorkspaces: Config.bar.scrollActions.workspaces ?? true + property bool scrollVolume: Config.bar.scrollActions.volume ?? true + property bool scrollBrightness: Config.bar.scrollActions.brightness ?? true + property bool popoutActiveWindow: Config.bar.popouts.activeWindow ?? true + property bool popoutTray: Config.bar.popouts.tray ?? true + property bool popoutStatusIcons: Config.bar.popouts.statusIcons ?? true + + anchors.fill: parent + + Component.onCompleted: { + if (Config.bar.entries) { + entriesModel.clear(); + for (let i = 0; i < Config.bar.entries.length; i++) { + const entry = Config.bar.entries[i]; + entriesModel.append({ + id: entry.id, + enabled: entry.enabled !== false + }); + } + } + } + + function saveConfig(entryIndex, entryEnabled) { + Config.bar.clock.showIcon = root.clockShowIcon; + Config.bar.persistent = root.persistent; + Config.bar.showOnHover = root.showOnHover; + Config.bar.dragThreshold = root.dragThreshold; + Config.bar.status.showAudio = root.showAudio; + Config.bar.status.showMicrophone = root.showMicrophone; + Config.bar.status.showKbLayout = root.showKbLayout; + Config.bar.status.showNetwork = root.showNetwork; + Config.bar.status.showWifi = root.showWifi; + Config.bar.status.showBluetooth = root.showBluetooth; + Config.bar.status.showBattery = root.showBattery; + Config.bar.status.showLockStatus = root.showLockStatus; + Config.bar.tray.background = root.trayBackground; + Config.bar.tray.compact = root.trayCompact; + Config.bar.tray.recolour = root.trayRecolour; + Config.bar.workspaces.shown = root.workspacesShown; + Config.bar.workspaces.activeIndicator = root.workspacesActiveIndicator; + Config.bar.workspaces.occupiedBg = root.workspacesOccupiedBg; + Config.bar.workspaces.showWindows = root.workspacesShowWindows; + Config.bar.workspaces.perMonitorWorkspaces = root.workspacesPerMonitor; + Config.bar.scrollActions.workspaces = root.scrollWorkspaces; + Config.bar.scrollActions.volume = root.scrollVolume; + Config.bar.scrollActions.brightness = root.scrollBrightness; + Config.bar.popouts.activeWindow = root.popoutActiveWindow; + Config.bar.popouts.tray = root.popoutTray; + Config.bar.popouts.statusIcons = root.popoutStatusIcons; + + const entries = []; + for (let i = 0; i < entriesModel.count; i++) { + const entry = entriesModel.get(i); + let enabled = entry.enabled; + if (entryIndex !== undefined && i === entryIndex) { + enabled = entryEnabled; + } + entries.push({ + id: entry.id, + enabled: enabled + }); + } + Config.bar.entries = entries; + Config.save(); + } + + ListModel { + id: entriesModel + } + + ClippingRectangle { + id: taskbarClippingRect + anchors.fill: parent + anchors.margins: Appearance.padding.normal + anchors.leftMargin: 0 + anchors.rightMargin: Appearance.padding.normal + + radius: taskbarBorder.innerRadius + color: "transparent" + + Loader { + id: taskbarLoader + + anchors.fill: parent + anchors.margins: Appearance.padding.large + Appearance.padding.normal + anchors.leftMargin: Appearance.padding.large + anchors.rightMargin: Appearance.padding.large + + sourceComponent: taskbarContentComponent + } + } + + InnerBorder { + id: taskbarBorder + leftThickness: 0 + rightThickness: Appearance.padding.normal + } + + Component { + id: taskbarContentComponent + + StyledFlickable { + id: sidebarFlickable + flickableDirection: Flickable.VerticalFlick + contentHeight: sidebarLayout.height + + StyledScrollBar.vertical: StyledScrollBar { + flickable: sidebarFlickable + } + + ColumnLayout { + id: sidebarLayout + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + + spacing: Appearance.spacing.normal + + RowLayout { + spacing: Appearance.spacing.smaller + + StyledText { + text: qsTr("Taskbar") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + } + + SectionContainer { + Layout.fillWidth: true + alignTop: true + + StyledText { + text: qsTr("Status Icons") + font.pointSize: Appearance.font.size.normal + } + + ConnectedButtonGroup { + rootItem: root + + options: [ + { + label: qsTr("Speakers"), + propertyName: "showAudio", + onToggled: function (checked) { + root.showAudio = checked; + root.saveConfig(); + } + }, + { + label: qsTr("Microphone"), + propertyName: "showMicrophone", + onToggled: function (checked) { + root.showMicrophone = checked; + root.saveConfig(); + } + }, + { + label: qsTr("Keyboard"), + propertyName: "showKbLayout", + onToggled: function (checked) { + root.showKbLayout = checked; + root.saveConfig(); + } + }, + { + label: qsTr("Network"), + propertyName: "showNetwork", + onToggled: function (checked) { + root.showNetwork = checked; + root.saveConfig(); + } + }, + { + label: qsTr("Wifi"), + propertyName: "showWifi", + onToggled: function (checked) { + root.showWifi = checked; + root.saveConfig(); + } + }, + { + label: qsTr("Bluetooth"), + propertyName: "showBluetooth", + onToggled: function (checked) { + root.showBluetooth = checked; + root.saveConfig(); + } + }, + { + label: qsTr("Battery"), + propertyName: "showBattery", + onToggled: function (checked) { + root.showBattery = checked; + root.saveConfig(); + } + }, + { + label: qsTr("Capslock"), + propertyName: "showLockStatus", + onToggled: function (checked) { + root.showLockStatus = checked; + root.saveConfig(); + } + } + ] + } + } + + RowLayout { + id: mainRowLayout + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + ColumnLayout { + id: leftColumnLayout + Layout.fillWidth: true + Layout.alignment: Qt.AlignTop + spacing: Appearance.spacing.normal + + SectionContainer { + Layout.fillWidth: true + alignTop: true + + StyledText { + text: qsTr("Workspaces") + font.pointSize: Appearance.font.size.normal + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: workspacesShownRow.implicitHeight + Appearance.padding.large * 2 + radius: Appearance.rounding.normal + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + + Behavior on implicitHeight { + Anim {} + } + + RowLayout { + id: workspacesShownRow + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: qsTr("Shown") + } + + CustomSpinBox { + min: 1 + max: 20 + value: root.workspacesShown + onValueModified: value => { + root.workspacesShown = value; + root.saveConfig(); + } + } + } + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: workspacesActiveIndicatorRow.implicitHeight + Appearance.padding.large * 2 + radius: Appearance.rounding.normal + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + + Behavior on implicitHeight { + Anim {} + } + + RowLayout { + id: workspacesActiveIndicatorRow + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: qsTr("Active indicator") + } + + StyledSwitch { + checked: root.workspacesActiveIndicator + onToggled: { + root.workspacesActiveIndicator = checked; + root.saveConfig(); + } + } + } + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: workspacesOccupiedBgRow.implicitHeight + Appearance.padding.large * 2 + radius: Appearance.rounding.normal + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + + Behavior on implicitHeight { + Anim {} + } + + RowLayout { + id: workspacesOccupiedBgRow + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: qsTr("Occupied background") + } + + StyledSwitch { + checked: root.workspacesOccupiedBg + onToggled: { + root.workspacesOccupiedBg = checked; + root.saveConfig(); + } + } + } + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: workspacesShowWindowsRow.implicitHeight + Appearance.padding.large * 2 + radius: Appearance.rounding.normal + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + + Behavior on implicitHeight { + Anim {} + } + + RowLayout { + id: workspacesShowWindowsRow + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: qsTr("Show windows") + } + + StyledSwitch { + checked: root.workspacesShowWindows + onToggled: { + root.workspacesShowWindows = checked; + root.saveConfig(); + } + } + } + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: workspacesPerMonitorRow.implicitHeight + Appearance.padding.large * 2 + radius: Appearance.rounding.normal + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + + Behavior on implicitHeight { + Anim {} + } + + RowLayout { + id: workspacesPerMonitorRow + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: qsTr("Per monitor workspaces") + } + + StyledSwitch { + checked: root.workspacesPerMonitor + onToggled: { + root.workspacesPerMonitor = checked; + root.saveConfig(); + } + } + } + } + } + + SectionContainer { + Layout.fillWidth: true + alignTop: true + + StyledText { + text: qsTr("Scroll Actions") + font.pointSize: Appearance.font.size.normal + } + + ConnectedButtonGroup { + rootItem: root + + options: [ + { + label: qsTr("Workspaces"), + propertyName: "scrollWorkspaces", + onToggled: function (checked) { + root.scrollWorkspaces = checked; + root.saveConfig(); + } + }, + { + label: qsTr("Volume"), + propertyName: "scrollVolume", + onToggled: function (checked) { + root.scrollVolume = checked; + root.saveConfig(); + } + }, + { + label: qsTr("Brightness"), + propertyName: "scrollBrightness", + onToggled: function (checked) { + root.scrollBrightness = checked; + root.saveConfig(); + } + } + ] + } + } + } + + ColumnLayout { + id: middleColumnLayout + Layout.fillWidth: true + Layout.alignment: Qt.AlignTop + spacing: Appearance.spacing.normal + + SectionContainer { + Layout.fillWidth: true + alignTop: true + + StyledText { + text: qsTr("Clock") + font.pointSize: Appearance.font.size.normal + } + + SwitchRow { + label: qsTr("Show clock icon") + checked: root.clockShowIcon + onToggled: checked => { + root.clockShowIcon = checked; + root.saveConfig(); + } + } + } + + SectionContainer { + Layout.fillWidth: true + alignTop: true + + StyledText { + text: qsTr("Bar Behavior") + font.pointSize: Appearance.font.size.normal + } + + SwitchRow { + label: qsTr("Persistent") + checked: root.persistent + onToggled: checked => { + root.persistent = checked; + root.saveConfig(); + } + } + + SwitchRow { + label: qsTr("Show on hover") + checked: root.showOnHover + onToggled: checked => { + root.showOnHover = checked; + root.saveConfig(); + } + } + + SectionContainer { + contentSpacing: Appearance.spacing.normal + + SliderInput { + Layout.fillWidth: true + + label: qsTr("Drag threshold") + value: root.dragThreshold + from: 0 + to: 100 + suffix: "px" + validator: IntValidator { + bottom: 0 + top: 100 + } + formatValueFunction: val => Math.round(val).toString() + parseValueFunction: text => parseInt(text) + + onValueModified: newValue => { + root.dragThreshold = Math.round(newValue); + root.saveConfig(); + } + } + } + } + } + + ColumnLayout { + id: rightColumnLayout + Layout.fillWidth: true + Layout.alignment: Qt.AlignTop + spacing: Appearance.spacing.normal + + SectionContainer { + Layout.fillWidth: true + alignTop: true + + StyledText { + text: qsTr("Popouts") + font.pointSize: Appearance.font.size.normal + } + + SwitchRow { + label: qsTr("Active window") + checked: root.popoutActiveWindow + onToggled: checked => { + root.popoutActiveWindow = checked; + root.saveConfig(); + } + } + + SwitchRow { + label: qsTr("Tray") + checked: root.popoutTray + onToggled: checked => { + root.popoutTray = checked; + root.saveConfig(); + } + } + + SwitchRow { + label: qsTr("Status icons") + checked: root.popoutStatusIcons + onToggled: checked => { + root.popoutStatusIcons = checked; + root.saveConfig(); + } + } + } + + SectionContainer { + Layout.fillWidth: true + alignTop: true + + StyledText { + text: qsTr("Tray Settings") + font.pointSize: Appearance.font.size.normal + } + + ConnectedButtonGroup { + rootItem: root + + options: [ + { + label: qsTr("Background"), + propertyName: "trayBackground", + onToggled: function (checked) { + root.trayBackground = checked; + root.saveConfig(); + } + }, + { + label: qsTr("Compact"), + propertyName: "trayCompact", + onToggled: function (checked) { + root.trayCompact = checked; + root.saveConfig(); + } + }, + { + label: qsTr("Recolour"), + propertyName: "trayRecolour", + onToggled: function (checked) { + root.trayRecolour = checked; + root.saveConfig(); + } + } + ] + } + } + } + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/Background.qml b/.config/quickshell/caelestia/modules/dashboard/Background.qml new file mode 100644 index 0000000..e2a91f7 --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/Background.qml @@ -0,0 +1,66 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + readonly property real rounding: Config.border.rounding + readonly property bool flatten: wrapper.height < rounding * 2 + readonly property real roundingY: flatten ? wrapper.height / 2 : rounding + + strokeWidth: -1 + fillColor: Colours.palette.m3surface + + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.roundingY * 2 + } + + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + + PathLine { + relativeX: root.wrapper.width - root.rounding * 2 + relativeY: 0 + } + + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + + PathLine { + relativeX: 0 + relativeY: -(root.wrapper.height - root.roundingY * 2) + } + + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/Content.qml b/.config/quickshell/caelestia/modules/dashboard/Content.qml new file mode 100644 index 0000000..1cc960a --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/Content.qml @@ -0,0 +1,152 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.filedialog +import qs.config +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property PersistentProperties visibilities + required property PersistentProperties state + required property FileDialog facePicker + readonly property real nonAnimWidth: view.implicitWidth + viewWrapper.anchors.margins * 2 + readonly property real nonAnimHeight: tabs.implicitHeight + tabs.anchors.topMargin + view.implicitHeight + viewWrapper.anchors.margins * 2 + + implicitWidth: nonAnimWidth + implicitHeight: nonAnimHeight + + Tabs { + id: tabs + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: Appearance.padding.normal + anchors.margins: Appearance.padding.large + + nonAnimWidth: root.nonAnimWidth - anchors.margins * 2 + state: root.state + } + + ClippingRectangle { + id: viewWrapper + + anchors.top: tabs.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: Appearance.padding.large + + radius: Appearance.rounding.normal + color: "transparent" + + Flickable { + id: view + + readonly property int currentIndex: root.state.currentTab + readonly property Item currentItem: row.children[currentIndex] + + anchors.fill: parent + + flickableDirection: Flickable.HorizontalFlick + + implicitWidth: currentItem.implicitWidth + implicitHeight: currentItem.implicitHeight + + contentX: currentItem.x + contentWidth: row.implicitWidth + contentHeight: row.implicitHeight + + onContentXChanged: { + if (!moving) + return; + + const x = contentX - currentItem.x; + if (x > currentItem.implicitWidth / 2) + root.state.currentTab = Math.min(root.state.currentTab + 1, tabs.count - 1); + else if (x < -currentItem.implicitWidth / 2) + root.state.currentTab = Math.max(root.state.currentTab - 1, 0); + } + + onDragEnded: { + const x = contentX - currentItem.x; + if (x > currentItem.implicitWidth / 10) + root.state.currentTab = Math.min(root.state.currentTab + 1, tabs.count - 1); + else if (x < -currentItem.implicitWidth / 10) + root.state.currentTab = Math.max(root.state.currentTab - 1, 0); + else + contentX = Qt.binding(() => currentItem.x); + } + + RowLayout { + id: row + + Pane { + index: 0 + sourceComponent: Dash { + visibilities: root.visibilities + state: root.state + facePicker: root.facePicker + } + } + + Pane { + index: 1 + sourceComponent: Media { + visibilities: root.visibilities + } + } + + Pane { + index: 2 + sourceComponent: Performance {} + } + + Pane { + index: 3 + sourceComponent: Weather {} + } + } + + Behavior on contentX { + Anim {} + } + } + } + + Behavior on implicitWidth { + Anim { + duration: Appearance.anim.durations.large + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.large + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + component Pane: Loader { + id: pane + + required property int index + + Layout.alignment: Qt.AlignTop + + Component.onCompleted: active = Qt.binding(() => { + // Always keep current tab loaded + if (pane.index === view.currentIndex) + return true; + const vx = Math.floor(view.visibleArea.xPosition * view.contentWidth); + const vex = Math.floor(vx + view.visibleArea.widthRatio * view.contentWidth); + return (vx >= x && vx <= x + implicitWidth) || (vex >= x && vex <= x + implicitWidth); + }) + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/Dash.qml b/.config/quickshell/caelestia/modules/dashboard/Dash.qml new file mode 100644 index 0000000..71e224f --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/Dash.qml @@ -0,0 +1,105 @@ +import qs.components +import qs.components.filedialog +import qs.services +import qs.config +import "dash" +import Quickshell +import QtQuick.Layouts + +GridLayout { + id: root + + required property PersistentProperties visibilities + required property PersistentProperties state + required property FileDialog facePicker + + rowSpacing: Appearance.spacing.normal + columnSpacing: Appearance.spacing.normal + + Rect { + Layout.column: 2 + Layout.columnSpan: 3 + Layout.preferredWidth: user.implicitWidth + Layout.preferredHeight: user.implicitHeight + + radius: Appearance.rounding.large + + User { + id: user + + visibilities: root.visibilities + state: root.state + facePicker: root.facePicker + } + } + + Rect { + Layout.row: 0 + Layout.columnSpan: 2 + Layout.preferredWidth: Config.dashboard.sizes.weatherWidth + Layout.fillHeight: true + + radius: Appearance.rounding.large * 1.5 + + Weather {} + } + + Rect { + Layout.row: 1 + Layout.preferredWidth: dateTime.implicitWidth + Layout.fillHeight: true + + radius: Appearance.rounding.normal + + DateTime { + id: dateTime + } + } + + Rect { + Layout.row: 1 + Layout.column: 1 + Layout.columnSpan: 3 + Layout.fillWidth: true + Layout.preferredHeight: calendar.implicitHeight + + radius: Appearance.rounding.large + + Calendar { + id: calendar + + state: root.state + } + } + + Rect { + Layout.row: 1 + Layout.column: 4 + Layout.preferredWidth: resources.implicitWidth + Layout.fillHeight: true + + radius: Appearance.rounding.normal + + Resources { + id: resources + } + } + + Rect { + Layout.row: 0 + Layout.column: 5 + Layout.rowSpan: 2 + Layout.preferredWidth: media.implicitWidth + Layout.fillHeight: true + + radius: Appearance.rounding.large * 2 + + Media { + id: media + } + } + + component Rect: StyledRect { + color: Colours.tPalette.m3surfaceContainer + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/Media.qml b/.config/quickshell/caelestia/modules/dashboard/Media.qml new file mode 100644 index 0000000..722bc93 --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/Media.qml @@ -0,0 +1,403 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.services +import qs.utils +import qs.config +import Caelestia.Services +import Quickshell +import Quickshell.Services.Mpris +import QtQuick +import QtQuick.Layouts +import QtQuick.Shapes + +Item { + id: root + + required property PersistentProperties visibilities + + property real playerProgress: { + const active = Players.active; + return active?.length ? active.position / active.length : 0; + } + + function lengthStr(length: int): string { + if (length < 0) + return "-1:-1"; + + const hours = Math.floor(length / 3600); + const mins = Math.floor((length % 3600) / 60); + const secs = Math.floor(length % 60).toString().padStart(2, "0"); + + if (hours > 0) + return `${hours}:${mins.toString().padStart(2, "0")}:${secs}`; + return `${mins}:${secs}`; + } + + implicitWidth: cover.implicitWidth + Config.dashboard.sizes.mediaVisualiserSize * 2 + details.implicitWidth + details.anchors.leftMargin + bongocat.implicitWidth + bongocat.anchors.leftMargin * 2 + Appearance.padding.large * 2 + implicitHeight: Math.max(cover.implicitHeight + Config.dashboard.sizes.mediaVisualiserSize * 2, details.implicitHeight, bongocat.implicitHeight) + Appearance.padding.large * 2 + + Behavior on playerProgress { + Anim { + duration: Appearance.anim.durations.large + } + } + + Timer { + running: Players.active?.isPlaying ?? false + interval: Config.dashboard.mediaUpdateInterval + triggeredOnStart: true + repeat: true + onTriggered: Players.active?.positionChanged() + } + + ServiceRef { + service: Audio.cava + } + + ServiceRef { + service: Audio.beatTracker + } + + Shape { + id: visualiser + + readonly property real centerX: width / 2 + readonly property real centerY: height / 2 + readonly property real innerX: cover.implicitWidth / 2 + Appearance.spacing.small + readonly property real innerY: cover.implicitHeight / 2 + Appearance.spacing.small + property color colour: Colours.palette.m3primary + + anchors.fill: cover + anchors.margins: -Config.dashboard.sizes.mediaVisualiserSize + + asynchronous: true + preferredRendererType: Shape.CurveRenderer + data: visualiserBars.instances + } + + Variants { + id: visualiserBars + + model: Array.from({ + length: Config.services.visualiserBars + }, (_, i) => i) + + ShapePath { + id: visualiserBar + + required property int modelData + readonly property real value: Math.max(1e-3, Math.min(1, Audio.cava.values[modelData])) + + readonly property real angle: modelData * 2 * Math.PI / Config.services.visualiserBars + readonly property real magnitude: value * Config.dashboard.sizes.mediaVisualiserSize + readonly property real cos: Math.cos(angle) + readonly property real sin: Math.sin(angle) + + capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap + strokeWidth: 360 / Config.services.visualiserBars - Appearance.spacing.small / 4 + strokeColor: Colours.palette.m3primary + + startX: visualiser.centerX + (visualiser.innerX + strokeWidth / 2) * cos + startY: visualiser.centerY + (visualiser.innerY + strokeWidth / 2) * sin + + PathLine { + x: visualiser.centerX + (visualiser.innerX + visualiserBar.strokeWidth / 2 + visualiserBar.magnitude) * visualiserBar.cos + y: visualiser.centerY + (visualiser.innerY + visualiserBar.strokeWidth / 2 + visualiserBar.magnitude) * visualiserBar.sin + } + + Behavior on strokeColor { + CAnim {} + } + } + } + + StyledClippingRect { + id: cover + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Appearance.padding.large + Config.dashboard.sizes.mediaVisualiserSize + + implicitWidth: Config.dashboard.sizes.mediaCoverArtSize + implicitHeight: Config.dashboard.sizes.mediaCoverArtSize + + color: Colours.tPalette.m3surfaceContainerHigh + radius: Infinity + + MaterialIcon { + anchors.centerIn: parent + + grade: 200 + text: "art_track" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: (parent.width * 0.4) || 1 + } + + Image { + id: image + + anchors.fill: parent + + source: Players.active?.trackArtUrl ?? "" // qmllint disable incompatible-type + asynchronous: true + fillMode: Image.PreserveAspectCrop + sourceSize.width: width + sourceSize.height: height + } + } + + ColumnLayout { + id: details + + anchors.verticalCenter: parent.verticalCenter + anchors.left: visualiser.right + anchors.leftMargin: Appearance.spacing.normal + + spacing: Appearance.spacing.small + + StyledText { + id: title + + Layout.fillWidth: true + Layout.maximumWidth: parent.implicitWidth + + animate: true + horizontalAlignment: Text.AlignHCenter + text: (Players.active?.trackTitle ?? qsTr("No media")) || qsTr("Unknown title") + color: Players.active ? Colours.palette.m3primary : Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.normal + elide: Text.ElideRight + } + + StyledText { + id: album + + Layout.fillWidth: true + Layout.maximumWidth: parent.implicitWidth + + animate: true + horizontalAlignment: Text.AlignHCenter + visible: !!Players.active + text: Players.active?.trackAlbum || qsTr("Unknown album") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + elide: Text.ElideRight + } + + StyledText { + id: artist + + Layout.fillWidth: true + Layout.maximumWidth: parent.implicitWidth + + animate: true + horizontalAlignment: Text.AlignHCenter + text: (Players.active?.trackArtist ?? qsTr("Play some music for stuff to show up here!")) || qsTr("Unknown artist") + color: Players.active ? Colours.palette.m3secondary : Colours.palette.m3outline + elide: Text.ElideRight + wrapMode: Players.active ? Text.NoWrap : Text.WordWrap + } + + RowLayout { + id: controls + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Appearance.spacing.small + Layout.bottomMargin: Appearance.spacing.smaller + + spacing: Appearance.spacing.small + + PlayerControl { + type: IconButton.Text + icon: "skip_previous" + font.pointSize: Math.round(Appearance.font.size.large * 1.5) + disabled: !Players.active?.canGoPrevious + onClicked: Players.active?.previous() + } + + PlayerControl { + icon: Players.active?.isPlaying ? "pause" : "play_arrow" + label.animate: true + toggle: true + padding: Appearance.padding.small / 2 + checked: Players.active?.isPlaying ?? false + font.pointSize: Math.round(Appearance.font.size.large * 1.5) + disabled: !Players.active?.canTogglePlaying + onClicked: Players.active?.togglePlaying() + } + + PlayerControl { + type: IconButton.Text + icon: "skip_next" + font.pointSize: Math.round(Appearance.font.size.large * 1.5) + disabled: !Players.active?.canGoNext + onClicked: Players.active?.next() + } + } + + StyledSlider { + id: slider + + enabled: !!Players.active + implicitWidth: 280 + implicitHeight: Appearance.padding.normal * 3 + + onMoved: { + const active = Players.active; + if (active?.canSeek && active?.positionSupported) + active.position = value * active.length; + } + + Binding { + target: slider + property: "value" + value: root.playerProgress + when: !slider.pressed + } + + CustomMouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + + function onWheel(event: WheelEvent) { + const active = Players.active; + if (!active?.canSeek || !active?.positionSupported) + return; + + event.accepted = true; + const delta = event.angleDelta.y > 0 ? 10 : -10; // Time 10 seconds + Qt.callLater(() => { + active.position = Math.max(0, Math.min(active.length, active.position + delta)); + }); + } + } + } + + Item { + Layout.fillWidth: true + implicitHeight: Math.max(position.implicitHeight, length.implicitHeight) + + StyledText { + id: position + + anchors.left: parent.left + + text: root.lengthStr(Players.active?.position ?? -1) + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + } + + StyledText { + id: length + + anchors.right: parent.right + + text: root.lengthStr(Players.active?.length ?? -1) + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + } + } + + RowLayout { + Layout.alignment: Qt.AlignHCenter + spacing: Appearance.spacing.small + + PlayerControl { + type: IconButton.Text + icon: "move_up" + inactiveOnColour: Colours.palette.m3secondary + padding: Appearance.padding.small + font.pointSize: Appearance.font.size.large + disabled: !Players.active?.canRaise + onClicked: { + Players.active?.raise(); + root.visibilities.dashboard = false; + } + } + + SplitButton { + id: playerSelector + + disabled: !Players.list.length + active: menuItems.find(m => m.modelData === Players.active) ?? menuItems[0] ?? null + menu.onItemSelected: item => Players.manualActive = (item as PlayerItem).modelData + + menuItems: playerList.instances + fallbackIcon: "music_off" + fallbackText: qsTr("No players") + + label.Layout.maximumWidth: slider.implicitWidth * 0.28 + label.elide: Text.ElideRight + + stateLayer.disabled: true + menuOnTop: true + + Variants { + id: playerList + + model: Players.list + + PlayerItem {} + } + } + + PlayerControl { + type: IconButton.Text + icon: "delete" + inactiveOnColour: Colours.palette.m3error + padding: Appearance.padding.small + font.pointSize: Appearance.font.size.large + disabled: !Players.active?.canQuit + onClicked: Players.active?.quit() + } + } + } + + Item { + id: bongocat + + anchors.verticalCenter: parent.verticalCenter + anchors.left: details.right + anchors.leftMargin: Appearance.spacing.normal + + implicitWidth: visualiser.width + implicitHeight: visualiser.height + + AnimatedImage { + anchors.centerIn: parent + + width: visualiser.width * 0.75 + height: visualiser.height * 0.75 + + playing: Players.active?.isPlaying ?? false + speed: Audio.beatTracker.bpm / Appearance.anim.mediaGifSpeedAdjustment // qmllint disable unresolved-type + source: Paths.absolutePath(Config.paths.mediaGif) + asynchronous: true + fillMode: AnimatedImage.PreserveAspectFit + } + } + + component PlayerItem: MenuItem { + required property MprisPlayer modelData + + icon: modelData === Players.active ? "check" : "" + text: Players.getIdentity(modelData) + activeIcon: "animated_images" + } + + component PlayerControl: IconButton { + Layout.preferredWidth: implicitWidth + (stateLayer.pressed ? Appearance.padding.large : internalChecked ? Appearance.padding.smaller : 0) + radius: stateLayer.pressed ? Appearance.rounding.small / 2 : internalChecked ? Appearance.rounding.small : implicitHeight / 2 + radiusAnim.duration: Appearance.anim.durations.expressiveFastSpatial + radiusAnim.easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + + Behavior on Layout.preferredWidth { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/Performance.qml b/.config/quickshell/caelestia/modules/dashboard/Performance.qml new file mode 100644 index 0000000..e73d8ed --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/Performance.qml @@ -0,0 +1,967 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell.Services.UPower +import qs.components +import qs.components.misc +import qs.config +import qs.services + +Item { + id: root + + readonly property int minWidth: 400 + 400 + Appearance.spacing.normal + 120 + Appearance.padding.large * 2 + + function displayTemp(temp: real): string { + return `${Math.ceil(Config.services.useFahrenheitPerformance ? temp * 1.8 + 32 : temp)}°${Config.services.useFahrenheitPerformance ? "F" : "C"}`; + } + + implicitWidth: Math.max(minWidth, content.implicitWidth) + implicitHeight: placeholder.visible ? placeholder.height : content.implicitHeight + + StyledRect { + id: placeholder + + anchors.centerIn: parent + width: 400 + height: 350 + radius: Appearance.rounding.large + color: Colours.tPalette.m3surfaceContainer + visible: !Config.dashboard.performance.showCpu && !(Config.dashboard.performance.showGpu && SystemUsage.gpuType !== "NONE") && !Config.dashboard.performance.showMemory && !Config.dashboard.performance.showStorage && !Config.dashboard.performance.showNetwork && !(UPower.displayDevice.isLaptopBattery && Config.dashboard.performance.showBattery) + + ColumnLayout { + anchors.centerIn: parent + spacing: Appearance.spacing.normal + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: "tune" + font.pointSize: Appearance.font.size.extraLarge * 2 + color: Colours.palette.m3onSurfaceVariant + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("No widgets enabled") + font.pointSize: Appearance.font.size.large + color: Colours.palette.m3onSurface + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("Enable widgets in dashboard settings") + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + } + } + } + + RowLayout { + id: content + + anchors.left: parent.left + anchors.right: parent.right + spacing: Appearance.spacing.normal + visible: !placeholder.visible + + Ref { + service: SystemUsage + } + + ColumnLayout { + id: mainColumn + + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + visible: Config.dashboard.performance.showCpu || (Config.dashboard.performance.showGpu && SystemUsage.gpuType !== "NONE") + + HeroCard { + Layout.fillWidth: true + Layout.minimumWidth: 400 + Layout.preferredHeight: 150 + visible: Config.dashboard.performance.showCpu + icon: "memory" + title: SystemUsage.cpuName ? `CPU - ${SystemUsage.cpuName}` : qsTr("CPU") + mainValue: `${Math.round(SystemUsage.cpuPerc * 100)}%` + mainLabel: qsTr("Usage") + secondaryValue: root.displayTemp(SystemUsage.cpuTemp) + secondaryLabel: qsTr("Temp") + usage: SystemUsage.cpuPerc + temperature: SystemUsage.cpuTemp + accentColor: Colours.palette.m3primary + } + + HeroCard { + Layout.fillWidth: true + Layout.minimumWidth: 400 + Layout.preferredHeight: 150 + visible: Config.dashboard.performance.showGpu && SystemUsage.gpuType !== "NONE" + icon: "desktop_windows" + title: SystemUsage.gpuName ? `GPU - ${SystemUsage.gpuName}` : qsTr("GPU") + mainValue: `${Math.round(SystemUsage.gpuPerc * 100)}%` + mainLabel: qsTr("Usage") + secondaryValue: root.displayTemp(SystemUsage.gpuTemp) + secondaryLabel: qsTr("Temp") + usage: SystemUsage.gpuPerc + temperature: SystemUsage.gpuTemp + accentColor: Colours.palette.m3secondary + } + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + visible: Config.dashboard.performance.showMemory || Config.dashboard.performance.showStorage || Config.dashboard.performance.showNetwork + + GaugeCard { + Layout.minimumWidth: 250 + Layout.preferredHeight: 220 + Layout.fillWidth: !Config.dashboard.performance.showStorage && !Config.dashboard.performance.showNetwork + icon: "memory_alt" + title: qsTr("Memory") + percentage: SystemUsage.memPerc + subtitle: { + const usedFmt = SystemUsage.formatKib(SystemUsage.memUsed); + const totalFmt = SystemUsage.formatKib(SystemUsage.memTotal); + return `${usedFmt.value.toFixed(1)} / ${Math.floor(totalFmt.value)} ${totalFmt.unit}`; + } + accentColor: Colours.palette.m3tertiary + visible: Config.dashboard.performance.showMemory + } + + StorageGaugeCard { + Layout.minimumWidth: 250 + Layout.preferredHeight: 220 + Layout.fillWidth: !Config.dashboard.performance.showNetwork + visible: Config.dashboard.performance.showStorage + } + + NetworkCard { + Layout.fillWidth: true + Layout.minimumWidth: 200 + Layout.preferredHeight: 220 + visible: Config.dashboard.performance.showNetwork + } + } + } + + BatteryTank { + Layout.preferredWidth: 120 + Layout.preferredHeight: mainColumn.implicitHeight + visible: UPower.displayDevice.isLaptopBattery && Config.dashboard.performance.showBattery + } + } + + component BatteryTank: StyledClippingRect { + id: batteryTank + + property real percentage: UPower.displayDevice.percentage + property bool isCharging: UPower.displayDevice.state === UPowerDeviceState.Charging + property color accentColor: Colours.palette.m3primary + property real animatedPercentage: 0 + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.large + Component.onCompleted: animatedPercentage = percentage + onPercentageChanged: animatedPercentage = percentage + + // Background Fill + StyledRect { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + height: parent.height * batteryTank.animatedPercentage + color: Qt.alpha(batteryTank.accentColor, 0.15) + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.small + + // Header Section + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + MaterialIcon { + text: { + if (!UPower.displayDevice.isLaptopBattery) { + if (PowerProfiles.profile === PowerProfile.PowerSaver) + return "energy_savings_leaf"; + + if (PowerProfiles.profile === PowerProfile.Performance) + return "rocket_launch"; + + return "balance"; + } + if (UPower.displayDevice.state === UPowerDeviceState.FullyCharged) + return "battery_full"; + + const perc = UPower.displayDevice.percentage; + const charging = [UPowerDeviceState.Charging, UPowerDeviceState.PendingCharge].includes(UPower.displayDevice.state); + if (perc >= 0.99) + return "battery_full"; + + let level = Math.floor(perc * 7); + if (charging && (level === 4 || level === 1)) + level--; + + return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`; + } + font.pointSize: Appearance.font.size.large + color: batteryTank.accentColor + } + + StyledText { + Layout.fillWidth: true + text: qsTr("Battery") + font.pointSize: Appearance.font.size.normal + color: Colours.palette.m3onSurface + } + } + + Item { + Layout.fillHeight: true + } + + // Bottom Info Section + ColumnLayout { + Layout.fillWidth: true + spacing: -4 + + StyledText { + Layout.alignment: Qt.AlignRight + text: `${Math.round(batteryTank.percentage * 100)}%` + font.pointSize: Appearance.font.size.extraLarge + font.weight: Font.Medium + color: batteryTank.accentColor + } + + StyledText { + Layout.alignment: Qt.AlignRight + text: { + if (UPower.displayDevice.state === UPowerDeviceState.FullyCharged) + return qsTr("Full"); + + if (batteryTank.isCharging) + return qsTr("Charging"); + + const s = UPower.displayDevice.timeToEmpty; + if (s === 0) + return qsTr("..."); + + const hr = Math.floor(s / 3600); + const min = Math.floor((s % 3600) / 60); + if (hr > 0) + return `${hr}h ${min}m`; + + return `${min}m`; + } + font.pointSize: Appearance.font.size.smaller + color: Colours.palette.m3onSurfaceVariant + } + } + } + + Behavior on animatedPercentage { + Anim { + duration: Appearance.anim.durations.large + } + } + } + + component CardHeader: RowLayout { + property string icon + property string title + property color accentColor: Colours.palette.m3primary + + Layout.fillWidth: true + spacing: Appearance.spacing.small + + MaterialIcon { + text: parent.icon + fill: 1 + color: parent.accentColor + font.pointSize: Appearance.spacing.large + } + + StyledText { + Layout.fillWidth: true + text: parent.title + font.pointSize: Appearance.font.size.normal + elide: Text.ElideRight + } + } + + component ProgressBar: StyledRect { + id: progressBar + + property real value: 0 + property color fgColor: Colours.palette.m3primary + property color bgColor: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + property real animatedValue: 0 + + color: bgColor + radius: Appearance.rounding.full + Component.onCompleted: animatedValue = value + onValueChanged: animatedValue = value + + StyledRect { + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + width: parent.width * progressBar.animatedValue + color: progressBar.fgColor + radius: Appearance.rounding.full + } + + Behavior on animatedValue { + Anim { + duration: Appearance.anim.durations.large + } + } + } + + component HeroCard: StyledClippingRect { + id: heroCard + + property string icon + property string title + property string mainValue + property string mainLabel + property string secondaryValue + property string secondaryLabel + property real usage: 0 + property real temperature: 0 + property color accentColor: Colours.palette.m3primary + readonly property real maxTemp: 100 + readonly property real tempProgress: Math.min(1, Math.max(0, temperature / maxTemp)) + property real animatedUsage: 0 + property real animatedTemp: 0 + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.large + Component.onCompleted: { + animatedUsage = usage; + animatedTemp = tempProgress; + } + onUsageChanged: animatedUsage = usage + onTempProgressChanged: animatedTemp = tempProgress + + StyledRect { + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + width: parent.width * heroCard.animatedUsage + color: Qt.alpha(heroCard.accentColor, 0.15) + } + + ColumnLayout { + anchors.fill: parent + anchors.leftMargin: Appearance.padding.large + anchors.rightMargin: Appearance.padding.large + anchors.topMargin: Appearance.padding.normal + anchors.bottomMargin: Appearance.padding.normal + spacing: Appearance.spacing.small + + CardHeader { + icon: heroCard.icon + title: heroCard.title + accentColor: heroCard.accentColor + } + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + spacing: Appearance.spacing.normal + + Column { + Layout.alignment: Qt.AlignBottom + Layout.fillWidth: true + spacing: Appearance.spacing.small + + Row { + spacing: Appearance.spacing.small + + StyledText { + text: heroCard.secondaryValue + font.pointSize: Appearance.font.size.normal + font.weight: Font.Medium + } + + StyledText { + text: heroCard.secondaryLabel + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + anchors.baseline: parent.children[0].baseline + } + } + + ProgressBar { + width: parent.width * 0.5 + height: 6 + value: heroCard.tempProgress + fgColor: heroCard.accentColor + bgColor: Qt.alpha(heroCard.accentColor, 0.2) + } + } + + Item { + Layout.fillWidth: true + } + } + } + + Column { + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + anchors.rightMargin: 32 + spacing: 0 + + StyledText { + anchors.right: parent.right + text: heroCard.mainLabel + font.pointSize: Appearance.font.size.normal + color: Colours.palette.m3onSurfaceVariant + } + + StyledText { + anchors.right: parent.right + text: heroCard.mainValue + font.pointSize: Appearance.font.size.extraLarge + font.weight: Font.Medium + color: heroCard.accentColor + } + } + + Behavior on animatedUsage { + Anim { + duration: Appearance.anim.durations.large + } + } + + Behavior on animatedTemp { + Anim { + duration: Appearance.anim.durations.large + } + } + } + + component GaugeCard: StyledRect { + id: gaugeCard + + property string icon + property string title + property real percentage: 0 + property string subtitle + property color accentColor: Colours.palette.m3primary + readonly property real arcStartAngle: 0.75 * Math.PI + readonly property real arcSweep: 1.5 * Math.PI + property real animatedPercentage: 0 + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.large + clip: true + Component.onCompleted: animatedPercentage = percentage + onPercentageChanged: animatedPercentage = percentage + + ColumnLayout { + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.smaller + + CardHeader { + icon: gaugeCard.icon + title: gaugeCard.title + accentColor: gaugeCard.accentColor + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + Canvas { + id: gaugeCanvas + + anchors.centerIn: parent + width: Math.min(parent.width, parent.height) + height: width + onPaint: { + const ctx = getContext("2d"); + ctx.reset(); + const cx = width / 2; + const cy = height / 2; + const radius = (Math.min(width, height) - 12) / 2; + const lineWidth = 10; + ctx.beginPath(); + ctx.arc(cx, cy, radius, gaugeCard.arcStartAngle, gaugeCard.arcStartAngle + gaugeCard.arcSweep); + ctx.lineWidth = lineWidth; + ctx.lineCap = "round"; + ctx.strokeStyle = Colours.layer(Colours.palette.m3surfaceContainerHigh, 2); + ctx.stroke(); + if (gaugeCard.animatedPercentage > 0) { + ctx.beginPath(); + ctx.arc(cx, cy, radius, gaugeCard.arcStartAngle, gaugeCard.arcStartAngle + gaugeCard.arcSweep * gaugeCard.animatedPercentage); + ctx.lineWidth = lineWidth; + ctx.lineCap = "round"; + ctx.strokeStyle = gaugeCard.accentColor; + ctx.stroke(); + } + } + Component.onCompleted: requestPaint() + + Connections { + function onAnimatedPercentageChanged() { + gaugeCanvas.requestPaint(); + } + + target: gaugeCard + } + + Connections { + function onPaletteChanged() { + gaugeCanvas.requestPaint(); + } + + target: Colours + } + } + + StyledText { + anchors.centerIn: parent + text: `${Math.round(gaugeCard.percentage * 100)}%` + font.pointSize: Appearance.font.size.extraLarge + font.weight: Font.Medium + color: gaugeCard.accentColor + } + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: gaugeCard.subtitle + font.pointSize: Appearance.font.size.smaller + color: Colours.palette.m3onSurfaceVariant + } + } + + Behavior on animatedPercentage { + Anim { + duration: Appearance.anim.durations.large + } + } + } + + component StorageGaugeCard: StyledRect { + id: storageGaugeCard + + property int currentDiskIndex: 0 + readonly property var currentDisk: SystemUsage.disks.length > 0 ? SystemUsage.disks[currentDiskIndex] : null + property int diskCount: 0 + readonly property real arcStartAngle: 0.75 * Math.PI + readonly property real arcSweep: 1.5 * Math.PI + property real animatedPercentage: 0 + property color accentColor: Colours.palette.m3secondary + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.large + clip: true + Component.onCompleted: { + diskCount = SystemUsage.disks.length; + if (currentDisk) + animatedPercentage = currentDisk.perc; + } + onCurrentDiskChanged: { + if (currentDisk) + animatedPercentage = currentDisk.perc; + } + + // Update diskCount and animatedPercentage when disks data changes + Connections { + function onDisksChanged() { + if (SystemUsage.disks.length !== storageGaugeCard.diskCount) + storageGaugeCard.diskCount = SystemUsage.disks.length; + + // Update animated percentage when disk data refreshes + if (storageGaugeCard.currentDisk) + storageGaugeCard.animatedPercentage = storageGaugeCard.currentDisk.perc; + } + + target: SystemUsage + } + + MouseArea { + anchors.fill: parent + onWheel: wheel => { + if (wheel.angleDelta.y > 0) + storageGaugeCard.currentDiskIndex = (storageGaugeCard.currentDiskIndex - 1 + storageGaugeCard.diskCount) % storageGaugeCard.diskCount; + else if (wheel.angleDelta.y < 0) + storageGaugeCard.currentDiskIndex = (storageGaugeCard.currentDiskIndex + 1) % storageGaugeCard.diskCount; + } + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.smaller + + CardHeader { + icon: "hard_disk" + title: { + const base = qsTr("Storage"); + if (!storageGaugeCard.currentDisk) + return base; + + return `${base} - ${storageGaugeCard.currentDisk.mount}`; + } + accentColor: storageGaugeCard.accentColor + + // Scroll hint icon + MaterialIcon { + text: "unfold_more" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.normal + visible: storageGaugeCard.diskCount > 1 + opacity: 0.7 + ToolTip.visible: hintHover.hovered + ToolTip.text: qsTr("Scroll to switch disks") + ToolTip.delay: 500 + + HoverHandler { + id: hintHover + } + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + Canvas { + id: storageGaugeCanvas + + anchors.centerIn: parent + width: Math.min(parent.width, parent.height) + height: width + onPaint: { + const ctx = getContext("2d"); + ctx.reset(); + const cx = width / 2; + const cy = height / 2; + const radius = (Math.min(width, height) - 12) / 2; + const lineWidth = 10; + ctx.beginPath(); + ctx.arc(cx, cy, radius, storageGaugeCard.arcStartAngle, storageGaugeCard.arcStartAngle + storageGaugeCard.arcSweep); + ctx.lineWidth = lineWidth; + ctx.lineCap = "round"; + ctx.strokeStyle = Colours.layer(Colours.palette.m3surfaceContainerHigh, 2); + ctx.stroke(); + if (storageGaugeCard.animatedPercentage > 0) { + ctx.beginPath(); + ctx.arc(cx, cy, radius, storageGaugeCard.arcStartAngle, storageGaugeCard.arcStartAngle + storageGaugeCard.arcSweep * storageGaugeCard.animatedPercentage); + ctx.lineWidth = lineWidth; + ctx.lineCap = "round"; + ctx.strokeStyle = storageGaugeCard.accentColor; + ctx.stroke(); + } + } + Component.onCompleted: requestPaint() + + Connections { + function onAnimatedPercentageChanged() { + storageGaugeCanvas.requestPaint(); + } + + target: storageGaugeCard + } + + Connections { + function onPaletteChanged() { + storageGaugeCanvas.requestPaint(); + } + + target: Colours + } + } + + StyledText { + anchors.centerIn: parent + text: storageGaugeCard.currentDisk ? `${Math.round(storageGaugeCard.currentDisk.perc * 100)}%` : "—" + font.pointSize: Appearance.font.size.extraLarge + font.weight: Font.Medium + color: storageGaugeCard.accentColor + } + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: { + if (!storageGaugeCard.currentDisk) + return "—"; + + const usedFmt = SystemUsage.formatKib(storageGaugeCard.currentDisk.used); + const totalFmt = SystemUsage.formatKib(storageGaugeCard.currentDisk.total); + return `${usedFmt.value.toFixed(1)} / ${Math.floor(totalFmt.value)} ${totalFmt.unit}`; + } + font.pointSize: Appearance.font.size.smaller + color: Colours.palette.m3onSurfaceVariant + } + } + + Behavior on animatedPercentage { + Anim { + duration: Appearance.anim.durations.large + } + } + } + + component NetworkCard: StyledRect { + id: networkCard + + property color accentColor: Colours.palette.m3primary + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.large + clip: true + + Ref { + service: NetworkUsage + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.small + + CardHeader { + icon: "swap_vert" + title: qsTr("Network") + accentColor: networkCard.accentColor + } + + // Sparkline graph + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + Canvas { + id: sparklineCanvas + + property var downHistory: NetworkUsage.downloadHistory + property var upHistory: NetworkUsage.uploadHistory + property real targetMax: 1024 + property real smoothMax: targetMax + property real slideProgress: 0 + property int _tickCount: 0 + property int _lastTickCount: -1 + + function checkAndAnimate(): void { + const currentLength = (downHistory || []).length; + if (currentLength > 0 && _tickCount !== _lastTickCount) { + _lastTickCount = _tickCount; + updateMax(); + } + } + + function updateMax(): void { + const downHist = downHistory || []; + const upHist = upHistory || []; + const allValues = downHist.concat(upHist); + targetMax = Math.max(...allValues, 1024); + requestPaint(); + } + + anchors.fill: parent + onDownHistoryChanged: checkAndAnimate() + onUpHistoryChanged: checkAndAnimate() + onSmoothMaxChanged: requestPaint() + onSlideProgressChanged: requestPaint() + + onPaint: { + const ctx = getContext("2d"); + ctx.reset(); + const w = width; + const h = height; + const downHist = downHistory || []; + const upHist = upHistory || []; + if (downHist.length < 2 && upHist.length < 2) + return; + + const maxVal = smoothMax; + + const drawLine = (history, color, fillAlpha) => { + if (history.length < 2) + return; + + const len = history.length; + const stepX = w / (NetworkUsage.historyLength - 1); + const startX = w - (len - 1) * stepX - stepX * slideProgress + stepX; + ctx.beginPath(); + ctx.moveTo(startX, h - (history[0] / maxVal) * h); + for (let i = 1; i < len; i++) { + const x = startX + i * stepX; + const y = h - (history[i] / maxVal) * h; + ctx.lineTo(x, y); + } + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.lineCap = "round"; + ctx.lineJoin = "round"; + ctx.stroke(); + ctx.lineTo(startX + (len - 1) * stepX, h); + ctx.lineTo(startX, h); + ctx.closePath(); + ctx.fillStyle = Qt.rgba(Qt.color(color).r, Qt.color(color).g, Qt.color(color).b, fillAlpha); + ctx.fill(); + }; + + drawLine(upHist, Colours.palette.m3secondary.toString(), 0.15); + drawLine(downHist, Colours.palette.m3tertiary.toString(), 0.2); + } + + Component.onCompleted: updateMax() + + Connections { + function onPaletteChanged() { + sparklineCanvas.requestPaint(); + } + + target: Colours + } + + Timer { + interval: Config.dashboard.resourceUpdateInterval + running: true + repeat: true + onTriggered: sparklineCanvas._tickCount++ + } + + NumberAnimation on slideProgress { + from: 0 + to: 1 + duration: Config.dashboard.resourceUpdateInterval + loops: Animation.Infinite + running: true + } + + Behavior on smoothMax { + Anim { + duration: Appearance.anim.durations.large + } + } + } + + // "No data" placeholder + StyledText { + anchors.centerIn: parent + text: qsTr("Collecting data...") + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + visible: NetworkUsage.downloadHistory.length < 2 + opacity: 0.6 + } + } + + // Download row + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + MaterialIcon { + text: "download" + color: Colours.palette.m3tertiary + font.pointSize: Appearance.font.size.normal + } + + StyledText { + text: qsTr("Download") + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + } + + Item { + Layout.fillWidth: true + } + + StyledText { + text: { + const fmt = NetworkUsage.formatBytes(NetworkUsage.downloadSpeed ?? 0); + return fmt ? `${fmt.value.toFixed(1)} ${fmt.unit}` : "0.0 B/s"; + } + font.pointSize: Appearance.font.size.normal + font.weight: Font.Medium + color: Colours.palette.m3tertiary + } + } + + // Upload row + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + MaterialIcon { + text: "upload" + color: Colours.palette.m3secondary + font.pointSize: Appearance.font.size.normal + } + + StyledText { + text: qsTr("Upload") + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + } + + Item { + Layout.fillWidth: true + } + + StyledText { + text: { + const fmt = NetworkUsage.formatBytes(NetworkUsage.uploadSpeed ?? 0); + return fmt ? `${fmt.value.toFixed(1)} ${fmt.unit}` : "0.0 B/s"; + } + font.pointSize: Appearance.font.size.normal + font.weight: Font.Medium + color: Colours.palette.m3secondary + } + } + + // Session totals + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + MaterialIcon { + text: "history" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.normal + } + + StyledText { + text: qsTr("Total") + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + } + + Item { + Layout.fillWidth: true + } + + StyledText { + text: { + const down = NetworkUsage.formatBytesTotal(NetworkUsage.downloadTotal ?? 0); + const up = NetworkUsage.formatBytesTotal(NetworkUsage.uploadTotal ?? 0); + return (down && up) ? `↓${down.value.toFixed(1)}${down.unit} ↑${up.value.toFixed(1)}${up.unit}` : "↓0.0B ↑0.0B"; + } + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/Tabs.qml b/.config/quickshell/caelestia/modules/dashboard/Tabs.qml new file mode 100644 index 0000000..1d50d26 --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/Tabs.qml @@ -0,0 +1,247 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.services +import qs.config +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Controls + +Item { + id: root + + required property real nonAnimWidth + required property PersistentProperties state + readonly property alias count: bar.count + + implicitHeight: bar.implicitHeight + indicator.implicitHeight + indicator.anchors.topMargin + separator.implicitHeight + + TabBar { + id: bar + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + + currentIndex: root.state.currentTab + background: null + + onCurrentIndexChanged: root.state.currentTab = currentIndex + + Tab { + iconName: "dashboard" + text: qsTr("Dashboard") + } + + Tab { + iconName: "queue_music" + text: qsTr("Media") + } + + Tab { + iconName: "speed" + text: qsTr("Performance") + } + + Tab { + iconName: "cloud" + text: qsTr("Weather") + } + + // Tab { + // iconName: "workspaces" + // text: qsTr("Workspaces") + // } + } + + Item { + id: indicator + + anchors.top: bar.bottom + anchors.topMargin: 5 + + implicitWidth: bar.currentItem.implicitWidth + implicitHeight: 3 + + x: { + const tab = bar.currentItem; + const width = (root.nonAnimWidth - bar.spacing * (bar.count - 1)) / bar.count; + return width * tab.TabBar.index + (width - tab.implicitWidth) / 2; + } + + clip: true + + StyledRect { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: parent.implicitHeight * 2 + + color: Colours.palette.m3primary + radius: Appearance.rounding.full + } + + Behavior on x { + Anim {} + } + + Behavior on implicitWidth { + Anim {} + } + } + + StyledRect { + id: separator + + anchors.top: indicator.bottom + anchors.left: parent.left + anchors.right: parent.right + + implicitHeight: 1 + color: Colours.palette.m3outlineVariant + } + + component Tab: TabButton { + id: tab + + required property string iconName + readonly property bool current: TabBar.tabBar.currentItem === this + + background: null + + contentItem: CustomMouseArea { + id: mouse + + implicitWidth: Math.max(icon.width, label.width) + implicitHeight: icon.height + label.height + + cursorShape: Qt.PointingHandCursor + + onPressed: event => { + root.state.currentTab = tab.TabBar.index; + + const stateY = stateWrapper.y; + rippleAnim.x = event.x; + rippleAnim.y = event.y - stateY; + + const dist = (ox, oy) => ox * ox + oy * oy; + rippleAnim.radius = Math.sqrt(Math.max(dist(event.x, event.y + stateY), dist(event.x, stateWrapper.height - event.y), dist(width - event.x, event.y + stateY), dist(width - event.x, stateWrapper.height - event.y))); + + rippleAnim.restart(); + } + + function onWheel(event: WheelEvent): void { + if (event.angleDelta.y < 0) + root.state.currentTab = Math.min(root.state.currentTab + 1, bar.count - 1); + else if (event.angleDelta.y > 0) + root.state.currentTab = Math.max(root.state.currentTab - 1, 0); + } + + SequentialAnimation { + id: rippleAnim + + property real x + property real y + property real radius + + PropertyAction { + target: ripple + property: "x" + value: rippleAnim.x + } + PropertyAction { + target: ripple + property: "y" + value: rippleAnim.y + } + PropertyAction { + target: ripple + property: "opacity" + value: 0.08 + } + Anim { + target: ripple + properties: "implicitWidth,implicitHeight" + from: 0 + to: rippleAnim.radius * 2 + duration: Appearance.anim.durations.normal + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + target: ripple + property: "opacity" + to: 0 + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + + ClippingRectangle { + id: stateWrapper + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + implicitHeight: parent.height + Config.dashboard.sizes.tabIndicatorSpacing * 2 + + color: "transparent" + radius: Appearance.rounding.small + + StyledRect { + id: stateLayer + + anchors.fill: parent + + color: tab.current ? Colours.palette.m3primary : Colours.palette.m3onSurface + opacity: mouse.pressed ? 0.1 : tab.hovered ? 0.08 : 0 + + Behavior on opacity { + Anim {} + } + } + + StyledRect { + id: ripple + + radius: Appearance.rounding.full + color: tab.current ? Colours.palette.m3primary : Colours.palette.m3onSurface + opacity: 0 + + transform: Translate { + x: -ripple.width / 2 + y: -ripple.height / 2 + } + } + } + + MaterialIcon { + id: icon + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: label.top + + text: tab.iconName + color: tab.current ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant + fill: tab.current ? 1 : 0 + font.pointSize: Appearance.font.size.large + + Behavior on fill { + Anim {} + } + } + + StyledText { + id: label + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + text: tab.text + color: tab.current ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/Weather.qml b/.config/quickshell/caelestia/modules/dashboard/Weather.qml new file mode 100644 index 0000000..3981633 --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/Weather.qml @@ -0,0 +1,280 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + implicitWidth: layout.implicitWidth > 800 ? layout.implicitWidth : 840 + implicitHeight: layout.implicitHeight + + readonly property var today: Weather.forecast && Weather.forecast.length > 0 ? Weather.forecast[0] : null + + Component.onCompleted: Weather.reload() + + ColumnLayout { + id: layout + + anchors.fill: parent + spacing: Appearance.spacing.smaller + + RowLayout { + Layout.leftMargin: Appearance.padding.large + Layout.rightMargin: Appearance.padding.large + Layout.fillWidth: true + + Column { + spacing: Appearance.spacing.small / 2 + + StyledText { + text: Weather.city || qsTr("Loading...") + font.pointSize: Appearance.font.size.extraLarge + font.weight: 600 + color: Colours.palette.m3onSurface + } + + StyledText { + text: new Date().toLocaleDateString(Qt.locale(), "dddd, MMMM d") + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3onSurfaceVariant + } + } + + Item { + Layout.fillWidth: true + } + + Row { + spacing: Appearance.spacing.large + + WeatherStat { + icon: "wb_twilight" + label: "Sunrise" + value: Weather.sunrise + colour: Colours.palette.m3tertiary + } + + WeatherStat { + icon: "bedtime" + label: "Sunset" + value: Weather.sunset + colour: Colours.palette.m3tertiary + } + } + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: bigInfoRow.implicitHeight + Appearance.padding.small * 2 + + radius: Appearance.rounding.large * 2 + color: Colours.tPalette.m3surfaceContainer + + RowLayout { + id: bigInfoRow + + anchors.centerIn: parent + spacing: Appearance.spacing.large + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + text: Weather.icon + font.pointSize: Appearance.font.size.extraLarge * 3 + color: Colours.palette.m3secondary + animate: true + } + + ColumnLayout { + Layout.alignment: Qt.AlignVCenter + spacing: -Appearance.spacing.small + + StyledText { + text: Weather.temp + font.pointSize: Appearance.font.size.extraLarge * 2 + font.weight: 500 + color: Colours.palette.m3primary + } + + StyledText { + Layout.leftMargin: Appearance.padding.small + text: Weather.description + font.pointSize: Appearance.font.size.normal + color: Colours.palette.m3onSurfaceVariant + } + } + } + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.smaller + + DetailCard { + icon: "water_drop" + label: "Humidity" + value: Weather.humidity + "%" + colour: Colours.palette.m3secondary + } + DetailCard { + icon: "thermostat" + label: "Feels Like" + value: Weather.feelsLike + colour: Colours.palette.m3primary + } + DetailCard { + icon: "air" + label: "Wind" + value: Weather.windSpeed ? Weather.windSpeed + " km/h" : "--" + colour: Colours.palette.m3tertiary + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + Layout.leftMargin: Appearance.padding.normal + visible: forecastRepeater.count > 0 + text: qsTr("7-Day Forecast") + font.pointSize: Appearance.font.size.normal + font.weight: 600 + color: Colours.palette.m3onSurface + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.smaller + + Repeater { + id: forecastRepeater + + model: Weather.forecast + + StyledRect { + id: forecastItem + + required property int index + required property var modelData + + Layout.fillWidth: true + implicitHeight: forecastItemColumn.implicitHeight + Appearance.padding.normal * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: forecastItemColumn + + anchors.centerIn: parent + spacing: Appearance.spacing.small + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: forecastItem.index === 0 ? qsTr("Today") : new Date(forecastItem.modelData.date).toLocaleDateString(Qt.locale(), "ddd") + font.pointSize: Appearance.font.size.normal + font.weight: 600 + color: Colours.palette.m3primary + } + + StyledText { + Layout.topMargin: -Appearance.spacing.small / 2 + Layout.alignment: Qt.AlignHCenter + text: new Date(forecastItem.modelData.date).toLocaleDateString(Qt.locale(), "MMM d") + font.pointSize: Appearance.font.size.small + opacity: 0.7 + color: Colours.palette.m3onSurfaceVariant + } + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: forecastItem.modelData.icon + font.pointSize: Appearance.font.size.extraLarge + color: Colours.palette.m3secondary + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: Config.services.useFahrenheit ? forecastItem.modelData.maxTempF + "°" + " / " + forecastItem.modelData.minTempF + "°" : forecastItem.modelData.maxTempC + "°" + " / " + forecastItem.modelData.minTempC + "°" + font.weight: 600 + color: Colours.palette.m3tertiary + } + } + } + } + } + } + + component DetailCard: StyledRect { + id: detailRoot + + property string icon + property string label + property string value + property color colour + + Layout.fillWidth: true + Layout.preferredHeight: 60 + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainer + + Row { + anchors.centerIn: parent + spacing: Appearance.spacing.normal + + MaterialIcon { + text: detailRoot.icon + color: detailRoot.colour + font.pointSize: Appearance.font.size.large + anchors.verticalCenter: parent.verticalCenter + } + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: 0 + + StyledText { + text: detailRoot.label + font.pointSize: Appearance.font.size.smaller + opacity: 0.7 + horizontalAlignment: Text.AlignLeft + } + StyledText { + text: detailRoot.value + font.weight: 600 + horizontalAlignment: Text.AlignLeft + } + } + } + } + + component WeatherStat: Row { + id: weatherStat + + property string icon + property string label + property string value + property color colour + + spacing: Appearance.spacing.small + + MaterialIcon { + text: weatherStat.icon + font.pointSize: Appearance.font.size.extraLarge + color: weatherStat.colour + } + + Column { + StyledText { + text: weatherStat.label + font.pointSize: Appearance.font.size.smaller + color: Colours.palette.m3onSurfaceVariant + } + StyledText { + text: weatherStat.value + font.pointSize: Appearance.font.size.small + font.weight: 600 + color: Colours.palette.m3onSurface + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/Wrapper.qml b/.config/quickshell/caelestia/modules/dashboard/Wrapper.qml new file mode 100644 index 0000000..0e37909 --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/Wrapper.qml @@ -0,0 +1,105 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.filedialog +import qs.config +import qs.utils +import Caelestia +import Quickshell +import QtQuick + +Item { + id: root + + required property PersistentProperties visibilities + readonly property PersistentProperties dashState: PersistentProperties { + property int currentTab + property date currentDate: new Date() + + reloadableId: "dashboardState" + } + readonly property FileDialog facePicker: FileDialog { + title: qsTr("Select a profile picture") + filterLabel: qsTr("Image files") + filters: Images.validImageExtensions + onAccepted: path => { + if (CUtils.copyFile(Qt.resolvedUrl(path), Qt.resolvedUrl(`${Paths.home}/.face`))) + Quickshell.execDetached(["notify-send", "-a", "caelestia-shell", "-u", "low", "-h", `STRING:image-path:${path}`, "Profile picture changed", `Profile picture changed to ${Paths.shortenHome(path)}`]); + else + Quickshell.execDetached(["notify-send", "-a", "caelestia-shell", "-u", "critical", "Unable to change profile picture", `Failed to change profile picture to ${Paths.shortenHome(path)}`]); + } + } + + readonly property real nonAnimHeight: state === "visible" ? (content.item?.nonAnimHeight ?? 0) : 0 + + visible: height > 0 + implicitHeight: 0 + implicitWidth: content.implicitWidth + + onStateChanged: { + if (state === "visible" && timer.running) { + timer.triggered(); + timer.stop(); + } + } + + states: State { + name: "visible" + when: root.visibilities.dashboard && Config.dashboard.enabled + + PropertyChanges { + root.implicitHeight: content.implicitHeight + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + target: root + property: "implicitHeight" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + }, + Transition { + from: "visible" + to: "" + + Anim { + target: root + property: "implicitHeight" + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + ] + + Timer { + id: timer + + running: true + interval: Appearance.anim.durations.extraLarge + onTriggered: { + content.active = Qt.binding(() => (root.visibilities.dashboard && Config.dashboard.enabled) || root.visible); + content.visible = true; + } + } + + Loader { + id: content + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + visible: false + active: true + + sourceComponent: Content { + visibilities: root.visibilities + state: root.dashState + facePicker: root.facePicker + } + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/dash/Calendar.qml b/.config/quickshell/caelestia/modules/dashboard/dash/Calendar.qml new file mode 100644 index 0000000..56c0493 --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/dash/Calendar.qml @@ -0,0 +1,253 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.effects +import qs.components.controls +import qs.services +import qs.config +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +CustomMouseArea { + id: root + + required property var state + + readonly property int currMonth: state.currentDate.getMonth() + readonly property int currYear: state.currentDate.getFullYear() + + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: inner.implicitHeight + inner.anchors.margins * 2 + + acceptedButtons: Qt.MiddleButton + onClicked: root.state.currentDate = new Date() + + function onWheel(event: WheelEvent): void { + if (event.angleDelta.y > 0) + root.state.currentDate = new Date(root.currYear, root.currMonth - 1, 1); + else if (event.angleDelta.y < 0) + root.state.currentDate = new Date(root.currYear, root.currMonth + 1, 1); + } + + ColumnLayout { + id: inner + + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.small + + RowLayout { + id: monthNavigationRow + + Layout.fillWidth: true + spacing: Appearance.spacing.small + + Item { + implicitWidth: implicitHeight + implicitHeight: prevMonthText.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + id: prevMonthStateLayer + + radius: Appearance.rounding.full + + function onClicked(): void { + root.state.currentDate = new Date(root.currYear, root.currMonth - 1, 1); + } + } + + MaterialIcon { + id: prevMonthText + + anchors.centerIn: parent + text: "chevron_left" + color: Colours.palette.m3tertiary + font.pointSize: Appearance.font.size.normal + font.weight: 700 + } + } + + Item { + Layout.fillWidth: true + + implicitWidth: monthYearDisplay.implicitWidth + Appearance.padding.small * 2 + implicitHeight: monthYearDisplay.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + anchors.fill: monthYearDisplay + anchors.margins: -Appearance.padding.small + anchors.leftMargin: -Appearance.padding.normal + anchors.rightMargin: -Appearance.padding.normal + + radius: Appearance.rounding.full + disabled: { + const now = new Date(); + return root.currMonth === now.getMonth() && root.currYear === now.getFullYear(); + } + + function onClicked(): void { + root.state.currentDate = new Date(); + } + } + + StyledText { + id: monthYearDisplay + + anchors.centerIn: parent + text: grid.title + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.normal + font.weight: 500 + font.capitalization: Font.Capitalize + } + } + + Item { + implicitWidth: implicitHeight + implicitHeight: nextMonthText.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + id: nextMonthStateLayer + + radius: Appearance.rounding.full + + function onClicked(): void { + root.state.currentDate = new Date(root.currYear, root.currMonth + 1, 1); + } + } + + MaterialIcon { + id: nextMonthText + + anchors.centerIn: parent + text: "chevron_right" + color: Colours.palette.m3tertiary + font.pointSize: Appearance.font.size.normal + font.weight: 700 + } + } + } + + DayOfWeekRow { + id: daysRow + + Layout.fillWidth: true + locale: grid.locale + + delegate: StyledText { + required property var model + + horizontalAlignment: Text.AlignHCenter + text: model.shortName + font.weight: 500 + color: (model.day === 0 || model.day === 6) ? Colours.palette.m3secondary : Colours.palette.m3onSurfaceVariant + } + } + + Item { + Layout.fillWidth: true + implicitHeight: grid.implicitHeight + + MonthGrid { + id: grid + + month: root.currMonth + year: root.currYear + + anchors.fill: parent + + spacing: 3 + locale: Qt.locale() + + delegate: Item { + id: dayItem + + required property var model + + implicitWidth: implicitHeight + implicitHeight: text.implicitHeight + Appearance.padding.small * 2 + + StyledText { + id: text + + anchors.centerIn: parent + + horizontalAlignment: Text.AlignHCenter + text: grid.locale.toString(dayItem.model.day) + color: { + const dayOfWeek = dayItem.model.date.getUTCDay(); + if (dayOfWeek === 0 || dayOfWeek === 6) + return Colours.palette.m3secondary; + + return Colours.palette.m3onSurfaceVariant; + } + opacity: dayItem.model.today || dayItem.model.month === grid.month ? 1 : 0.4 + font.pointSize: Appearance.font.size.normal + font.weight: 500 + } + } + } + + StyledRect { + id: todayIndicator + + readonly property Item todayItem: grid.contentItem.children.find(c => c.model.today) ?? null + property Item today + + onTodayItemChanged: { + if (todayItem) + today = todayItem; + } + + x: today ? today.x + (today.width - implicitWidth) / 2 : 0 + y: today?.y ?? 0 + + implicitWidth: today?.implicitWidth ?? 0 + implicitHeight: today?.implicitHeight ?? 0 + + clip: true + radius: Appearance.rounding.full + color: Colours.palette.m3primary + + opacity: todayItem ? 1 : 0 + scale: todayItem ? 1 : 0.7 + + Colouriser { + x: -todayIndicator.x + y: -todayIndicator.y + + implicitWidth: grid.width + implicitHeight: grid.height + + source: grid + sourceColor: Colours.palette.m3onSurface + colorizationColor: Colours.palette.m3onPrimary + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + Behavior on x { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + Behavior on y { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/dash/DateTime.qml b/.config/quickshell/caelestia/modules/dashboard/dash/DateTime.qml new file mode 100644 index 0000000..e740448 --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/dash/DateTime.qml @@ -0,0 +1,65 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + anchors.top: parent.top + anchors.bottom: parent.bottom + implicitWidth: Config.dashboard.sizes.dateTimeWidth + + ColumnLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + spacing: 0 + + StyledText { + Layout.bottomMargin: -(font.pointSize * 0.4) + Layout.alignment: Qt.AlignHCenter + text: Time.hourStr + color: Colours.palette.m3secondary + font.pointSize: Appearance.font.size.extraLarge + font.family: Appearance.font.family.clock + font.weight: 600 + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: "•••" + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.extraLarge * 0.9 + font.family: Appearance.font.family.clock + } + + StyledText { + Layout.topMargin: -(font.pointSize * 0.4) + Layout.alignment: Qt.AlignHCenter + text: Time.minuteStr + color: Colours.palette.m3secondary + font.pointSize: Appearance.font.size.extraLarge + font.family: Appearance.font.family.clock + font.weight: 600 + } + + Loader { + Layout.alignment: Qt.AlignHCenter + + active: Config.services.useTwelveHourClock + visible: active + + sourceComponent: StyledText { + text: Time.amPmStr + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.large + font.family: Appearance.font.family.clock + font.weight: 600 + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/dash/Media.qml b/.config/quickshell/caelestia/modules/dashboard/dash/Media.qml new file mode 100644 index 0000000..d650669 --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/dash/Media.qml @@ -0,0 +1,254 @@ +import qs.components +import qs.services +import qs.config +import qs.utils +import Caelestia.Services +import QtQuick +import QtQuick.Shapes + +Item { + id: root + + property real playerProgress: { + const active = Players.active; + return active?.length ? active.position / active.length : 0; + } + + anchors.top: parent.top + anchors.bottom: parent.bottom + implicitWidth: Config.dashboard.sizes.mediaWidth + + Behavior on playerProgress { + Anim { + duration: Appearance.anim.durations.large + } + } + + Timer { + running: Players.active?.isPlaying ?? false + interval: Config.dashboard.mediaUpdateInterval + triggeredOnStart: true + repeat: true + onTriggered: Players.active?.positionChanged() + } + + ServiceRef { + service: Audio.beatTracker + } + + Shape { + preferredRendererType: Shape.CurveRenderer + + ShapePath { + fillColor: "transparent" + strokeColor: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + strokeWidth: Config.dashboard.sizes.mediaProgressThickness + capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap + + PathAngleArc { + centerX: cover.x + cover.width / 2 + centerY: cover.y + cover.height / 2 + radiusX: (cover.width + Config.dashboard.sizes.mediaProgressThickness) / 2 + Appearance.spacing.small + radiusY: (cover.height + Config.dashboard.sizes.mediaProgressThickness) / 2 + Appearance.spacing.small + startAngle: -90 - Config.dashboard.sizes.mediaProgressSweep / 2 + sweepAngle: Config.dashboard.sizes.mediaProgressSweep + } + + Behavior on strokeColor { + CAnim {} + } + } + + ShapePath { + fillColor: "transparent" + strokeColor: Colours.palette.m3primary + strokeWidth: Config.dashboard.sizes.mediaProgressThickness + capStyle: Appearance.rounding.scale === 0 ? ShapePath.SquareCap : ShapePath.RoundCap + + PathAngleArc { + centerX: cover.x + cover.width / 2 + centerY: cover.y + cover.height / 2 + radiusX: (cover.width + Config.dashboard.sizes.mediaProgressThickness) / 2 + Appearance.spacing.small + radiusY: (cover.height + Config.dashboard.sizes.mediaProgressThickness) / 2 + Appearance.spacing.small + startAngle: -90 - Config.dashboard.sizes.mediaProgressSweep / 2 + sweepAngle: Config.dashboard.sizes.mediaProgressSweep * root.playerProgress + } + + Behavior on strokeColor { + CAnim {} + } + } + } + + StyledClippingRect { + id: cover + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.large + Config.dashboard.sizes.mediaProgressThickness + Appearance.spacing.small + + implicitHeight: width + color: Colours.tPalette.m3surfaceContainerHigh + radius: Infinity + + MaterialIcon { + anchors.centerIn: parent + + grade: 200 + text: "art_track" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: (parent.width * 0.4) || 1 + } + + Image { + id: image + + anchors.fill: parent + + source: Players.active?.trackArtUrl ?? "" // qmllint disable incompatible-type + asynchronous: true + fillMode: Image.PreserveAspectCrop + sourceSize.width: width + sourceSize.height: height + } + } + + StyledText { + id: title + + anchors.top: cover.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Appearance.spacing.normal + + animate: true + horizontalAlignment: Text.AlignHCenter + text: (Players.active?.trackTitle ?? qsTr("No media")) || qsTr("Unknown title") + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.normal + + width: parent.implicitWidth - Appearance.padding.large * 2 + elide: Text.ElideRight + } + + StyledText { + id: album + + anchors.top: title.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Appearance.spacing.small + + animate: true + horizontalAlignment: Text.AlignHCenter + text: (Players.active?.trackAlbum ?? qsTr("No media")) || qsTr("Unknown album") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + + width: parent.implicitWidth - Appearance.padding.large * 2 + elide: Text.ElideRight + } + + StyledText { + id: artist + + anchors.top: album.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Appearance.spacing.small + + animate: true + horizontalAlignment: Text.AlignHCenter + text: (Players.active?.trackArtist ?? qsTr("No media")) || qsTr("Unknown artist") + color: Colours.palette.m3secondary + + width: parent.implicitWidth - Appearance.padding.large * 2 + elide: Text.ElideRight + } + + Row { + id: controls + + anchors.top: artist.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Appearance.spacing.smaller + + spacing: Appearance.spacing.small + + Control { + icon: "skip_previous" + canUse: Players.active?.canGoPrevious ?? false + + function onClicked(): void { + Players.active?.previous(); + } + } + + Control { + icon: Players.active?.isPlaying ? "pause" : "play_arrow" + canUse: Players.active?.canTogglePlaying ?? false + + function onClicked(): void { + Players.active?.togglePlaying(); + } + } + + Control { + icon: "skip_next" + canUse: Players.active?.canGoNext ?? false + + function onClicked(): void { + Players.active?.next(); + } + } + } + + AnimatedImage { + id: bongocat + + anchors.top: controls.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: Appearance.spacing.small + anchors.bottomMargin: Appearance.padding.large + anchors.margins: Appearance.padding.large * 2 + + playing: Players.active?.isPlaying ?? false + speed: Audio.beatTracker.bpm / Appearance.anim.mediaGifSpeedAdjustment + source: Paths.absolutePath(Config.paths.mediaGif) + asynchronous: true + fillMode: AnimatedImage.PreserveAspectFit + } + + component Control: StyledRect { + id: control + + required property string icon + required property bool canUse + function onClicked(): void { + } + + implicitWidth: Math.max(icon.implicitHeight, icon.implicitHeight) + Appearance.padding.small + implicitHeight: implicitWidth + + StateLayer { + disabled: !control.canUse + radius: Appearance.rounding.full + + function onClicked(): void { + control.onClicked(); + } + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + anchors.verticalCenterOffset: font.pointSize * 0.05 + + animate: true + text: control.icon + color: control.canUse ? Colours.palette.m3onSurface : Colours.palette.m3outline + font.pointSize: Appearance.font.size.large + } + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/dash/Resources.qml b/.config/quickshell/caelestia/modules/dashboard/dash/Resources.qml new file mode 100644 index 0000000..7f44a9d --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/dash/Resources.qml @@ -0,0 +1,87 @@ +import qs.components +import qs.components.misc +import qs.services +import qs.config +import QtQuick + +Row { + id: root + + anchors.top: parent.top + anchors.bottom: parent.bottom + + padding: Appearance.padding.large + spacing: Appearance.spacing.normal + + Ref { + service: SystemUsage + } + + Resource { + icon: "memory" + value: SystemUsage.cpuPerc + colour: Colours.palette.m3primary + } + + Resource { + icon: "memory_alt" + value: SystemUsage.memPerc + colour: Colours.palette.m3secondary + } + + Resource { + icon: "hard_disk" + value: SystemUsage.storagePerc + colour: Colours.palette.m3tertiary + } + + component Resource: Item { + id: res + + required property string icon + required property real value + required property color colour + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: Appearance.padding.large + implicitWidth: icon.implicitWidth + + StyledRect { + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.bottom: icon.top + anchors.bottomMargin: Appearance.spacing.small + + implicitWidth: Config.dashboard.sizes.resourceProgessThickness + + color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + radius: Appearance.rounding.full + + StyledRect { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + implicitHeight: res.value * parent.height + + color: res.colour + radius: Appearance.rounding.full + } + } + + MaterialIcon { + id: icon + + anchors.bottom: parent.bottom + + text: res.icon + color: res.colour + } + + Behavior on value { + Anim { + duration: Appearance.anim.durations.large + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/dash/User.qml b/.config/quickshell/caelestia/modules/dashboard/dash/User.qml new file mode 100644 index 0000000..b66b1f9 --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/dash/User.qml @@ -0,0 +1,195 @@ +import qs.components +import qs.components.effects +import qs.components.images +import qs.components.filedialog +import qs.services +import qs.config +import qs.utils +import Quickshell +import QtQuick + +Row { + id: root + + required property PersistentProperties visibilities + required property PersistentProperties state + required property FileDialog facePicker + + padding: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledClippingRect { + implicitWidth: info.implicitHeight + implicitHeight: info.implicitHeight + + radius: Appearance.rounding.large + color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + + MaterialIcon { + anchors.centerIn: parent + + text: "person" + fill: 1 + grade: 200 + font.pointSize: Math.floor(info.implicitHeight / 2) || 1 + } + + CachingImage { + id: pfp + + anchors.fill: parent + path: `${Paths.home}/.face` + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + + StyledRect { + anchors.fill: parent + + color: Qt.alpha(Colours.palette.m3scrim, 0.5) + opacity: parent.containsMouse ? 1 : 0 + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + } + } + } + + StyledRect { + anchors.centerIn: parent + + implicitWidth: selectIcon.implicitHeight + Appearance.padding.small * 2 + implicitHeight: selectIcon.implicitHeight + Appearance.padding.small * 2 + + radius: Appearance.rounding.normal + color: Colours.palette.m3primary + scale: parent.containsMouse ? 1 : 0.5 + opacity: parent.containsMouse ? 1 : 0 + + StateLayer { + color: Colours.palette.m3onPrimary + + function onClicked(): void { + root.visibilities.launcher = false; + root.facePicker.open(); + } + } + + MaterialIcon { + id: selectIcon + + anchors.centerIn: parent + anchors.horizontalCenterOffset: -font.pointSize * 0.02 + + text: "frame_person" + color: Colours.palette.m3onPrimary + font.pointSize: Appearance.font.size.extraLarge + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + } + } + } + } + } + + Column { + id: info + + anchors.verticalCenter: parent.verticalCenter + spacing: Appearance.spacing.normal + + Item { + id: line + + implicitWidth: icon.implicitWidth + text.width + text.anchors.leftMargin + implicitHeight: Math.max(icon.implicitHeight, text.implicitHeight) + + ColouredIcon { + id: icon + + anchors.left: parent.left + anchors.leftMargin: (Config.dashboard.sizes.infoIconSize - implicitWidth) / 2 + + source: SysInfo.osLogo + implicitSize: Math.floor(Appearance.font.size.normal * 1.34) + colour: Colours.palette.m3primary + } + + StyledText { + id: text + + anchors.verticalCenter: icon.verticalCenter + anchors.left: icon.right + anchors.leftMargin: icon.anchors.leftMargin + text: `: ${SysInfo.osPrettyName || SysInfo.osName}` + font.pointSize: Appearance.font.size.normal + + width: Config.dashboard.sizes.infoWidth + elide: Text.ElideRight + } + } + + InfoLine { + icon: "select_window_2" + text: SysInfo.wm + colour: Colours.palette.m3secondary + } + + InfoLine { + id: uptime + + icon: "timer" + text: qsTr("up %1").arg(SysInfo.uptime) + colour: Colours.palette.m3tertiary + } + } + + component InfoLine: Item { + id: line + + required property string icon + required property string text + required property color colour + + implicitWidth: icon.implicitWidth + text.width + text.anchors.leftMargin + implicitHeight: Math.max(icon.implicitHeight, text.implicitHeight) + + MaterialIcon { + id: icon + + anchors.left: parent.left + anchors.leftMargin: (Config.dashboard.sizes.infoIconSize - implicitWidth) / 2 + + fill: 1 + text: line.icon + color: line.colour + font.pointSize: Appearance.font.size.normal + } + + StyledText { + id: text + + anchors.verticalCenter: icon.verticalCenter + anchors.left: icon.right + anchors.leftMargin: icon.anchors.leftMargin + text: `: ${line.text}` + font.pointSize: Appearance.font.size.normal + + width: Config.dashboard.sizes.infoWidth + elide: Text.ElideRight + } + } +} diff --git a/.config/quickshell/caelestia/modules/dashboard/dash/Weather.qml b/.config/quickshell/caelestia/modules/dashboard/dash/Weather.qml new file mode 100644 index 0000000..c90ccf0 --- /dev/null +++ b/.config/quickshell/caelestia/modules/dashboard/dash/Weather.qml @@ -0,0 +1,57 @@ +import qs.components +import qs.services +import qs.config +import qs.utils +import QtQuick + +Item { + id: root + + anchors.centerIn: parent + + implicitWidth: icon.implicitWidth + info.implicitWidth + info.anchors.leftMargin + + Component.onCompleted: Weather.reload() + + MaterialIcon { + id: icon + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + + animate: true + text: Weather.icon + color: Colours.palette.m3secondary + font.pointSize: Appearance.font.size.extraLarge * 2 + } + + Column { + id: info + + anchors.verticalCenter: parent.verticalCenter + anchors.left: icon.right + anchors.leftMargin: Appearance.spacing.large + + spacing: Appearance.spacing.small + + StyledText { + anchors.horizontalCenter: parent.horizontalCenter + + animate: true + text: Weather.temp + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.extraLarge + font.weight: 500 + } + + StyledText { + anchors.horizontalCenter: parent.horizontalCenter + + animate: true + text: Weather.description + + elide: Text.ElideRight + width: Math.min(implicitWidth, root.parent.width - icon.implicitWidth - info.anchors.leftMargin - Appearance.padding.large * 2) + } + } +} diff --git a/.config/quickshell/caelestia/modules/drawers/Backgrounds.qml b/.config/quickshell/caelestia/modules/drawers/Backgrounds.qml new file mode 100644 index 0000000..7fa2ca1 --- /dev/null +++ b/.config/quickshell/caelestia/modules/drawers/Backgrounds.qml @@ -0,0 +1,86 @@ +import qs.services +import qs.config +import qs.modules.osd as Osd +import qs.modules.notifications as Notifications +import qs.modules.session as Session +import qs.modules.launcher as Launcher +import qs.modules.dashboard as Dashboard +import qs.modules.bar.popouts as BarPopouts +import qs.modules.utilities as Utilities +import qs.modules.sidebar as Sidebar +import QtQuick +import QtQuick.Shapes + +Shape { + id: root + + required property Panels panels + required property Item bar + + anchors.fill: parent + anchors.margins: Config.border.thickness + anchors.leftMargin: bar.implicitWidth + preferredRendererType: Shape.CurveRenderer + + Osd.Background { + wrapper: root.panels.osd + + startX: root.width - root.panels.session.width - root.panels.sidebar.width + startY: (root.height - wrapper.height) / 2 - rounding + } + + Notifications.Background { + wrapper: root.panels.notifications + sidebar: sidebar + + startX: root.width + startY: 0 + } + + Session.Background { + wrapper: root.panels.session + + startX: root.width - root.panels.sidebar.width + startY: (root.height - wrapper.height) / 2 - rounding + } + + Launcher.Background { + wrapper: root.panels.launcher + + startX: (root.width - wrapper.width) / 2 - rounding + startY: root.height + } + + Dashboard.Background { + wrapper: root.panels.dashboard + + startX: (root.width - wrapper.width) / 2 - rounding + startY: 0 + } + + BarPopouts.Background { + wrapper: root.panels.popouts + invertBottomRounding: wrapper.y + wrapper.height + 1 >= root.height + + startX: wrapper.x + startY: wrapper.y - rounding * sideRounding + } + + Utilities.Background { + wrapper: root.panels.utilities + sidebar: sidebar + + startX: root.width + startY: root.height + } + + Sidebar.Background { + id: sidebar + + wrapper: root.panels.sidebar + panels: root.panels + + startX: root.width + startY: root.panels.notifications.height + } +} diff --git a/.config/quickshell/caelestia/modules/drawers/Border.qml b/.config/quickshell/caelestia/modules/drawers/Border.qml new file mode 100644 index 0000000..6fdd73b --- /dev/null +++ b/.config/quickshell/caelestia/modules/drawers/Border.qml @@ -0,0 +1,44 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Effects + +Item { + id: root + + required property Item bar + + anchors.fill: parent + + StyledRect { + anchors.fill: parent + color: Colours.palette.m3surface + + layer.enabled: true + layer.effect: MultiEffect { + maskSource: mask + maskEnabled: true + maskInverted: true + maskThresholdMin: 0.5 + maskSpreadAtMin: 1 + } + } + + Item { + id: mask + + anchors.fill: parent + layer.enabled: true + visible: false + + Rectangle { + anchors.fill: parent + anchors.margins: Config.border.thickness + anchors.leftMargin: root.bar.implicitWidth + radius: Config.border.rounding + } + } +} diff --git a/.config/quickshell/caelestia/modules/drawers/Drawers.qml b/.config/quickshell/caelestia/modules/drawers/Drawers.qml new file mode 100644 index 0000000..93534ec --- /dev/null +++ b/.config/quickshell/caelestia/modules/drawers/Drawers.qml @@ -0,0 +1,181 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import qs.modules.bar +import Quickshell +import Quickshell.Wayland +import Quickshell.Hyprland +import QtQuick +import QtQuick.Effects + +Variants { + model: Quickshell.screens + + Scope { + id: scope + + required property ShellScreen modelData + readonly property bool barDisabled: Strings.testRegexList(Config.bar.excludedScreens, modelData.name) + + Exclusions { + screen: scope.modelData + bar: bar + } + + StyledWindow { + id: win + + readonly property bool hasFullscreen: Hypr.monitorFor(screen)?.activeWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen === 2) ?? false + readonly property int dragMaskPadding: { + if (focusGrab.active || panels.popouts.isDetached) + return 0; + + const mon = Hypr.monitorFor(screen); + if (mon?.lastIpcObject?.specialWorkspace?.name || mon?.activeWorkspace?.lastIpcObject?.windows > 0) + return 0; + + const thresholds = []; + for (const panel of ["dashboard", "launcher", "session", "sidebar"]) + if (Config[panel].enabled) + thresholds.push(Config[panel].dragThreshold); + return Math.max(...thresholds); + } + + onHasFullscreenChanged: { + visibilities.launcher = false; + visibilities.session = false; + visibilities.dashboard = false; + } + + screen: scope.modelData + name: "drawers" + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.keyboardFocus: visibilities.launcher || visibilities.session ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None + + mask: Region { + x: bar.implicitWidth + win.dragMaskPadding + y: Config.border.thickness + win.dragMaskPadding + width: win.width - bar.implicitWidth - Config.border.thickness - win.dragMaskPadding * 2 + height: win.height - Config.border.thickness * 2 - win.dragMaskPadding * 2 + intersection: Intersection.Xor + + regions: regions.instances + } + + anchors.top: true + anchors.bottom: true + anchors.left: true + anchors.right: true + + Variants { + id: regions + + model: panels.children + + Region { + required property Item modelData + + x: modelData.x + bar.implicitWidth + y: modelData.y + Config.border.thickness + width: modelData.width + height: modelData.height + intersection: Intersection.Subtract + } + } + + HyprlandFocusGrab { + id: focusGrab + + active: (visibilities.launcher && Config.launcher.enabled) || (visibilities.session && Config.session.enabled) || (visibilities.sidebar && Config.sidebar.enabled) || (!Config.dashboard.showOnHover && visibilities.dashboard && Config.dashboard.enabled) || (panels.popouts.currentName.startsWith("traymenu") && panels.popouts.current?.depth > 1) + windows: [win] + onCleared: { + visibilities.launcher = false; + visibilities.session = false; + visibilities.sidebar = false; + visibilities.dashboard = false; + panels.popouts.hasCurrent = false; + bar.closeTray(); + } + } + + StyledRect { + anchors.fill: parent + opacity: visibilities.session && Config.session.enabled ? 0.5 : 0 + color: Colours.palette.m3scrim + + Behavior on opacity { + Anim {} + } + } + + Item { + anchors.fill: parent + opacity: Colours.transparency.enabled ? Colours.transparency.base : 1 + layer.enabled: true + layer.effect: MultiEffect { + shadowEnabled: true + blurMax: 15 + shadowColor: Qt.alpha(Colours.palette.m3shadow, 0.7) + } + + Border { + bar: bar + } + + Backgrounds { + panels: panels + bar: bar + } + } + + PersistentProperties { + id: visibilities + + property bool bar + property bool osd + property bool session + property bool launcher + property bool dashboard + property bool utilities + property bool sidebar + + Component.onCompleted: Visibilities.load(scope.modelData, this) + } + + Interactions { + screen: scope.modelData + popouts: panels.popouts + visibilities: visibilities + panels: panels + bar: bar + + Panels { + id: panels + + screen: scope.modelData + visibilities: visibilities + bar: bar + } + + BarWrapper { + id: bar + + anchors.top: parent.top + anchors.bottom: parent.bottom + + screen: scope.modelData + visibilities: visibilities + popouts: panels.popouts + + disabled: scope.barDisabled + + Component.onCompleted: Visibilities.bars.set(scope.modelData, this) + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/drawers/Exclusions.qml b/.config/quickshell/caelestia/modules/drawers/Exclusions.qml new file mode 100644 index 0000000..e4015c8 --- /dev/null +++ b/.config/quickshell/caelestia/modules/drawers/Exclusions.qml @@ -0,0 +1,39 @@ +pragma ComponentBehavior: Bound + +import qs.components.containers +import qs.config +import Quickshell +import QtQuick + +Scope { + id: root + + required property ShellScreen screen + required property Item bar + + ExclusionZone { + anchors.left: true + exclusiveZone: root.bar.exclusiveZone + } + + ExclusionZone { + anchors.top: true + } + + ExclusionZone { + anchors.right: true + } + + ExclusionZone { + anchors.bottom: true + } + + component ExclusionZone: StyledWindow { + screen: root.screen + name: "border-exclusion" + exclusiveZone: Config.border.thickness + mask: Region {} + implicitWidth: 1 + implicitHeight: 1 + } +} diff --git a/.config/quickshell/caelestia/modules/drawers/Interactions.qml b/.config/quickshell/caelestia/modules/drawers/Interactions.qml new file mode 100644 index 0000000..9579b15 --- /dev/null +++ b/.config/quickshell/caelestia/modules/drawers/Interactions.qml @@ -0,0 +1,274 @@ +import qs.components.controls +import qs.config +import qs.modules.bar.popouts as BarPopouts +import Quickshell +import QtQuick + +CustomMouseArea { + id: root + + required property ShellScreen screen + required property BarPopouts.Wrapper popouts + required property PersistentProperties visibilities + required property Panels panels + required property Item bar + + property point dragStart + property bool dashboardShortcutActive + property bool osdShortcutActive + property bool utilitiesShortcutActive + + function withinPanelHeight(panel: Item, x: real, y: real): bool { + const panelY = Config.border.thickness + panel.y; + return y >= panelY - Config.border.rounding && y <= panelY + panel.height + Config.border.rounding; + } + + function withinPanelWidth(panel: Item, x: real, y: real): bool { + const panelX = bar.implicitWidth + panel.x; + return x >= panelX - Config.border.rounding && x <= panelX + panel.width + Config.border.rounding; + } + + function inLeftPanel(panel: Item, x: real, y: real): bool { + return x < bar.implicitWidth + panel.x + panel.width && withinPanelHeight(panel, x, y); + } + + function inRightPanel(panel: Item, x: real, y: real): bool { + return x > bar.implicitWidth + panel.x && withinPanelHeight(panel, x, y); + } + + function inTopPanel(panel: Item, x: real, y: real): bool { + return y < Config.border.thickness + panel.y + panel.height && withinPanelWidth(panel, x, y); + } + + function inBottomPanel(panel: Item, x: real, y: real): bool { + return y > root.height - Config.border.thickness - panel.height - Config.border.rounding && withinPanelWidth(panel, x, y); + } + + function onWheel(event: WheelEvent): void { + if (event.x < bar.implicitWidth) { + bar.handleWheel(event.y, event.angleDelta); + } + } + + anchors.fill: parent + hoverEnabled: true + + onPressed: event => dragStart = Qt.point(event.x, event.y) + onContainsMouseChanged: { + if (!containsMouse) { + // Only hide if not activated by shortcut + if (!osdShortcutActive) { + visibilities.osd = false; + root.panels.osd.hovered = false; + } + + if (!dashboardShortcutActive) + visibilities.dashboard = false; + + if (!utilitiesShortcutActive) + visibilities.utilities = false; + + if (!popouts.currentName.startsWith("traymenu") || (popouts.current?.depth ?? 0) <= 1) { + popouts.hasCurrent = false; + bar.closeTray(); + } + + if (Config.bar.showOnHover) + bar.isHovered = false; + } + } + + onPositionChanged: event => { + if (popouts.isDetached) + return; + + const x = event.x; + const y = event.y; + const dragX = x - dragStart.x; + const dragY = y - dragStart.y; + + // Show bar in non-exclusive mode on hover + if (!visibilities.bar && Config.bar.showOnHover && x < bar.implicitWidth) + bar.isHovered = true; + + // Show/hide bar on drag + if (pressed && dragStart.x < bar.implicitWidth) { + if (dragX > Config.bar.dragThreshold) + visibilities.bar = true; + else if (dragX < -Config.bar.dragThreshold) + visibilities.bar = false; + } + + if (panels.sidebar.width === 0) { + // Show osd on hover + const showOsd = inRightPanel(panels.osd, x, y); + + // Always update visibility based on hover if not in shortcut mode + if (!osdShortcutActive) { + visibilities.osd = showOsd; + root.panels.osd.hovered = showOsd; + } else if (showOsd) { + // If hovering over OSD area while in shortcut mode, transition to hover control + osdShortcutActive = false; + root.panels.osd.hovered = true; + } + + const showSidebar = pressed && dragStart.x > bar.implicitWidth + panels.sidebar.x; + + // Show/hide session on drag + if (pressed && inRightPanel(panels.session, dragStart.x, dragStart.y) && withinPanelHeight(panels.session, x, y)) { + if (dragX < -Config.session.dragThreshold) + visibilities.session = true; + else if (dragX > Config.session.dragThreshold) + visibilities.session = false; + + // Show sidebar on drag if in session area and session is nearly fully visible + if (showSidebar && panels.session.width >= panels.session.nonAnimWidth && dragX < -Config.sidebar.dragThreshold) + visibilities.sidebar = true; + } else if (showSidebar && dragX < -Config.sidebar.dragThreshold) { + // Show sidebar on drag if not in session area + visibilities.sidebar = true; + } + } else { + const outOfSidebar = x < width - panels.sidebar.width; + // Show osd on hover + const showOsd = outOfSidebar && inRightPanel(panels.osd, x, y); + + // Always update visibility based on hover if not in shortcut mode + if (!osdShortcutActive) { + visibilities.osd = showOsd; + root.panels.osd.hovered = showOsd; + } else if (showOsd) { + // If hovering over OSD area while in shortcut mode, transition to hover control + osdShortcutActive = false; + root.panels.osd.hovered = true; + } + + // Show/hide session on drag + if (pressed && outOfSidebar && inRightPanel(panels.session, dragStart.x, dragStart.y) && withinPanelHeight(panels.session, x, y)) { + if (dragX < -Config.session.dragThreshold) + visibilities.session = true; + else if (dragX > Config.session.dragThreshold) + visibilities.session = false; + } + + // Hide sidebar on drag + if (pressed && inRightPanel(panels.sidebar, dragStart.x, 0) && dragX > Config.sidebar.dragThreshold) + visibilities.sidebar = false; + } + + // Show launcher on hover, or show/hide on drag if hover is disabled + if (Config.launcher.showOnHover) { + if (!visibilities.launcher && inBottomPanel(panels.launcher, x, y)) + visibilities.launcher = true; + } else if (pressed && inBottomPanel(panels.launcher, dragStart.x, dragStart.y) && withinPanelWidth(panels.launcher, x, y)) { + if (dragY < -Config.launcher.dragThreshold) + visibilities.launcher = true; + else if (dragY > Config.launcher.dragThreshold) + visibilities.launcher = false; + } + + // Show dashboard on hover + const showDashboard = Config.dashboard.showOnHover && inTopPanel(panels.dashboard, x, y); + + // Always update visibility based on hover if not in shortcut mode + if (!dashboardShortcutActive) { + visibilities.dashboard = showDashboard; + } else if (showDashboard) { + // If hovering over dashboard area while in shortcut mode, transition to hover control + dashboardShortcutActive = false; + } + + // Show/hide dashboard on drag (for touchscreen devices) + if (pressed && inTopPanel(panels.dashboard, dragStart.x, dragStart.y) && withinPanelWidth(panels.dashboard, x, y)) { + if (dragY > Config.dashboard.dragThreshold) + visibilities.dashboard = true; + else if (dragY < -Config.dashboard.dragThreshold) + visibilities.dashboard = false; + } + + // Show utilities on hover + const showUtilities = inBottomPanel(panels.utilities, x, y); + + // Always update visibility based on hover if not in shortcut mode + if (!utilitiesShortcutActive) { + visibilities.utilities = showUtilities; + } else if (showUtilities) { + // If hovering over utilities area while in shortcut mode, transition to hover control + utilitiesShortcutActive = false; + } + + // Show popouts on hover + if (x < bar.implicitWidth) { + bar.checkPopout(y); + } else if ((!popouts.currentName.startsWith("traymenu") || (popouts.current?.depth ?? 0) <= 1) && !inLeftPanel(panels.popouts, x, y)) { + popouts.hasCurrent = false; + bar.closeTray(); + } + } + + // Monitor individual visibility changes + Connections { + target: root.visibilities + + function onLauncherChanged() { + // If launcher is hidden, clear shortcut flags for dashboard and OSD + if (!root.visibilities.launcher) { + root.dashboardShortcutActive = false; + root.osdShortcutActive = false; + root.utilitiesShortcutActive = false; + + // Also hide dashboard and OSD if they're not being hovered + const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY); + const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY); + + if (!inDashboardArea) { + root.visibilities.dashboard = false; + } + if (!inOsdArea) { + root.visibilities.osd = false; + root.panels.osd.hovered = false; + } + } + } + + function onDashboardChanged() { + if (root.visibilities.dashboard) { + // Dashboard became visible, immediately check if this should be shortcut mode + const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY); + if (!inDashboardArea) { + root.dashboardShortcutActive = true; + } + } else { + // Dashboard hidden, clear shortcut flag + root.dashboardShortcutActive = false; + } + } + + function onOsdChanged() { + if (root.visibilities.osd) { + // OSD became visible, immediately check if this should be shortcut mode + const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY); + if (!inOsdArea) { + root.osdShortcutActive = true; + } + } else { + // OSD hidden, clear shortcut flag + root.osdShortcutActive = false; + } + } + + function onUtilitiesChanged() { + if (root.visibilities.utilities) { + // Utilities became visible, immediately check if this should be shortcut mode + const inUtilitiesArea = root.inBottomPanel(root.panels.utilities, root.mouseX, root.mouseY); + if (!inUtilitiesArea) { + root.utilitiesShortcutActive = true; + } + } else { + // Utilities hidden, clear shortcut flag + root.utilitiesShortcutActive = false; + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/drawers/Panels.qml b/.config/quickshell/caelestia/modules/drawers/Panels.qml new file mode 100644 index 0000000..7705732 --- /dev/null +++ b/.config/quickshell/caelestia/modules/drawers/Panels.qml @@ -0,0 +1,136 @@ +import qs.config +import qs.modules.osd as Osd +import qs.modules.notifications as Notifications +import qs.modules.session as Session +import qs.modules.launcher as Launcher +import qs.modules.dashboard as Dashboard +import qs.modules.bar.popouts as BarPopouts +import qs.modules.utilities as Utilities +import qs.modules.utilities.toasts as Toasts +import qs.modules.sidebar as Sidebar +import Quickshell +import QtQuick + +Item { + id: root + + required property ShellScreen screen + required property PersistentProperties visibilities + required property Item bar + + readonly property alias osd: osd + readonly property alias notifications: notifications + readonly property alias session: session + readonly property alias launcher: launcher + readonly property alias dashboard: dashboard + readonly property alias popouts: popouts + readonly property alias utilities: utilities + readonly property alias toasts: toasts + readonly property alias sidebar: sidebar + + anchors.fill: parent + anchors.margins: Config.border.thickness + anchors.leftMargin: bar.implicitWidth + + Osd.Wrapper { + id: osd + + clip: session.width > 0 || sidebar.width > 0 + screen: root.screen + visibilities: root.visibilities + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: session.width + sidebar.width + } + + Notifications.Wrapper { + id: notifications + + visibilities: root.visibilities + panels: root + + anchors.top: parent.top + anchors.right: parent.right + } + + Session.Wrapper { + id: session + + clip: sidebar.width > 0 + visibilities: root.visibilities + panels: root + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: sidebar.width + } + + Launcher.Wrapper { + id: launcher + + screen: root.screen + visibilities: root.visibilities + panels: root + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + } + + Dashboard.Wrapper { + id: dashboard + + visibilities: root.visibilities + + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + } + + BarPopouts.Wrapper { + id: popouts + + screen: root.screen + + x: isDetached ? (root.width - nonAnimWidth) / 2 : 0 + y: { + if (isDetached) + return (root.height - nonAnimHeight) / 2; + + const off = currentCenter - Config.border.thickness - nonAnimHeight / 2; + const diff = root.height - Math.floor(off + nonAnimHeight); + if (diff < 0) + return off + diff; + return Math.max(off, 0); + } + } + + Utilities.Wrapper { + id: utilities + + visibilities: root.visibilities + sidebar: sidebar + popouts: popouts + + anchors.bottom: parent.bottom + anchors.right: parent.right + } + + Toasts.Toasts { + id: toasts + + anchors.bottom: sidebar.visible ? parent.bottom : utilities.top + anchors.right: sidebar.left + anchors.margins: Appearance.padding.normal + } + + Sidebar.Wrapper { + id: sidebar + + visibilities: root.visibilities + panels: root + + anchors.top: notifications.bottom + anchors.bottom: utilities.top + anchors.right: parent.right + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/AppList.qml b/.config/quickshell/caelestia/modules/launcher/AppList.qml new file mode 100644 index 0000000..7f7b843 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/AppList.qml @@ -0,0 +1,257 @@ +pragma ComponentBehavior: Bound + +import "items" +import "services" +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import Quickshell +import QtQuick + +StyledListView { + id: root + + required property StyledTextField search + required property PersistentProperties visibilities + + model: ScriptModel { + id: model + + onValuesChanged: root.currentIndex = 0 + } + + spacing: Appearance.spacing.small + orientation: Qt.Vertical + implicitHeight: (Config.launcher.sizes.itemHeight + spacing) * Math.min(Config.launcher.maxShown, count) - spacing + + preferredHighlightBegin: 0 + preferredHighlightEnd: height + highlightRangeMode: ListView.ApplyRange + + highlightFollowsCurrentItem: false + highlight: StyledRect { + radius: Appearance.rounding.normal + color: Colours.palette.m3onSurface + opacity: 0.08 + + y: root.currentItem?.y ?? 0 + implicitWidth: root.width + implicitHeight: root.currentItem?.implicitHeight ?? 0 + + Behavior on y { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + + state: { + const text = search.text; + const prefix = Config.launcher.actionPrefix; + if (text.startsWith(prefix)) { + for (const action of ["calc", "scheme", "variant"]) + if (text.startsWith(`${prefix}${action} `)) + return action; + + return "actions"; + } + + return "apps"; + } + + onStateChanged: { + if (state === "scheme" || state === "variant") + Schemes.reload(); + } + + states: [ + State { + name: "apps" + + PropertyChanges { + model.values: Apps.search(search.text) + root.delegate: appItem + } + }, + State { + name: "actions" + + PropertyChanges { + model.values: Actions.query(search.text) + root.delegate: actionItem + } + }, + State { + name: "calc" + + PropertyChanges { + model.values: [0] + root.delegate: calcItem + } + }, + State { + name: "scheme" + + PropertyChanges { + model.values: Schemes.query(search.text) + root.delegate: schemeItem + } + }, + State { + name: "variant" + + PropertyChanges { + model.values: M3Variants.query(search.text) + root.delegate: variantItem + } + } + ] + + transitions: Transition { + SequentialAnimation { + ParallelAnimation { + Anim { + target: root + property: "opacity" + from: 1 + to: 0 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + Anim { + target: root + property: "scale" + from: 1 + to: 0.9 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + } + PropertyAction { + targets: [model, root] + properties: "values,delegate" + } + ParallelAnimation { + Anim { + target: root + property: "opacity" + from: 0 + to: 1 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + target: root + property: "scale" + from: 0.9 + to: 1 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + PropertyAction { + targets: [root.add, root.remove] + property: "enabled" + value: true + } + } + } + + StyledScrollBar.vertical: StyledScrollBar { + flickable: root + } + + add: Transition { + enabled: !root.state + + Anim { + properties: "opacity,scale" + from: 0 + to: 1 + } + } + + remove: Transition { + enabled: !root.state + + Anim { + properties: "opacity,scale" + from: 1 + to: 0 + } + } + + move: Transition { + Anim { + property: "y" + } + Anim { + properties: "opacity,scale" + to: 1 + } + } + + addDisplaced: Transition { + Anim { + property: "y" + duration: Appearance.anim.durations.small + } + Anim { + properties: "opacity,scale" + to: 1 + } + } + + displaced: Transition { + Anim { + property: "y" + } + Anim { + properties: "opacity,scale" + to: 1 + } + } + + Component { + id: appItem + + AppItem { + visibilities: root.visibilities + } + } + + Component { + id: actionItem + + ActionItem { + list: root + } + } + + Component { + id: calcItem + + CalcItem { + list: root + } + } + + Component { + id: schemeItem + + SchemeItem { + list: root + } + } + + Component { + id: variantItem + + VariantItem { + list: root + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/Background.qml b/.config/quickshell/caelestia/modules/launcher/Background.qml new file mode 100644 index 0000000..709c7d0 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/Background.qml @@ -0,0 +1,60 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + readonly property real rounding: Config.border.rounding + readonly property bool flatten: wrapper.height < rounding * 2 + readonly property real roundingY: flatten ? wrapper.height / 2 : rounding + + strokeWidth: -1 + fillColor: Colours.palette.m3surface + + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: -(root.wrapper.height - root.roundingY * 2) + } + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + PathLine { + relativeX: root.wrapper.width - root.rounding * 2 + relativeY: 0 + } + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.roundingY * 2 + } + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/Content.qml b/.config/quickshell/caelestia/modules/launcher/Content.qml new file mode 100644 index 0000000..c085976 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/Content.qml @@ -0,0 +1,191 @@ +pragma ComponentBehavior: Bound + +import "services" +import qs.components +import qs.components.controls +import qs.services +import qs.config +import Quickshell +import QtQuick + +Item { + id: root + + required property PersistentProperties visibilities + required property var panels + required property real maxHeight + + readonly property int padding: Appearance.padding.large + readonly property int rounding: Appearance.rounding.large + + implicitWidth: listWrapper.width + padding * 2 + implicitHeight: searchWrapper.height + listWrapper.height + padding * 2 + + Item { + id: listWrapper + + implicitWidth: list.width + implicitHeight: list.height + root.padding + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: searchWrapper.top + anchors.bottomMargin: root.padding + + ContentList { + id: list + + content: root + visibilities: root.visibilities + panels: root.panels + maxHeight: root.maxHeight - searchWrapper.implicitHeight - root.padding * 3 + search: search + padding: root.padding + rounding: root.rounding + } + } + + StyledRect { + id: searchWrapper + + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + radius: Appearance.rounding.full + + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: root.padding + + implicitHeight: Math.max(searchIcon.implicitHeight, search.implicitHeight, clearIcon.implicitHeight) + + MaterialIcon { + id: searchIcon + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: root.padding + + text: "search" + color: Colours.palette.m3onSurfaceVariant + } + + StyledTextField { + id: search + + anchors.left: searchIcon.right + anchors.right: clearIcon.left + anchors.leftMargin: Appearance.spacing.small + anchors.rightMargin: Appearance.spacing.small + + topPadding: Appearance.padding.larger + bottomPadding: Appearance.padding.larger + + placeholderText: qsTr("Type \"%1\" for commands").arg(Config.launcher.actionPrefix) + + onAccepted: { + const currentItem = list.currentList?.currentItem; + if (currentItem) { + if (list.showWallpapers) { + if (Colours.scheme === "dynamic" && currentItem.modelData.path !== Wallpapers.actualCurrent) + Wallpapers.previewColourLock = true; + Wallpapers.setWallpaper(currentItem.modelData.path); + root.visibilities.launcher = false; + } else if (text.startsWith(Config.launcher.actionPrefix)) { + if (text.startsWith(`${Config.launcher.actionPrefix}calc `)) + currentItem.onClicked(); + else + currentItem.modelData.onClicked(list.currentList); + } else { + Apps.launch(currentItem.modelData); + root.visibilities.launcher = false; + } + } + } + + Keys.onUpPressed: list.currentList?.decrementCurrentIndex() + Keys.onDownPressed: list.currentList?.incrementCurrentIndex() + + Keys.onEscapePressed: root.visibilities.launcher = false + + Keys.onPressed: event => { + if (!Config.launcher.vimKeybinds) + return; + + if (event.modifiers & Qt.ControlModifier) { + if (event.key === Qt.Key_J) { + list.currentList?.incrementCurrentIndex(); + event.accepted = true; + } else if (event.key === Qt.Key_K) { + list.currentList?.decrementCurrentIndex(); + event.accepted = true; + } + } else if (event.key === Qt.Key_Tab) { + list.currentList?.incrementCurrentIndex(); + event.accepted = true; + } else if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier))) { + list.currentList?.decrementCurrentIndex(); + event.accepted = true; + } + } + + Component.onCompleted: forceActiveFocus() + + Connections { + target: root.visibilities + + function onLauncherChanged(): void { + if (!root.visibilities.launcher) + search.text = ""; + } + + function onSessionChanged(): void { + if (!root.visibilities.session) + search.forceActiveFocus(); + } + } + } + + MaterialIcon { + id: clearIcon + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: root.padding + + width: search.text ? implicitWidth : implicitWidth / 2 + opacity: { + if (!search.text) + return 0; + if (mouse.pressed) + return 0.7; + if (mouse.containsMouse) + return 0.8; + return 1; + } + + text: "close" + color: Colours.palette.m3onSurfaceVariant + + MouseArea { + id: mouse + + anchors.fill: parent + hoverEnabled: true + cursorShape: search.text ? Qt.PointingHandCursor : undefined + + onClicked: search.text = "" + } + + Behavior on width { + Anim { + duration: Appearance.anim.durations.small + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.small + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/ContentList.qml b/.config/quickshell/caelestia/modules/launcher/ContentList.qml new file mode 100644 index 0000000..b2a9c77 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/ContentList.qml @@ -0,0 +1,170 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.services +import qs.config +import qs.utils +import Quickshell +import QtQuick + +Item { + id: root + + required property var content + required property PersistentProperties visibilities + required property var panels + required property real maxHeight + required property StyledTextField search + required property int padding + required property int rounding + + readonly property bool showWallpapers: search.text.startsWith(`${Config.launcher.actionPrefix}wallpaper `) + readonly property Item currentList: showWallpapers ? wallpaperList.item : appList.item + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + clip: true + state: showWallpapers ? "wallpapers" : "apps" + + states: [ + State { + name: "apps" + + PropertyChanges { + root.implicitWidth: Config.launcher.sizes.itemWidth + root.implicitHeight: Math.min(root.maxHeight, appList.implicitHeight > 0 ? appList.implicitHeight : empty.implicitHeight) + appList.active: true + } + + AnchorChanges { + anchors.left: root.parent.left + anchors.right: root.parent.right + } + }, + State { + name: "wallpapers" + + PropertyChanges { + root.implicitWidth: Math.max(Config.launcher.sizes.itemWidth * 1.2, wallpaperList.implicitWidth) + root.implicitHeight: Config.launcher.sizes.wallpaperHeight + wallpaperList.active: true + } + } + ] + + Behavior on state { + SequentialAnimation { + Anim { + target: root + property: "opacity" + from: 1 + to: 0 + duration: Appearance.anim.durations.small + } + PropertyAction {} + Anim { + target: root + property: "opacity" + from: 0 + to: 1 + duration: Appearance.anim.durations.small + } + } + } + + Loader { + id: appList + + active: false + + anchors.fill: parent + + sourceComponent: AppList { + search: root.search + visibilities: root.visibilities + } + } + + Loader { + id: wallpaperList + + active: false + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + + sourceComponent: WallpaperList { + search: root.search + visibilities: root.visibilities + panels: root.panels + content: root.content + } + } + + Row { + id: empty + + opacity: root.currentList?.count === 0 ? 1 : 0 + scale: root.currentList?.count === 0 ? 1 : 0.5 + + spacing: Appearance.spacing.normal + padding: Appearance.padding.large + + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + + MaterialIcon { + text: root.state === "wallpapers" ? "wallpaper_slideshow" : "manage_search" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.extraLarge + + anchors.verticalCenter: parent.verticalCenter + } + + Column { + anchors.verticalCenter: parent.verticalCenter + + StyledText { + text: root.state === "wallpapers" ? qsTr("No wallpapers found") : qsTr("No results") + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: root.state === "wallpapers" && Wallpapers.list.length === 0 ? qsTr("Try putting some wallpapers in %1").arg(Paths.shortenHome(Paths.wallsdir)) : qsTr("Try searching for something else") + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.normal + } + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + } + + Behavior on implicitWidth { + enabled: root.visibilities.launcher + + Anim { + duration: Appearance.anim.durations.large + easing.bezierCurve: Appearance.anim.curves.emphasizedDecel + } + } + + Behavior on implicitHeight { + enabled: root.visibilities.launcher + + Anim { + duration: Appearance.anim.durations.large + easing.bezierCurve: Appearance.anim.curves.emphasizedDecel + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/WallpaperList.qml b/.config/quickshell/caelestia/modules/launcher/WallpaperList.qml new file mode 100644 index 0000000..4aba436 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/WallpaperList.qml @@ -0,0 +1,97 @@ +pragma ComponentBehavior: Bound + +import "items" +import qs.components.controls +import qs.services +import qs.config +import Quickshell +import QtQuick + +PathView { + id: root + + required property StyledTextField search + required property var visibilities + required property var panels + required property var content + + readonly property int itemWidth: Config.launcher.sizes.wallpaperWidth * 0.8 + Appearance.padding.larger * 2 + + readonly property int numItems: { + const screen = QsWindow.window?.screen; + if (!screen) + return 0; + + // Screen width - 4x outer rounding - 2x max side thickness (cause centered) + const barMargins = Math.max(Config.border.thickness, panels.bar.implicitWidth); + let outerMargins = 0; + if (panels.popouts.hasCurrent && panels.popouts.currentCenter + panels.popouts.nonAnimHeight / 2 > screen.height - content.implicitHeight - Config.border.thickness * 2) + outerMargins = panels.popouts.nonAnimWidth; + if ((visibilities.utilities || visibilities.sidebar) && panels.utilities.implicitWidth > outerMargins) + outerMargins = panels.utilities.implicitWidth; + const maxWidth = screen.width - Config.border.rounding * 4 - (barMargins + outerMargins) * 2; + + if (maxWidth <= 0) + return 0; + + const maxItemsOnScreen = Math.floor(maxWidth / itemWidth); + const visible = Math.min(maxItemsOnScreen, Config.launcher.maxWallpapers, scriptModel.values.length); + + if (visible === 2) + return 1; + if (visible > 1 && visible % 2 === 0) + return visible - 1; + return visible; + } + + model: ScriptModel { + id: scriptModel + + readonly property string search: root.search.text.split(" ").slice(1).join(" ") + + values: Wallpapers.query(search) + onValuesChanged: root.currentIndex = search ? 0 : values.findIndex(w => w.path === Wallpapers.actualCurrent) + } + + Component.onCompleted: currentIndex = Wallpapers.list.findIndex(w => w.path === Wallpapers.actualCurrent) + Component.onDestruction: Wallpapers.stopPreview() + + onCurrentItemChanged: { + if (currentItem) + Wallpapers.preview(currentItem.modelData.path); + } + + implicitWidth: Math.min(numItems, count) * itemWidth + pathItemCount: numItems + cacheItemCount: 4 + + snapMode: PathView.SnapToItem + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + highlightRangeMode: PathView.StrictlyEnforceRange + + delegate: WallpaperItem { + visibilities: root.visibilities + } + + path: Path { + startY: root.height / 2 + + PathAttribute { + name: "z" + value: 0 + } + PathLine { + x: root.width / 2 + relativeY: 0 + } + PathAttribute { + name: "z" + value: 1 + } + PathLine { + x: root.width + relativeY: 0 + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/Wrapper.qml b/.config/quickshell/caelestia/modules/launcher/Wrapper.qml new file mode 100644 index 0000000..d62d726 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/Wrapper.qml @@ -0,0 +1,130 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.config +import Quickshell +import QtQuick + +Item { + id: root + + required property ShellScreen screen + required property PersistentProperties visibilities + required property var panels + + readonly property bool shouldBeActive: visibilities.launcher && Config.launcher.enabled + property int contentHeight + + readonly property real maxHeight: { + let max = screen.height - Config.border.thickness * 2 - Appearance.spacing.large; + if (visibilities.dashboard) + max -= panels.dashboard.nonAnimHeight; + return max; + } + + onMaxHeightChanged: timer.start() + + visible: height > 0 + implicitHeight: 0 + implicitWidth: content.implicitWidth + + onShouldBeActiveChanged: { + if (shouldBeActive) { + timer.stop(); + hideAnim.stop(); + showAnim.start(); + } else { + showAnim.stop(); + hideAnim.start(); + } + } + + SequentialAnimation { + id: showAnim + + Anim { + target: root + property: "implicitHeight" + to: root.contentHeight + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + ScriptAction { + script: root.implicitHeight = Qt.binding(() => content.implicitHeight) + } + } + + SequentialAnimation { + id: hideAnim + + ScriptAction { + script: root.implicitHeight = root.implicitHeight + } + Anim { + target: root + property: "implicitHeight" + to: 0 + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + Connections { + target: Config.launcher + + function onEnabledChanged(): void { + timer.start(); + } + + function onMaxShownChanged(): void { + timer.start(); + } + } + + Connections { + target: DesktopEntries.applications + + function onValuesChanged(): void { + if (DesktopEntries.applications.values.length < Config.launcher.maxShown) + timer.start(); + } + } + + Timer { + id: timer + + interval: Appearance.anim.durations.extraLarge + onRunningChanged: { + if (running && !root.shouldBeActive) { + content.visible = false; + content.active = true; + } else { + root.contentHeight = Math.min(root.maxHeight, content.implicitHeight); + content.active = Qt.binding(() => root.shouldBeActive || root.visible); + content.visible = true; + if (showAnim.running) { + showAnim.stop(); + showAnim.start(); + } + } + } + } + + Loader { + id: content + + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + + visible: false + active: false + Component.onCompleted: timer.start() + + sourceComponent: Content { + visibilities: root.visibilities + panels: root.panels + maxHeight: root.maxHeight + + Component.onCompleted: root.contentHeight = implicitHeight + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/items/ActionItem.qml b/.config/quickshell/caelestia/modules/launcher/items/ActionItem.qml new file mode 100644 index 0000000..e158029 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/items/ActionItem.qml @@ -0,0 +1,70 @@ +import "../services" +import qs.components +import qs.services +import qs.config +import QtQuick + +Item { + id: root + + required property var modelData + required property var list + + implicitHeight: Config.launcher.sizes.itemHeight + + anchors.left: parent?.left + anchors.right: parent?.right + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + root.modelData?.onClicked(root.list); + } + } + + Item { + anchors.fill: parent + anchors.leftMargin: Appearance.padding.larger + anchors.rightMargin: Appearance.padding.larger + anchors.margins: Appearance.padding.smaller + + MaterialIcon { + id: icon + + text: root.modelData?.icon ?? "" + font.pointSize: Appearance.font.size.extraLarge + + anchors.verticalCenter: parent.verticalCenter + } + + Item { + anchors.left: icon.right + anchors.leftMargin: Appearance.spacing.normal + anchors.verticalCenter: icon.verticalCenter + + implicitWidth: parent.width - icon.width + implicitHeight: name.implicitHeight + desc.implicitHeight + + StyledText { + id: name + + text: root.modelData?.name ?? "" + font.pointSize: Appearance.font.size.normal + } + + StyledText { + id: desc + + text: root.modelData?.desc ?? "" + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3outline + + elide: Text.ElideRight + width: root.width - icon.width - Appearance.rounding.normal * 2 + + anchors.top: name.bottom + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/items/AppItem.qml b/.config/quickshell/caelestia/modules/launcher/items/AppItem.qml new file mode 100644 index 0000000..2bd818d --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/items/AppItem.qml @@ -0,0 +1,88 @@ +import "../services" +import qs.components +import qs.services +import qs.config +import qs.utils +import Quickshell +import Quickshell.Widgets +import QtQuick + +Item { + id: root + + required property DesktopEntry modelData + required property PersistentProperties visibilities + + implicitHeight: Config.launcher.sizes.itemHeight + + anchors.left: parent?.left + anchors.right: parent?.right + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + Apps.launch(root.modelData); + root.visibilities.launcher = false; + } + } + + Item { + anchors.fill: parent + anchors.leftMargin: Appearance.padding.larger + anchors.rightMargin: Appearance.padding.larger + anchors.margins: Appearance.padding.smaller + + IconImage { + id: icon + + source: Quickshell.iconPath(root.modelData?.icon, "image-missing") + implicitSize: parent.height * 0.8 + + anchors.verticalCenter: parent.verticalCenter + } + + Item { + anchors.left: icon.right + anchors.leftMargin: Appearance.spacing.normal + anchors.verticalCenter: icon.verticalCenter + + implicitWidth: parent.width - icon.width - favouriteIcon.width + implicitHeight: name.implicitHeight + comment.implicitHeight + + StyledText { + id: name + + text: root.modelData?.name ?? "" + font.pointSize: Appearance.font.size.normal + } + + StyledText { + id: comment + + text: (root.modelData?.comment || root.modelData?.genericName || root.modelData?.name) ?? "" + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3outline + + elide: Text.ElideRight + width: root.width - icon.width - favouriteIcon.width - Appearance.rounding.normal * 2 + + anchors.top: name.bottom + } + } + + Loader { + id: favouriteIcon + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + active: modelData && Strings.testRegexList(Config.launcher.favouriteApps, modelData.id) + + sourceComponent: MaterialIcon { + text: "favorite" + fill: 1 + color: Colours.palette.m3primary + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/items/CalcItem.qml b/.config/quickshell/caelestia/modules/launcher/items/CalcItem.qml new file mode 100644 index 0000000..65489d9 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/items/CalcItem.qml @@ -0,0 +1,123 @@ +import qs.components +import qs.services +import qs.config +import Caelestia +import Quickshell +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property var list + readonly property string math: list.search.text.slice(`${Config.launcher.actionPrefix}calc `.length) + + function onClicked(): void { + Quickshell.execDetached(["wl-copy", Qalculator.eval(math, false)]); + root.list.visibilities.launcher = false; + } + + implicitHeight: Config.launcher.sizes.itemHeight + + anchors.left: parent?.left + anchors.right: parent?.right + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + root.onClicked(); + } + } + + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.larger + + spacing: Appearance.spacing.normal + + MaterialIcon { + text: "function" + font.pointSize: Appearance.font.size.extraLarge + Layout.alignment: Qt.AlignVCenter + } + + StyledText { + id: result + + color: { + if (text.includes("error: ") || text.includes("warning: ")) + return Colours.palette.m3error; + if (!root.math) + return Colours.palette.m3onSurfaceVariant; + return Colours.palette.m3onSurface; + } + + text: root.math.length > 0 ? Qalculator.eval(root.math) : qsTr("Type an expression to calculate") + elide: Text.ElideLeft + + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + } + + StyledRect { + color: Colours.palette.m3tertiary + radius: Appearance.rounding.normal + clip: true + + implicitWidth: (stateLayer.containsMouse ? label.implicitWidth + label.anchors.rightMargin : 0) + icon.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: Math.max(label.implicitHeight, icon.implicitHeight) + Appearance.padding.small * 2 + + Layout.alignment: Qt.AlignVCenter + + StateLayer { + id: stateLayer + + color: Colours.palette.m3onTertiary + + function onClicked(): void { + Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.terminal, "fish", "-C", `exec qalc -i '${root.math}'`]); + root.list.visibilities.launcher = false; + } + } + + StyledText { + id: label + + anchors.verticalCenter: parent.verticalCenter + anchors.right: icon.left + anchors.rightMargin: Appearance.spacing.small + + text: qsTr("Open in calculator") + color: Colours.palette.m3onTertiary + font.pointSize: Appearance.font.size.normal + + opacity: stateLayer.containsMouse ? 1 : 0 + + Behavior on opacity { + Anim {} + } + } + + MaterialIcon { + id: icon + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: Appearance.padding.normal + + text: "open_in_new" + color: Colours.palette.m3onTertiary + font.pointSize: Appearance.font.size.large + } + + Behavior on implicitWidth { + Anim { + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/items/SchemeItem.qml b/.config/quickshell/caelestia/modules/launcher/items/SchemeItem.qml new file mode 100644 index 0000000..3ff1846 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/items/SchemeItem.qml @@ -0,0 +1,104 @@ +import "../services" +import qs.components +import qs.services +import qs.config +import QtQuick + +Item { + id: root + + required property Schemes.Scheme modelData + required property var list + + implicitHeight: Config.launcher.sizes.itemHeight + + anchors.left: parent?.left + anchors.right: parent?.right + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + root.modelData?.onClicked(root.list); + } + } + + Item { + anchors.fill: parent + anchors.leftMargin: Appearance.padding.larger + anchors.rightMargin: Appearance.padding.larger + anchors.margins: Appearance.padding.smaller + + StyledRect { + id: preview + + anchors.verticalCenter: parent.verticalCenter + + border.width: 1 + border.color: Qt.alpha(`#${root.modelData?.colours?.outline}`, 0.5) + + color: `#${root.modelData?.colours?.surface}` + radius: Appearance.rounding.full + implicitWidth: parent.height * 0.8 + implicitHeight: parent.height * 0.8 + + Item { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + + implicitWidth: parent.implicitWidth / 2 + clip: true + + StyledRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + + implicitWidth: preview.implicitWidth + color: `#${root.modelData?.colours?.primary}` + radius: Appearance.rounding.full + } + } + } + + Column { + anchors.left: preview.right + anchors.leftMargin: Appearance.spacing.normal + anchors.verticalCenter: parent.verticalCenter + + width: parent.width - preview.width - anchors.leftMargin - (current.active ? current.width + Appearance.spacing.normal : 0) + spacing: 0 + + StyledText { + text: root.modelData?.flavour ?? "" + font.pointSize: Appearance.font.size.normal + } + + StyledText { + text: root.modelData?.name ?? "" + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3outline + + elide: Text.ElideRight + anchors.left: parent.left + anchors.right: parent.right + } + } + + Loader { + id: current + + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + active: `${root.modelData?.name} ${root.modelData?.flavour}` === Schemes.currentScheme + + sourceComponent: MaterialIcon { + text: "check" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.large + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/items/VariantItem.qml b/.config/quickshell/caelestia/modules/launcher/items/VariantItem.qml new file mode 100644 index 0000000..5c34fa8 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/items/VariantItem.qml @@ -0,0 +1,80 @@ +import "../services" +import qs.components +import qs.services +import qs.config +import QtQuick + +Item { + id: root + + required property M3Variants.Variant modelData + required property var list + + implicitHeight: Config.launcher.sizes.itemHeight + + anchors.left: parent?.left + anchors.right: parent?.right + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + root.modelData?.onClicked(root.list); + } + } + + Item { + anchors.fill: parent + anchors.leftMargin: Appearance.padding.larger + anchors.rightMargin: Appearance.padding.larger + anchors.margins: Appearance.padding.smaller + + MaterialIcon { + id: icon + + text: root.modelData?.icon ?? "" + font.pointSize: Appearance.font.size.extraLarge + + anchors.verticalCenter: parent.verticalCenter + } + + Column { + anchors.left: icon.right + anchors.leftMargin: Appearance.spacing.larger + anchors.verticalCenter: icon.verticalCenter + + width: parent.width - icon.width - anchors.leftMargin - (current.active ? current.width + Appearance.spacing.normal : 0) + spacing: 0 + + StyledText { + text: root.modelData?.name ?? "" + font.pointSize: Appearance.font.size.normal + } + + StyledText { + text: root.modelData?.description ?? "" + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3outline + + elide: Text.ElideRight + anchors.left: parent.left + anchors.right: parent.right + } + } + + Loader { + id: current + + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + active: root.modelData?.variant === Schemes.currentVariant + + sourceComponent: MaterialIcon { + text: "check" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.large + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/items/WallpaperItem.qml b/.config/quickshell/caelestia/modules/launcher/items/WallpaperItem.qml new file mode 100644 index 0000000..9fdac3f --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/items/WallpaperItem.qml @@ -0,0 +1,98 @@ +import qs.components +import qs.components.effects +import qs.components.images +import qs.services +import qs.config +import Caelestia.Models +import Quickshell +import QtQuick + +Item { + id: root + + required property FileSystemEntry modelData + required property PersistentProperties visibilities + + scale: 0.5 + opacity: 0 + z: PathView.z ?? 0 + + Component.onCompleted: { + scale = Qt.binding(() => PathView.isCurrentItem ? 1 : PathView.onPath ? 0.8 : 0); + opacity = Qt.binding(() => PathView.onPath ? 1 : 0); + } + + implicitWidth: image.width + Appearance.padding.larger * 2 + implicitHeight: image.height + label.height + Appearance.spacing.small / 2 + Appearance.padding.large + Appearance.padding.normal + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + Wallpapers.setWallpaper(root.modelData.path); + root.visibilities.launcher = false; + } + } + + Elevation { + anchors.fill: image + radius: image.radius + opacity: root.PathView.isCurrentItem ? 1 : 0 + level: 4 + + Behavior on opacity { + Anim {} + } + } + + StyledClippingRect { + id: image + + anchors.horizontalCenter: parent.horizontalCenter + y: Appearance.padding.large + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.normal + + implicitWidth: Config.launcher.sizes.wallpaperWidth + implicitHeight: implicitWidth / 16 * 9 + + MaterialIcon { + anchors.centerIn: parent + text: "image" + color: Colours.tPalette.m3outline + font.pointSize: Appearance.font.size.extraLarge * 2 + font.weight: 600 + } + + CachingImage { + path: root.modelData.path + smooth: !root.PathView.view.moving + cache: true + + anchors.fill: parent + } + } + + StyledText { + id: label + + anchors.top: image.bottom + anchors.topMargin: Appearance.spacing.small / 2 + anchors.horizontalCenter: parent.horizontalCenter + + width: image.width - Appearance.padding.normal * 2 + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + renderType: Text.QtRendering + text: root.modelData.relativePath + font.pointSize: Appearance.font.size.normal + } + + Behavior on scale { + Anim {} + } + + Behavior on opacity { + Anim {} + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/services/Actions.qml b/.config/quickshell/caelestia/modules/launcher/services/Actions.qml new file mode 100644 index 0000000..5c1cb6b --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/services/Actions.qml @@ -0,0 +1,52 @@ +pragma Singleton + +import ".." +import qs.services +import qs.config +import qs.utils +import Quickshell +import QtQuick + +Searcher { + id: root + + function transformSearch(search: string): string { + return search.slice(Config.launcher.actionPrefix.length); + } + + list: variants.instances + useFuzzy: Config.launcher.useFuzzy.actions + + Variants { + id: variants + + model: Config.launcher.actions.filter(a => (a.enabled ?? true) && (Config.launcher.enableDangerousActions || !(a.dangerous ?? false))) + + Action {} + } + + component Action: QtObject { + required property var modelData + readonly property string name: modelData.name ?? qsTr("Unnamed") + readonly property string desc: modelData.description ?? qsTr("No description") + readonly property string icon: modelData.icon ?? "help_outline" + readonly property list command: modelData.command ?? [] + readonly property bool enabled: modelData.enabled ?? true + readonly property bool dangerous: modelData.dangerous ?? false + + function onClicked(list: AppList): void { + if (command.length === 0) + return; + + if (command[0] === "autocomplete" && command.length > 1) { + list.search.text = `${Config.launcher.actionPrefix}${command[1]} `; + } else if (command[0] === "setMode" && command.length > 1) { + list.visibilities.launcher = false; + Colours.setMode(command[1]); + } else { + list.visibilities.launcher = false; + Quickshell.execDetached(command); + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/services/Apps.qml b/.config/quickshell/caelestia/modules/launcher/services/Apps.qml new file mode 100644 index 0000000..3002eb5 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/services/Apps.qml @@ -0,0 +1,78 @@ +pragma Singleton + +import qs.config +import qs.utils +import Caelestia +import Quickshell + +Searcher { + id: root + + function launch(entry: DesktopEntry): void { + appDb.incrementFrequency(entry.id); + + if (entry.runInTerminal) + Quickshell.execDetached({ + command: ["app2unit", "--", ...Config.general.apps.terminal, `${Quickshell.shellDir}/assets/wrap_term_launch.sh`, ...entry.command], + workingDirectory: entry.workingDirectory + }); + else + Quickshell.execDetached({ + command: ["app2unit", "--", ...entry.command], + workingDirectory: entry.workingDirectory + }); + } + + function search(search: string): list { + const prefix = Config.launcher.specialPrefix; + + if (search.startsWith(`${prefix}i `)) { + keys = ["id", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}c `)) { + keys = ["categories", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}d `)) { + keys = ["comment", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}e `)) { + keys = ["execString", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}w `)) { + keys = ["startupClass", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}g `)) { + keys = ["genericName", "name"]; + weights = [0.9, 0.1]; + } else if (search.startsWith(`${prefix}k `)) { + keys = ["keywords", "name"]; + weights = [0.9, 0.1]; + } else { + keys = ["name"]; + weights = [1]; + + if (!search.startsWith(`${prefix}t `)) + return query(search).map(e => e.entry); + } + + const results = query(search.slice(prefix.length + 2)).map(e => e.entry); + if (search.startsWith(`${prefix}t `)) + return results.filter(a => a.runInTerminal); + return results; + } + + function selector(item: var): string { + return keys.map(k => item[k]).join(" "); + } + + list: appDb.apps + useFuzzy: Config.launcher.useFuzzy.apps + + AppDb { + id: appDb + + path: `${Paths.state}/apps.sqlite` + // favouriteApps: Config.launcher.favouriteApps + entries: DesktopEntries.applications.values.filter(a => !Strings.testRegexList(Config.launcher.hiddenApps, a.id)) + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/services/M3Variants.qml b/.config/quickshell/caelestia/modules/launcher/services/M3Variants.qml new file mode 100644 index 0000000..963a4d4 --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/services/M3Variants.qml @@ -0,0 +1,85 @@ +pragma Singleton + +import ".." +import qs.config +import qs.utils +import Quickshell +import QtQuick + +Searcher { + id: root + + function transformSearch(search: string): string { + return search.slice(`${Config.launcher.actionPrefix}variant `.length); + } + + list: [ + Variant { + variant: "vibrant" + icon: "sentiment_very_dissatisfied" + name: qsTr("Vibrant") + description: qsTr("A high chroma palette. The primary palette's chroma is at maximum.") + }, + Variant { + variant: "tonalspot" + icon: "android" + name: qsTr("Tonal Spot") + description: qsTr("Default for Material theme colours. A pastel palette with a low chroma.") + }, + Variant { + variant: "expressive" + icon: "compare_arrows" + name: qsTr("Expressive") + description: qsTr("A medium chroma palette. The primary palette's hue is different from the seed colour, for variety.") + }, + Variant { + variant: "fidelity" + icon: "compare" + name: qsTr("Fidelity") + description: qsTr("Matches the seed colour, even if the seed colour is very bright (high chroma).") + }, + Variant { + variant: "content" + icon: "sentiment_calm" + name: qsTr("Content") + description: qsTr("Almost identical to fidelity.") + }, + Variant { + variant: "fruitsalad" + icon: "nutrition" + name: qsTr("Fruit Salad") + description: qsTr("A playful theme - the seed colour's hue does not appear in the theme.") + }, + Variant { + variant: "rainbow" + icon: "looks" + name: qsTr("Rainbow") + description: qsTr("A playful theme - the seed colour's hue does not appear in the theme.") + }, + Variant { + variant: "neutral" + icon: "contrast" + name: qsTr("Neutral") + description: qsTr("Close to grayscale, a hint of chroma.") + }, + Variant { + variant: "monochrome" + icon: "filter_b_and_w" + name: qsTr("Monochrome") + description: qsTr("All colours are grayscale, no chroma.") + } + ] + useFuzzy: Config.launcher.useFuzzy.variants + + component Variant: QtObject { + required property string variant + required property string icon + required property string name + required property string description + + function onClicked(list: AppList): void { + list.visibilities.launcher = false; + Quickshell.execDetached(["caelestia", "scheme", "set", "-v", variant]); + } + } +} diff --git a/.config/quickshell/caelestia/modules/launcher/services/Schemes.qml b/.config/quickshell/caelestia/modules/launcher/services/Schemes.qml new file mode 100644 index 0000000..dbb2dac --- /dev/null +++ b/.config/quickshell/caelestia/modules/launcher/services/Schemes.qml @@ -0,0 +1,88 @@ +pragma Singleton + +import ".." +import qs.config +import qs.utils +import Quickshell +import Quickshell.Io +import QtQuick + +Searcher { + id: root + + property string currentScheme + property string currentVariant + + function transformSearch(search: string): string { + return search.slice(`${Config.launcher.actionPrefix}scheme `.length); + } + + function selector(item: var): string { + return `${item.name} ${item.flavour}`; + } + + function reload(): void { + getCurrent.running = true; + } + + list: schemes.instances + useFuzzy: Config.launcher.useFuzzy.schemes + keys: ["name", "flavour"] + weights: [0.9, 0.1] + + Variants { + id: schemes + + Scheme {} + } + + Process { + id: getSchemes + + running: true + command: ["caelestia", "scheme", "list"] + stdout: StdioCollector { + onStreamFinished: { + const schemeData = JSON.parse(text); + const list = Object.entries(schemeData).map(([name, f]) => Object.entries(f).map(([flavour, colours]) => ({ + name, + flavour, + colours + }))); + + const flat = []; + for (const s of list) + for (const f of s) + flat.push(f); + + schemes.model = flat.sort((a, b) => (a.name + a.flavour).localeCompare((b.name + b.flavour))); + } + } + } + + Process { + id: getCurrent + + running: true + command: ["caelestia", "scheme", "get", "-nfv"] + stdout: StdioCollector { + onStreamFinished: { + const [name, flavour, variant] = text.trim().split("\n"); + root.currentScheme = `${name} ${flavour}`; + root.currentVariant = variant; + } + } + } + + component Scheme: QtObject { + required property var modelData + readonly property string name: modelData.name + readonly property string flavour: modelData.flavour + readonly property var colours: modelData.colours + + function onClicked(list: AppList): void { + list.visibilities.launcher = false; + Quickshell.execDetached(["caelestia", "scheme", "set", "-n", name, "-f", flavour]); + } + } +} diff --git a/.config/quickshell/caelestia/modules/lock/Center.qml b/.config/quickshell/caelestia/modules/lock/Center.qml new file mode 100644 index 0000000..19cf9d2 --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/Center.qml @@ -0,0 +1,416 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.components.images +import qs.services +import qs.config +import qs.utils +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property var lock + readonly property real centerScale: Math.min(1, (lock.screen?.height ?? 1440) / 1440) + readonly property int centerWidth: Config.lock.sizes.centerWidth * centerScale + + Layout.preferredWidth: centerWidth + Layout.fillWidth: false + Layout.fillHeight: true + + spacing: Appearance.spacing.large * 2 + + RowLayout { + Layout.alignment: Qt.AlignHCenter + spacing: Appearance.spacing.small + + StyledText { + Layout.alignment: Qt.AlignVCenter + text: Time.hourStr + color: Colours.palette.m3secondary + font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) + font.family: Appearance.font.family.clock + font.bold: true + } + + StyledText { + Layout.alignment: Qt.AlignVCenter + text: ":" + color: Colours.palette.m3primary + font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) + font.family: Appearance.font.family.clock + font.bold: true + } + + StyledText { + Layout.alignment: Qt.AlignVCenter + text: Time.minuteStr + color: Colours.palette.m3secondary + font.pointSize: Math.floor(Appearance.font.size.extraLarge * 3 * root.centerScale) + font.family: Appearance.font.family.clock + font.bold: true + } + + Loader { + Layout.leftMargin: Appearance.spacing.small + Layout.alignment: Qt.AlignVCenter + + active: Config.services.useTwelveHourClock + visible: active + + sourceComponent: StyledText { + text: Time.amPmStr + color: Colours.palette.m3primary + font.pointSize: Math.floor(Appearance.font.size.extraLarge * 2 * root.centerScale) + font.family: Appearance.font.family.clock + font.bold: true + } + } + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: -Appearance.padding.large * 2 + + text: Time.format("dddd, d MMMM yyyy") + color: Colours.palette.m3tertiary + font.pointSize: Math.floor(Appearance.font.size.extraLarge * root.centerScale) + font.family: Appearance.font.family.mono + font.bold: true + } + + StyledClippingRect { + Layout.topMargin: Appearance.spacing.large * 2 + Layout.alignment: Qt.AlignHCenter + + implicitWidth: root.centerWidth / 2 + implicitHeight: root.centerWidth / 2 + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.full + + MaterialIcon { + anchors.centerIn: parent + + text: "person" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Math.floor(root.centerWidth / 4) + } + + CachingImage { + id: pfp + + anchors.fill: parent + path: `${Paths.home}/.face` + } + } + + StyledRect { + Layout.alignment: Qt.AlignHCenter + + implicitWidth: root.centerWidth * 0.8 + implicitHeight: input.implicitHeight + Appearance.padding.small * 2 + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.full + + focus: true + onActiveFocusChanged: { + if (!activeFocus) + forceActiveFocus(); + } + + Keys.onPressed: event => { + if (root.lock.unlocking) + return; + + if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) + inputField.placeholder.animate = false; + + root.lock.pam.handleKey(event); + } + + StateLayer { + hoverEnabled: false + cursorShape: Qt.IBeamCursor + + function onClicked(): void { + parent.forceActiveFocus(); + } + } + + RowLayout { + id: input + + anchors.fill: parent + anchors.margins: Appearance.padding.small + spacing: Appearance.spacing.normal + + Item { + implicitWidth: implicitHeight + implicitHeight: fprintIcon.implicitHeight + Appearance.padding.small * 2 + + MaterialIcon { + id: fprintIcon + + anchors.centerIn: parent + animate: true + text: { + if (root.lock.pam.fprint.tries >= Config.lock.maxFprintTries) + return "fingerprint_off"; + if (root.lock.pam.fprint.active) + return "fingerprint"; + return "lock"; + } + color: root.lock.pam.fprint.tries >= Config.lock.maxFprintTries ? Colours.palette.m3error : Colours.palette.m3onSurface + opacity: root.lock.pam.passwd.active ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + + CircularIndicator { + anchors.fill: parent + running: root.lock.pam.passwd.active + } + } + + InputField { + id: inputField + + pam: root.lock.pam + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: enterIcon.implicitHeight + Appearance.padding.small * 2 + + color: root.lock.pam.buffer ? Colours.palette.m3primary : Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + radius: Appearance.rounding.full + + StateLayer { + color: root.lock.pam.buffer ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + + function onClicked(): void { + root.lock.pam.passwd.start(); + } + } + + MaterialIcon { + id: enterIcon + + anchors.centerIn: parent + text: "arrow_forward" + color: root.lock.pam.buffer ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + font.weight: 500 + } + } + } + } + + Item { + Layout.fillWidth: true + Layout.topMargin: -Appearance.spacing.large + + implicitHeight: Math.max(message.implicitHeight, stateMessage.implicitHeight) + + Behavior on implicitHeight { + Anim {} + } + + StyledText { + id: stateMessage + + readonly property string msg: { + if (Hypr.kbLayout !== Hypr.defaultKbLayout) { + if (Hypr.capsLock && Hypr.numLock) + return qsTr("Caps lock and Num lock are ON.\nKeyboard layout: %1").arg(Hypr.kbLayoutFull); + if (Hypr.capsLock) + return qsTr("Caps lock is ON. Kb layout: %1").arg(Hypr.kbLayoutFull); + if (Hypr.numLock) + return qsTr("Num lock is ON. Kb layout: %1").arg(Hypr.kbLayoutFull); + return qsTr("Keyboard layout: %1").arg(Hypr.kbLayoutFull); + } + + if (Hypr.capsLock && Hypr.numLock) + return qsTr("Caps lock and Num lock are ON."); + if (Hypr.capsLock) + return qsTr("Caps lock is ON."); + if (Hypr.numLock) + return qsTr("Num lock is ON."); + + return ""; + } + + property bool shouldBeVisible + + onMsgChanged: { + if (msg) { + if (opacity > 0) { + animate = true; + text = msg; + animate = false; + } else { + text = msg; + } + shouldBeVisible = true; + } else { + shouldBeVisible = false; + } + } + + anchors.left: parent.left + anchors.right: parent.right + + scale: shouldBeVisible && !message.msg ? 1 : 0.7 + opacity: shouldBeVisible && !message.msg ? 1 : 0 + color: Colours.palette.m3onSurfaceVariant + animateProp: "opacity" + + font.family: Appearance.font.family.mono + horizontalAlignment: Qt.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + lineHeight: 1.2 + + Behavior on scale { + Anim {} + } + + Behavior on opacity { + Anim {} + } + } + + StyledText { + id: message + + readonly property Pam pam: root.lock.pam + readonly property string msg: { + if (pam.fprintState === "error") + return qsTr("FP ERROR: %1").arg(pam.fprint.message); + if (pam.state === "error") + return qsTr("PW ERROR: %1").arg(pam.passwd.message); + + if (pam.lockMessage) + return pam.lockMessage; + + if (pam.state === "max" && pam.fprintState === "max") + return qsTr("Maximum password and fingerprint attempts reached."); + if (pam.state === "max") { + if (pam.fprint.available) + return qsTr("Maximum password attempts reached. Please use fingerprint."); + return qsTr("Maximum password attempts reached."); + } + if (pam.fprintState === "max") + return qsTr("Maximum fingerprint attempts reached. Please use password."); + + if (pam.state === "fail") { + if (pam.fprint.available) + return qsTr("Incorrect password. Please try again or use fingerprint."); + return qsTr("Incorrect password. Please try again."); + } + if (pam.fprintState === "fail") + return qsTr("Fingerprint not recognized (%1/%2). Please try again or use password.").arg(pam.fprint.tries).arg(Config.lock.maxFprintTries); + + return ""; + } + + anchors.left: parent.left + anchors.right: parent.right + + scale: 0.7 + opacity: 0 + color: Colours.palette.m3error + + font.pointSize: Appearance.font.size.small + font.family: Appearance.font.family.mono + horizontalAlignment: Qt.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + + onMsgChanged: { + if (msg) { + if (opacity > 0) { + animate = true; + text = msg; + animate = false; + + exitAnim.stop(); + if (scale < 1) + appearAnim.restart(); + else + flashAnim.restart(); + } else { + text = msg; + exitAnim.stop(); + appearAnim.restart(); + } + } else { + appearAnim.stop(); + flashAnim.stop(); + exitAnim.start(); + } + } + + Connections { + target: root.lock.pam + + function onFlashMsg(): void { + exitAnim.stop(); + if (message.scale < 1) + appearAnim.restart(); + else + flashAnim.restart(); + } + } + + Anim { + id: appearAnim + + target: message + properties: "scale,opacity" + to: 1 + onFinished: flashAnim.restart() + } + + SequentialAnimation { + id: flashAnim + + loops: 2 + + FlashAnim { + to: 0.3 + } + FlashAnim { + to: 1 + } + } + + ParallelAnimation { + id: exitAnim + + Anim { + target: message + property: "scale" + to: 0.7 + duration: Appearance.anim.durations.large + } + Anim { + target: message + property: "opacity" + to: 0 + duration: Appearance.anim.durations.large + } + } + } + } + + component FlashAnim: NumberAnimation { + target: message + property: "opacity" + duration: Appearance.anim.durations.small + easing.type: Easing.Linear + } +} diff --git a/.config/quickshell/caelestia/modules/lock/Content.qml b/.config/quickshell/caelestia/modules/lock/Content.qml new file mode 100644 index 0000000..a024ddc --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/Content.qml @@ -0,0 +1,93 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +RowLayout { + id: root + + required property var lock + + spacing: Appearance.spacing.large * 2 + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledRect { + Layout.fillWidth: true + implicitHeight: weather.implicitHeight + + topLeftRadius: Appearance.rounding.large + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainer + + WeatherInfo { + id: weather + + rootHeight: root.height + } + } + + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true + + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainer + + Fetch {} + } + + StyledClippingRect { + Layout.fillWidth: true + implicitHeight: media.implicitHeight + + bottomLeftRadius: Appearance.rounding.large + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainer + + Media { + id: media + + lock: root.lock + } + } + } + + Center { + lock: root.lock + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledRect { + Layout.fillWidth: true + implicitHeight: resources.implicitHeight + + topRightRadius: Appearance.rounding.large + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainer + + Resources { + id: resources + } + } + + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true + + bottomRightRadius: Appearance.rounding.large + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainer + + NotifDock { + lock: root.lock + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/lock/Fetch.qml b/.config/quickshell/caelestia/modules/lock/Fetch.qml new file mode 100644 index 0000000..55d6aa7 --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/Fetch.qml @@ -0,0 +1,178 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.effects +import qs.services +import qs.config +import qs.utils +import Quickshell.Services.UPower +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + anchors.fill: parent + anchors.margins: Appearance.padding.large * 2 + anchors.topMargin: Appearance.padding.large + + spacing: Appearance.spacing.small + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: false + spacing: Appearance.spacing.normal + + StyledRect { + implicitWidth: prompt.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: prompt.implicitHeight + Appearance.padding.normal * 2 + + color: Colours.palette.m3primary + radius: Appearance.rounding.small + + MonoText { + id: prompt + + anchors.centerIn: parent + text: ">" + font.pointSize: root.width > 400 ? Appearance.font.size.larger : Appearance.font.size.normal + color: Colours.palette.m3onPrimary + } + } + + MonoText { + Layout.fillWidth: true + text: "caelestiafetch.sh" + font.pointSize: root.width > 400 ? Appearance.font.size.larger : Appearance.font.size.normal + elide: Text.ElideRight + } + + WrappedLoader { + Layout.fillHeight: true + active: !iconLoader.active + + sourceComponent: SysInfo.isDefaultLogo ? caelestiaLogo : distroIcon + } + } + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: false + spacing: height * 0.15 + + WrappedLoader { + id: iconLoader + + Layout.fillHeight: true + active: root.width > 320 + + sourceComponent: SysInfo.isDefaultLogo ? caelestiaLogo : distroIcon + } + + ColumnLayout { + Layout.fillWidth: true + Layout.topMargin: Appearance.padding.normal + Layout.bottomMargin: Appearance.padding.normal + Layout.leftMargin: iconLoader.active ? 0 : width * 0.1 + spacing: Appearance.spacing.normal + + WrappedLoader { + Layout.fillWidth: true + active: !batLoader.active && root.height > 200 + + sourceComponent: FetchText { + text: `OS : ${SysInfo.osPrettyName || SysInfo.osName}` + } + } + + WrappedLoader { + Layout.fillWidth: true + active: root.height > (batLoader.active ? 200 : 110) + + sourceComponent: FetchText { + text: `WM : ${SysInfo.wm}` + } + } + + WrappedLoader { + Layout.fillWidth: true + active: !batLoader.active || root.height > 110 + + sourceComponent: FetchText { + text: `USER: ${SysInfo.user}` + } + } + + FetchText { + text: `UP : ${SysInfo.uptime}` + } + + WrappedLoader { + id: batLoader + + Layout.fillWidth: true + active: UPower.displayDevice.isLaptopBattery + + sourceComponent: FetchText { + text: `BATT: ${[UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(UPower.displayDevice.state) ? "(+) " : ""}${Math.round(UPower.displayDevice.percentage * 100)}%` + } + } + } + } + + WrappedLoader { + Layout.alignment: Qt.AlignHCenter + active: root.height > 180 + + sourceComponent: RowLayout { + spacing: Appearance.spacing.large + + Repeater { + model: Math.max(0, Math.min(8, root.width / (Appearance.font.size.larger * 2 + Appearance.spacing.large))) + + StyledRect { + required property int index + + implicitWidth: implicitHeight + implicitHeight: Appearance.font.size.larger * 2 + color: Colours.palette[`term${index}`] + radius: Appearance.rounding.small + } + } + } + } + + Component { + id: caelestiaLogo + + Logo { + width: height + height: height + } + } + + Component { + id: distroIcon + + ColouredIcon { + source: SysInfo.osLogo + implicitSize: height + colour: Colours.palette.m3primary + layer.enabled: Config.lock.recolourLogo + } + } + + component WrappedLoader: Loader { + visible: active + } + + component FetchText: MonoText { + Layout.fillWidth: true + font.pointSize: root.width > 400 ? Appearance.font.size.larger : Appearance.font.size.normal + elide: Text.ElideRight + } + + component MonoText: StyledText { + font.family: Appearance.font.family.mono + } +} diff --git a/.config/quickshell/caelestia/modules/lock/InputField.qml b/.config/quickshell/caelestia/modules/lock/InputField.qml new file mode 100644 index 0000000..358093f --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/InputField.qml @@ -0,0 +1,149 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Pam pam + readonly property alias placeholder: placeholder + property string buffer + + Layout.fillWidth: true + Layout.fillHeight: true + + clip: true + + Connections { + target: root.pam + + function onBufferChanged(): void { + if (root.pam.buffer.length > root.buffer.length) { + charList.bindImWidth(); + } else if (root.pam.buffer.length === 0) { + charList.implicitWidth = charList.implicitWidth; + placeholder.animate = true; + } + + root.buffer = root.pam.buffer; + } + } + + StyledText { + id: placeholder + + anchors.centerIn: parent + + text: { + if (root.pam.passwd.active) + return qsTr("Loading..."); + if (root.pam.state === "max") + return qsTr("You have reached the maximum number of tries"); + return qsTr("Enter your password"); + } + + animate: true + color: root.pam.passwd.active ? Colours.palette.m3secondary : Colours.palette.m3outline + font.pointSize: Appearance.font.size.normal + font.family: Appearance.font.family.mono + + opacity: root.buffer ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + + ListView { + id: charList + + readonly property int fullWidth: count * (implicitHeight + spacing) - spacing + + function bindImWidth(): void { + imWidthBehavior.enabled = false; + implicitWidth = Qt.binding(() => fullWidth); + imWidthBehavior.enabled = true; + } + + anchors.centerIn: parent + anchors.horizontalCenterOffset: implicitWidth > root.width ? -(implicitWidth - root.width) / 2 : 0 + + implicitWidth: fullWidth + implicitHeight: Appearance.font.size.normal + + orientation: Qt.Horizontal + spacing: Appearance.spacing.small / 2 + interactive: false + + model: ScriptModel { + values: root.buffer.split("") + } + + delegate: StyledRect { + id: ch + + implicitWidth: implicitHeight + implicitHeight: charList.implicitHeight + + color: Colours.palette.m3onSurface + radius: Appearance.rounding.small / 2 + + opacity: 0 + scale: 0 + Component.onCompleted: { + opacity = 1; + scale = 1; + } + ListView.onRemove: removeAnim.start() + + SequentialAnimation { + id: removeAnim + + PropertyAction { + target: ch + property: "ListView.delayRemove" + value: true + } + ParallelAnimation { + Anim { + target: ch + property: "opacity" + to: 0 + } + Anim { + target: ch + property: "scale" + to: 0.5 + } + } + PropertyAction { + target: ch + property: "ListView.delayRemove" + value: false + } + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } + + Behavior on implicitWidth { + id: imWidthBehavior + + Anim {} + } + } +} diff --git a/.config/quickshell/caelestia/modules/lock/Lock.qml b/.config/quickshell/caelestia/modules/lock/Lock.qml new file mode 100644 index 0000000..6fd5277 --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/Lock.qml @@ -0,0 +1,55 @@ +pragma ComponentBehavior: Bound + +import qs.components.misc +import Quickshell +import Quickshell.Io +import Quickshell.Wayland + +Scope { + property alias lock: lock + + WlSessionLock { + id: lock + + signal unlock + + LockSurface { + lock: lock + pam: pam + } + } + + Pam { + id: pam + + lock: lock + } + + CustomShortcut { + name: "lock" + description: "Lock the current session" + onPressed: lock.locked = true + } + + CustomShortcut { + name: "unlock" + description: "Unlock the current session" + onPressed: lock.unlock() + } + + IpcHandler { + target: "lock" + + function lock(): void { + lock.locked = true; + } + + function unlock(): void { + lock.unlock(); + } + + function isLocked(): bool { + return lock.locked; + } + } +} diff --git a/.config/quickshell/caelestia/modules/lock/LockSurface.qml b/.config/quickshell/caelestia/modules/lock/LockSurface.qml new file mode 100644 index 0000000..279c551 --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/LockSurface.qml @@ -0,0 +1,230 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Quickshell.Wayland +import QtQuick +import QtQuick.Effects + +WlSessionLockSurface { + id: root + + required property WlSessionLock lock + required property Pam pam + + readonly property alias unlocking: unlockAnim.running + + color: "transparent" + + Connections { + target: root.lock + + function onUnlock(): void { + unlockAnim.start(); + } + } + + SequentialAnimation { + id: unlockAnim + + ParallelAnimation { + Anim { + target: lockContent + properties: "implicitWidth,implicitHeight" + to: lockContent.size + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + Anim { + target: lockBg + property: "radius" + to: lockContent.radius + } + Anim { + target: content + property: "scale" + to: 0 + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + Anim { + target: content + property: "opacity" + to: 0 + duration: Appearance.anim.durations.small + } + Anim { + target: lockIcon + property: "opacity" + to: 1 + duration: Appearance.anim.durations.large + } + Anim { + target: background + property: "opacity" + to: 0 + duration: Appearance.anim.durations.large + } + SequentialAnimation { + PauseAnimation { + duration: Appearance.anim.durations.small + } + Anim { + target: lockContent + property: "opacity" + to: 0 + } + } + } + PropertyAction { + target: root.lock + property: "locked" + value: false + } + } + + ParallelAnimation { + id: initAnim + + running: true + + Anim { + target: background + property: "opacity" + to: 1 + duration: Appearance.anim.durations.large + } + SequentialAnimation { + ParallelAnimation { + Anim { + target: lockContent + property: "scale" + to: 1 + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + Anim { + target: lockContent + property: "rotation" + to: 360 + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + } + ParallelAnimation { + Anim { + target: lockIcon + property: "rotation" + to: 360 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + target: lockIcon + property: "opacity" + to: 0 + } + Anim { + target: content + property: "opacity" + to: 1 + } + Anim { + target: content + property: "scale" + to: 1 + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + Anim { + target: lockBg + property: "radius" + to: Appearance.rounding.large * 1.5 + } + Anim { + target: lockContent + property: "implicitWidth" + to: (root.screen?.height ?? 0) * Config.lock.sizes.heightMult * Config.lock.sizes.ratio + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + Anim { + target: lockContent + property: "implicitHeight" + to: (root.screen?.height ?? 0) * Config.lock.sizes.heightMult + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } + + ScreencopyView { + id: background + + anchors.fill: parent + captureSource: root.screen + opacity: 0 + + layer.enabled: true + layer.effect: MultiEffect { + autoPaddingEnabled: false + blurEnabled: true + blur: 1 + blurMax: 64 + blurMultiplier: 1 + } + } + + Item { + id: lockContent + + readonly property int size: lockIcon.implicitHeight + Appearance.padding.large * 4 + readonly property int radius: size / 4 * Appearance.rounding.scale + + anchors.centerIn: parent + implicitWidth: size + implicitHeight: size + + rotation: 180 + scale: 0 + + StyledRect { + id: lockBg + + anchors.fill: parent + color: Colours.palette.m3surface + radius: parent.radius + opacity: Colours.transparency.enabled ? Colours.transparency.base : 1 + + layer.enabled: true + layer.effect: MultiEffect { + shadowEnabled: true + blurMax: 15 + shadowColor: Qt.alpha(Colours.palette.m3shadow, 0.7) + } + } + + MaterialIcon { + id: lockIcon + + anchors.centerIn: parent + text: "lock" + font.pointSize: Appearance.font.size.extraLarge * 4 + font.bold: true + rotation: 180 + } + + Content { + id: content + + anchors.centerIn: parent + width: (root.screen?.height ?? 0) * Config.lock.sizes.heightMult * Config.lock.sizes.ratio - Appearance.padding.large * 2 + height: (root.screen?.height ?? 0) * Config.lock.sizes.heightMult - Appearance.padding.large * 2 + + lock: root + opacity: 0 + scale: 0 + } + } +} diff --git a/.config/quickshell/caelestia/modules/lock/Media.qml b/.config/quickshell/caelestia/modules/lock/Media.qml new file mode 100644 index 0000000..b7e58bb --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/Media.qml @@ -0,0 +1,208 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property var lock + + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: layout.implicitHeight + + Image { + anchors.fill: parent + source: Players.active?.trackArtUrl ?? "" + + asynchronous: true + fillMode: Image.PreserveAspectCrop + sourceSize.width: width + sourceSize.height: height + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: mask + } + + opacity: status === Image.Ready ? 1 : 0 + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.extraLarge + } + } + } + + Rectangle { + id: mask + + anchors.fill: parent + layer.enabled: true + visible: false + + gradient: Gradient { + orientation: Gradient.Horizontal + + GradientStop { + position: 0 + color: Qt.rgba(0, 0, 0, 0.5) + } + GradientStop { + position: 0.4 + color: Qt.rgba(0, 0, 0, 0.2) + } + GradientStop { + position: 0.8 + color: Qt.rgba(0, 0, 0, 0) + } + } + } + + ColumnLayout { + id: layout + + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.large + + StyledText { + Layout.topMargin: Appearance.padding.large + Layout.bottomMargin: Appearance.spacing.larger + text: qsTr("Now playing") + color: Colours.palette.m3onSurfaceVariant + font.family: Appearance.font.family.mono + font.weight: 500 + } + + StyledText { + Layout.fillWidth: true + animate: true + text: Players.active?.trackArtist ?? qsTr("No media") + color: Colours.palette.m3primary + horizontalAlignment: Text.AlignHCenter + font.pointSize: Appearance.font.size.large + font.family: Appearance.font.family.mono + font.weight: 600 + elide: Text.ElideRight + } + + StyledText { + Layout.fillWidth: true + animate: true + text: Players.active?.trackTitle ?? qsTr("No media") + horizontalAlignment: Text.AlignHCenter + font.pointSize: Appearance.font.size.larger + font.family: Appearance.font.family.mono + elide: Text.ElideRight + } + + RowLayout { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Appearance.spacing.large * 1.2 + Layout.bottomMargin: Appearance.padding.large + + spacing: Appearance.spacing.large + + PlayerControl { + icon: "skip_previous" + + function onClicked(): void { + if (Players.active?.canGoPrevious) + Players.active.previous(); + } + } + + PlayerControl { + animate: true + icon: active ? "pause" : "play_arrow" + colour: "Primary" + level: active ? 2 : 1 + active: Players.active?.isPlaying ?? false + + function onClicked(): void { + if (Players.active?.canTogglePlaying) + Players.active.togglePlaying(); + } + } + + PlayerControl { + icon: "skip_next" + + function onClicked(): void { + if (Players.active?.canGoNext) + Players.active.next(); + } + } + } + } + + component PlayerControl: StyledRect { + id: control + + property alias animate: controlIcon.animate + property alias icon: controlIcon.text + property bool active + property string colour: "Secondary" + property int level: 1 + + function onClicked(): void { + } + + Layout.preferredWidth: implicitWidth + (controlState.pressed ? Appearance.padding.normal * 2 : active ? Appearance.padding.small * 2 : 0) + implicitWidth: controlIcon.implicitWidth + Appearance.padding.large * 2 + implicitHeight: controlIcon.implicitHeight + Appearance.padding.normal * 2 + + color: active ? Colours.palette[`m3${colour.toLowerCase()}`] : Colours.palette[`m3${colour.toLowerCase()}Container`] + radius: active || controlState.pressed ? Appearance.rounding.normal : Math.min(implicitWidth, implicitHeight) / 2 * Math.min(1, Appearance.rounding.scale) + + Elevation { + anchors.fill: parent + radius: parent.radius + z: -1 + level: controlState.containsMouse && !controlState.pressed ? control.level + 1 : control.level + } + + StateLayer { + id: controlState + + color: control.active ? Colours.palette[`m3on${control.colour}`] : Colours.palette[`m3on${control.colour}Container`] + + function onClicked(): void { + control.onClicked(); + } + } + + MaterialIcon { + id: controlIcon + + anchors.centerIn: parent + color: control.active ? Colours.palette[`m3on${control.colour}`] : Colours.palette[`m3on${control.colour}Container`] + font.pointSize: Appearance.font.size.large + fill: control.active ? 1 : 0 + + Behavior on fill { + Anim {} + } + } + + Behavior on Layout.preferredWidth { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + Behavior on radius { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/lock/NotifDock.qml b/.config/quickshell/caelestia/modules/lock/NotifDock.qml new file mode 100644 index 0000000..01f7e4b --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/NotifDock.qml @@ -0,0 +1,145 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.containers +import qs.components.effects +import qs.services +import qs.config +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property var lock + + anchors.fill: parent + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.smaller + + StyledText { + Layout.fillWidth: true + text: Notifs.list.length > 0 ? qsTr("%1 notification%2").arg(Notifs.list.length).arg(Notifs.list.length === 1 ? "" : "s") : qsTr("Notifications") + color: Colours.palette.m3outline + font.family: Appearance.font.family.mono + font.weight: 500 + elide: Text.ElideRight + } + + ClippingRectangle { + id: clipRect + + Layout.fillWidth: true + Layout.fillHeight: true + + radius: Appearance.rounding.small + color: "transparent" + + Loader { + anchors.centerIn: parent + active: opacity > 0 + opacity: Notifs.list.length > 0 ? 0 : 1 + + sourceComponent: ColumnLayout { + spacing: Appearance.spacing.large + + Image { + asynchronous: true + source: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/dino.png`) + fillMode: Image.PreserveAspectFit + sourceSize.width: clipRect.width * 0.8 + + layer.enabled: true + layer.effect: Colouriser { + colorizationColor: Colours.palette.m3outlineVariant + brightness: 1 + } + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("No Notifications") + color: Colours.palette.m3outlineVariant + font.pointSize: Appearance.font.size.large + font.family: Appearance.font.family.mono + font.weight: 500 + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.extraLarge + } + } + } + + StyledListView { + anchors.fill: parent + + spacing: Appearance.spacing.small + clip: true + + model: ScriptModel { + values: { + const list = Notifs.notClosed.map(n => [n.appName, null]); + return [...new Map(list).keys()]; + } + } + + delegate: NotifGroup {} + + add: Transition { + Anim { + property: "opacity" + from: 0 + to: 1 + } + Anim { + property: "scale" + from: 0 + to: 1 + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + remove: Transition { + Anim { + property: "opacity" + to: 0 + } + Anim { + property: "scale" + to: 0.6 + } + } + + move: Transition { + Anim { + properties: "opacity,scale" + to: 1 + } + Anim { + property: "y" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + displaced: Transition { + Anim { + properties: "opacity,scale" + to: 1 + } + Anim { + property: "y" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/lock/NotifGroup.qml b/.config/quickshell/caelestia/modules/lock/NotifGroup.qml new file mode 100644 index 0000000..7796090 --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/NotifGroup.qml @@ -0,0 +1,316 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.effects +import qs.services +import qs.config +import qs.utils +import Quickshell +import Quickshell.Widgets +import Quickshell.Services.Notifications +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property string modelData + + readonly property list notifs: Notifs.list.filter(notif => notif.appName === modelData) + readonly property string image: notifs.find(n => n.image.length > 0)?.image ?? "" + readonly property string appIcon: notifs.find(n => n.appIcon.length > 0)?.appIcon ?? "" + readonly property string urgency: notifs.some(n => n.urgency === NotificationUrgency.Critical) ? "critical" : notifs.some(n => n.urgency === NotificationUrgency.Normal) ? "normal" : "low" + + property bool expanded + + anchors.left: parent?.left + anchors.right: parent?.right + implicitHeight: content.implicitHeight + Appearance.padding.normal * 2 + + clip: true + radius: Appearance.rounding.normal + color: root.urgency === "critical" ? Colours.palette.m3secondaryContainer : Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + + RowLayout { + id: content + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + Item { + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + implicitWidth: Config.notifs.sizes.image + implicitHeight: Config.notifs.sizes.image + + Component { + id: imageComp + + Image { + source: Qt.resolvedUrl(root.image) + fillMode: Image.PreserveAspectCrop + cache: false + asynchronous: true + width: Config.notifs.sizes.image + height: Config.notifs.sizes.image + } + } + + Component { + id: appIconComp + + ColouredIcon { + implicitSize: Math.round(Config.notifs.sizes.image * 0.6) + source: Quickshell.iconPath(root.appIcon) + colour: root.urgency === "critical" ? Colours.palette.m3onError : root.urgency === "low" ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + layer.enabled: root.appIcon.endsWith("symbolic") + } + } + + Component { + id: materialIconComp + + MaterialIcon { + text: Icons.getNotifIcon(root.notifs[0]?.summary, root.urgency) + color: root.urgency === "critical" ? Colours.palette.m3onError : root.urgency === "low" ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + font.pointSize: Appearance.font.size.large + } + } + + ClippingRectangle { + anchors.fill: parent + color: root.urgency === "critical" ? Colours.palette.m3error : root.urgency === "low" ? Colours.layer(Colours.palette.m3surfaceContainerHighest, 3) : Colours.palette.m3secondaryContainer + radius: Appearance.rounding.full + + Loader { + anchors.centerIn: parent + sourceComponent: root.image ? imageComp : root.appIcon ? appIconComp : materialIconComp + } + } + + Loader { + anchors.right: parent.right + anchors.bottom: parent.bottom + active: root.appIcon && root.image + + sourceComponent: StyledRect { + implicitWidth: Config.notifs.sizes.badge + implicitHeight: Config.notifs.sizes.badge + + color: root.urgency === "critical" ? Colours.palette.m3error : root.urgency === "low" ? Colours.palette.m3surfaceContainerHighest : Colours.palette.m3secondaryContainer + radius: Appearance.rounding.full + + ColouredIcon { + anchors.centerIn: parent + implicitSize: Math.round(Config.notifs.sizes.badge * 0.6) + source: Quickshell.iconPath(root.appIcon) + colour: root.urgency === "critical" ? Colours.palette.m3onError : root.urgency === "low" ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + layer.enabled: root.appIcon.endsWith("symbolic") + } + } + } + } + + ColumnLayout { + Layout.topMargin: -Appearance.padding.small + Layout.bottomMargin: -Appearance.padding.small / 2 - (root.expanded ? 0 : spacing) + Layout.fillWidth: true + spacing: Math.round(Appearance.spacing.small / 2) + + RowLayout { + Layout.bottomMargin: -parent.spacing + Layout.fillWidth: true + spacing: Appearance.spacing.smaller + + StyledText { + Layout.fillWidth: true + text: root.modelData + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + elide: Text.ElideRight + } + + StyledText { + animate: true + text: root.notifs[0]?.timeStr ?? "" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledRect { + implicitWidth: expandBtn.implicitWidth + Appearance.padding.smaller * 2 + implicitHeight: groupCount.implicitHeight + Appearance.padding.small + + color: root.urgency === "critical" ? Colours.palette.m3error : Colours.layer(Colours.palette.m3surfaceContainerHighest, 2) + radius: Appearance.rounding.full + + opacity: root.notifs.length > Config.notifs.groupPreviewNum ? 1 : 0 + Layout.preferredWidth: root.notifs.length > Config.notifs.groupPreviewNum ? implicitWidth : 0 + + StateLayer { + color: root.urgency === "critical" ? Colours.palette.m3onError : Colours.palette.m3onSurface + + function onClicked(): void { + root.expanded = !root.expanded; + } + } + + RowLayout { + id: expandBtn + + anchors.centerIn: parent + spacing: Appearance.spacing.small / 2 + + StyledText { + id: groupCount + + Layout.leftMargin: Appearance.padding.small / 2 + animate: true + text: root.notifs.length + color: root.urgency === "critical" ? Colours.palette.m3onError : Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.small + } + + MaterialIcon { + Layout.rightMargin: -Appearance.padding.small / 2 + animate: true + text: root.expanded ? "expand_less" : "expand_more" + color: root.urgency === "critical" ? Colours.palette.m3onError : Colours.palette.m3onSurface + } + } + + Behavior on opacity { + Anim {} + } + + Behavior on Layout.preferredWidth { + Anim {} + } + } + } + + Repeater { + model: ScriptModel { + values: root.notifs.slice(0, Config.notifs.groupPreviewNum) + } + + NotifLine { + id: notif + + ParallelAnimation { + running: true + + Anim { + target: notif + property: "opacity" + from: 0 + to: 1 + } + Anim { + target: notif + property: "scale" + from: 0.7 + to: 1 + } + Anim { + target: notif.Layout + property: "preferredHeight" + from: 0 + to: notif.implicitHeight + } + } + + ParallelAnimation { + running: notif.modelData.closed + onFinished: notif.modelData.unlock(notif) + + Anim { + target: notif + property: "opacity" + to: 0 + } + Anim { + target: notif + property: "scale" + to: 0.7 + } + Anim { + target: notif.Layout + property: "preferredHeight" + to: 0 + } + } + } + } + + Loader { + Layout.fillWidth: true + + opacity: root.expanded ? 1 : 0 + Layout.preferredHeight: root.expanded ? implicitHeight : 0 + active: opacity > 0 + + sourceComponent: ColumnLayout { + Repeater { + model: ScriptModel { + values: root.notifs.slice(Config.notifs.groupPreviewNum) + } + + NotifLine {} + } + } + + Behavior on opacity { + Anim {} + } + } + } + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + component NotifLine: StyledText { + id: notifLine + + required property Notifs.Notif modelData + + Layout.fillWidth: true + textFormat: Text.MarkdownText + text: { + const summary = modelData.summary.replace(/\n/g, " "); + const body = modelData.body.replace(/\n/g, " "); + const colour = root.urgency === "critical" ? Colours.palette.m3secondary : Colours.palette.m3outline; + + if (metrics.text === metrics.elidedText) + return `${summary} ${body}`; + + const t = metrics.elidedText.length - 3; + if (t < summary.length) + return `${summary.slice(0, t)}...`; + + return `${summary} ${body.slice(0, t - summary.length)}...`; + } + color: root.urgency === "critical" ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + + Component.onCompleted: modelData.lock(this) + Component.onDestruction: modelData.unlock(this) + + TextMetrics { + id: metrics + + text: `${notifLine.modelData.summary} ${notifLine.modelData.body}`.replace(/\n/g, " ") + font.pointSize: notifLine.font.pointSize + font.family: notifLine.font.family + elideWidth: notifLine.width + elide: Text.ElideRight + } + } +} diff --git a/.config/quickshell/caelestia/modules/lock/Pam.qml b/.config/quickshell/caelestia/modules/lock/Pam.qml new file mode 100644 index 0000000..0186c2f --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/Pam.qml @@ -0,0 +1,193 @@ +import qs.config +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Services.Pam +import QtQuick + +Scope { + id: root + + required property WlSessionLock lock + + readonly property alias passwd: passwd + readonly property alias fprint: fprint + property string lockMessage + property string state + property string fprintState + property string buffer + + signal flashMsg + + function handleKey(event: KeyEvent): void { + if (passwd.active || state === "max") + return; + + if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { + passwd.start(); + } else if (event.key === Qt.Key_Backspace) { + if (event.modifiers & Qt.ControlModifier) { + buffer = ""; + } else { + buffer = buffer.slice(0, -1); + } + } else if (" abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?".includes(event.text.toLowerCase())) { + // No illegal characters (you are insane if you use unicode in your password) + buffer += event.text; + } + } + + PamContext { + id: passwd + + config: "passwd" + configDirectory: Quickshell.shellDir + "/assets/pam.d" + + onMessageChanged: { + if (message.startsWith("The account is locked")) + root.lockMessage = message; + else if (root.lockMessage && message.endsWith(" left to unlock)")) + root.lockMessage += "\n" + message; + } + + onResponseRequiredChanged: { + if (!responseRequired) + return; + + respond(root.buffer); + root.buffer = ""; + } + + onCompleted: res => { + if (res === PamResult.Success) + return root.lock.unlock(); + + 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(); + } + } + + PamContext { + id: fprint + + property bool available + property int tries + property int errorTries + + function checkAvail(): void { + if (!available || !Config.lock.enableFprint || !root.lock.secure) { + abort(); + return; + } + + tries = 0; + errorTries = 0; + start(); + } + + config: "fprint" + configDirectory: Quickshell.shellDir + "/assets/pam.d" + + onCompleted: res => { + if (!available) + return; + + if (res === PamResult.Success) + return root.lock.unlock(); + + if (res === PamResult.Error) { + root.fprintState = "error"; + errorTries++; + if (errorTries < 5) { + abort(); + errorRetry.restart(); + } + } else if (res === PamResult.MaxTries) { + // Isn't actually the real max tries as pam only reports completed + // when max tries is reached. + tries++; + if (tries < Config.lock.maxFprintTries) { + // Restart if not actually real max tries + root.fprintState = "fail"; + start(); + } else { + root.fprintState = "max"; + abort(); + } + } + + root.flashMsg(); + fprintStateReset.start(); + } + } + + Process { + id: availProc + + command: ["sh", "-c", "fprintd-list $USER"] + onExited: code => { + fprint.available = code === 0; + fprint.checkAvail(); + } + } + + Timer { + id: errorRetry + + interval: 800 + onTriggered: fprint.start() + } + + Timer { + id: stateReset + + interval: 4000 + onTriggered: { + if (root.state !== "max") + root.state = ""; + } + } + + Timer { + id: fprintStateReset + + interval: 4000 + onTriggered: { + root.fprintState = ""; + fprint.errorTries = 0; + } + } + + Connections { + target: root.lock + + function onSecureChanged(): void { + if (root.lock.secure) { + availProc.running = true; + root.buffer = ""; + root.state = ""; + root.fprintState = ""; + root.lockMessage = ""; + } + } + + function onUnlock(): void { + fprint.abort(); + } + } + + Connections { + target: Config.lock + + function onEnableFprintChanged(): void { + fprint.checkAvail(); + } + } +} diff --git a/.config/quickshell/caelestia/modules/lock/Resources.qml b/.config/quickshell/caelestia/modules/lock/Resources.qml new file mode 100644 index 0000000..82c004c --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/Resources.qml @@ -0,0 +1,93 @@ +import qs.components +import qs.components.controls +import qs.components.misc +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +GridLayout { + id: root + + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.large + + rowSpacing: Appearance.spacing.large + columnSpacing: Appearance.spacing.large + rows: 2 + columns: 2 + + Ref { + service: SystemUsage + } + + Resource { + Layout.topMargin: Appearance.padding.large + icon: "memory" + value: SystemUsage.cpuPerc + colour: Colours.palette.m3primary + } + + Resource { + Layout.topMargin: Appearance.padding.large + icon: "thermostat" + value: Math.min(1, SystemUsage.cpuTemp / 90) + colour: Colours.palette.m3secondary + } + + Resource { + Layout.bottomMargin: Appearance.padding.large + icon: "memory_alt" + value: SystemUsage.memPerc + colour: Colours.palette.m3secondary + } + + Resource { + Layout.bottomMargin: Appearance.padding.large + icon: "hard_disk" + value: SystemUsage.storagePerc + colour: Colours.palette.m3tertiary + } + + component Resource: StyledRect { + id: res + + required property string icon + required property real value + required property color colour + + Layout.fillWidth: true + implicitHeight: width + + color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + radius: Appearance.rounding.large + + CircularProgress { + id: circ + + anchors.fill: parent + value: res.value + padding: Appearance.padding.large * 3 + fgColour: res.colour + bgColour: Colours.layer(Colours.palette.m3surfaceContainerHighest, 3) + strokeWidth: width < 200 ? Appearance.padding.smaller : Appearance.padding.normal + } + + MaterialIcon { + id: icon + + anchors.centerIn: parent + text: res.icon + color: res.colour + font.pointSize: (circ.arcRadius * 0.7) || 1 + font.weight: 600 + } + + Behavior on value { + Anim { + duration: Appearance.anim.durations.large + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/lock/WeatherInfo.qml b/.config/quickshell/caelestia/modules/lock/WeatherInfo.qml new file mode 100644 index 0000000..d6c25af --- /dev/null +++ b/.config/quickshell/caelestia/modules/lock/WeatherInfo.qml @@ -0,0 +1,176 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import qs.utils +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property int rootHeight + + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.large * 2 + + spacing: Appearance.spacing.small + + Loader { + Layout.topMargin: Appearance.padding.large * 2 + Layout.bottomMargin: -Appearance.padding.large + Layout.alignment: Qt.AlignHCenter + + active: root.rootHeight > 610 + visible: active + + sourceComponent: StyledText { + text: qsTr("Weather") + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.extraLarge + font.weight: 500 + } + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.large + + MaterialIcon { + animate: true + text: Weather.icon + color: Colours.palette.m3secondary + font.pointSize: Appearance.font.size.extraLarge * 2.5 + } + + ColumnLayout { + spacing: Appearance.spacing.small + + StyledText { + Layout.fillWidth: true + + animate: true + text: Weather.description + color: Colours.palette.m3secondary + font.pointSize: Appearance.font.size.large + font.weight: 500 + elide: Text.ElideRight + } + + StyledText { + Layout.fillWidth: true + + animate: true + text: qsTr("Humidity: %1%").arg(Weather.humidity) + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.normal + elide: Text.ElideRight + } + } + + Loader { + Layout.rightMargin: Appearance.padding.smaller + active: root.width > 400 + visible: active + + sourceComponent: ColumnLayout { + spacing: Appearance.spacing.small + + StyledText { + Layout.fillWidth: true + + animate: true + text: Weather.temp + color: Colours.palette.m3primary + horizontalAlignment: Text.AlignRight + font.pointSize: Appearance.font.size.extraLarge + font.weight: 500 + elide: Text.ElideLeft + } + + StyledText { + Layout.fillWidth: true + + animate: true + text: qsTr("Feels like: %1").arg(Weather.feelsLike) + color: Colours.palette.m3outline + horizontalAlignment: Text.AlignRight + font.pointSize: Appearance.font.size.smaller + elide: Text.ElideLeft + } + } + } + } + + Loader { + id: forecastLoader + + Layout.topMargin: Appearance.spacing.smaller + Layout.bottomMargin: Appearance.padding.large * 2 + Layout.fillWidth: true + + active: root.rootHeight > 820 + visible: active + + sourceComponent: RowLayout { + spacing: Appearance.spacing.large + + Repeater { + model: { + const forecast = Weather.hourlyForecast; + const count = root.width < 320 ? 3 : root.width < 400 ? 4 : 5; + if (!forecast) + return Array.from({ + length: count + }, () => null); + + return forecast.slice(0, count); + } + + ColumnLayout { + id: forecastHour + + required property var modelData + + Layout.fillWidth: true + spacing: Appearance.spacing.small + + StyledText { + Layout.fillWidth: true + text: { + const hour = forecastHour.modelData?.hour ?? 0; + return hour > 12 ? `${(hour - 12).toString().padStart(2, "0")} PM` : `${hour.toString().padStart(2, "0")} AM`; + } + color: Colours.palette.m3outline + horizontalAlignment: Text.AlignHCenter + font.pointSize: Appearance.font.size.larger + } + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: forecastHour.modelData?.icon ?? "cloud_alert" + font.pointSize: Appearance.font.size.extraLarge * 1.5 + font.weight: 500 + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: Config.services.useFahrenheit ? `${forecastHour.modelData?.tempF ?? 0}°F` : `${forecastHour.modelData?.tempC ?? 0}°C` + color: Colours.palette.m3secondary + font.pointSize: Appearance.font.size.larger + } + } + } + } + } + + Timer { + running: true + triggeredOnStart: true + repeat: true + interval: 900000 // 15 minutes + onTriggered: Weather.reload() + } +} diff --git a/.config/quickshell/caelestia/modules/notifications/Background.qml b/.config/quickshell/caelestia/modules/notifications/Background.qml new file mode 100644 index 0000000..a44cb19 --- /dev/null +++ b/.config/quickshell/caelestia/modules/notifications/Background.qml @@ -0,0 +1,54 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + required property var sidebar + readonly property real rounding: Config.border.rounding + readonly property bool flatten: wrapper.height < rounding * 2 + readonly property real roundingY: flatten ? wrapper.height / 2 : rounding + + strokeWidth: -1 + fillColor: Colours.palette.m3surface + + PathLine { + relativeX: -(root.wrapper.width + root.rounding) + relativeY: 0 + } + PathArc { + relativeX: root.rounding + relativeY: root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + } + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.roundingY * 2 + } + PathArc { + relativeX: root.sidebar.notifsRoundingX + relativeY: root.roundingY + radiusX: root.sidebar.notifsRoundingX + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: root.wrapper.height > 0 ? root.wrapper.width - root.rounding - root.sidebar.notifsRoundingX : root.wrapper.width + relativeY: 0 + } + PathArc { + relativeX: root.rounding + relativeY: root.rounding + radiusX: root.rounding + radiusY: root.rounding + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/modules/notifications/Content.qml b/.config/quickshell/caelestia/modules/notifications/Content.qml new file mode 100644 index 0000000..2d4590e --- /dev/null +++ b/.config/quickshell/caelestia/modules/notifications/Content.qml @@ -0,0 +1,204 @@ +import qs.components.containers +import qs.components.widgets +import qs.services +import qs.config +import Quickshell +import Quickshell.Widgets +import QtQuick + +Item { + id: root + + required property PersistentProperties visibilities + required property Item panels + readonly property int padding: Appearance.padding.large + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + + implicitWidth: Config.notifs.sizes.width + padding * 2 + implicitHeight: { + const count = list.count; + if (count === 0) + return 0; + + let height = (count - 1) * Appearance.spacing.smaller; + for (let i = 0; i < count; i++) + height += list.itemAtIndex(i)?.nonAnimHeight ?? 0; + + if (visibilities && panels) { + if (visibilities.osd) { + const h = panels.osd.y - Config.border.rounding * 2 - padding * 2; + if (height > h) + height = h; + } + + if (visibilities.session) { + const h = panels.session.y - Config.border.rounding * 2 - padding * 2; + if (height > h) + height = h; + } + } + + return Math.min((QsWindow.window?.screen?.height ?? 0) - Config.border.thickness * 2, height + padding * 2); + } + + ClippingWrapperRectangle { + anchors.fill: parent + anchors.margins: root.padding + + color: "transparent" + radius: Appearance.rounding.normal + + StyledListView { + id: list + + model: ScriptModel { + values: Notifs.popups.filter(n => !n.closed) + } + + anchors.fill: parent + + orientation: Qt.Vertical + spacing: 0 + cacheBuffer: QsWindow.window?.screen.height ?? 0 + + delegate: Item { + id: wrapper + + required property Notifs.Notif modelData + required property int index + readonly property alias nonAnimHeight: notif.nonAnimHeight + property int idx + + onIndexChanged: { + if (index !== -1) + idx = index; + } + + implicitWidth: notif.implicitWidth + implicitHeight: notif.implicitHeight + (idx === 0 ? 0 : Appearance.spacing.smaller) + + ListView.onRemove: removeAnim.start() + + SequentialAnimation { + id: removeAnim + + PropertyAction { + target: wrapper + property: "ListView.delayRemove" + value: true + } + PropertyAction { + target: wrapper + property: "enabled" + value: false + } + PropertyAction { + target: wrapper + property: "implicitHeight" + value: 0 + } + PropertyAction { + target: wrapper + property: "z" + value: 1 + } + Anim { + target: notif + property: "x" + to: (notif.x >= 0 ? Config.notifs.sizes.width : -Config.notifs.sizes.width) * 2 + duration: Appearance.anim.durations.normal + easing.bezierCurve: Appearance.anim.curves.emphasized + } + PropertyAction { + target: wrapper + property: "ListView.delayRemove" + value: false + } + } + + ClippingRectangle { + anchors.top: parent.top + anchors.topMargin: wrapper.idx === 0 ? 0 : Appearance.spacing.smaller + + color: "transparent" + radius: notif.radius + implicitWidth: notif.implicitWidth + implicitHeight: notif.implicitHeight + + Notification { + id: notif + + modelData: wrapper.modelData + } + } + } + + move: Transition { + Anim { + property: "y" + } + } + + displaced: Transition { + Anim { + property: "y" + } + } + + ExtraIndicator { + anchors.top: parent.top + extra: { + const count = list.count; + if (count === 0) + return 0; + + const scrollY = list.contentY; + + let height = 0; + for (let i = 0; i < count; i++) { + height += (list.itemAtIndex(i)?.nonAnimHeight ?? 0) + Appearance.spacing.smaller; + + if (height - Appearance.spacing.smaller >= scrollY) + return i; + } + + return count; + } + } + + ExtraIndicator { + anchors.bottom: parent.bottom + extra: { + const count = list.count; + if (count === 0) + return 0; + + const scrollY = list.contentHeight - (list.contentY + list.height); + + let height = 0; + for (let i = count - 1; i >= 0; i--) { + height += (list.itemAtIndex(i)?.nonAnimHeight ?? 0) + Appearance.spacing.smaller; + + if (height - Appearance.spacing.smaller >= scrollY) + return count - i - 1; + } + + return 0; + } + } + } + } + + Behavior on implicitHeight { + Anim {} + } + + component Anim: NumberAnimation { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } +} diff --git a/.config/quickshell/caelestia/modules/notifications/Notification.qml b/.config/quickshell/caelestia/modules/notifications/Notification.qml new file mode 100644 index 0000000..8c2d3ec --- /dev/null +++ b/.config/quickshell/caelestia/modules/notifications/Notification.qml @@ -0,0 +1,480 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.effects +import qs.services +import qs.config +import qs.utils +import Quickshell +import Quickshell.Widgets +import Quickshell.Services.Notifications +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property Notifs.Notif modelData + readonly property bool hasImage: modelData.image.length > 0 + readonly property bool hasAppIcon: modelData.appIcon.length > 0 + readonly property int nonAnimHeight: summary.implicitHeight + (root.expanded ? appName.height + body.height + actions.height + actions.anchors.topMargin : bodyPreview.height) + inner.anchors.margins * 2 + property bool expanded: Config.notifs.openExpanded + + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondaryContainer : Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.normal + implicitWidth: Config.notifs.sizes.width + implicitHeight: inner.implicitHeight + + x: Config.notifs.sizes.width + Component.onCompleted: { + x = 0; + modelData.lock(this); + } + Component.onDestruction: modelData.unlock(this) + + Behavior on x { + Anim { + easing.bezierCurve: Appearance.anim.curves.emphasizedDecel + } + } + + MouseArea { + property int startY + + anchors.fill: parent + hoverEnabled: true + cursorShape: root.expanded && body.hoveredLink ? Qt.PointingHandCursor : pressed ? Qt.ClosedHandCursor : undefined + acceptedButtons: Qt.LeftButton | Qt.MiddleButton + preventStealing: true + + onEntered: root.modelData.timer.stop() + onExited: { + if (!pressed) + root.modelData.timer.start(); + } + + drag.target: parent + drag.axis: Drag.XAxis + + onPressed: event => { + root.modelData.timer.stop(); + startY = event.y; + if (event.button === Qt.MiddleButton) + root.modelData.close(); + } + onReleased: event => { + if (!containsMouse) + root.modelData.timer.start(); + + if (Math.abs(root.x) < Config.notifs.sizes.width * Config.notifs.clearThreshold) + root.x = 0; + else + root.modelData.popup = false; + } + onPositionChanged: event => { + if (pressed) { + const diffY = event.y - startY; + if (Math.abs(diffY) > Config.notifs.expandThreshold) + root.expanded = diffY > 0; + } + } + onClicked: event => { + if (!Config.notifs.actionOnClick || event.button !== Qt.LeftButton) + return; + + const actions = root.modelData.actions; + if (actions?.length === 1) + actions[0].invoke(); + } + + Item { + id: inner + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: Appearance.padding.normal + + implicitHeight: root.nonAnimHeight + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + Loader { + id: image + + active: root.hasImage + + anchors.left: parent.left + anchors.top: parent.top + width: Config.notifs.sizes.image + height: Config.notifs.sizes.image + visible: root.hasImage || root.hasAppIcon + + sourceComponent: ClippingRectangle { + radius: Appearance.rounding.full + implicitWidth: Config.notifs.sizes.image + implicitHeight: Config.notifs.sizes.image + + Image { + anchors.fill: parent + source: Qt.resolvedUrl(root.modelData.image) + fillMode: Image.PreserveAspectCrop + cache: false + asynchronous: true + } + } + } + + Loader { + id: appIcon + + active: root.hasAppIcon || !root.hasImage + + anchors.horizontalCenter: root.hasImage ? undefined : image.horizontalCenter + anchors.verticalCenter: root.hasImage ? undefined : image.verticalCenter + anchors.right: root.hasImage ? image.right : undefined + anchors.bottom: root.hasImage ? image.bottom : undefined + + sourceComponent: StyledRect { + radius: Appearance.rounding.full + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3error : root.modelData.urgency === NotificationUrgency.Low ? Colours.layer(Colours.palette.m3surfaceContainerHighest, 2) : Colours.palette.m3secondaryContainer + implicitWidth: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image + implicitHeight: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image + + Loader { + id: icon + + active: root.hasAppIcon + + anchors.centerIn: parent + + width: Math.round(parent.width * 0.6) + height: Math.round(parent.width * 0.6) + + sourceComponent: ColouredIcon { + anchors.fill: parent + source: Quickshell.iconPath(root.modelData.appIcon) + colour: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : root.modelData.urgency === NotificationUrgency.Low ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + layer.enabled: root.modelData.appIcon.endsWith("symbolic") + } + } + + Loader { + active: !root.hasAppIcon + anchors.centerIn: parent + anchors.horizontalCenterOffset: -Appearance.font.size.large * 0.02 + anchors.verticalCenterOffset: Appearance.font.size.large * 0.02 + + sourceComponent: MaterialIcon { + text: Icons.getNotifIcon(root.modelData.summary, root.modelData.urgency) + + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : root.modelData.urgency === NotificationUrgency.Low ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + font.pointSize: Appearance.font.size.large + } + } + } + } + + StyledText { + id: appName + + anchors.top: parent.top + anchors.left: image.right + anchors.leftMargin: Appearance.spacing.smaller + + animate: true + text: appNameMetrics.elidedText + maximumLineCount: 1 + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + + opacity: root.expanded ? 1 : 0 + + Behavior on opacity { + Anim {} + } + } + + TextMetrics { + id: appNameMetrics + + text: root.modelData.appName + font.family: appName.font.family + font.pointSize: appName.font.pointSize + elide: Text.ElideRight + elideWidth: expandBtn.x - time.width - timeSep.width - summary.x - Appearance.spacing.small * 3 + } + + StyledText { + id: summary + + anchors.top: parent.top + anchors.left: image.right + anchors.leftMargin: Appearance.spacing.smaller + + animate: true + text: summaryMetrics.elidedText + maximumLineCount: 1 + height: implicitHeight + + states: State { + name: "expanded" + when: root.expanded + + PropertyChanges { + summary.maximumLineCount: undefined + } + + AnchorChanges { + target: summary + anchors.top: appName.bottom + } + } + + transitions: Transition { + PropertyAction { + target: summary + property: "maximumLineCount" + } + AnchorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + + Behavior on height { + Anim {} + } + } + + TextMetrics { + id: summaryMetrics + + text: root.modelData.summary + font.family: summary.font.family + font.pointSize: summary.font.pointSize + elide: Text.ElideRight + elideWidth: expandBtn.x - time.width - timeSep.width - summary.x - Appearance.spacing.small * 3 + } + + StyledText { + id: timeSep + + anchors.top: parent.top + anchors.left: summary.right + anchors.leftMargin: Appearance.spacing.small + + text: "•" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + + states: State { + name: "expanded" + when: root.expanded + + AnchorChanges { + target: timeSep + anchors.left: appName.right + } + } + + transitions: Transition { + AnchorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + } + + StyledText { + id: time + + anchors.top: parent.top + anchors.left: timeSep.right + anchors.leftMargin: Appearance.spacing.small + + animate: true + horizontalAlignment: Text.AlignLeft + text: root.modelData.timeStr + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + } + + Item { + id: expandBtn + + anchors.right: parent.right + anchors.top: parent.top + + implicitWidth: expandIcon.height + implicitHeight: expandIcon.height + + StateLayer { + radius: Appearance.rounding.full + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + + function onClicked() { + root.expanded = !root.expanded; + } + } + + MaterialIcon { + id: expandIcon + + anchors.centerIn: parent + + animate: true + text: root.expanded ? "expand_less" : "expand_more" + font.pointSize: Appearance.font.size.normal + } + } + + StyledText { + id: bodyPreview + + anchors.left: summary.left + anchors.right: expandBtn.left + anchors.top: summary.bottom + anchors.rightMargin: Appearance.spacing.small + + animate: true + textFormat: Text.MarkdownText + text: bodyPreviewMetrics.elidedText + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + + opacity: root.expanded ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + + TextMetrics { + id: bodyPreviewMetrics + + text: root.modelData.body + font.family: bodyPreview.font.family + font.pointSize: bodyPreview.font.pointSize + elide: Text.ElideRight + elideWidth: bodyPreview.width + } + + StyledText { + id: body + + anchors.left: summary.left + anchors.right: expandBtn.left + anchors.top: summary.bottom + anchors.rightMargin: Appearance.spacing.small + + animate: true + textFormat: Text.MarkdownText + text: root.modelData.body + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + height: text ? implicitHeight : 0 + + onLinkActivated: link => { + if (!root.expanded) + return; + + Quickshell.execDetached(["app2unit", "-O", "--", link]); + root.modelData.popup = false; + } + + opacity: root.expanded ? 1 : 0 + + Behavior on opacity { + Anim {} + } + } + + RowLayout { + id: actions + + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: body.bottom + anchors.topMargin: Appearance.spacing.small + + spacing: Appearance.spacing.smaller + + opacity: root.expanded ? 1 : 0 + + Behavior on opacity { + Anim {} + } + + Action { + modelData: QtObject { + readonly property string text: qsTr("Close") + function invoke(): void { + root.modelData.close(); + } + } + } + + Repeater { + model: root.modelData.actions + + delegate: Component { + Action {} + } + } + } + } + } + + component Action: StyledRect { + id: action + + required property var modelData + + radius: Appearance.rounding.full + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondary : Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + + Layout.preferredWidth: actionText.width + Appearance.padding.normal * 2 + Layout.preferredHeight: actionText.height + Appearance.padding.small * 2 + implicitWidth: actionText.width + Appearance.padding.normal * 2 + implicitHeight: actionText.height + Appearance.padding.small * 2 + + StateLayer { + radius: Appearance.rounding.full + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondary : Colours.palette.m3onSurface + + function onClicked(): void { + action.modelData.invoke(); + } + } + + StyledText { + id: actionText + + anchors.centerIn: parent + text: actionTextMetrics.elidedText + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondary : Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + } + + TextMetrics { + id: actionTextMetrics + + text: action.modelData.text + font.family: actionText.font.family + font.pointSize: actionText.font.pointSize + elide: Text.ElideRight + elideWidth: { + const numActions = root.modelData.actions.length + 1; + return (inner.width - actions.spacing * (numActions - 1)) / numActions - Appearance.padding.normal * 2; + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/notifications/Wrapper.qml b/.config/quickshell/caelestia/modules/notifications/Wrapper.qml new file mode 100644 index 0000000..61acc56 --- /dev/null +++ b/.config/quickshell/caelestia/modules/notifications/Wrapper.qml @@ -0,0 +1,39 @@ +import qs.components +import qs.config +import QtQuick + +Item { + id: root + + required property var visibilities + required property Item panels + + visible: height > 0 + implicitWidth: Math.max(panels.sidebar.width, content.implicitWidth) + implicitHeight: content.implicitHeight + + states: State { + name: "hidden" + when: root.visibilities.sidebar && Config.sidebar.enabled + + PropertyChanges { + root.implicitHeight: 0 + } + } + + transitions: Transition { + Anim { + target: root + property: "implicitHeight" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + Content { + id: content + + visibilities: root.visibilities + panels: root.panels + } +} diff --git a/.config/quickshell/caelestia/modules/osd/Background.qml b/.config/quickshell/caelestia/modules/osd/Background.qml new file mode 100644 index 0000000..78955c7 --- /dev/null +++ b/.config/quickshell/caelestia/modules/osd/Background.qml @@ -0,0 +1,60 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + readonly property real rounding: Config.border.rounding + readonly property bool flatten: wrapper.width < rounding * 2 + readonly property real roundingX: flatten ? wrapper.width / 2 : rounding + + strokeWidth: -1 + fillColor: Colours.palette.m3surface + + PathArc { + relativeX: -root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + } + PathLine { + relativeX: -(root.wrapper.width - root.roundingX * 2) + relativeY: 0 + } + PathArc { + relativeX: -root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.rounding * 2 + } + PathArc { + relativeX: root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: root.wrapper.width - root.roundingX * 2 + relativeY: 0 + } + PathArc { + relativeX: root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/modules/osd/Content.qml b/.config/quickshell/caelestia/modules/osd/Content.qml new file mode 100644 index 0000000..770fb69 --- /dev/null +++ b/.config/quickshell/caelestia/modules/osd/Content.qml @@ -0,0 +1,127 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.services +import qs.config +import qs.utils +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Brightness.Monitor monitor + required property var visibilities + + required property real volume + required property bool muted + required property real sourceVolume + required property bool sourceMuted + required property real brightness + + implicitWidth: layout.implicitWidth + Appearance.padding.large * 2 + implicitHeight: layout.implicitHeight + Appearance.padding.large * 2 + + ColumnLayout { + id: layout + + anchors.centerIn: parent + spacing: Appearance.spacing.normal + + // Speaker volume + CustomMouseArea { + implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: Config.osd.sizes.sliderHeight + + function onWheel(event: WheelEvent) { + if (event.angleDelta.y > 0) + Audio.incrementVolume(); + else if (event.angleDelta.y < 0) + Audio.decrementVolume(); + } + + FilledSlider { + anchors.fill: parent + + icon: Icons.getVolumeIcon(value, root.muted) + value: root.volume + to: Config.services.maxVolume + onMoved: Audio.setVolume(value) + } + } + + // Microphone volume + WrappedLoader { + shouldBeActive: Config.osd.enableMicrophone && (!Config.osd.enableBrightness || !root.visibilities.session) + + sourceComponent: CustomMouseArea { + implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: Config.osd.sizes.sliderHeight + + function onWheel(event: WheelEvent) { + if (event.angleDelta.y > 0) + Audio.incrementSourceVolume(); + else if (event.angleDelta.y < 0) + Audio.decrementSourceVolume(); + } + + FilledSlider { + anchors.fill: parent + + icon: Icons.getMicVolumeIcon(value, root.sourceMuted) + value: root.sourceVolume + to: Config.services.maxVolume + onMoved: Audio.setSourceVolume(value) + } + } + } + + // Brightness + WrappedLoader { + shouldBeActive: Config.osd.enableBrightness + + sourceComponent: CustomMouseArea { + implicitWidth: Config.osd.sizes.sliderWidth + implicitHeight: Config.osd.sizes.sliderHeight + + function onWheel(event: WheelEvent) { + const monitor = root.monitor; + if (!monitor) + return; + if (event.angleDelta.y > 0) + monitor.setBrightness(monitor.brightness + Config.services.brightnessIncrement); + else if (event.angleDelta.y < 0) + monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement); + } + + FilledSlider { + anchors.fill: parent + + icon: `brightness_${(Math.round(value * 6) + 1)}` + value: root.brightness + onMoved: root.monitor?.setBrightness(value) + } + } + } + } + + component WrappedLoader: Loader { + required property bool shouldBeActive + + Layout.preferredHeight: shouldBeActive ? Config.osd.sizes.sliderHeight : 0 + opacity: shouldBeActive ? 1 : 0 + active: opacity > 0 + visible: active + + Behavior on Layout.preferredHeight { + Anim { + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + Behavior on opacity { + Anim {} + } + } +} diff --git a/.config/quickshell/caelestia/modules/osd/Wrapper.qml b/.config/quickshell/caelestia/modules/osd/Wrapper.qml new file mode 100644 index 0000000..2519609 --- /dev/null +++ b/.config/quickshell/caelestia/modules/osd/Wrapper.qml @@ -0,0 +1,134 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Quickshell +import QtQuick + +Item { + id: root + + required property ShellScreen screen + required property var visibilities + property bool hovered + readonly property Brightness.Monitor monitor: Brightness.getMonitorForScreen(root.screen) + readonly property bool shouldBeActive: visibilities.osd && Config.osd.enabled && !(visibilities.utilities && Config.utilities.enabled) + + property real volume + property bool muted + property real sourceVolume + property bool sourceMuted + property real brightness + + function show(): void { + visibilities.osd = true; + timer.restart(); + } + + Component.onCompleted: { + volume = Audio.volume; + muted = Audio.muted; + sourceVolume = Audio.sourceVolume; + sourceMuted = Audio.sourceMuted; + brightness = root.monitor?.brightness ?? 0; + } + + visible: width > 0 + implicitWidth: 0 + implicitHeight: content.implicitHeight + + states: State { + name: "visible" + when: root.shouldBeActive + + PropertyChanges { + root.implicitWidth: content.implicitWidth + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + target: root + property: "implicitWidth" + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + }, + Transition { + from: "visible" + to: "" + + Anim { + target: root + property: "implicitWidth" + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + ] + + Connections { + target: Audio + + function onMutedChanged(): void { + root.show(); + root.muted = Audio.muted; + } + + function onVolumeChanged(): void { + root.show(); + root.volume = Audio.volume; + } + + function onSourceMutedChanged(): void { + root.show(); + root.sourceMuted = Audio.sourceMuted; + } + + function onSourceVolumeChanged(): void { + root.show(); + root.sourceVolume = Audio.sourceVolume; + } + } + + Connections { + target: root.monitor + + function onBrightnessChanged(): void { + root.show(); + root.brightness = root.monitor?.brightness ?? 0; + } + } + + Timer { + id: timer + + interval: Config.osd.hideDelay + onTriggered: { + if (!root.hovered) + root.visibilities.osd = false; + } + } + + Loader { + id: content + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + + Component.onCompleted: active = Qt.binding(() => root.shouldBeActive || root.visible) + + sourceComponent: Content { + monitor: root.monitor + visibilities: root.visibilities + volume: root.volume + muted: root.muted + sourceVolume: root.sourceVolume + sourceMuted: root.sourceMuted + brightness: root.brightness + } + } +} diff --git a/.config/quickshell/caelestia/modules/session/Background.qml b/.config/quickshell/caelestia/modules/session/Background.qml new file mode 100644 index 0000000..78955c7 --- /dev/null +++ b/.config/quickshell/caelestia/modules/session/Background.qml @@ -0,0 +1,60 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + readonly property real rounding: Config.border.rounding + readonly property bool flatten: wrapper.width < rounding * 2 + readonly property real roundingX: flatten ? wrapper.width / 2 : rounding + + strokeWidth: -1 + fillColor: Colours.palette.m3surface + + PathArc { + relativeX: -root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + } + PathLine { + relativeX: -(root.wrapper.width - root.roundingX * 2) + relativeY: 0 + } + PathArc { + relativeX: -root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.rounding * 2 + } + PathArc { + relativeX: root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: root.wrapper.width - root.roundingX * 2 + relativeY: 0 + } + PathArc { + relativeX: root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapper.width) + radiusY: root.rounding + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/modules/session/Content.qml b/.config/quickshell/caelestia/modules/session/Content.qml new file mode 100644 index 0000000..45152e2 --- /dev/null +++ b/.config/quickshell/caelestia/modules/session/Content.qml @@ -0,0 +1,135 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import qs.utils +import Quickshell +import QtQuick + +Column { + id: root + + required property PersistentProperties visibilities + + padding: Appearance.padding.large + spacing: Appearance.spacing.large + + SessionButton { + id: logout + + icon: Config.session.icons.logout + command: Config.session.commands.logout + + KeyNavigation.down: shutdown + + Component.onCompleted: forceActiveFocus() + + Connections { + target: root.visibilities + + function onLauncherChanged(): void { + if (!root.visibilities.launcher) + logout.forceActiveFocus(); + } + } + } + + SessionButton { + id: shutdown + + icon: Config.session.icons.shutdown + command: Config.session.commands.shutdown + + KeyNavigation.up: logout + KeyNavigation.down: hibernate + } + + AnimatedImage { + width: Config.session.sizes.button + height: Config.session.sizes.button + sourceSize.width: width + sourceSize.height: height + + playing: visible + asynchronous: true + speed: Appearance.anim.sessionGifSpeed + source: Paths.absolutePath(Config.paths.sessionGif) + } + + SessionButton { + id: hibernate + + icon: Config.session.icons.hibernate + command: Config.session.commands.hibernate + + KeyNavigation.up: shutdown + KeyNavigation.down: reboot + } + + SessionButton { + id: reboot + + icon: Config.session.icons.reboot + command: Config.session.commands.reboot + + KeyNavigation.up: hibernate + } + + component SessionButton: StyledRect { + id: button + + required property string icon + required property list command + + implicitWidth: Config.session.sizes.button + implicitHeight: Config.session.sizes.button + + radius: Appearance.rounding.large + color: button.activeFocus ? Colours.palette.m3secondaryContainer : Colours.tPalette.m3surfaceContainer + + Keys.onEnterPressed: Quickshell.execDetached(button.command) + Keys.onReturnPressed: Quickshell.execDetached(button.command) + Keys.onEscapePressed: root.visibilities.session = false + Keys.onPressed: event => { + if (!Config.session.vimKeybinds) + return; + + if (event.modifiers & Qt.ControlModifier) { + if (event.key === Qt.Key_J && KeyNavigation.down) { + KeyNavigation.down.focus = true; + event.accepted = true; + } else if (event.key === Qt.Key_K && KeyNavigation.up) { + KeyNavigation.up.focus = true; + event.accepted = true; + } + } else if (event.key === Qt.Key_Tab && KeyNavigation.down) { + KeyNavigation.down.focus = true; + event.accepted = true; + } else if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier))) { + if (KeyNavigation.up) { + KeyNavigation.up.focus = true; + event.accepted = true; + } + } + } + + StateLayer { + radius: parent.radius + color: button.activeFocus ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + + function onClicked(): void { + Quickshell.execDetached(button.command); + } + } + + MaterialIcon { + anchors.centerIn: parent + + text: button.icon + color: button.activeFocus ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.extraLarge + font.weight: 500 + } + } +} diff --git a/.config/quickshell/caelestia/modules/session/Wrapper.qml b/.config/quickshell/caelestia/modules/session/Wrapper.qml new file mode 100644 index 0000000..14b03a8 --- /dev/null +++ b/.config/quickshell/caelestia/modules/session/Wrapper.qml @@ -0,0 +1,63 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.config +import Quickshell +import QtQuick + +Item { + id: root + + required property PersistentProperties visibilities + required property var panels + readonly property real nonAnimWidth: content.implicitWidth + + visible: width > 0 + implicitWidth: 0 + implicitHeight: content.implicitHeight + + states: State { + name: "visible" + when: root.visibilities.session && Config.session.enabled + + PropertyChanges { + root.implicitWidth: root.nonAnimWidth + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + target: root + property: "implicitWidth" + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + }, + Transition { + from: "visible" + to: "" + + Anim { + target: root + property: "implicitWidth" + easing.bezierCurve: root.panels.osd.width > 0 ? Appearance.anim.curves.expressiveDefaultSpatial : Appearance.anim.curves.emphasized + } + } + ] + + Loader { + id: content + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + + Component.onCompleted: active = Qt.binding(() => (root.visibilities.session && Config.session.enabled) || root.visible) + + sourceComponent: Content { + visibilities: root.visibilities + } + } +} diff --git a/.config/quickshell/caelestia/modules/sidebar/Background.qml b/.config/quickshell/caelestia/modules/sidebar/Background.qml new file mode 100644 index 0000000..beefdf5 --- /dev/null +++ b/.config/quickshell/caelestia/modules/sidebar/Background.qml @@ -0,0 +1,52 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + required property var panels + + readonly property real rounding: Config.border.rounding + + readonly property real notifsWidthDiff: panels.notifications.width - wrapper.width + readonly property real notifsRoundingX: panels.notifications.height > 0 && notifsWidthDiff < rounding * 2 ? notifsWidthDiff / 2 : rounding + + readonly property real utilsWidthDiff: panels.utilities.width - wrapper.width + readonly property real utilsRoundingX: utilsWidthDiff < rounding * 2 ? utilsWidthDiff / 2 : rounding + + strokeWidth: -1 + fillColor: Colours.palette.m3surface + + PathLine { + relativeX: -root.wrapper.width - root.notifsRoundingX + relativeY: 0 + } + PathArc { + relativeX: root.notifsRoundingX + relativeY: root.rounding + radiusX: root.notifsRoundingX + radiusY: root.rounding + } + PathLine { + relativeX: 0 + relativeY: root.wrapper.height - root.rounding * 2 + } + PathArc { + relativeX: -root.utilsRoundingX + relativeY: root.rounding + radiusX: root.utilsRoundingX + radiusY: root.rounding + } + PathLine { + relativeX: root.wrapper.width + root.utilsRoundingX + relativeY: 0 + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/modules/sidebar/Content.qml b/.config/quickshell/caelestia/modules/sidebar/Content.qml new file mode 100644 index 0000000..1b7feed --- /dev/null +++ b/.config/quickshell/caelestia/modules/sidebar/Content.qml @@ -0,0 +1,40 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Props props + required property var visibilities + + ColumnLayout { + id: layout + + anchors.fill: parent + spacing: Appearance.spacing.normal + + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainerLow + + NotifDock { + props: root.props + visibilities: root.visibilities + } + } + + StyledRect { + Layout.topMargin: Appearance.padding.large - layout.spacing + Layout.fillWidth: true + implicitHeight: 1 + + color: Colours.tPalette.m3outlineVariant + } + } +} diff --git a/.config/quickshell/caelestia/modules/sidebar/Notif.qml b/.config/quickshell/caelestia/modules/sidebar/Notif.qml new file mode 100644 index 0000000..5a31764 --- /dev/null +++ b/.config/quickshell/caelestia/modules/sidebar/Notif.qml @@ -0,0 +1,164 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property Notifs.Notif modelData + required property Props props + required property bool expanded + required property var visibilities + + readonly property StyledText body: expandedContent.item?.body ?? null + readonly property real nonAnimHeight: expanded ? summary.implicitHeight + expandedContent.implicitHeight + expandedContent.anchors.topMargin + Appearance.padding.normal * 2 : summaryHeightMetrics.height + + implicitHeight: nonAnimHeight + + radius: Appearance.rounding.small + color: { + const c = root.modelData.urgency === "critical" ? Colours.palette.m3secondaryContainer : Colours.layer(Colours.palette.m3surfaceContainerHigh, 2); + return expanded ? c : Qt.alpha(c, 0); + } + + states: State { + name: "expanded" + when: root.expanded + + PropertyChanges { + summary.anchors.margins: Appearance.padding.normal + dummySummary.anchors.margins: Appearance.padding.normal + compactBody.anchors.margins: Appearance.padding.normal + timeStr.anchors.margins: Appearance.padding.normal + expandedContent.anchors.margins: Appearance.padding.normal + summary.width: root.width - Appearance.padding.normal * 2 - timeStr.implicitWidth - Appearance.spacing.small + summary.maximumLineCount: Number.MAX_SAFE_INTEGER + } + } + + transitions: Transition { + Anim { + properties: "margins,width,maximumLineCount" + } + } + + TextMetrics { + id: summaryHeightMetrics + + font: summary.font + text: " " // Use this height to prevent weird characters from changing the line height + } + + StyledText { + id: summary + + anchors.top: parent.top + anchors.left: parent.left + + width: parent.width + text: root.modelData.summary + color: root.modelData.urgency === "critical" ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + elide: Text.ElideRight + wrapMode: Text.WordWrap + maximumLineCount: 1 + } + + StyledText { + id: dummySummary + + anchors.top: parent.top + anchors.left: parent.left + + visible: false + text: root.modelData.summary + } + + WrappedLoader { + id: compactBody + + shouldBeActive: !root.expanded + anchors.top: parent.top + anchors.left: dummySummary.right + anchors.right: parent.right + anchors.leftMargin: Appearance.spacing.small + + sourceComponent: StyledText { + text: root.modelData.body.replace(/\n/g, " ") + color: root.modelData.urgency === "critical" ? Colours.palette.m3secondary : Colours.palette.m3outline + elide: Text.ElideRight + } + } + + WrappedLoader { + id: timeStr + + shouldBeActive: root.expanded + anchors.top: parent.top + anchors.right: parent.right + + sourceComponent: StyledText { + animate: true + text: root.modelData.timeStr + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + } + + WrappedLoader { + id: expandedContent + + shouldBeActive: root.expanded + anchors.top: summary.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: Appearance.spacing.small / 2 + + sourceComponent: ColumnLayout { + readonly property alias body: body + + spacing: Appearance.spacing.smaller + + StyledText { + id: body + + Layout.fillWidth: true + textFormat: Text.MarkdownText + text: root.modelData.body.replace(/(.)\n(?!\n)/g, "$1\n\n") || qsTr("No body here! :/") + color: root.modelData.urgency === "critical" ? Colours.palette.m3secondary : Colours.palette.m3outline + wrapMode: Text.WordWrap + + onLinkActivated: link => { + Quickshell.execDetached(["app2unit", "-O", "--", link]); + root.visibilities.sidebar = false; + } + } + + NotifActionList { + notif: root.modelData + } + } + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + component WrappedLoader: Loader { + required property bool shouldBeActive + + opacity: shouldBeActive ? 1 : 0 + active: opacity > 0 + + Behavior on opacity { + Anim {} + } + } +} diff --git a/.config/quickshell/caelestia/modules/sidebar/NotifActionList.qml b/.config/quickshell/caelestia/modules/sidebar/NotifActionList.qml new file mode 100644 index 0000000..d1f1e1f --- /dev/null +++ b/.config/quickshell/caelestia/modules/sidebar/NotifActionList.qml @@ -0,0 +1,200 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.containers +import qs.components.effects +import qs.services +import qs.config +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Notifs.Notif notif + + Layout.fillWidth: true + implicitHeight: flickable.contentHeight + + layer.enabled: true + layer.smooth: true + layer.effect: OpacityMask { + maskSource: gradientMask + } + + Item { + id: gradientMask + + anchors.fill: parent + layer.enabled: true + visible: false + + Rectangle { + anchors.fill: parent + + gradient: Gradient { + orientation: Gradient.Horizontal + + GradientStop { + position: 0 + color: Qt.rgba(0, 0, 0, 0) + } + GradientStop { + position: 0.1 + color: Qt.rgba(0, 0, 0, 1) + } + GradientStop { + position: 0.9 + color: Qt.rgba(0, 0, 0, 1) + } + GradientStop { + position: 1 + color: Qt.rgba(0, 0, 0, 0) + } + } + } + + Rectangle { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + + implicitWidth: parent.width / 2 + opacity: flickable.contentX > 0 ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + + Rectangle { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + + implicitWidth: parent.width / 2 + opacity: flickable.contentX < flickable.contentWidth - parent.width ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + } + + StyledFlickable { + id: flickable + + anchors.fill: parent + contentWidth: Math.max(width, actionList.implicitWidth) + contentHeight: actionList.implicitHeight + + RowLayout { + id: actionList + + anchors.fill: parent + spacing: Appearance.spacing.small + + Repeater { + model: [ + { + isClose: true + }, + ...root.notif.actions, + { + isCopy: true + } + ] + + StyledRect { + id: action + + required property var modelData + + Layout.fillWidth: true + Layout.fillHeight: true + implicitWidth: actionInner.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: actionInner.implicitHeight + Appearance.padding.small * 2 + + Layout.preferredWidth: implicitWidth + (actionStateLayer.pressed ? Appearance.padding.large : 0) + radius: actionStateLayer.pressed ? Appearance.rounding.small / 2 : Appearance.rounding.small + color: Colours.layer(Colours.palette.m3surfaceContainerHighest, 4) + + Timer { + id: copyTimer + + interval: 3000 + onTriggered: actionInner.item.text = "content_copy" + } + + StateLayer { + id: actionStateLayer + + function onClicked(): void { + if (action.modelData.isClose) { + root.notif.close(); + } else if (action.modelData.isCopy) { + Quickshell.clipboardText = root.notif.body; + actionInner.item.text = "inventory"; + copyTimer.start(); + } else if (action.modelData.invoke) { + action.modelData.invoke(); + } else if (!root.notif.resident) { + root.notif.close(); + } + } + } + + Loader { + id: actionInner + + anchors.centerIn: parent + sourceComponent: action.modelData.isClose || action.modelData.isCopy ? iconBtn : root.notif.hasActionIcons ? iconComp : textComp + } + + Component { + id: iconBtn + + MaterialIcon { + animate: action.modelData.isCopy ?? false + text: action.modelData.isCopy ? "content_copy" : "close" + color: Colours.palette.m3onSurfaceVariant + } + } + + Component { + id: iconComp + + IconImage { + source: Quickshell.iconPath(action.modelData.identifier) + } + } + + Component { + id: textComp + + StyledText { + text: action.modelData.text + color: Colours.palette.m3onSurfaceVariant + } + } + + Behavior on Layout.preferredWidth { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + Behavior on radius { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/sidebar/NotifDock.qml b/.config/quickshell/caelestia/modules/sidebar/NotifDock.qml new file mode 100644 index 0000000..d039d15 --- /dev/null +++ b/.config/quickshell/caelestia/modules/sidebar/NotifDock.qml @@ -0,0 +1,207 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.components.containers +import qs.components.effects +import qs.services +import qs.config +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Props props + required property var visibilities + readonly property int notifCount: Notifs.list.reduce((acc, n) => n.closed ? acc : acc + 1, 0) + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + + Component.onCompleted: Notifs.list.forEach(n => n.popup = false) + + Item { + id: title + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.small + + implicitHeight: Math.max(count.implicitHeight, titleText.implicitHeight) + + StyledText { + id: count + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: root.notifCount > 0 ? 0 : -width - titleText.anchors.leftMargin + opacity: root.notifCount > 0 ? 1 : 0 + + text: root.notifCount + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.normal + font.family: Appearance.font.family.mono + font.weight: 500 + + Behavior on anchors.leftMargin { + Anim {} + } + + Behavior on opacity { + Anim {} + } + } + + StyledText { + id: titleText + + anchors.verticalCenter: parent.verticalCenter + anchors.left: count.right + anchors.right: parent.right + anchors.leftMargin: Appearance.spacing.small + + text: root.notifCount > 0 ? qsTr("notification%1").arg(root.notifCount === 1 ? "" : "s") : qsTr("Notifications") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.normal + font.family: Appearance.font.family.mono + font.weight: 500 + elide: Text.ElideRight + } + } + + ClippingRectangle { + id: clipRect + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: title.bottom + anchors.bottom: parent.bottom + anchors.topMargin: Appearance.spacing.smaller + + radius: Appearance.rounding.small + color: "transparent" + + Loader { + anchors.centerIn: parent + active: opacity > 0 + opacity: root.notifCount > 0 ? 0 : 1 + + sourceComponent: ColumnLayout { + spacing: Appearance.spacing.large + + Image { + asynchronous: true + source: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/dino.png`) + fillMode: Image.PreserveAspectFit + sourceSize.width: clipRect.width * 0.8 + + layer.enabled: true + layer.effect: Colouriser { + colorizationColor: Colours.palette.m3outlineVariant + brightness: 1 + } + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("No Notifications") + color: Colours.palette.m3outlineVariant + font.pointSize: Appearance.font.size.large + font.family: Appearance.font.family.mono + font.weight: 500 + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.extraLarge + } + } + } + + StyledFlickable { + id: view + + anchors.fill: parent + + flickableDirection: Flickable.VerticalFlick + contentWidth: width + contentHeight: notifList.implicitHeight + + StyledScrollBar.vertical: StyledScrollBar { + flickable: view + } + + NotifDockList { + id: notifList + + props: root.props + visibilities: root.visibilities + container: view + } + } + } + + Timer { + id: clearTimer + + repeat: true + interval: 50 + onTriggered: { + let next = null; + for (let i = 0; i < notifList.repeater.count; i++) { + next = notifList.repeater.itemAt(i); + if (!next?.closed) + break; + } + if (next) + next.closeAll(); + else + stop(); + } + } + + Loader { + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: Appearance.padding.normal + + scale: root.notifCount > 0 ? 1 : 0.5 + opacity: root.notifCount > 0 ? 1 : 0 + active: opacity > 0 + + sourceComponent: IconButton { + id: clearBtn + + icon: "clear_all" + radius: Appearance.rounding.normal + padding: Appearance.padding.normal + font.pointSize: Math.round(Appearance.font.size.large * 1.2) + onClicked: clearTimer.start() + + Elevation { + anchors.fill: parent + radius: parent.radius + z: -1 + level: clearBtn.stateLayer.containsMouse ? 4 : 3 + } + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/sidebar/NotifDockList.qml b/.config/quickshell/caelestia/modules/sidebar/NotifDockList.qml new file mode 100644 index 0000000..b927e91 --- /dev/null +++ b/.config/quickshell/caelestia/modules/sidebar/NotifDockList.qml @@ -0,0 +1,167 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Quickshell +import QtQuick + +Item { + id: root + + required property Props props + required property Flickable container + required property var visibilities + + readonly property alias repeater: repeater + readonly property int spacing: Appearance.spacing.small + property bool flag + + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: { + const item = repeater.itemAt(repeater.count - 1); + return item ? item.y + item.implicitHeight : 0; + } + + Repeater { + id: repeater + + model: ScriptModel { + values: { + const map = new Map(); + for (const n of Notifs.notClosed) + map.set(n.appName, null); + for (const n of Notifs.list) + map.set(n.appName, null); + return [...map.keys()]; + } + onValuesChanged: root.flagChanged() + } + + MouseArea { + id: notif + + required property int index + required property string modelData + + readonly property bool closed: notifInner.notifCount === 0 + readonly property alias nonAnimHeight: notifInner.nonAnimHeight + property int startY + + function closeAll(): void { + for (const n of Notifs.notClosed.filter(n => n.appName === modelData)) + n.close(); + } + + y: { + root.flag; // Force update + let y = 0; + for (let i = 0; i < index; i++) { + const item = repeater.itemAt(i); + if (!item.closed) + y += item.nonAnimHeight + root.spacing; + } + return y; + } + + containmentMask: QtObject { + function contains(p: point): bool { + if (!root.container.contains(notif.mapToItem(root.container, p))) + return false; + return notifInner.contains(p); + } + } + + implicitWidth: root.width + implicitHeight: notifInner.implicitHeight + + hoverEnabled: true + cursorShape: pressed ? Qt.ClosedHandCursor : undefined + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + preventStealing: true + enabled: !closed + + drag.target: this + drag.axis: Drag.XAxis + + onPressed: event => { + startY = event.y; + if (event.button === Qt.RightButton) + notifInner.toggleExpand(!notifInner.expanded); + else if (event.button === Qt.MiddleButton) + closeAll(); + } + onPositionChanged: event => { + if (pressed) { + const diffY = event.y - startY; + if (Math.abs(diffY) > Config.notifs.expandThreshold) + notifInner.toggleExpand(diffY > 0); + } + } + onReleased: event => { + if (Math.abs(x) < width * Config.notifs.clearThreshold) + x = 0; + else + closeAll(); + } + + ParallelAnimation { + running: true + + Anim { + target: notif + property: "opacity" + from: 0 + to: 1 + } + Anim { + target: notif + property: "scale" + from: 0 + to: 1 + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + ParallelAnimation { + running: notif.closed + + Anim { + target: notif + property: "opacity" + to: 0 + } + Anim { + target: notif + property: "scale" + to: 0.6 + } + } + + NotifGroup { + id: notifInner + + modelData: notif.modelData + props: root.props + container: root.container + visibilities: root.visibilities + } + + Behavior on x { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + Behavior on y { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/sidebar/NotifGroup.qml b/.config/quickshell/caelestia/modules/sidebar/NotifGroup.qml new file mode 100644 index 0000000..16aac33 --- /dev/null +++ b/.config/quickshell/caelestia/modules/sidebar/NotifGroup.qml @@ -0,0 +1,241 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.effects +import qs.services +import qs.config +import qs.utils +import Quickshell +import Quickshell.Services.Notifications +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property string modelData + required property Props props + required property Flickable container + required property var visibilities + + readonly property list notifs: Notifs.list.filter(n => n.appName === modelData) + readonly property int notifCount: notifs.reduce((acc, n) => n.closed ? acc : acc + 1, 0) + readonly property string image: notifs.find(n => !n.closed && n.image.length > 0)?.image ?? "" + readonly property string appIcon: notifs.find(n => !n.closed && n.appIcon.length > 0)?.appIcon ?? "" + readonly property int urgency: notifs.some(n => !n.closed && n.urgency === NotificationUrgency.Critical) ? NotificationUrgency.Critical : notifs.some(n => n.urgency === NotificationUrgency.Normal) ? NotificationUrgency.Normal : NotificationUrgency.Low + + readonly property int nonAnimHeight: { + const headerHeight = header.implicitHeight + (root.expanded ? Math.round(Appearance.spacing.small / 2) : 0); + const columnHeight = headerHeight + notifList.nonAnimHeight + column.Layout.topMargin + column.Layout.bottomMargin; + return Math.round(Math.max(Config.notifs.sizes.image, columnHeight) + Appearance.padding.normal * 2); + } + readonly property bool expanded: props.expandedNotifs.includes(modelData) + + function toggleExpand(expand: bool): void { + if (expand) { + if (!expanded) + props.expandedNotifs.push(modelData); + } else if (expanded) { + props.expandedNotifs.splice(props.expandedNotifs.indexOf(modelData), 1); + } + } + + Component.onDestruction: { + if (notifCount === 0 && expanded) + props.expandedNotifs.splice(props.expandedNotifs.indexOf(modelData), 1); + } + + anchors.left: parent?.left + anchors.right: parent?.right + implicitHeight: content.implicitHeight + Appearance.padding.normal * 2 + + clip: true + radius: Appearance.rounding.normal + color: Colours.layer(Colours.palette.m3surfaceContainer, 2) + + RowLayout { + id: content + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + Item { + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + implicitWidth: Config.notifs.sizes.image + implicitHeight: Config.notifs.sizes.image + + Component { + id: imageComp + + Image { + source: Qt.resolvedUrl(root.image) + fillMode: Image.PreserveAspectCrop + cache: false + asynchronous: true + width: Config.notifs.sizes.image + height: Config.notifs.sizes.image + } + } + + Component { + id: appIconComp + + ColouredIcon { + implicitSize: Math.round(Config.notifs.sizes.image * 0.6) + source: Quickshell.iconPath(root.appIcon) + colour: root.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : root.urgency === NotificationUrgency.Low ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + layer.enabled: root.appIcon.endsWith("symbolic") + } + } + + Component { + id: materialIconComp + + MaterialIcon { + text: Icons.getNotifIcon(root.notifs[0]?.summary, root.urgency) + color: root.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : root.urgency === NotificationUrgency.Low ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + font.pointSize: Appearance.font.size.large + } + } + + StyledClippingRect { + anchors.fill: parent + color: root.urgency === NotificationUrgency.Critical ? Colours.palette.m3error : root.urgency === NotificationUrgency.Low ? Colours.layer(Colours.palette.m3surfaceContainerHigh, 3) : Colours.palette.m3secondaryContainer + radius: Appearance.rounding.full + + Loader { + anchors.centerIn: parent + sourceComponent: root.image ? imageComp : root.appIcon ? appIconComp : materialIconComp + } + } + + Loader { + anchors.right: parent.right + anchors.bottom: parent.bottom + active: root.appIcon && root.image + + sourceComponent: StyledRect { + implicitWidth: Config.notifs.sizes.badge + implicitHeight: Config.notifs.sizes.badge + + color: root.urgency === NotificationUrgency.Critical ? Colours.palette.m3error : root.urgency === NotificationUrgency.Low ? Colours.palette.m3surfaceContainerHigh : Colours.palette.m3secondaryContainer + radius: Appearance.rounding.full + + ColouredIcon { + anchors.centerIn: parent + implicitSize: Math.round(Config.notifs.sizes.badge * 0.6) + source: Quickshell.iconPath(root.appIcon) + colour: root.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : root.urgency === NotificationUrgency.Low ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + layer.enabled: root.appIcon.endsWith("symbolic") + } + } + } + } + + ColumnLayout { + id: column + + Layout.topMargin: -Appearance.padding.small + Layout.bottomMargin: -Appearance.padding.small / 2 + Layout.fillWidth: true + spacing: 0 + + RowLayout { + id: header + + Layout.bottomMargin: root.expanded ? Math.round(Appearance.spacing.small / 2) : 0 + Layout.fillWidth: true + spacing: Appearance.spacing.smaller + + StyledText { + Layout.fillWidth: true + text: root.modelData + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + elide: Text.ElideRight + } + + StyledText { + animate: true + text: root.notifs.find(n => !n.closed)?.timeStr ?? "" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledRect { + implicitWidth: expandBtn.implicitWidth + Appearance.padding.smaller * 2 + implicitHeight: groupCount.implicitHeight + Appearance.padding.small + + color: root.urgency === NotificationUrgency.Critical ? Colours.palette.m3error : Colours.layer(Colours.palette.m3surfaceContainerHigh, 3) + radius: Appearance.rounding.full + + StateLayer { + color: root.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : Colours.palette.m3onSurface + + function onClicked(): void { + root.toggleExpand(!root.expanded); + } + } + + RowLayout { + id: expandBtn + + anchors.centerIn: parent + spacing: Appearance.spacing.small / 2 + + StyledText { + id: groupCount + + Layout.leftMargin: Appearance.padding.small / 2 + animate: true + text: root.notifCount + color: root.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.small + } + + MaterialIcon { + Layout.rightMargin: -Appearance.padding.small / 2 + text: "expand_more" + color: root.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : Colours.palette.m3onSurface + rotation: root.expanded ? 180 : 0 + Layout.topMargin: root.expanded ? -Math.floor(Appearance.padding.smaller / 2) : 0 + + Behavior on rotation { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + Behavior on Layout.topMargin { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } + } + + Behavior on Layout.bottomMargin { + Anim {} + } + } + + NotifGroupList { + id: notifList + + props: root.props + notifs: root.notifs + expanded: root.expanded + container: root.container + visibilities: root.visibilities + onRequestToggleExpand: expand => root.toggleExpand(expand) + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/sidebar/NotifGroupList.qml b/.config/quickshell/caelestia/modules/sidebar/NotifGroupList.qml new file mode 100644 index 0000000..e586b5f --- /dev/null +++ b/.config/quickshell/caelestia/modules/sidebar/NotifGroupList.qml @@ -0,0 +1,213 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Props props + required property list notifs + required property bool expanded + required property Flickable container + required property var visibilities + + readonly property real nonAnimHeight: { + let h = -root.spacing; + for (let i = 0; i < repeater.count; i++) { + const item = repeater.itemAt(i); + if (!item.modelData.closed && !item.previewHidden) + h += item.nonAnimHeight + root.spacing; + } + return h; + } + + readonly property int spacing: Math.round(Appearance.spacing.small / 2) + property bool showAllNotifs + property bool flag + + signal requestToggleExpand(expand: bool) + + onExpandedChanged: { + if (expanded) { + clearTimer.stop(); + showAllNotifs = true; + } else { + clearTimer.start(); + } + } + + Layout.fillWidth: true + implicitHeight: nonAnimHeight + + Timer { + id: clearTimer + + interval: Appearance.anim.durations.normal + onTriggered: root.showAllNotifs = false + } + + Repeater { + id: repeater + + model: ScriptModel { + values: root.showAllNotifs ? root.notifs : root.notifs.slice(0, Config.notifs.groupPreviewNum + 1) + onValuesChanged: root.flagChanged() + } + + MouseArea { + id: notif + + required property int index + required property Notifs.Notif modelData + + readonly property alias nonAnimHeight: notifInner.nonAnimHeight + readonly property bool previewHidden: { + if (root.expanded) + return false; + + let extraHidden = 0; + for (let i = 0; i < index; i++) + if (root.notifs[i].closed) + extraHidden++; + + return index >= Config.notifs.groupPreviewNum + extraHidden; + } + property int startY + + y: { + root.flag; // Force update + let y = 0; + for (let i = 0; i < index; i++) { + const item = repeater.itemAt(i); + if (!item.modelData.closed && !item.previewHidden) + y += item.nonAnimHeight + root.spacing; + } + return y; + } + + containmentMask: QtObject { + function contains(p: point): bool { + if (!root.container.contains(notif.mapToItem(root.container, p))) + return false; + return notifInner.contains(p); + } + } + + opacity: previewHidden ? 0 : 1 + scale: previewHidden ? 0.7 : 1 + + implicitWidth: root.width + implicitHeight: notifInner.implicitHeight + + hoverEnabled: true + cursorShape: notifInner.body?.hoveredLink ? Qt.PointingHandCursor : pressed ? Qt.ClosedHandCursor : undefined + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + preventStealing: !root.expanded + enabled: !modelData.closed + + drag.target: this + drag.axis: Drag.XAxis + + onPressed: event => { + startY = event.y; + if (event.button === Qt.RightButton) + root.requestToggleExpand(!root.expanded); + else if (event.button === Qt.MiddleButton) + modelData.close(); + } + onPositionChanged: event => { + if (pressed && !root.expanded) { + const diffY = event.y - startY; + if (Math.abs(diffY) > Config.notifs.expandThreshold) + root.requestToggleExpand(diffY > 0); + } + } + onReleased: event => { + if (Math.abs(x) < width * Config.notifs.clearThreshold) + x = 0; + else + modelData.close(); + } + + Component.onCompleted: modelData.lock(this) + Component.onDestruction: modelData.unlock(this) + + ParallelAnimation { + Component.onCompleted: running = !notif.previewHidden + + Anim { + target: notif + property: "opacity" + from: 0 + to: 1 + } + Anim { + target: notif + property: "scale" + from: 0.7 + to: 1 + } + } + + ParallelAnimation { + running: notif.modelData.closed + onFinished: notif.modelData.unlock(notif) + + Anim { + target: notif + property: "opacity" + to: 0 + } + Anim { + target: notif + property: "x" + to: notif.x >= 0 ? notif.width : -notif.width + } + } + + Notif { + id: notifInner + + anchors.fill: parent + modelData: notif.modelData + props: root.props + expanded: root.expanded + visibilities: root.visibilities + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + Behavior on x { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + Behavior on y { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } +} diff --git a/.config/quickshell/caelestia/modules/sidebar/Props.qml b/.config/quickshell/caelestia/modules/sidebar/Props.qml new file mode 100644 index 0000000..4613942 --- /dev/null +++ b/.config/quickshell/caelestia/modules/sidebar/Props.qml @@ -0,0 +1,7 @@ +import Quickshell + +PersistentProperties { + property list expandedNotifs: [] + + reloadableId: "sidebar" +} diff --git a/.config/quickshell/caelestia/modules/sidebar/Wrapper.qml b/.config/quickshell/caelestia/modules/sidebar/Wrapper.qml new file mode 100644 index 0000000..9303c6b --- /dev/null +++ b/.config/quickshell/caelestia/modules/sidebar/Wrapper.qml @@ -0,0 +1,68 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.config +import QtQuick + +Item { + id: root + + required property var visibilities + required property var panels + readonly property Props props: Props {} + + visible: width > 0 + implicitWidth: 0 + + states: State { + name: "visible" + when: root.visibilities.sidebar && Config.sidebar.enabled + + PropertyChanges { + root.implicitWidth: Config.sidebar.sizes.width + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + target: root + property: "implicitWidth" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + }, + Transition { + from: "visible" + to: "" + + Anim { + target: root + property: "implicitWidth" + easing.bezierCurve: root.panels.osd.width > 0 || root.panels.session.width > 0 ? Appearance.anim.curves.expressiveDefaultSpatial : Appearance.anim.curves.emphasized + } + } + ] + + Loader { + id: content + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.margins: Appearance.padding.large + anchors.bottomMargin: 0 + + active: true + Component.onCompleted: active = Qt.binding(() => (root.visibilities.sidebar && Config.sidebar.enabled) || root.visible) + + sourceComponent: Content { + implicitWidth: Config.sidebar.sizes.width - Appearance.padding.large * 2 + props: root.props + visibilities: root.visibilities + } + } +} diff --git a/.config/quickshell/caelestia/modules/utilities/Background.qml b/.config/quickshell/caelestia/modules/utilities/Background.qml new file mode 100644 index 0000000..fbce896 --- /dev/null +++ b/.config/quickshell/caelestia/modules/utilities/Background.qml @@ -0,0 +1,55 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Shapes + +ShapePath { + id: root + + required property Wrapper wrapper + required property var sidebar + readonly property real rounding: Config.border.rounding + readonly property bool flatten: wrapper.height < rounding * 2 + readonly property real roundingY: flatten ? wrapper.height / 2 : rounding + + strokeWidth: -1 + fillColor: Colours.palette.m3surface + + PathLine { + relativeX: -(root.wrapper.width + root.rounding) + relativeY: 0 + } + PathArc { + relativeX: root.rounding + relativeY: -root.roundingY + radiusX: root.rounding + radiusY: Math.min(root.rounding, root.wrapper.height) + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: -(root.wrapper.height - root.roundingY * 2) + } + PathArc { + relativeX: root.sidebar.utilsRoundingX + relativeY: -root.roundingY + radiusX: root.sidebar.utilsRoundingX + radiusY: Math.min(root.rounding, root.wrapper.height) + } + PathLine { + relativeX: root.wrapper.height > 0 ? root.wrapper.width - root.rounding - root.sidebar.utilsRoundingX : root.wrapper.width + relativeY: 0 + } + PathArc { + relativeX: root.rounding + relativeY: -root.rounding + radiusX: root.rounding + radiusY: root.rounding + direction: PathArc.Counterclockwise + } + + Behavior on fillColor { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/modules/utilities/Content.qml b/.config/quickshell/caelestia/modules/utilities/Content.qml new file mode 100644 index 0000000..902656d --- /dev/null +++ b/.config/quickshell/caelestia/modules/utilities/Content.qml @@ -0,0 +1,39 @@ +import "cards" +import qs.config +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property var props + required property var visibilities + required property Item popouts + + implicitWidth: layout.implicitWidth + implicitHeight: layout.implicitHeight + + ColumnLayout { + id: layout + + anchors.fill: parent + spacing: Appearance.spacing.normal + + IdleInhibit {} + + Record { + props: root.props + visibilities: root.visibilities + z: 1 + } + + Toggles { + visibilities: root.visibilities + popouts: root.popouts + } + } + + RecordingDeleteModal { + props: root.props + } +} diff --git a/.config/quickshell/caelestia/modules/utilities/RecordingDeleteModal.qml b/.config/quickshell/caelestia/modules/utilities/RecordingDeleteModal.qml new file mode 100644 index 0000000..127afe9 --- /dev/null +++ b/.config/quickshell/caelestia/modules/utilities/RecordingDeleteModal.qml @@ -0,0 +1,207 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.components.effects +import qs.services +import qs.config +import Caelestia +import QtQuick +import QtQuick.Layouts +import QtQuick.Shapes + +Loader { + id: root + + required property var props + + anchors.fill: parent + + opacity: root.props.recordingConfirmDelete ? 1 : 0 + active: opacity > 0 + + sourceComponent: MouseArea { + id: deleteConfirmation + + property string path + + Component.onCompleted: path = root.props.recordingConfirmDelete + + hoverEnabled: true + onClicked: root.props.recordingConfirmDelete = "" + + Item { + anchors.fill: parent + anchors.margins: -Appearance.padding.large + anchors.rightMargin: -Appearance.padding.large - Config.border.thickness + anchors.bottomMargin: -Appearance.padding.large - Config.border.thickness + opacity: 0.5 + + StyledRect { + anchors.fill: parent + topLeftRadius: Config.border.rounding + color: Colours.palette.m3scrim + } + + Shape { + id: shape + + anchors.fill: parent + preferredRendererType: Shape.CurveRenderer + asynchronous: true + + ShapePath { + startX: -Config.border.rounding * 2 + startY: shape.height - Config.border.thickness + strokeWidth: 0 + fillGradient: LinearGradient { + orientation: LinearGradient.Horizontal + x1: -Config.border.rounding * 2 + + GradientStop { + position: 0 + color: Qt.alpha(Colours.palette.m3scrim, 0) + } + GradientStop { + position: 1 + color: Colours.palette.m3scrim + } + } + + PathLine { + relativeX: Config.border.rounding + relativeY: 0 + } + PathArc { + relativeY: -Config.border.rounding + radiusX: Config.border.rounding + radiusY: Config.border.rounding + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: Config.border.rounding + Config.border.thickness + } + PathLine { + relativeX: -Config.border.rounding * 2 + relativeY: 0 + } + } + + ShapePath { + startX: shape.width - Config.border.rounding - Config.border.thickness + strokeWidth: 0 + fillGradient: LinearGradient { + orientation: LinearGradient.Vertical + y1: -Config.border.rounding * 2 + + GradientStop { + position: 0 + color: Qt.alpha(Colours.palette.m3scrim, 0) + } + GradientStop { + position: 1 + color: Colours.palette.m3scrim + } + } + + PathArc { + relativeX: Config.border.rounding + relativeY: -Config.border.rounding + radiusX: Config.border.rounding + radiusY: Config.border.rounding + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: -Config.border.rounding + } + PathLine { + relativeX: Config.border.thickness + relativeY: 0 + } + PathLine { + relativeX: 0 + } + } + } + } + + StyledRect { + anchors.centerIn: parent + radius: Appearance.rounding.large + color: Colours.palette.m3surfaceContainerHigh + + scale: 0 + Component.onCompleted: scale = Qt.binding(() => root.props.recordingConfirmDelete ? 1 : 0) + + width: Math.min(parent.width - Appearance.padding.large * 2, implicitWidth) + implicitWidth: deleteConfirmationLayout.implicitWidth + Appearance.padding.large * 3 + implicitHeight: deleteConfirmationLayout.implicitHeight + Appearance.padding.large * 3 + + MouseArea { + anchors.fill: parent + } + + Elevation { + anchors.fill: parent + radius: parent.radius + z: -1 + level: 3 + } + + ColumnLayout { + id: deleteConfirmationLayout + + anchors.fill: parent + anchors.margins: Appearance.padding.large * 1.5 + spacing: Appearance.spacing.normal + + StyledText { + text: qsTr("Delete recording?") + font.pointSize: Appearance.font.size.large + } + + StyledText { + Layout.fillWidth: true + text: qsTr("Recording '%1' will be permanently deleted.").arg(deleteConfirmation.path) + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + } + + RowLayout { + Layout.topMargin: Appearance.spacing.normal + Layout.alignment: Qt.AlignRight + spacing: Appearance.spacing.normal + + TextButton { + text: qsTr("Cancel") + type: TextButton.Text + onClicked: root.props.recordingConfirmDelete = "" + } + + TextButton { + text: qsTr("Delete") + type: TextButton.Text + onClicked: { + CUtils.deleteFile(Qt.resolvedUrl(root.props.recordingConfirmDelete)); + root.props.recordingConfirmDelete = ""; + } + } + } + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } + + Behavior on opacity { + Anim {} + } +} diff --git a/.config/quickshell/caelestia/modules/utilities/Wrapper.qml b/.config/quickshell/caelestia/modules/utilities/Wrapper.qml new file mode 100644 index 0000000..77178e3 --- /dev/null +++ b/.config/quickshell/caelestia/modules/utilities/Wrapper.qml @@ -0,0 +1,96 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.config +import Quickshell +import QtQuick + +Item { + id: root + + required property var visibilities + required property Item sidebar + required property Item popouts + + readonly property PersistentProperties props: PersistentProperties { + property bool recordingListExpanded: false + property string recordingConfirmDelete + property string recordingMode + + reloadableId: "utilities" + } + readonly property bool shouldBeActive: visibilities.sidebar || (visibilities.utilities && Config.utilities.enabled && !(visibilities.session && Config.session.enabled)) + + visible: height > 0 + implicitHeight: 0 + implicitWidth: sidebar.visible ? sidebar.width : Config.utilities.sizes.width + + onStateChanged: { + if (state === "visible" && timer.running) { + timer.triggered(); + timer.stop(); + } + } + + states: State { + name: "visible" + when: root.shouldBeActive + + PropertyChanges { + root.implicitHeight: content.implicitHeight + Appearance.padding.large * 2 + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + Anim { + target: root + property: "implicitHeight" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + }, + Transition { + from: "visible" + to: "" + + Anim { + target: root + property: "implicitHeight" + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + ] + + Timer { + id: timer + + running: true + interval: Appearance.anim.durations.extraLarge + onTriggered: { + content.active = Qt.binding(() => root.shouldBeActive || root.visible); + content.visible = true; + } + } + + Loader { + id: content + + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: Appearance.padding.large + + visible: false + active: true + + sourceComponent: Content { + implicitWidth: root.implicitWidth - Appearance.padding.large * 2 + props: root.props + visibilities: root.visibilities + popouts: root.popouts + } + } +} diff --git a/.config/quickshell/caelestia/modules/utilities/cards/IdleInhibit.qml b/.config/quickshell/caelestia/modules/utilities/cards/IdleInhibit.qml new file mode 100644 index 0000000..0344e3a --- /dev/null +++ b/.config/quickshell/caelestia/modules/utilities/cards/IdleInhibit.qml @@ -0,0 +1,125 @@ +import qs.components +import qs.components.controls +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + Layout.fillWidth: true + implicitHeight: layout.implicitHeight + (IdleInhibitor.enabled ? activeChip.implicitHeight + activeChip.anchors.topMargin : 0) + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + clip: true + + RowLayout { + id: layout + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.smaller * 2 + + radius: Appearance.rounding.full + color: IdleInhibitor.enabled ? Colours.palette.m3secondary : Colours.palette.m3secondaryContainer + + MaterialIcon { + id: icon + + anchors.centerIn: parent + text: "coffee" + color: IdleInhibitor.enabled ? Colours.palette.m3onSecondary : Colours.palette.m3onSecondaryContainer + font.pointSize: Appearance.font.size.large + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + + StyledText { + Layout.fillWidth: true + text: qsTr("Keep Awake") + font.pointSize: Appearance.font.size.normal + elide: Text.ElideRight + } + + StyledText { + Layout.fillWidth: true + text: IdleInhibitor.enabled ? qsTr("Preventing sleep mode") : qsTr("Normal power management") + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + elide: Text.ElideRight + } + } + + StyledSwitch { + checked: IdleInhibitor.enabled + onToggled: IdleInhibitor.enabled = checked + } + } + + Loader { + id: activeChip + + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.topMargin: Appearance.spacing.larger + anchors.bottomMargin: IdleInhibitor.enabled ? Appearance.padding.large : -implicitHeight + anchors.leftMargin: Appearance.padding.large + + opacity: IdleInhibitor.enabled ? 1 : 0 + scale: IdleInhibitor.enabled ? 1 : 0.5 + + Component.onCompleted: active = Qt.binding(() => opacity > 0) + + sourceComponent: StyledRect { + implicitWidth: activeText.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: activeText.implicitHeight + Appearance.padding.small * 2 + + radius: Appearance.rounding.full + color: Colours.palette.m3primary + + StyledText { + id: activeText + + anchors.centerIn: parent + text: qsTr("Active since %1").arg(Qt.formatTime(IdleInhibitor.enabledSince, Config.services.useTwelveHourClock ? "hh:mm a" : "hh:mm")) + color: Colours.palette.m3onPrimary + font.pointSize: Math.round(Appearance.font.size.small * 0.9) + } + } + + Behavior on anchors.bottomMargin { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.small + } + } + + Behavior on scale { + Anim {} + } + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } +} diff --git a/.config/quickshell/caelestia/modules/utilities/cards/Record.qml b/.config/quickshell/caelestia/modules/utilities/cards/Record.qml new file mode 100644 index 0000000..273c640 --- /dev/null +++ b/.config/quickshell/caelestia/modules/utilities/cards/Record.qml @@ -0,0 +1,277 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property var props + required property var visibilities + + Layout.fillWidth: true + implicitHeight: layout.implicitHeight + layout.anchors.margins * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: layout + + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + RowLayout { + spacing: Appearance.spacing.normal + z: 1 + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: { + const h = icon.implicitHeight + Appearance.padding.smaller * 2; + return h - (h % 2); + } + + radius: Appearance.rounding.full + color: Recorder.running ? Colours.palette.m3secondary : Colours.palette.m3secondaryContainer + + MaterialIcon { + id: icon + + anchors.centerIn: parent + anchors.horizontalCenterOffset: -0.5 + anchors.verticalCenterOffset: 1.5 + text: "screen_record" + color: Recorder.running ? Colours.palette.m3onSecondary : Colours.palette.m3onSecondaryContainer + font.pointSize: Appearance.font.size.large + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + + StyledText { + Layout.fillWidth: true + text: qsTr("Screen Recorder") + font.pointSize: Appearance.font.size.normal + elide: Text.ElideRight + } + + StyledText { + Layout.fillWidth: true + text: Recorder.paused ? qsTr("Recording paused") : Recorder.running ? qsTr("Recording running") : qsTr("Recording off") + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + elide: Text.ElideRight + } + } + + SplitButton { + disabled: Recorder.running + active: menuItems.find(m => root.props.recordingMode === m.icon + m.text) ?? menuItems[0] + menu.onItemSelected: item => root.props.recordingMode = item.icon + item.text + + menuItems: [ + MenuItem { + icon: "fullscreen" + text: qsTr("Record fullscreen") + activeText: qsTr("Fullscreen") + onClicked: Recorder.start() + }, + MenuItem { + icon: "screenshot_region" + text: qsTr("Record region") + activeText: qsTr("Region") + onClicked: Recorder.start(["-r"]) + }, + MenuItem { + icon: "select_to_speak" + text: qsTr("Record fullscreen with sound") + activeText: qsTr("Fullscreen") + onClicked: Recorder.start(["-s"]) + }, + MenuItem { + icon: "volume_up" + text: qsTr("Record region with sound") + activeText: qsTr("Region") + onClicked: Recorder.start(["-sr"]) + } + ] + } + } + + Loader { + id: listOrControls + + property bool running: Recorder.running + + Layout.fillWidth: true + Layout.preferredHeight: implicitHeight + sourceComponent: running ? recordingControls : recordingList + + Behavior on Layout.preferredHeight { + id: locHeightAnim + + enabled: false + + Anim {} + } + + Behavior on running { + SequentialAnimation { + ParallelAnimation { + Anim { + target: listOrControls + property: "scale" + to: 0.7 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + Anim { + target: listOrControls + property: "opacity" + to: 0 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + } + PropertyAction { + target: locHeightAnim + property: "enabled" + value: true + } + PropertyAction {} + PropertyAction { + target: locHeightAnim + property: "enabled" + value: false + } + ParallelAnimation { + Anim { + target: listOrControls + property: "scale" + to: 1 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + target: listOrControls + property: "opacity" + to: 1 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + } + } + } + } + + Component { + id: recordingList + + RecordingList { + props: root.props + visibilities: root.visibilities + } + } + + Component { + id: recordingControls + + RowLayout { + spacing: Appearance.spacing.normal + + StyledRect { + radius: Appearance.rounding.full + color: Recorder.paused ? Colours.palette.m3tertiary : Colours.palette.m3error + + implicitWidth: recText.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: recText.implicitHeight + Appearance.padding.smaller * 2 + + StyledText { + id: recText + + anchors.centerIn: parent + animate: true + text: Recorder.paused ? "PAUSED" : "REC" + color: Recorder.paused ? Colours.palette.m3onTertiary : Colours.palette.m3onError + font.family: Appearance.font.family.mono + } + + Behavior on implicitWidth { + Anim {} + } + + SequentialAnimation on opacity { + running: !Recorder.paused + alwaysRunToEnd: true + loops: Animation.Infinite + + Anim { + from: 1 + to: 0 + duration: Appearance.anim.durations.large + easing.bezierCurve: Appearance.anim.curves.emphasizedAccel + } + Anim { + from: 0 + to: 1 + duration: Appearance.anim.durations.extraLarge + easing.bezierCurve: Appearance.anim.curves.emphasizedDecel + } + } + } + + StyledText { + text: { + const elapsed = Recorder.elapsed; + + const hours = Math.floor(elapsed / 3600); + const mins = Math.floor((elapsed % 3600) / 60); + const secs = Math.floor(elapsed % 60).toString().padStart(2, "0"); + + let time; + if (hours > 0) + time = `${hours}:${mins.toString().padStart(2, "0")}:${secs}`; + else + time = `${mins}:${secs}`; + + return qsTr("Recording for %1").arg(time); + } + font.pointSize: Appearance.font.size.normal + } + + Item { + Layout.fillWidth: true + } + + IconButton { + label.animate: true + icon: Recorder.paused ? "play_arrow" : "pause" + toggle: true + checked: Recorder.paused + type: IconButton.Tonal + font.pointSize: Appearance.font.size.large + onClicked: { + Recorder.togglePause(); + internalChecked = Recorder.paused; + } + } + + IconButton { + icon: "stop" + inactiveColour: Colours.palette.m3error + inactiveOnColour: Colours.palette.m3onError + font.pointSize: Appearance.font.size.large + onClicked: Recorder.stop() + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/utilities/cards/RecordingList.qml b/.config/quickshell/caelestia/modules/utilities/cards/RecordingList.qml new file mode 100644 index 0000000..b9d757a --- /dev/null +++ b/.config/quickshell/caelestia/modules/utilities/cards/RecordingList.qml @@ -0,0 +1,241 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import qs.utils +import Caelestia +import Caelestia.Models +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property var props + required property var visibilities + + spacing: 0 + + WrapperMouseArea { + Layout.fillWidth: true + + cursorShape: Qt.PointingHandCursor + onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded + + RowLayout { + spacing: Appearance.spacing.smaller + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + text: "list" + font.pointSize: Appearance.font.size.large + } + + StyledText { + Layout.alignment: Qt.AlignVCenter + Layout.fillWidth: true + text: qsTr("Recordings") + font.pointSize: Appearance.font.size.normal + } + + IconButton { + icon: root.props.recordingListExpanded ? "unfold_less" : "unfold_more" + type: IconButton.Text + label.animate: true + onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded + } + } + } + + StyledListView { + id: list + + model: FileSystemModel { + path: Paths.recsdir + nameFilters: ["recording_*.mp4"] + sortReverse: true + } + + Layout.fillWidth: true + Layout.rightMargin: -Appearance.spacing.small + implicitHeight: (Appearance.font.size.larger + Appearance.padding.small) * (root.props.recordingListExpanded ? 10 : 3) + clip: true + + StyledScrollBar.vertical: StyledScrollBar { + flickable: list + } + + delegate: RowLayout { + id: recording + + required property FileSystemEntry modelData + property string baseName + + anchors.left: list.contentItem.left + anchors.right: list.contentItem.right + anchors.rightMargin: Appearance.spacing.small + spacing: Appearance.spacing.small / 2 + + Component.onCompleted: baseName = modelData.baseName + + StyledText { + Layout.fillWidth: true + Layout.rightMargin: Appearance.spacing.small / 2 + text: { + const time = recording.baseName; + const matches = time.match(/^recording_(\d{4})(\d{2})(\d{2})_(\d{2})-(\d{2})-(\d{2})/); + if (!matches) + return time; + const date = new Date(...matches.slice(1)); + date.setMonth(date.getMonth() - 1); // Woe (months start from 0) + return qsTr("Recording at %1").arg(Qt.formatDateTime(date, Qt.locale())); + } + color: Colours.palette.m3onSurfaceVariant + elide: Text.ElideRight + } + + IconButton { + icon: "play_arrow" + type: IconButton.Text + onClicked: { + root.visibilities.utilities = false; + root.visibilities.sidebar = false; + Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.playback, recording.modelData.path]); + } + } + + IconButton { + icon: "folder" + type: IconButton.Text + onClicked: { + root.visibilities.utilities = false; + root.visibilities.sidebar = false; + Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.explorer, recording.modelData.path]); + } + } + + IconButton { + icon: "delete_forever" + type: IconButton.Text + label.color: Colours.palette.m3error + stateLayer.color: Colours.palette.m3error + onClicked: root.props.recordingConfirmDelete = recording.modelData.path + } + } + + add: Transition { + Anim { + property: "opacity" + from: 0 + to: 1 + } + Anim { + property: "scale" + from: 0.5 + to: 1 + } + } + + remove: Transition { + Anim { + property: "opacity" + to: 0 + } + Anim { + property: "scale" + to: 0.5 + } + } + + displaced: Transition { + Anim { + properties: "opacity,scale" + to: 1 + } + Anim { + property: "y" + } + } + + Loader { + anchors.centerIn: parent + + opacity: list.count === 0 ? 1 : 0 + active: opacity > 0 + + sourceComponent: ColumnLayout { + spacing: Appearance.spacing.small + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: "scan_delete" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.extraLarge + + opacity: root.props.recordingListExpanded ? 1 : 0 + scale: root.props.recordingListExpanded ? 1 : 0 + Layout.preferredHeight: root.props.recordingListExpanded ? implicitHeight : 0 + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + Behavior on Layout.preferredHeight { + Anim {} + } + } + + RowLayout { + spacing: Appearance.spacing.smaller + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: "scan_delete" + color: Colours.palette.m3outline + + opacity: !root.props.recordingListExpanded ? 1 : 0 + scale: !root.props.recordingListExpanded ? 1 : 0 + Layout.preferredWidth: !root.props.recordingListExpanded ? implicitWidth : 0 + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + Behavior on Layout.preferredWidth { + Anim {} + } + } + + StyledText { + text: qsTr("No recordings found") + color: Colours.palette.m3outline + } + } + } + + Behavior on opacity { + Anim {} + } + } + + Behavior on implicitHeight { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/utilities/cards/Toggles.qml b/.config/quickshell/caelestia/modules/utilities/cards/Toggles.qml new file mode 100644 index 0000000..dd4a687 --- /dev/null +++ b/.config/quickshell/caelestia/modules/utilities/cards/Toggles.qml @@ -0,0 +1,113 @@ +import qs.components +import qs.components.controls +import qs.services +import qs.config +import qs.modules.controlcenter +import Quickshell +import Quickshell.Bluetooth +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property var visibilities + required property Item popouts + + Layout.fillWidth: true + implicitHeight: layout.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: layout + + anchors.fill: parent + anchors.margins: Appearance.padding.large + spacing: Appearance.spacing.normal + + StyledText { + text: qsTr("Quick Toggles") + font.pointSize: Appearance.font.size.normal + } + + RowLayout { + Layout.alignment: Qt.AlignHCenter + spacing: Appearance.spacing.small + + Toggle { + icon: "wifi" + checked: Nmcli.wifiEnabled + onClicked: Nmcli.toggleWifi() + } + + Toggle { + icon: "bluetooth" + checked: Bluetooth.defaultAdapter?.enabled ?? false + onClicked: { + const adapter = Bluetooth.defaultAdapter; + if (adapter) + adapter.enabled = !adapter.enabled; + } + } + + Toggle { + icon: "mic" + checked: !Audio.sourceMuted + onClicked: { + const audio = Audio.source?.audio; + if (audio) + audio.muted = !audio.muted; + } + } + + Toggle { + icon: "settings" + inactiveOnColour: Colours.palette.m3onSurfaceVariant + toggle: false + onClicked: { + root.visibilities.utilities = false; + root.popouts.detach("network"); + } + } + + Toggle { + icon: "gamepad" + checked: GameMode.enabled + onClicked: GameMode.enabled = !GameMode.enabled + } + + Toggle { + icon: "notifications_off" + checked: Notifs.dnd + onClicked: Notifs.dnd = !Notifs.dnd + } + + Toggle { + icon: "vpn_key" + checked: VPN.connected + enabled: !VPN.connecting + visible: Config.utilities.vpn.provider.some(p => typeof p === "object" ? (p.enabled === true) : false) + onClicked: VPN.toggle() + } + } + } + + component Toggle: IconButton { + Layout.fillWidth: true + Layout.preferredWidth: implicitWidth + (stateLayer.pressed ? Appearance.padding.large : internalChecked ? Appearance.padding.smaller : 0) + radius: stateLayer.pressed ? Appearance.rounding.small / 2 : internalChecked ? Appearance.rounding.small : Appearance.rounding.normal + inactiveColour: Colours.layer(Colours.palette.m3surfaceContainerHighest, 2) + toggle: true + radiusAnim.duration: Appearance.anim.durations.expressiveFastSpatial + radiusAnim.easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + + Behavior on Layout.preferredWidth { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/utilities/toasts/ToastItem.qml b/.config/quickshell/caelestia/modules/utilities/toasts/ToastItem.qml new file mode 100644 index 0000000..f475500 --- /dev/null +++ b/.config/quickshell/caelestia/modules/utilities/toasts/ToastItem.qml @@ -0,0 +1,135 @@ +import qs.components +import qs.components.effects +import qs.services +import qs.config +import Caelestia +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property Toast modelData + + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: layout.implicitHeight + Appearance.padding.smaller * 2 + + radius: Appearance.rounding.normal + color: { + if (root.modelData.type === Toast.Success) + return Colours.palette.m3successContainer; + if (root.modelData.type === Toast.Warning) + return Colours.palette.m3secondary; + if (root.modelData.type === Toast.Error) + return Colours.palette.m3errorContainer; + return Colours.palette.m3surface; + } + + border.width: 1 + border.color: { + let colour = Colours.palette.m3outlineVariant; + if (root.modelData.type === Toast.Success) + colour = Colours.palette.m3success; + if (root.modelData.type === Toast.Warning) + colour = Colours.palette.m3secondaryContainer; + if (root.modelData.type === Toast.Error) + colour = Colours.palette.m3error; + return Qt.alpha(colour, 0.3); + } + + Elevation { + anchors.fill: parent + radius: parent.radius + opacity: parent.opacity + z: -1 + level: 3 + } + + RowLayout { + id: layout + + anchors.fill: parent + anchors.margins: Appearance.padding.smaller + anchors.leftMargin: Appearance.padding.normal + anchors.rightMargin: Appearance.padding.normal + spacing: Appearance.spacing.normal + + StyledRect { + radius: Appearance.rounding.normal + color: { + if (root.modelData.type === Toast.Success) + return Colours.palette.m3success; + if (root.modelData.type === Toast.Warning) + return Colours.palette.m3secondaryContainer; + if (root.modelData.type === Toast.Error) + return Colours.palette.m3error; + return Colours.palette.m3surfaceContainerHigh; + } + + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.smaller * 2 + + MaterialIcon { + id: icon + + anchors.centerIn: parent + text: root.modelData.icon + color: { + if (root.modelData.type === Toast.Success) + return Colours.palette.m3onSuccess; + if (root.modelData.type === Toast.Warning) + return Colours.palette.m3onSecondaryContainer; + if (root.modelData.type === Toast.Error) + return Colours.palette.m3onError; + return Colours.palette.m3onSurfaceVariant; + } + font.pointSize: Math.round(Appearance.font.size.large * 1.2) + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + + StyledText { + id: title + + Layout.fillWidth: true + text: root.modelData.title + color: { + if (root.modelData.type === Toast.Success) + return Colours.palette.m3onSuccessContainer; + if (root.modelData.type === Toast.Warning) + return Colours.palette.m3onSecondary; + if (root.modelData.type === Toast.Error) + return Colours.palette.m3onErrorContainer; + return Colours.palette.m3onSurface; + } + font.pointSize: Appearance.font.size.normal + elide: Text.ElideRight + } + + StyledText { + Layout.fillWidth: true + textFormat: Text.StyledText + text: root.modelData.message + color: { + if (root.modelData.type === Toast.Success) + return Colours.palette.m3onSuccessContainer; + if (root.modelData.type === Toast.Warning) + return Colours.palette.m3onSecondary; + if (root.modelData.type === Toast.Error) + return Colours.palette.m3onErrorContainer; + return Colours.palette.m3onSurface; + } + opacity: 0.8 + elide: Text.ElideRight + } + } + } + + Behavior on border.color { + CAnim {} + } +} diff --git a/.config/quickshell/caelestia/modules/utilities/toasts/Toasts.qml b/.config/quickshell/caelestia/modules/utilities/toasts/Toasts.qml new file mode 100644 index 0000000..2915404 --- /dev/null +++ b/.config/quickshell/caelestia/modules/utilities/toasts/Toasts.qml @@ -0,0 +1,143 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.config +import Caelestia +import Quickshell +import QtQuick + +Item { + id: root + + readonly property int spacing: Appearance.spacing.small + property bool flag + + implicitWidth: Config.utilities.sizes.toastWidth - Appearance.padding.normal * 2 + implicitHeight: { + let h = -spacing; + for (let i = 0; i < repeater.count; i++) { + const item = repeater.itemAt(i) as ToastWrapper; + if (!item.modelData.closed && !item.previewHidden) + h += item.implicitHeight + spacing; + } + return h; + } + + Repeater { + id: repeater + + model: ScriptModel { + values: { + const toasts = []; + let count = 0; + for (const toast of Toaster.toasts) { + toasts.push(toast); + if (!toast.closed) { + count++; + if (count > Config.utilities.maxToasts) + break; + } + } + return toasts; + } + onValuesChanged: root.flagChanged() + } + + ToastWrapper {} + } + + component ToastWrapper: MouseArea { + id: toast + + required property int index + required property Toast modelData + + readonly property bool previewHidden: { + let extraHidden = 0; + for (let i = 0; i < index; i++) + if (Toaster.toasts[i].closed) + extraHidden++; + return index >= Config.utilities.maxToasts + extraHidden; + } + + onPreviewHiddenChanged: { + if (initAnim.running && previewHidden) + initAnim.stop(); + } + + opacity: modelData.closed || previewHidden ? 0 : 1 + scale: modelData.closed || previewHidden ? 0.7 : 1 + + anchors.bottomMargin: { + root.flag; // Force update + let y = 0; + for (let i = 0; i < index; i++) { + const item = repeater.itemAt(i) as ToastWrapper; + if (item && !item.modelData.closed && !item.previewHidden) + y += item.implicitHeight + root.spacing; + } + return y; + } + + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + implicitHeight: toastInner.implicitHeight + + acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton + onClicked: modelData.close() + + Component.onCompleted: modelData.lock(this) + + Anim { + id: initAnim + + Component.onCompleted: running = !toast.previewHidden + + target: toast + properties: "opacity,scale" + from: 0 + to: 1 + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + + ParallelAnimation { + running: toast.modelData.closed + onStarted: toast.anchors.bottomMargin = toast.anchors.bottomMargin + onFinished: toast.modelData.unlock(toast) + + Anim { + target: toast + property: "opacity" + to: 0 + } + Anim { + target: toast + property: "scale" + to: 0.7 + } + } + + ToastItem { + id: toastInner + + modelData: toast.modelData + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + Behavior on anchors.bottomMargin { + Anim { + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } +} diff --git a/.config/quickshell/caelestia/modules/windowinfo/Buttons.qml b/.config/quickshell/caelestia/modules/windowinfo/Buttons.qml new file mode 100644 index 0000000..89acfe6 --- /dev/null +++ b/.config/quickshell/caelestia/modules/windowinfo/Buttons.qml @@ -0,0 +1,180 @@ +import qs.components +import qs.services +import qs.config +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property var client + property bool moveToWsExpanded + + anchors.fill: parent + spacing: Appearance.spacing.small + + RowLayout { + Layout.topMargin: Appearance.padding.large + Layout.leftMargin: Appearance.padding.large + Layout.rightMargin: Appearance.padding.large + + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: qsTr("Move to workspace") + elide: Text.ElideRight + } + + StyledRect { + color: Colours.palette.m3primary + radius: Appearance.rounding.small + + implicitWidth: moveToWsIcon.implicitWidth + Appearance.padding.small * 2 + implicitHeight: moveToWsIcon.implicitHeight + Appearance.padding.small + + StateLayer { + color: Colours.palette.m3onPrimary + + function onClicked(): void { + root.moveToWsExpanded = !root.moveToWsExpanded; + } + } + + MaterialIcon { + id: moveToWsIcon + + anchors.centerIn: parent + + animate: true + text: root.moveToWsExpanded ? "expand_more" : "keyboard_arrow_right" + color: Colours.palette.m3onPrimary + font.pointSize: Appearance.font.size.large + } + } + } + + WrapperItem { + Layout.fillWidth: true + Layout.leftMargin: Appearance.padding.large * 2 + Layout.rightMargin: Appearance.padding.large * 2 + + Layout.preferredHeight: root.moveToWsExpanded ? implicitHeight : 0 + clip: true + + topMargin: Appearance.spacing.normal + bottomMargin: Appearance.spacing.normal + + GridLayout { + id: wsGrid + + rowSpacing: Appearance.spacing.smaller + columnSpacing: Appearance.spacing.normal + columns: 5 + + Repeater { + model: 10 + + Button { + required property int index + readonly property int wsId: Math.floor((Hypr.activeWsId - 1) / 10) * 10 + index + 1 + readonly property bool isCurrent: root.client?.workspace.id === wsId + + color: isCurrent ? Colours.tPalette.m3surfaceContainerHighest : Colours.palette.m3tertiaryContainer + onColor: isCurrent ? Colours.palette.m3onSurface : Colours.palette.m3onTertiaryContainer + text: wsId + disabled: isCurrent + + function onClicked(): void { + Hypr.dispatch(`movetoworkspace ${wsId},address:0x${root.client?.address}`); + } + } + } + } + + Behavior on Layout.preferredHeight { + Anim {} + } + } + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: Appearance.padding.large + Layout.rightMargin: Appearance.padding.large + Layout.bottomMargin: Appearance.padding.large + + spacing: root.client?.lastIpcObject.floating ? Appearance.spacing.normal : Appearance.spacing.small + + Button { + color: Colours.palette.m3secondaryContainer + onColor: Colours.palette.m3onSecondaryContainer + text: root.client?.lastIpcObject.floating ? qsTr("Tile") : qsTr("Float") + + function onClicked(): void { + Hypr.dispatch(`togglefloating address:0x${root.client?.address}`); + } + } + + Loader { + active: root.client?.lastIpcObject.floating + Layout.fillWidth: active + Layout.leftMargin: active ? 0 : -parent.spacing + Layout.rightMargin: active ? 0 : -parent.spacing + + sourceComponent: Button { + color: Colours.palette.m3secondaryContainer + onColor: Colours.palette.m3onSecondaryContainer + text: root.client?.lastIpcObject.pinned ? qsTr("Unpin") : qsTr("Pin") + + function onClicked(): void { + Hypr.dispatch(`pin address:0x${root.client?.address}`); + } + } + } + + Button { + color: Colours.palette.m3errorContainer + onColor: Colours.palette.m3onErrorContainer + text: qsTr("Kill") + + function onClicked(): void { + Hypr.dispatch(`killwindow address:0x${root.client?.address}`); + } + } + } + + component Button: StyledRect { + property color onColor: Colours.palette.m3onSurface + property alias disabled: stateLayer.disabled + property alias text: label.text + + function onClicked(): void { + } + + radius: Appearance.rounding.small + + Layout.fillWidth: true + implicitHeight: label.implicitHeight + Appearance.padding.small * 2 + + StateLayer { + id: stateLayer + + color: parent.onColor + + function onClicked(): void { + parent.onClicked(); + } + } + + StyledText { + id: label + + anchors.centerIn: parent + + animate: true + color: parent.onColor + font.pointSize: Appearance.font.size.normal + } + } +} diff --git a/.config/quickshell/caelestia/modules/windowinfo/Details.qml b/.config/quickshell/caelestia/modules/windowinfo/Details.qml new file mode 100644 index 0000000..f9ee66a --- /dev/null +++ b/.config/quickshell/caelestia/modules/windowinfo/Details.qml @@ -0,0 +1,164 @@ +import qs.components +import qs.services +import qs.config +import Quickshell.Hyprland +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property HyprlandToplevel client + + anchors.fill: parent + spacing: Appearance.spacing.small + + Label { + Layout.topMargin: Appearance.padding.large * 2 + + text: root.client?.title ?? qsTr("No active client") + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + Label { + text: root.client?.lastIpcObject.class ?? qsTr("No active client") + color: Colours.palette.m3tertiary + + font.pointSize: Appearance.font.size.larger + } + + StyledRect { + Layout.fillWidth: true + Layout.preferredHeight: 1 + Layout.leftMargin: Appearance.padding.large * 2 + Layout.rightMargin: Appearance.padding.large * 2 + Layout.topMargin: Appearance.spacing.normal + Layout.bottomMargin: Appearance.spacing.large + + color: Colours.palette.m3secondary + } + + Detail { + icon: "location_on" + text: qsTr("Address: %1").arg(`0x${root.client?.address}` ?? "unknown") + color: Colours.palette.m3primary + } + + Detail { + icon: "location_searching" + text: qsTr("Position: %1, %2").arg(root.client?.lastIpcObject.at[0] ?? -1).arg(root.client?.lastIpcObject.at[1] ?? -1) + } + + Detail { + icon: "resize" + text: qsTr("Size: %1 x %2").arg(root.client?.lastIpcObject.size[0] ?? -1).arg(root.client?.lastIpcObject.size[1] ?? -1) + color: Colours.palette.m3tertiary + } + + Detail { + icon: "workspaces" + text: qsTr("Workspace: %1 (%2)").arg(root.client?.workspace.name ?? -1).arg(root.client?.workspace.id ?? -1) + color: Colours.palette.m3secondary + } + + Detail { + icon: "desktop_windows" + text: { + const mon = root.client?.monitor; + if (mon) + return qsTr("Monitor: %1 (%2) at %3, %4").arg(mon.name).arg(mon.id).arg(mon.x).arg(mon.y); + return qsTr("Monitor: unknown"); + } + } + + Detail { + icon: "page_header" + text: qsTr("Initial title: %1").arg(root.client?.lastIpcObject.initialTitle ?? "unknown") + color: Colours.palette.m3tertiary + } + + Detail { + icon: "category" + text: qsTr("Initial class: %1").arg(root.client?.lastIpcObject.initialClass ?? "unknown") + } + + Detail { + icon: "account_tree" + text: qsTr("Process id: %1").arg(root.client?.lastIpcObject.pid ?? -1) + color: Colours.palette.m3primary + } + + Detail { + icon: "picture_in_picture_center" + text: qsTr("Floating: %1").arg(root.client?.lastIpcObject.floating ? "yes" : "no") + color: Colours.palette.m3secondary + } + + Detail { + icon: "gradient" + text: qsTr("Xwayland: %1").arg(root.client?.lastIpcObject.xwayland ? "yes" : "no") + } + + Detail { + icon: "keep" + text: qsTr("Pinned: %1").arg(root.client?.lastIpcObject.pinned ? "yes" : "no") + color: Colours.palette.m3secondary + } + + Detail { + icon: "fullscreen" + text: { + const fs = root.client?.lastIpcObject.fullscreen; + if (fs) + return qsTr("Fullscreen state: %1").arg(fs == 0 ? "off" : fs == 1 ? "maximised" : "on"); + return qsTr("Fullscreen state: unknown"); + } + color: Colours.palette.m3tertiary + } + + Item { + Layout.fillHeight: true + } + + component Detail: RowLayout { + id: detail + + required property string icon + required property string text + property alias color: icon.color + + Layout.leftMargin: Appearance.padding.large + Layout.rightMargin: Appearance.padding.large + Layout.fillWidth: true + + spacing: Appearance.spacing.smaller + + MaterialIcon { + id: icon + + Layout.alignment: Qt.AlignVCenter + text: detail.icon + } + + StyledText { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + + text: detail.text + elide: Text.ElideRight + font.pointSize: Appearance.font.size.normal + } + } + + component Label: StyledText { + Layout.leftMargin: Appearance.padding.large + Layout.rightMargin: Appearance.padding.large + Layout.fillWidth: true + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + animate: true + } +} diff --git a/.config/quickshell/caelestia/modules/windowinfo/Preview.qml b/.config/quickshell/caelestia/modules/windowinfo/Preview.qml new file mode 100644 index 0000000..4cc0aab --- /dev/null +++ b/.config/quickshell/caelestia/modules/windowinfo/Preview.qml @@ -0,0 +1,96 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.services +import qs.config +import Quickshell +import Quickshell.Wayland +import Quickshell.Hyprland +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property ShellScreen screen + required property HyprlandToplevel client + + Layout.preferredWidth: preview.implicitWidth + Appearance.padding.large * 2 + Layout.fillHeight: true + + StyledClippingRect { + id: preview + + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.bottom: label.top + anchors.topMargin: Appearance.padding.large + anchors.bottomMargin: Appearance.spacing.normal + + implicitWidth: view.implicitWidth + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.small + + Loader { + anchors.centerIn: parent + active: !root.client + + sourceComponent: ColumnLayout { + spacing: 0 + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: "web_asset_off" + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.extraLarge * 3 + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("No active client") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.extraLarge + font.weight: 500 + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("Try switching to a window") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.large + } + } + } + + ScreencopyView { + id: view + + anchors.centerIn: parent + + captureSource: root.client?.wayland ?? null + live: true + + constraintSize.width: root.client ? parent.height * Math.min(root.screen.width / root.screen.height, root.client?.lastIpcObject.size[0] / root.client?.lastIpcObject.size[1]) : parent.height + constraintSize.height: parent.height + } + } + + StyledText { + id: label + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: Appearance.padding.large + + animate: true + text: { + const client = root.client; + if (!client) + return qsTr("No active client"); + + const mon = client.monitor; + return qsTr("%1 on monitor %2 at %3, %4").arg(client.title).arg(mon.name).arg(client.lastIpcObject.at[0]).arg(client.lastIpcObject.at[1]); + } + } +} diff --git a/.config/quickshell/caelestia/modules/windowinfo/WindowInfo.qml b/.config/quickshell/caelestia/modules/windowinfo/WindowInfo.qml new file mode 100644 index 0000000..919b3fb --- /dev/null +++ b/.config/quickshell/caelestia/modules/windowinfo/WindowInfo.qml @@ -0,0 +1,64 @@ +import qs.components +import qs.services +import qs.config +import Quickshell +import Quickshell.Hyprland +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property ShellScreen screen + required property HyprlandToplevel client + + implicitWidth: child.implicitWidth + implicitHeight: screen.height * Config.winfo.sizes.heightMult + + RowLayout { + id: child + + anchors.fill: parent + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.normal + + Preview { + screen: root.screen + client: root.client + } + + ColumnLayout { + spacing: Appearance.spacing.normal + + Layout.preferredWidth: Config.winfo.sizes.detailsWidth + Layout.fillHeight: true + + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.normal + + Details { + client: root.client + } + } + + StyledRect { + Layout.fillWidth: true + Layout.preferredHeight: buttons.implicitHeight + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.normal + + Buttons { + id: buttons + + client: root.client + } + } + } + } +} diff --git a/.config/quickshell/caelestia/nix/app2unit.nix b/.config/quickshell/caelestia/nix/app2unit.nix new file mode 100644 index 0000000..51b4241 --- /dev/null +++ b/.config/quickshell/caelestia/nix/app2unit.nix @@ -0,0 +1,14 @@ +{ + pkgs, # To ensure the nixpkgs version of app2unit + fetchFromGitHub, + ... +}: +pkgs.app2unit.overrideAttrs (final: prev: rec { + version = "1.0.3"; # Fix old issue related to missing env var + src = fetchFromGitHub { + owner = "Vladimir-csp"; + repo = "app2unit"; + tag = "v${version}"; + hash = "sha256-7eEVjgs+8k+/NLteSBKgn4gPaPLHC+3Uzlmz6XB0930="; + }; +}) diff --git a/.config/quickshell/caelestia/nix/default.nix b/.config/quickshell/caelestia/nix/default.nix new file mode 100644 index 0000000..67747b2 --- /dev/null +++ b/.config/quickshell/caelestia/nix/default.nix @@ -0,0 +1,158 @@ +{ + rev, + lib, + stdenv, + makeWrapper, + makeFontsConf, + fish, + ddcutil, + brightnessctl, + app2unit, + networkmanager, + lm_sensors, + swappy, + wl-clipboard, + libqalculate, + bash, + hyprland, + material-symbols, + rubik, + nerd-fonts, + qt6, + quickshell, + aubio, + libcava, + fftw, + pipewire, + xkeyboard-config, + cmake, + ninja, + pkg-config, + caelestia-cli, + debug ? false, + withCli ? false, + extraRuntimeDeps ? [], +}: let + version = "1.0.0"; + + runtimeDeps = + [ + fish + ddcutil + brightnessctl + app2unit + networkmanager + lm_sensors + swappy + wl-clipboard + libqalculate + bash + hyprland + ] + ++ extraRuntimeDeps + ++ lib.optional withCli caelestia-cli; + + fontconfig = makeFontsConf { + fontDirectories = [material-symbols rubik nerd-fonts.caskaydia-cove]; + }; + + cmakeBuildType = + if debug + then "Debug" + else "RelWithDebInfo"; + + cmakeVersionFlags = [ + (lib.cmakeFeature "VERSION" version) + (lib.cmakeFeature "GIT_REVISION" rev) + (lib.cmakeFeature "DISTRIBUTOR" "nix-flake") + ]; + + extras = stdenv.mkDerivation { + inherit cmakeBuildType; + name = "caelestia-extras${lib.optionalString debug "-debug"}"; + src = lib.fileset.toSource { + root = ./..; + fileset = lib.fileset.union ./../CMakeLists.txt ./../extras; + }; + + nativeBuildInputs = [cmake ninja]; + + cmakeFlags = + [ + (lib.cmakeFeature "ENABLE_MODULES" "extras") + (lib.cmakeFeature "INSTALL_LIBDIR" "${placeholder "out"}/lib") + ] + ++ cmakeVersionFlags; + }; + + plugin = stdenv.mkDerivation { + inherit cmakeBuildType; + name = "caelestia-qml-plugin${lib.optionalString debug "-debug"}"; + src = lib.fileset.toSource { + root = ./..; + fileset = lib.fileset.union ./../CMakeLists.txt ./../plugin; + }; + + nativeBuildInputs = [cmake ninja pkg-config]; + buildInputs = [qt6.qtbase qt6.qtdeclarative libqalculate pipewire aubio libcava fftw]; + + dontWrapQtApps = true; + cmakeFlags = + [ + (lib.cmakeFeature "ENABLE_MODULES" "plugin") + (lib.cmakeFeature "INSTALL_QMLDIR" qt6.qtbase.qtQmlPrefix) + ] + ++ cmakeVersionFlags; + }; +in + stdenv.mkDerivation { + inherit version cmakeBuildType; + pname = "caelestia-shell${lib.optionalString debug "-debug"}"; + src = ./..; + + nativeBuildInputs = [cmake ninja makeWrapper qt6.wrapQtAppsHook]; + buildInputs = [quickshell extras plugin xkeyboard-config qt6.qtbase]; + propagatedBuildInputs = runtimeDeps; + + cmakeFlags = + [ + (lib.cmakeFeature "ENABLE_MODULES" "shell") + (lib.cmakeFeature "INSTALL_QSCONFDIR" "${placeholder "out"}/share/caelestia-shell") + ] + ++ cmakeVersionFlags; + + dontStrip = debug; + + prePatch = '' + substituteInPlace assets/pam.d/fprint \ + --replace-fail pam_fprintd.so /run/current-system/sw/lib/security/pam_fprintd.so + substituteInPlace shell.qml \ + --replace-fail 'ShellRoot {' 'ShellRoot { settings.watchFiles: false' + ''; + + postInstall = '' + makeWrapper ${quickshell}/bin/qs $out/bin/caelestia-shell \ + --prefix PATH : "${lib.makeBinPath runtimeDeps}" \ + --set FONTCONFIG_FILE "${fontconfig}" \ + --set CAELESTIA_LIB_DIR ${extras}/lib \ + --set CAELESTIA_XKB_RULES_PATH ${xkeyboard-config}/share/xkeyboard-config-2/rules/base.lst \ + --add-flags "-p $out/share/caelestia-shell" + + mkdir -p $out/lib + ln -s ${extras}/lib/* $out/lib/ + + # Ensure wrap_term_launch.sh is executable + chmod 755 $out/share/caelestia-shell/assets/wrap_term_launch.sh + ''; + + passthru = { + inherit plugin extras; + }; + + meta = { + description = "A very segsy desktop shell"; + homepage = "https://github.com/caelestia-dots/shell"; + license = lib.licenses.gpl3Only; + mainProgram = "caelestia-shell"; + }; + } diff --git a/.config/quickshell/caelestia/nix/hm-module.nix b/.config/quickshell/caelestia/nix/hm-module.nix new file mode 100644 index 0000000..2976cf6 --- /dev/null +++ b/.config/quickshell/caelestia/nix/hm-module.nix @@ -0,0 +1,136 @@ +self: { + config, + pkgs, + lib, + ... +}: let + inherit (pkgs.stdenv.hostPlatform) system; + + cli-default = self.inputs.caelestia-cli.packages.${system}.default; + shell-default = self.packages.${system}.with-cli; + + cfg = config.programs.caelestia; +in { + imports = [ + (lib.mkRenamedOptionModule ["programs" "caelestia" "environment"] ["programs" "caelestia" "systemd" "environment"]) + ]; + options = with lib; { + programs.caelestia = { + enable = mkEnableOption "Enable Caelestia shell"; + package = mkOption { + type = types.package; + default = shell-default; + description = "The package of Caelestia shell"; + }; + systemd = { + enable = mkOption { + type = types.bool; + default = true; + description = "Enable the systemd service for Caelestia shell"; + }; + target = mkOption { + type = types.str; + description = '' + The systemd target that will automatically start the Caelestia shell. + ''; + default = config.wayland.systemd.target; + }; + environment = mkOption { + type = types.listOf types.str; + description = "Extra Environment variables to pass to the Caelestia shell systemd service."; + default = []; + example = [ + "QT_QPA_PLATFORMTHEME=gtk3" + ]; + }; + }; + settings = mkOption { + type = types.attrsOf types.anything; + default = {}; + description = "Caelestia shell settings"; + }; + extraConfig = mkOption { + type = types.str; + default = ""; + description = "Caelestia shell extra configs written to shell.json"; + }; + cli = { + enable = mkEnableOption "Enable Caelestia CLI"; + package = mkOption { + type = types.package; + default = cli-default; + description = "The package of Caelestia CLI"; # Doesn't override the shell's CLI, only change from home.packages + }; + settings = mkOption { + type = types.attrsOf types.anything; + default = {}; + description = "Caelestia CLI settings"; + }; + extraConfig = mkOption { + type = types.str; + default = ""; + description = "Caelestia CLI extra configs written to cli.json"; + }; + }; + }; + }; + + config = let + cli = cfg.cli.package; + shell = cfg.package; + in + lib.mkIf cfg.enable { + systemd.user.services.caelestia = lib.mkIf cfg.systemd.enable { + Unit = { + Description = "Caelestia Shell Service"; + After = [cfg.systemd.target]; + PartOf = [cfg.systemd.target]; + X-Restart-Triggers = lib.mkIf (cfg.settings != {}) [ + "${config.xdg.configFile."caelestia/shell.json".source}" + ]; + }; + + Service = { + Type = "exec"; + ExecStart = "${shell}/bin/caelestia-shell"; + Restart = "on-failure"; + RestartSec = "5s"; + TimeoutStopSec = "5s"; + Environment = + [ + "QT_QPA_PLATFORM=wayland" + ] + ++ cfg.systemd.environment; + + Slice = "session.slice"; + }; + + Install = { + WantedBy = [cfg.systemd.target]; + }; + }; + + xdg.configFile = let + mkConfig = c: + lib.pipe ( + if c.extraConfig != "" + then c.extraConfig + else "{}" + ) [ + builtins.fromJSON + (lib.recursiveUpdate c.settings) + builtins.toJSON + ]; + shouldGenerate = c: c.extraConfig != "" || c.settings != {}; + in { + "caelestia/shell.json" = lib.mkIf (shouldGenerate cfg) { + text = mkConfig cfg; + }; + "caelestia/cli.json" = lib.mkIf (shouldGenerate cfg.cli) { + text = mkConfig cfg.cli; + }; + }; + + home.packages = [shell] ++ lib.optional cfg.cli.enable cli; + }; +} diff --git a/.config/quickshell/caelestia/plugin/CMakeLists.txt b/.config/quickshell/caelestia/plugin/CMakeLists.txt new file mode 100644 index 0000000..062959c --- /dev/null +++ b/.config/quickshell/caelestia/plugin/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(src/Caelestia) diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/CMakeLists.txt b/.config/quickshell/caelestia/plugin/src/Caelestia/CMakeLists.txt new file mode 100644 index 0000000..1b7d0e4 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/CMakeLists.txt @@ -0,0 +1,62 @@ +find_package(Qt6 REQUIRED COMPONENTS Core Qml Gui Quick Concurrent Sql Network DBus) +find_package(PkgConfig REQUIRED) +pkg_check_modules(Qalculate IMPORTED_TARGET libqalculate REQUIRED) +pkg_check_modules(Pipewire IMPORTED_TARGET libpipewire-0.3 REQUIRED) +pkg_check_modules(Aubio IMPORTED_TARGET aubio REQUIRED) +pkg_check_modules(Cava IMPORTED_TARGET libcava QUIET) +if(NOT Cava_FOUND) + pkg_check_modules(Cava IMPORTED_TARGET cava REQUIRED) +endif() + +set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qml") +qt_standard_project_setup(REQUIRES 6.9) + +function(qml_module arg_TARGET) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "URI" "SOURCES;LIBRARIES") + + qt_add_qml_module(${arg_TARGET} + URI ${arg_URI} + VERSION ${VERSION} + SOURCES ${arg_SOURCES} + ) + + qt_query_qml_module(${arg_TARGET} + URI module_uri + VERSION module_version + PLUGIN_TARGET module_plugin_target + TARGET_PATH module_target_path + QMLDIR module_qmldir + TYPEINFO module_typeinfo + ) + + message(STATUS "Created QML module ${module_uri}, version ${module_version}") + + set(module_dir "${INSTALL_QMLDIR}/${module_target_path}") + install(TARGETS ${arg_TARGET} LIBRARY DESTINATION "${module_dir}" RUNTIME DESTINATION "${module_dir}") + install(TARGETS "${module_plugin_target}" LIBRARY DESTINATION "${module_dir}" RUNTIME DESTINATION "${module_dir}") + install(FILES "${module_qmldir}" DESTINATION "${module_dir}") + install(FILES "${module_typeinfo}" DESTINATION "${module_dir}") + + target_link_libraries(${arg_TARGET} PRIVATE Qt::Core Qt::Qml ${arg_LIBRARIES}) +endfunction() + +qml_module(caelestia + URI Caelestia + SOURCES + cutils.hpp cutils.cpp + qalculator.hpp qalculator.cpp + appdb.hpp appdb.cpp + requests.hpp requests.cpp + toaster.hpp toaster.cpp + imageanalyser.hpp imageanalyser.cpp + LIBRARIES + Qt::Gui + Qt::Quick + Qt::Concurrent + Qt::Sql + PkgConfig::Qalculate +) + +add_subdirectory(Internal) +add_subdirectory(Models) +add_subdirectory(Services) diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/CMakeLists.txt b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/CMakeLists.txt new file mode 100644 index 0000000..bdc58db --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/CMakeLists.txt @@ -0,0 +1,15 @@ +qml_module(caelestia-internal + URI Caelestia.Internal + SOURCES + cachingimagemanager.hpp cachingimagemanager.cpp + circularindicatormanager.hpp circularindicatormanager.cpp + hyprdevices.hpp hyprdevices.cpp + hyprextras.hpp hyprextras.cpp + logindmanager.hpp logindmanager.cpp + LIBRARIES + Qt::Gui + Qt::Quick + Qt::Concurrent + Qt::Network + Qt::DBus +) diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/cachingimagemanager.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/cachingimagemanager.cpp new file mode 100644 index 0000000..1c15cd2 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/cachingimagemanager.cpp @@ -0,0 +1,223 @@ +#include "cachingimagemanager.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace caelestia::internal { + +qreal CachingImageManager::effectiveScale() const { + if (m_item && m_item->window()) { + return m_item->window()->devicePixelRatio(); + } + + return 1.0; +} + +QSize CachingImageManager::effectiveSize() const { + if (!m_item) { + return QSize(); + } + + const qreal scale = effectiveScale(); + const QSize size = QSizeF(m_item->width() * scale, m_item->height() * scale).toSize(); + m_item->setProperty("sourceSize", size); + return size; +} + +QQuickItem* CachingImageManager::item() const { + return m_item; +} + +void CachingImageManager::setItem(QQuickItem* item) { + if (m_item == item) { + return; + } + + if (m_widthConn) { + disconnect(m_widthConn); + } + if (m_heightConn) { + disconnect(m_heightConn); + } + + m_item = item; + emit itemChanged(); + + if (item) { + m_widthConn = connect(item, &QQuickItem::widthChanged, this, [this]() { + updateSource(); + }); + m_heightConn = connect(item, &QQuickItem::heightChanged, this, [this]() { + updateSource(); + }); + updateSource(); + } +} + +QUrl CachingImageManager::cacheDir() const { + return m_cacheDir; +} + +void CachingImageManager::setCacheDir(const QUrl& cacheDir) { + if (m_cacheDir == cacheDir) { + return; + } + + m_cacheDir = cacheDir; + if (!m_cacheDir.path().endsWith("/")) { + m_cacheDir.setPath(m_cacheDir.path() + "/"); + } + emit cacheDirChanged(); +} + +QString CachingImageManager::path() const { + return m_path; +} + +void CachingImageManager::setPath(const QString& path) { + if (m_path == path) { + return; + } + + m_path = path; + emit pathChanged(); + + if (!path.isEmpty()) { + updateSource(path); + } +} + +void CachingImageManager::updateSource() { + updateSource(m_path); +} + +void CachingImageManager::updateSource(const QString& path) { + if (path.isEmpty() || path == m_shaPath) { + // Path is empty or already calculating sha for path + return; + } + + m_shaPath = path; + + const auto future = QtConcurrent::run(&CachingImageManager::sha256sum, path); + + const auto watcher = new QFutureWatcher(this); + + connect(watcher, &QFutureWatcher::finished, this, [watcher, path, this]() { + if (m_path != path) { + // Object is destroyed or path has changed, ignore + watcher->deleteLater(); + return; + } + + const QSize size = effectiveSize(); + + if (!m_item || !size.width() || !size.height()) { + watcher->deleteLater(); + return; + } + + const QString fillMode = m_item->property("fillMode").toString(); + // clang-format off + const QString filename = QString("%1@%2x%3-%4.png") + .arg(watcher->result()).arg(size.width()).arg(size.height()) + .arg(fillMode == "PreserveAspectCrop" ? "crop" : fillMode == "PreserveAspectFit" ? "fit" : "stretch"); + // clang-format on + + const QUrl cache = m_cacheDir.resolved(QUrl(filename)); + if (m_cachePath == cache) { + watcher->deleteLater(); + return; + } + + m_cachePath = cache; + emit cachePathChanged(); + + if (!cache.isLocalFile()) { + qWarning() << "CachingImageManager::updateSource: cachePath" << cache << "is not a local file"; + watcher->deleteLater(); + return; + } + + const QImageReader reader(cache.toLocalFile()); + if (reader.canRead()) { + m_item->setProperty("source", cache); + } else { + m_item->setProperty("source", QUrl::fromLocalFile(path)); + createCache(path, cache.toLocalFile(), fillMode, size); + } + + // Clear current running sha if same + if (m_shaPath == path) { + m_shaPath = QString(); + } + + watcher->deleteLater(); + }); + + watcher->setFuture(future); +} + +QUrl CachingImageManager::cachePath() const { + return m_cachePath; +} + +void CachingImageManager::createCache( + const QString& path, const QString& cache, const QString& fillMode, const QSize& size) const { + QThreadPool::globalInstance()->start([path, cache, fillMode, size] { + QImage image(path); + + if (image.isNull()) { + qWarning() << "CachingImageManager::createCache: failed to read" << path; + return; + } + + image.convertTo(QImage::Format_ARGB32); + + if (fillMode == "PreserveAspectCrop") { + image = image.scaled(size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + } else if (fillMode == "PreserveAspectFit") { + image = image.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } else { + image = image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + } + + if (fillMode == "PreserveAspectCrop" || fillMode == "PreserveAspectFit") { + QImage canvas(size, QImage::Format_ARGB32); + canvas.fill(Qt::transparent); + + QPainter painter(&canvas); + painter.drawImage((size.width() - image.width()) / 2, (size.height() - image.height()) / 2, image); + painter.end(); + + image = canvas; + } + + const QString parent = QFileInfo(cache).absolutePath(); + if (!QDir().mkpath(parent) || !image.save(cache)) { + qWarning() << "CachingImageManager::createCache: failed to save to" << cache; + } + }); +} + +QString CachingImageManager::sha256sum(const QString& path) { + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "CachingImageManager::sha256sum: failed to open" << path; + return ""; + } + + QCryptographicHash hash(QCryptographicHash::Sha256); + hash.addData(&file); + file.close(); + + return hash.result().toHex(); +} + +} // namespace caelestia::internal diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/cachingimagemanager.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/cachingimagemanager.hpp new file mode 100644 index 0000000..3611699 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/cachingimagemanager.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include + +namespace caelestia::internal { + +class CachingImageManager : public QObject { + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(QQuickItem* item READ item WRITE setItem NOTIFY itemChanged REQUIRED) + Q_PROPERTY(QUrl cacheDir READ cacheDir WRITE setCacheDir NOTIFY cacheDirChanged REQUIRED) + + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) + Q_PROPERTY(QUrl cachePath READ cachePath NOTIFY cachePathChanged) + +public: + explicit CachingImageManager(QObject* parent = nullptr) + : QObject(parent) + , m_item(nullptr) {} + + [[nodiscard]] QQuickItem* item() const; + void setItem(QQuickItem* item); + + [[nodiscard]] QUrl cacheDir() const; + void setCacheDir(const QUrl& cacheDir); + + [[nodiscard]] QString path() const; + void setPath(const QString& path); + + [[nodiscard]] QUrl cachePath() const; + + Q_INVOKABLE void updateSource(); + Q_INVOKABLE void updateSource(const QString& path); + +signals: + void itemChanged(); + void cacheDirChanged(); + + void pathChanged(); + void cachePathChanged(); + void usingCacheChanged(); + +private: + QString m_shaPath; + + QQuickItem* m_item; + QUrl m_cacheDir; + + QString m_path; + QUrl m_cachePath; + + QMetaObject::Connection m_widthConn; + QMetaObject::Connection m_heightConn; + + [[nodiscard]] qreal effectiveScale() const; + [[nodiscard]] QSize effectiveSize() const; + + void createCache(const QString& path, const QString& cache, const QString& fillMode, const QSize& size) const; + [[nodiscard]] static QString sha256sum(const QString& path); +}; + +} // namespace caelestia::internal diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/circularindicatormanager.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/circularindicatormanager.cpp new file mode 100644 index 0000000..434b756 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/circularindicatormanager.cpp @@ -0,0 +1,211 @@ +#include "circularindicatormanager.hpp" +#include +#include + +namespace { + +namespace advance { + +constexpr qint32 TOTAL_CYCLES = 4; +constexpr qint32 TOTAL_DURATION_IN_MS = 5400; +constexpr qint32 DURATION_TO_EXPAND_IN_MS = 667; +constexpr qint32 DURATION_TO_COLLAPSE_IN_MS = 667; +constexpr qint32 DURATION_TO_COMPLETE_END_IN_MS = 333; +constexpr qint32 TAIL_DEGREES_OFFSET = -20; +constexpr qint32 EXTRA_DEGREES_PER_CYCLE = 250; +constexpr qint32 CONSTANT_ROTATION_DEGREES = 1520; + +constexpr std::array DELAY_TO_EXPAND_IN_MS = { 0, 1350, 2700, 4050 }; +constexpr std::array DELAY_TO_COLLAPSE_IN_MS = { 667, 2017, 3367, 4717 }; + +} // namespace advance + +namespace retreat { + +constexpr qint32 TOTAL_DURATION_IN_MS = 6000; +constexpr qint32 DURATION_SPIN_IN_MS = 500; +constexpr qint32 DURATION_GROW_ACTIVE_IN_MS = 3000; +constexpr qint32 DURATION_SHRINK_ACTIVE_IN_MS = 3000; +constexpr std::array DELAY_SPINS_IN_MS = { 0, 1500, 3000, 4500 }; +constexpr qint32 DELAY_GROW_ACTIVE_IN_MS = 0; +constexpr qint32 DELAY_SHRINK_ACTIVE_IN_MS = 3000; +constexpr qint32 DURATION_TO_COMPLETE_END_IN_MS = 500; + +// Constants for animation values. + +// The total degrees that a constant rotation goes by. +constexpr qint32 CONSTANT_ROTATION_DEGREES = 1080; +// Despite of the constant rotation, there are also 5 extra rotations the entire animation. The +// total degrees that each extra rotation goes by. +constexpr qint32 SPIN_ROTATION_DEGREES = 90; +constexpr std::array END_FRACTION_RANGE = { 0.10, 0.87 }; + +} // namespace retreat + +inline qreal getFractionInRange(qreal playtime, qreal start, qreal duration) { + const auto fraction = (playtime - start) / duration; + return std::clamp(fraction, 0.0, 1.0); +} + +} // namespace + +namespace caelestia::internal { + +CircularIndicatorManager::CircularIndicatorManager(QObject* parent) + : QObject(parent) + , m_type(IndeterminateAnimationType::Advance) + , m_curve(QEasingCurve(QEasingCurve::BezierSpline)) + , m_progress(0) + , m_startFraction(0) + , m_endFraction(0) + , m_rotation(0) + , m_completeEndProgress(0) { + // Fast out slow in + m_curve.addCubicBezierSegment({ 0.4, 0.0 }, { 0.2, 1.0 }, { 1.0, 1.0 }); +} + +qreal CircularIndicatorManager::startFraction() const { + return m_startFraction; +} + +qreal CircularIndicatorManager::endFraction() const { + return m_endFraction; +} + +qreal CircularIndicatorManager::rotation() const { + return m_rotation; +} + +qreal CircularIndicatorManager::progress() const { + return m_progress; +} + +void CircularIndicatorManager::setProgress(qreal progress) { + update(progress); +} + +qreal CircularIndicatorManager::duration() const { + if (m_type == IndeterminateAnimationType::Advance) { + return advance::TOTAL_DURATION_IN_MS; + } else { + return retreat::TOTAL_DURATION_IN_MS; + } +} + +qreal CircularIndicatorManager::completeEndDuration() const { + if (m_type == IndeterminateAnimationType::Advance) { + return advance::DURATION_TO_COMPLETE_END_IN_MS; + } else { + return retreat::DURATION_TO_COMPLETE_END_IN_MS; + } +} + +CircularIndicatorManager::IndeterminateAnimationType CircularIndicatorManager::indeterminateAnimationType() const { + return m_type; +} + +void CircularIndicatorManager::setIndeterminateAnimationType(IndeterminateAnimationType t) { + if (m_type != t) { + m_type = t; + emit indeterminateAnimationTypeChanged(); + } +} + +qreal CircularIndicatorManager::completeEndProgress() const { + return m_completeEndProgress; +} + +void CircularIndicatorManager::setCompleteEndProgress(qreal progress) { + if (qFuzzyCompare(m_completeEndProgress + 1.0, progress + 1.0)) { + return; + } + + m_completeEndProgress = progress; + emit completeEndProgressChanged(); + + update(m_progress); +} + +void CircularIndicatorManager::update(qreal progress) { + if (qFuzzyCompare(m_progress + 1.0, progress + 1.0)) { + return; + } + + if (m_type == IndeterminateAnimationType::Advance) { + updateAdvance(progress); + } else { + updateRetreat(progress); + } + + m_progress = progress; + emit progressChanged(); +} + +void CircularIndicatorManager::updateRetreat(qreal progress) { + using namespace retreat; + const auto playtime = progress * TOTAL_DURATION_IN_MS; + + // Constant rotation. + const qreal constantRotation = CONSTANT_ROTATION_DEGREES * progress; + // Extra rotation for the faster spinning. + qreal spinRotation = 0; + for (const int spinDelay : DELAY_SPINS_IN_MS) { + spinRotation += m_curve.valueForProgress(getFractionInRange(playtime, spinDelay, DURATION_SPIN_IN_MS)) * + SPIN_ROTATION_DEGREES; + } + m_rotation = constantRotation + spinRotation; + emit rotationChanged(); + + // Grow active indicator. + qreal fraction = + m_curve.valueForProgress(getFractionInRange(playtime, DELAY_GROW_ACTIVE_IN_MS, DURATION_GROW_ACTIVE_IN_MS)); + fraction -= + m_curve.valueForProgress(getFractionInRange(playtime, DELAY_SHRINK_ACTIVE_IN_MS, DURATION_SHRINK_ACTIVE_IN_MS)); + + if (!qFuzzyIsNull(m_startFraction)) { + m_startFraction = 0.0; + emit startFractionChanged(); + } + const auto oldEndFrac = m_endFraction; + m_endFraction = std::lerp(END_FRACTION_RANGE[0], END_FRACTION_RANGE[1], fraction); + + // Completing animation. + if (m_completeEndProgress > 0) { + m_endFraction *= 1 - m_completeEndProgress; + } + + if (!qFuzzyCompare(m_endFraction + 1.0, oldEndFrac + 1.0)) { + emit endFractionChanged(); + } +} + +void CircularIndicatorManager::updateAdvance(qreal progress) { + using namespace advance; + const auto playtime = progress * TOTAL_DURATION_IN_MS; + + // Adds constant rotation to segment positions. + m_startFraction = CONSTANT_ROTATION_DEGREES * progress + TAIL_DEGREES_OFFSET; + m_endFraction = CONSTANT_ROTATION_DEGREES * progress; + + // Adds cycle specific rotation to segment positions. + for (size_t cycleIndex = 0; cycleIndex < TOTAL_CYCLES; ++cycleIndex) { + // While expanding. + qreal fraction = getFractionInRange(playtime, DELAY_TO_EXPAND_IN_MS[cycleIndex], DURATION_TO_EXPAND_IN_MS); + m_endFraction += m_curve.valueForProgress(fraction) * EXTRA_DEGREES_PER_CYCLE; + + // While collapsing. + fraction = getFractionInRange(playtime, DELAY_TO_COLLAPSE_IN_MS[cycleIndex], DURATION_TO_COLLAPSE_IN_MS); + m_startFraction += m_curve.valueForProgress(fraction) * EXTRA_DEGREES_PER_CYCLE; + } + + // Closes the gap between head and tail for complete end. + m_startFraction += (m_endFraction - m_startFraction) * m_completeEndProgress; + + m_startFraction /= 360.0; + m_endFraction /= 360.0; + + emit startFractionChanged(); + emit endFractionChanged(); +} + +} // namespace caelestia::internal diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/circularindicatormanager.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/circularindicatormanager.hpp new file mode 100644 index 0000000..2dbc9d6 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/circularindicatormanager.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include + +namespace caelestia::internal { + +class CircularIndicatorManager : public QObject { + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(qreal startFraction READ startFraction NOTIFY startFractionChanged) + Q_PROPERTY(qreal endFraction READ endFraction NOTIFY endFractionChanged) + Q_PROPERTY(qreal rotation READ rotation NOTIFY rotationChanged) + Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged) + Q_PROPERTY(qreal completeEndProgress READ completeEndProgress WRITE setCompleteEndProgress NOTIFY + completeEndProgressChanged) + Q_PROPERTY(qreal duration READ duration NOTIFY indeterminateAnimationTypeChanged) + Q_PROPERTY(qreal completeEndDuration READ completeEndDuration NOTIFY indeterminateAnimationTypeChanged) + Q_PROPERTY(IndeterminateAnimationType indeterminateAnimationType READ indeterminateAnimationType WRITE + setIndeterminateAnimationType NOTIFY indeterminateAnimationTypeChanged) + +public: + explicit CircularIndicatorManager(QObject* parent = nullptr); + + enum IndeterminateAnimationType { + Advance = 0, + Retreat + }; + Q_ENUM(IndeterminateAnimationType) + + [[nodiscard]] qreal startFraction() const; + [[nodiscard]] qreal endFraction() const; + [[nodiscard]] qreal rotation() const; + + [[nodiscard]] qreal progress() const; + void setProgress(qreal progress); + + [[nodiscard]] qreal completeEndProgress() const; + void setCompleteEndProgress(qreal progress); + + [[nodiscard]] qreal duration() const; + [[nodiscard]] qreal completeEndDuration() const; + + [[nodiscard]] IndeterminateAnimationType indeterminateAnimationType() const; + void setIndeterminateAnimationType(IndeterminateAnimationType t); + +signals: + void startFractionChanged(); + void endFractionChanged(); + void rotationChanged(); + void progressChanged(); + void completeEndProgressChanged(); + void indeterminateAnimationTypeChanged(); + +private: + IndeterminateAnimationType m_type; + QEasingCurve m_curve; + + qreal m_progress; + qreal m_startFraction; + qreal m_endFraction; + qreal m_rotation; + qreal m_completeEndProgress; + + void update(qreal progress); + void updateAdvance(qreal progress); + void updateRetreat(qreal progress); +}; + +} // namespace caelestia::internal diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprdevices.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprdevices.cpp new file mode 100644 index 0000000..1ac7d25 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprdevices.cpp @@ -0,0 +1,134 @@ +#include "hyprdevices.hpp" + +#include + +namespace caelestia::internal::hypr { + +HyprKeyboard::HyprKeyboard(QJsonObject ipcObject, QObject* parent) + : QObject(parent) + , m_lastIpcObject(ipcObject) {} + +QVariantHash HyprKeyboard::lastIpcObject() const { + return m_lastIpcObject.toVariantHash(); +} + +QString HyprKeyboard::address() const { + return m_lastIpcObject.value("address").toString(); +} + +QString HyprKeyboard::name() const { + return m_lastIpcObject.value("name").toString(); +} + +QString HyprKeyboard::layout() const { + return m_lastIpcObject.value("layout").toString(); +} + +QString HyprKeyboard::activeKeymap() const { + return m_lastIpcObject.value("active_keymap").toString(); +} + +bool HyprKeyboard::capsLock() const { + return m_lastIpcObject.value("capsLock").toBool(); +} + +bool HyprKeyboard::numLock() const { + return m_lastIpcObject.value("numLock").toBool(); +} + +bool HyprKeyboard::main() const { + return m_lastIpcObject.value("main").toBool(); +} + +bool HyprKeyboard::updateLastIpcObject(QJsonObject object) { + if (m_lastIpcObject == object) { + return false; + } + + const auto last = m_lastIpcObject; + + m_lastIpcObject = object; + emit lastIpcObjectChanged(); + + bool dirty = false; + if (last.value("address") != object.value("address")) { + dirty = true; + emit addressChanged(); + } + if (last.value("name") != object.value("name")) { + dirty = true; + emit nameChanged(); + } + if (last.value("layout") != object.value("layout")) { + dirty = true; + emit layoutChanged(); + } + if (last.value("active_keymap") != object.value("active_keymap")) { + dirty = true; + emit activeKeymapChanged(); + } + if (last.value("capsLock") != object.value("capsLock")) { + dirty = true; + emit capsLockChanged(); + } + if (last.value("numLock") != object.value("numLock")) { + dirty = true; + emit numLockChanged(); + } + if (last.value("main") != object.value("main")) { + dirty = true; + emit mainChanged(); + } + return dirty; +} + +HyprDevices::HyprDevices(QObject* parent) + : QObject(parent) {} + +QQmlListProperty HyprDevices::keyboards() { + return QQmlListProperty(this, &m_keyboards); +} + +bool HyprDevices::updateLastIpcObject(QJsonObject object) { + const auto val = object.value("keyboards").toArray(); + bool dirty = false; + + for (auto it = m_keyboards.begin(); it != m_keyboards.end();) { + auto* const keyboard = *it; + const auto inNewValues = std::any_of(val.begin(), val.end(), [keyboard](const QJsonValue& o) { + return o.toObject().value("address").toString() == keyboard->address(); + }); + + if (!inNewValues) { + dirty = true; + it = m_keyboards.erase(it); + keyboard->deleteLater(); + } else { + ++it; + } + } + + for (const auto& o : val) { + const auto obj = o.toObject(); + const auto addr = obj.value("address").toString(); + + auto it = std::find_if(m_keyboards.begin(), m_keyboards.end(), [addr](const HyprKeyboard* kb) { + return kb->address() == addr; + }); + + if (it != m_keyboards.end()) { + dirty |= (*it)->updateLastIpcObject(obj); + } else { + dirty = true; + m_keyboards << new HyprKeyboard(obj, this); + } + } + + if (dirty) { + emit keyboardsChanged(); + } + + return dirty; +} + +} // namespace caelestia::internal::hypr diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprdevices.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprdevices.hpp new file mode 100644 index 0000000..da18063 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprdevices.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include +#include + +namespace caelestia::internal::hypr { + +class HyprKeyboard : public QObject { + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("HyprKeyboard instances can only be retrieved from a HyprDevices") + + Q_PROPERTY(QVariantHash lastIpcObject READ lastIpcObject NOTIFY lastIpcObjectChanged) + Q_PROPERTY(QString address READ address NOTIFY addressChanged) + Q_PROPERTY(QString name READ name NOTIFY nameChanged) + Q_PROPERTY(QString layout READ layout NOTIFY layoutChanged) + Q_PROPERTY(QString activeKeymap READ activeKeymap NOTIFY activeKeymapChanged) + Q_PROPERTY(bool capsLock READ capsLock NOTIFY capsLockChanged) + Q_PROPERTY(bool numLock READ numLock NOTIFY numLockChanged) + Q_PROPERTY(bool main READ main NOTIFY mainChanged) + +public: + explicit HyprKeyboard(QJsonObject ipcObject, QObject* parent = nullptr); + + [[nodiscard]] QVariantHash lastIpcObject() const; + [[nodiscard]] QString address() const; + [[nodiscard]] QString name() const; + [[nodiscard]] QString layout() const; + [[nodiscard]] QString activeKeymap() const; + [[nodiscard]] bool capsLock() const; + [[nodiscard]] bool numLock() const; + [[nodiscard]] bool main() const; + + bool updateLastIpcObject(QJsonObject object); + +signals: + void lastIpcObjectChanged(); + void addressChanged(); + void nameChanged(); + void layoutChanged(); + void activeKeymapChanged(); + void capsLockChanged(); + void numLockChanged(); + void mainChanged(); + +private: + QJsonObject m_lastIpcObject; +}; + +class HyprDevices : public QObject { + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("HyprDevices instances can only be retrieved from a HyprExtras") + + Q_PROPERTY( + QQmlListProperty keyboards READ keyboards NOTIFY keyboardsChanged) + +public: + explicit HyprDevices(QObject* parent = nullptr); + + [[nodiscard]] QQmlListProperty keyboards(); + + bool updateLastIpcObject(QJsonObject object); + +signals: + void keyboardsChanged(); + +private: + QList m_keyboards; +}; + +} // namespace caelestia::internal::hypr diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprextras.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprextras.cpp new file mode 100644 index 0000000..5308524 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprextras.cpp @@ -0,0 +1,217 @@ +#include "hyprextras.hpp" + +#include +#include +#include +#include + +namespace caelestia::internal::hypr { + +HyprExtras::HyprExtras(QObject* parent) + : QObject(parent) + , m_requestSocket("") + , m_eventSocket("") + , m_socket(nullptr) + , m_socketValid(false) + , m_devices(new HyprDevices(this)) { + const auto his = qEnvironmentVariable("HYPRLAND_INSTANCE_SIGNATURE"); + if (his.isEmpty()) { + qWarning() + << "HyprExtras::HyprExtras: $HYPRLAND_INSTANCE_SIGNATURE is unset. Unable to connect to Hyprland socket."; + return; + } + + auto hyprDir = QString("%1/hypr/%2").arg(qEnvironmentVariable("XDG_RUNTIME_DIR"), his); + if (!QDir(hyprDir).exists()) { + hyprDir = "/tmp/hypr/" + his; + + if (!QDir(hyprDir).exists()) { + qWarning() << "HyprExtras::HyprExtras: Hyprland socket directory does not exist. Unable to connect to " + "Hyprland socket."; + return; + } + } + + m_requestSocket = hyprDir + "/.socket.sock"; + m_eventSocket = hyprDir + "/.socket2.sock"; + + refreshOptions(); + refreshDevices(); + + m_socket = new QLocalSocket(this); + + QObject::connect(m_socket, &QLocalSocket::errorOccurred, this, &HyprExtras::socketError); + QObject::connect(m_socket, &QLocalSocket::stateChanged, this, &HyprExtras::socketStateChanged); + QObject::connect(m_socket, &QLocalSocket::readyRead, this, &HyprExtras::readEvent); + + m_socket->connectToServer(m_eventSocket, QLocalSocket::ReadOnly); +} + +QVariantHash HyprExtras::options() const { + return m_options; +} + +HyprDevices* HyprExtras::devices() const { + return m_devices; +} + +void HyprExtras::message(const QString& message) { + if (message.isEmpty()) { + return; + } + + makeRequest(message, [](bool success, const QByteArray& res) { + if (!success) { + qWarning() << "HyprExtras::message: request error:" << QString::fromUtf8(res); + } + }); +} + +void HyprExtras::batchMessage(const QStringList& messages) { + if (messages.isEmpty()) { + return; + } + + makeRequest("[[BATCH]]" + messages.join(";"), [](bool success, const QByteArray& res) { + if (!success) { + qWarning() << "HyprExtras::batchMessage: request error:" << QString::fromUtf8(res); + } + }); +} + +void HyprExtras::applyOptions(const QVariantHash& options) { + if (options.isEmpty()) { + return; + } + + QString request = "[[BATCH]]"; + for (auto it = options.constBegin(); it != options.constEnd(); ++it) { + request += QString("keyword %1 %2;").arg(it.key(), it.value().toString()); + } + + makeRequest(request, [this](bool success, const QByteArray& res) { + if (success) { + refreshOptions(); + } else { + qWarning() << "HyprExtras::applyOptions: request error" << QString::fromUtf8(res); + } + }); +} + +void HyprExtras::refreshOptions() { + if (!m_optionsRefresh.isNull()) { + m_optionsRefresh->close(); + } + + m_optionsRefresh = makeRequestJson("descriptions", [this](bool success, const QJsonDocument& response) { + m_optionsRefresh.reset(); + if (!success) { + return; + } + + const auto options = response.array(); + bool dirty = false; + + for (const auto& o : std::as_const(options)) { + const auto obj = o.toObject(); + const auto key = obj.value("value").toString(); + const auto value = obj.value("data").toObject().value("current").toVariant(); + if (m_options.value(key) != value) { + dirty = true; + m_options.insert(key, value); + } + } + + if (dirty) { + emit optionsChanged(); + } + }); +} + +void HyprExtras::refreshDevices() { + if (!m_devicesRefresh.isNull()) { + m_devicesRefresh->close(); + } + + m_devicesRefresh = makeRequestJson("devices", [this](bool success, const QJsonDocument& response) { + m_devicesRefresh.reset(); + if (success) { + m_devices->updateLastIpcObject(response.object()); + } + }); +} + +void HyprExtras::socketError(QLocalSocket::LocalSocketError error) const { + if (!m_socketValid) { + qWarning() << "HyprExtras::socketError: unable to connect to Hyprland event socket:" << error; + } else { + qWarning() << "HyprExtras::socketError: Hyprland event socket error:" << error; + } +} + +void HyprExtras::socketStateChanged(QLocalSocket::LocalSocketState state) { + if (state == QLocalSocket::UnconnectedState && m_socketValid) { + qWarning() << "HyprExtras::socketStateChanged: Hyprland event socket disconnected."; + } + + m_socketValid = state == QLocalSocket::ConnectedState; +} + +void HyprExtras::readEvent() { + while (true) { + auto rawEvent = m_socket->readLine(); + if (rawEvent.isEmpty()) { + break; + } + rawEvent.truncate(rawEvent.length() - 1); // Remove trailing \n + const auto event = QByteArrayView(rawEvent.data(), rawEvent.indexOf(">>")); + handleEvent(QString::fromUtf8(event)); + } +} + +void HyprExtras::handleEvent(const QString& event) { + if (event == "configreloaded") { + refreshOptions(); + } else if (event == "activelayout") { + refreshDevices(); + } +} + +HyprExtras::SocketPtr HyprExtras::makeRequestJson( + const QString& request, const std::function& callback) { + return makeRequest("j/" + request, [callback](bool success, const QByteArray& response) { + callback(success, QJsonDocument::fromJson(response)); + }); +} + +HyprExtras::SocketPtr HyprExtras::makeRequest( + const QString& request, const std::function& callback) { + if (m_requestSocket.isEmpty()) { + return SocketPtr(); + } + + auto socket = SocketPtr::create(this); + + QObject::connect(socket.data(), &QLocalSocket::connected, this, [=, this]() { + QObject::connect(socket.data(), &QLocalSocket::readyRead, this, [socket, callback]() { + const auto response = socket->readAll(); + callback(true, std::move(response)); + socket->close(); + }); + + socket->write(request.toUtf8()); + socket->flush(); + }); + + QObject::connect(socket.data(), &QLocalSocket::errorOccurred, this, [=](QLocalSocket::LocalSocketError err) { + qWarning() << "HyprExtras::makeRequest: error making request:" << err << "| request:" << request; + callback(false, {}); + socket->close(); + }); + + socket->connectToServer(m_requestSocket); + + return socket; +} + +} // namespace caelestia::internal::hypr diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprextras.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprextras.hpp new file mode 100644 index 0000000..14563c0 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/hyprextras.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include "hyprdevices.hpp" +#include +#include +#include + +namespace caelestia::internal::hypr { + +class HyprExtras : public QObject { + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(QVariantHash options READ options NOTIFY optionsChanged) + Q_PROPERTY(caelestia::internal::hypr::HyprDevices* devices READ devices CONSTANT) + +public: + explicit HyprExtras(QObject* parent = nullptr); + + [[nodiscard]] QVariantHash options() const; + [[nodiscard]] HyprDevices* devices() const; + + Q_INVOKABLE void message(const QString& message); + Q_INVOKABLE void batchMessage(const QStringList& messages); + Q_INVOKABLE void applyOptions(const QVariantHash& options); + + Q_INVOKABLE void refreshOptions(); + Q_INVOKABLE void refreshDevices(); + +signals: + void optionsChanged(); + +private: + using SocketPtr = QSharedPointer; + + QString m_requestSocket; + QString m_eventSocket; + QLocalSocket* m_socket; + bool m_socketValid; + + QVariantHash m_options; + HyprDevices* const m_devices; + + SocketPtr m_optionsRefresh; + SocketPtr m_devicesRefresh; + + void socketError(QLocalSocket::LocalSocketError error) const; + void socketStateChanged(QLocalSocket::LocalSocketState state); + void readEvent(); + void handleEvent(const QString& event); + + SocketPtr makeRequestJson(const QString& request, const std::function& callback); + SocketPtr makeRequest(const QString& request, const std::function& callback); +}; + +} // namespace caelestia::internal::hypr diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/logindmanager.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/logindmanager.cpp new file mode 100644 index 0000000..4194ee1 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/logindmanager.cpp @@ -0,0 +1,65 @@ +#include "logindmanager.hpp" + +#include +#include +#include +#include + +namespace caelestia::internal { + +LogindManager::LogindManager(QObject* parent) + : QObject(parent) { + auto bus = QDBusConnection::systemBus(); + if (!bus.isConnected()) { + qWarning() << "LogindManager::LogindManager: failed to connect to system bus:" << bus.lastError().message(); + return; + } + + bool ok = bus.connect("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", + "PrepareForSleep", this, SLOT(handlePrepareForSleep(bool))); + + if (!ok) { + qWarning() << "LogindManager::LogindManager: failed to connect to PrepareForSleep signal:" + << bus.lastError().message(); + } + + QDBusInterface login1("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", bus); + const QDBusReply reply = login1.call("GetSession", "auto"); + if (!reply.isValid()) { + qWarning() << "LogindManager::LogindManager: failed to get session path"; + return; + } + const auto sessionPath = reply.value().path(); + + ok = bus.connect("org.freedesktop.login1", sessionPath, "org.freedesktop.login1.Session", "Lock", this, + SLOT(handleLockRequested())); + + if (!ok) { + qWarning() << "LogindManager::LogindManager: failed to connect to Lock signal:" << bus.lastError().message(); + } + + ok = bus.connect("org.freedesktop.login1", sessionPath, "org.freedesktop.login1.Session", "Unlock", this, + SLOT(handleUnlockRequested())); + + if (!ok) { + qWarning() << "LogindManager::LogindManager: failed to connect to Unlock signal:" << bus.lastError().message(); + } +} + +void LogindManager::handlePrepareForSleep(bool sleep) { + if (sleep) { + emit aboutToSleep(); + } else { + emit resumed(); + } +} + +void LogindManager::handleLockRequested() { + emit lockRequested(); +} + +void LogindManager::handleUnlockRequested() { + emit unlockRequested(); +} + +} // namespace caelestia::internal diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/logindmanager.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/logindmanager.hpp new file mode 100644 index 0000000..72a3401 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Internal/logindmanager.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace caelestia::internal { + +class LogindManager : public QObject { + Q_OBJECT + QML_ELEMENT + +public: + explicit LogindManager(QObject* parent = nullptr); + +signals: + void aboutToSleep(); + void resumed(); + void lockRequested(); + void unlockRequested(); + +private slots: + void handlePrepareForSleep(bool sleep); + void handleLockRequested(); + void handleUnlockRequested(); +}; + +} // namespace caelestia::internal diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Models/CMakeLists.txt b/.config/quickshell/caelestia/plugin/src/Caelestia/Models/CMakeLists.txt new file mode 100644 index 0000000..640e29e --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Models/CMakeLists.txt @@ -0,0 +1,8 @@ +qml_module(caelestia-models + URI Caelestia.Models + SOURCES + filesystemmodel.hpp filesystemmodel.cpp + LIBRARIES + Qt::Gui + Qt::Concurrent +) diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Models/filesystemmodel.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Models/filesystemmodel.cpp new file mode 100644 index 0000000..e387ecd --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Models/filesystemmodel.cpp @@ -0,0 +1,479 @@ +#include "filesystemmodel.hpp" + +#include +#include +#include + +namespace caelestia::models { + +FileSystemEntry::FileSystemEntry(const QString& path, const QString& relativePath, QObject* parent) + : QObject(parent) + , m_fileInfo(path) + , m_path(path) + , m_relativePath(relativePath) + , m_isImageInitialised(false) + , m_mimeTypeInitialised(false) {} + +QString FileSystemEntry::path() const { + return m_path; +}; + +QString FileSystemEntry::relativePath() const { + return m_relativePath; +}; + +QString FileSystemEntry::name() const { + return m_fileInfo.fileName(); +}; + +QString FileSystemEntry::baseName() const { + return m_fileInfo.baseName(); +}; + +QString FileSystemEntry::parentDir() const { + return m_fileInfo.absolutePath(); +}; + +QString FileSystemEntry::suffix() const { + return m_fileInfo.completeSuffix(); +}; + +qint64 FileSystemEntry::size() const { + return m_fileInfo.size(); +}; + +bool FileSystemEntry::isDir() const { + return m_fileInfo.isDir(); +}; + +bool FileSystemEntry::isImage() const { + if (!m_isImageInitialised) { + QImageReader reader(m_path); + m_isImage = reader.canRead(); + m_isImageInitialised = true; + } + return m_isImage; +} + +QString FileSystemEntry::mimeType() const { + if (!m_mimeTypeInitialised) { + const QMimeDatabase db; + m_mimeType = db.mimeTypeForFile(m_path).name(); + m_mimeTypeInitialised = true; + } + return m_mimeType; +} + +void FileSystemEntry::updateRelativePath(const QDir& dir) { + const auto relPath = dir.relativeFilePath(m_path); + if (m_relativePath != relPath) { + m_relativePath = relPath; + emit relativePathChanged(); + } +} + +FileSystemModel::FileSystemModel(QObject* parent) + : QAbstractListModel(parent) + , m_recursive(false) + , m_watchChanges(true) + , m_showHidden(false) + , m_filter(NoFilter) { + connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &FileSystemModel::watchDirIfRecursive); + connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &FileSystemModel::updateEntriesForDir); +} + +int FileSystemModel::rowCount(const QModelIndex& parent) const { + if (parent != QModelIndex()) { + return 0; + } + return static_cast(m_entries.size()); +} + +QVariant FileSystemModel::data(const QModelIndex& index, int role) const { + if (role != Qt::UserRole || !index.isValid() || index.row() >= m_entries.size()) { + return QVariant(); + } + return QVariant::fromValue(m_entries.at(index.row())); +} + +QHash FileSystemModel::roleNames() const { + return { { Qt::UserRole, "modelData" } }; +} + +QString FileSystemModel::path() const { + return m_path; +} + +void FileSystemModel::setPath(const QString& path) { + if (m_path == path) { + return; + } + + m_path = path; + emit pathChanged(); + + m_dir.setPath(m_path); + + for (const auto& entry : std::as_const(m_entries)) { + entry->updateRelativePath(m_dir); + } + + update(); +} + +bool FileSystemModel::recursive() const { + return m_recursive; +} + +void FileSystemModel::setRecursive(bool recursive) { + if (m_recursive == recursive) { + return; + } + + m_recursive = recursive; + emit recursiveChanged(); + + update(); +} + +bool FileSystemModel::watchChanges() const { + return m_watchChanges; +} + +void FileSystemModel::setWatchChanges(bool watchChanges) { + if (m_watchChanges == watchChanges) { + return; + } + + m_watchChanges = watchChanges; + emit watchChangesChanged(); + + update(); +} + +bool FileSystemModel::showHidden() const { + return m_showHidden; +} + +void FileSystemModel::setShowHidden(bool showHidden) { + if (m_showHidden == showHidden) { + return; + } + + m_showHidden = showHidden; + emit showHiddenChanged(); + + update(); +} + +bool FileSystemModel::sortReverse() const { + return m_sortReverse; +} + +void FileSystemModel::setSortReverse(bool sortReverse) { + if (m_sortReverse == sortReverse) { + return; + } + + m_sortReverse = sortReverse; + emit sortReverseChanged(); + + update(); +} + +FileSystemModel::Filter FileSystemModel::filter() const { + return m_filter; +} + +void FileSystemModel::setFilter(Filter filter) { + if (m_filter == filter) { + return; + } + + m_filter = filter; + emit filterChanged(); + + update(); +} + +QStringList FileSystemModel::nameFilters() const { + return m_nameFilters; +} + +void FileSystemModel::setNameFilters(const QStringList& nameFilters) { + if (m_nameFilters == nameFilters) { + return; + } + + m_nameFilters = nameFilters; + emit nameFiltersChanged(); + + update(); +} + +QQmlListProperty FileSystemModel::entries() { + return QQmlListProperty(this, &m_entries); +} + +void FileSystemModel::watchDirIfRecursive(const QString& path) { + if (m_recursive && m_watchChanges) { + const auto currentDir = m_dir; + const bool showHidden = m_showHidden; + const auto future = QtConcurrent::run([showHidden, path]() { + QDir::Filters filters = QDir::Dirs | QDir::NoDotAndDotDot; + if (showHidden) { + filters |= QDir::Hidden; + } + + QDirIterator iter(path, filters, QDirIterator::Subdirectories); + QStringList dirs; + while (iter.hasNext()) { + dirs << iter.next(); + } + return dirs; + }); + const auto watcher = new QFutureWatcher(this); + connect(watcher, &QFutureWatcher::finished, this, [currentDir, showHidden, watcher, this]() { + const auto paths = watcher->result(); + if (currentDir == m_dir && showHidden == m_showHidden && !paths.isEmpty()) { + // Ignore if dir or showHidden has changed + m_watcher.addPaths(paths); + } + watcher->deleteLater(); + }); + watcher->setFuture(future); + } +} + +void FileSystemModel::update() { + updateWatcher(); + updateEntries(); +} + +void FileSystemModel::updateWatcher() { + if (!m_watcher.directories().isEmpty()) { + m_watcher.removePaths(m_watcher.directories()); + } + + if (!m_watchChanges || m_path.isEmpty()) { + return; + } + + m_watcher.addPath(m_path); + watchDirIfRecursive(m_path); +} + +void FileSystemModel::updateEntries() { + if (m_path.isEmpty()) { + if (!m_entries.isEmpty()) { + beginResetModel(); + qDeleteAll(m_entries); + m_entries.clear(); + endResetModel(); + emit entriesChanged(); + } + + return; + } + + for (auto& future : m_futures) { + future.cancel(); + } + m_futures.clear(); + + updateEntriesForDir(m_path); +} + +void FileSystemModel::updateEntriesForDir(const QString& dir) { + const auto recursive = m_recursive; + const auto showHidden = m_showHidden; + const auto filter = m_filter; + const auto nameFilters = m_nameFilters; + + QSet oldPaths; + for (const auto& entry : std::as_const(m_entries)) { + oldPaths << entry->path(); + } + + const auto future = QtConcurrent::run([=](QPromise, QSet>>& promise) { + const auto flags = recursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags; + + std::optional iter; + + if (filter == Images) { + QStringList extraNameFilters = nameFilters; + const auto formats = QImageReader::supportedImageFormats(); + for (const auto& format : formats) { + extraNameFilters << "*." + format; + } + + QDir::Filters filters = QDir::Files; + if (showHidden) { + filters |= QDir::Hidden; + } + + iter.emplace(dir, extraNameFilters, filters, flags); + } else { + QDir::Filters filters; + + if (filter == Files) { + filters = QDir::Files; + } else if (filter == Dirs) { + filters = QDir::Dirs | QDir::NoDotAndDotDot; + } else { + filters = QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot; + } + + if (showHidden) { + filters |= QDir::Hidden; + } + + if (nameFilters.isEmpty()) { + iter.emplace(dir, filters, flags); + } else { + iter.emplace(dir, nameFilters, filters, flags); + } + } + + QSet newPaths; + while (iter->hasNext()) { + if (promise.isCanceled()) { + return; + } + + QString path = iter->next(); + + if (filter == Images) { + QImageReader reader(path); + if (!reader.canRead()) { + continue; + } + } + + newPaths.insert(path); + } + + if (promise.isCanceled() || newPaths == oldPaths) { + return; + } + + promise.addResult(qMakePair(oldPaths - newPaths, newPaths - oldPaths)); + }); + + if (m_futures.contains(dir)) { + m_futures[dir].cancel(); + } + m_futures.insert(dir, future); + + const auto watcher = new QFutureWatcher, QSet>>(this); + + connect(watcher, &QFutureWatcher, QSet>>::finished, this, [dir, watcher, this]() { + m_futures.remove(dir); + + if (!watcher->future().isResultReadyAt(0)) { + watcher->deleteLater(); + return; + } + + const auto result = watcher->result(); + applyChanges(result.first, result.second); + + watcher->deleteLater(); + }); + + watcher->setFuture(future); +} + +void FileSystemModel::applyChanges(const QSet& removedPaths, const QSet& addedPaths) { + QList removedIndices; + for (int i = 0; i < m_entries.size(); ++i) { + if (removedPaths.contains(m_entries[i]->path())) { + removedIndices << i; + } + } + std::sort(removedIndices.begin(), removedIndices.end(), std::greater()); + + // Batch remove old entries + int start = -1; + int end = -1; + for (int idx : std::as_const(removedIndices)) { + if (start == -1) { + start = idx; + end = idx; + } else if (idx == end - 1) { + end = idx; + } else { + beginRemoveRows(QModelIndex(), end, start); + for (int i = start; i >= end; --i) { + m_entries.takeAt(i)->deleteLater(); + } + endRemoveRows(); + + start = idx; + end = idx; + } + } + if (start != -1) { + beginRemoveRows(QModelIndex(), end, start); + for (int i = start; i >= end; --i) { + m_entries.takeAt(i)->deleteLater(); + } + endRemoveRows(); + } + + // Create new entries + QList newEntries; + for (const auto& path : addedPaths) { + newEntries << new FileSystemEntry(path, m_dir.relativeFilePath(path), this); + } + std::sort(newEntries.begin(), newEntries.end(), [this](const FileSystemEntry* a, const FileSystemEntry* b) { + return compareEntries(a, b); + }); + + // Batch insert new entries + int insertStart = -1; + QList batchItems; + for (const auto& entry : std::as_const(newEntries)) { + const auto it = std::lower_bound( + m_entries.begin(), m_entries.end(), entry, [this](const FileSystemEntry* a, const FileSystemEntry* b) { + return compareEntries(a, b); + }); + const auto row = static_cast(it - m_entries.begin()); + + if (insertStart == -1) { + insertStart = row; + batchItems << entry; + } else if (row == insertStart + batchItems.size()) { + batchItems << entry; + } else { + beginInsertRows(QModelIndex(), insertStart, insertStart + static_cast(batchItems.size()) - 1); + for (int i = 0; i < batchItems.size(); ++i) { + m_entries.insert(insertStart + i, batchItems[i]); + } + endInsertRows(); + + insertStart = row; + batchItems.clear(); + batchItems << entry; + } + } + if (!batchItems.isEmpty()) { + beginInsertRows(QModelIndex(), insertStart, insertStart + static_cast(batchItems.size()) - 1); + for (int i = 0; i < batchItems.size(); ++i) { + m_entries.insert(insertStart + i, batchItems[i]); + } + endInsertRows(); + } + + emit entriesChanged(); +} + +bool FileSystemModel::compareEntries(const FileSystemEntry* a, const FileSystemEntry* b) const { + if (a->isDir() != b->isDir()) { + return m_sortReverse ^ a->isDir(); + } + const auto cmp = a->relativePath().localeAwareCompare(b->relativePath()); + return m_sortReverse ? cmp > 0 : cmp < 0; +} + +} // namespace caelestia::models diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Models/filesystemmodel.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Models/filesystemmodel.hpp new file mode 100644 index 0000000..cf8eae8 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Models/filesystemmodel.hpp @@ -0,0 +1,148 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace caelestia::models { + +class FileSystemEntry : public QObject { + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("FileSystemEntry instances can only be retrieved from a FileSystemModel") + + Q_PROPERTY(QString path READ path CONSTANT) + Q_PROPERTY(QString relativePath READ relativePath NOTIFY relativePathChanged) + Q_PROPERTY(QString name READ name CONSTANT) + Q_PROPERTY(QString baseName READ baseName CONSTANT) + Q_PROPERTY(QString parentDir READ parentDir CONSTANT) + Q_PROPERTY(QString suffix READ suffix CONSTANT) + Q_PROPERTY(qint64 size READ size CONSTANT) + Q_PROPERTY(bool isDir READ isDir CONSTANT) + Q_PROPERTY(bool isImage READ isImage CONSTANT) + Q_PROPERTY(QString mimeType READ mimeType CONSTANT) + +public: + explicit FileSystemEntry(const QString& path, const QString& relativePath, QObject* parent = nullptr); + + [[nodiscard]] QString path() const; + [[nodiscard]] QString relativePath() const; + [[nodiscard]] QString name() const; + [[nodiscard]] QString baseName() const; + [[nodiscard]] QString parentDir() const; + [[nodiscard]] QString suffix() const; + [[nodiscard]] qint64 size() const; + [[nodiscard]] bool isDir() const; + [[nodiscard]] bool isImage() const; + [[nodiscard]] QString mimeType() const; + + void updateRelativePath(const QDir& dir); + +signals: + void relativePathChanged(); + +private: + const QFileInfo m_fileInfo; + + const QString m_path; + QString m_relativePath; + + mutable bool m_isImage; + mutable bool m_isImageInitialised; + + mutable QString m_mimeType; + mutable bool m_mimeTypeInitialised; +}; + +class FileSystemModel : public QAbstractListModel { + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) + Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged) + Q_PROPERTY(bool watchChanges READ watchChanges WRITE setWatchChanges NOTIFY watchChangesChanged) + Q_PROPERTY(bool showHidden READ showHidden WRITE setShowHidden NOTIFY showHiddenChanged) + Q_PROPERTY(bool sortReverse READ sortReverse WRITE setSortReverse NOTIFY sortReverseChanged) + Q_PROPERTY(Filter filter READ filter WRITE setFilter NOTIFY filterChanged) + Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged) + + Q_PROPERTY(QQmlListProperty entries READ entries NOTIFY entriesChanged) + +public: + enum Filter { + NoFilter, + Images, + Files, + Dirs + }; + Q_ENUM(Filter) + + explicit FileSystemModel(QObject* parent = nullptr); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override; + + [[nodiscard]] QString path() const; + void setPath(const QString& path); + + [[nodiscard]] bool recursive() const; + void setRecursive(bool recursive); + + [[nodiscard]] bool watchChanges() const; + void setWatchChanges(bool watchChanges); + + [[nodiscard]] bool showHidden() const; + void setShowHidden(bool showHidden); + + [[nodiscard]] bool sortReverse() const; + void setSortReverse(bool sortReverse); + + [[nodiscard]] Filter filter() const; + void setFilter(Filter filter); + + [[nodiscard]] QStringList nameFilters() const; + void setNameFilters(const QStringList& nameFilters); + + [[nodiscard]] QQmlListProperty entries(); + +signals: + void pathChanged(); + void recursiveChanged(); + void watchChangesChanged(); + void showHiddenChanged(); + void sortReverseChanged(); + void filterChanged(); + void nameFiltersChanged(); + void entriesChanged(); + +private: + QDir m_dir; + QFileSystemWatcher m_watcher; + QList m_entries; + QHash, QSet>>> m_futures; + + QString m_path; + bool m_recursive; + bool m_watchChanges; + bool m_showHidden; + bool m_sortReverse; + Filter m_filter; + QStringList m_nameFilters; + + void watchDirIfRecursive(const QString& path); + void update(); + void updateWatcher(); + void updateEntries(); + void updateEntriesForDir(const QString& dir); + void applyChanges(const QSet& removedPaths, const QSet& addedPaths); + [[nodiscard]] bool compareEntries(const FileSystemEntry* a, const FileSystemEntry* b) const; +}; + +} // namespace caelestia::models diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/CMakeLists.txt b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/CMakeLists.txt new file mode 100644 index 0000000..8ce868b --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/CMakeLists.txt @@ -0,0 +1,14 @@ +qml_module(caelestia-services + URI Caelestia.Services + SOURCES + service.hpp service.cpp + serviceref.hpp serviceref.cpp + beattracker.hpp beattracker.cpp + audiocollector.hpp audiocollector.cpp + audioprovider.hpp audioprovider.cpp + cavaprovider.hpp cavaprovider.cpp + LIBRARIES + PkgConfig::Pipewire + PkgConfig::Aubio + PkgConfig::Cava +) diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audiocollector.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audiocollector.cpp new file mode 100644 index 0000000..1563405 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audiocollector.cpp @@ -0,0 +1,246 @@ +#include "audiocollector.hpp" + +#include "service.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace caelestia::services { + +PipeWireWorker::PipeWireWorker(std::stop_token token, AudioCollector* collector) + : m_loop(nullptr) + , m_stream(nullptr) + , m_timer(nullptr) + , m_idle(true) + , m_token(token) + , m_collector(collector) { + pw_init(nullptr, nullptr); + + m_loop = pw_main_loop_new(nullptr); + if (!m_loop) { + qWarning() << "PipeWireWorker::init: failed to create PipeWire main loop"; + pw_deinit(); + return; + } + + timespec timeout = { 0, 10 * SPA_NSEC_PER_MSEC }; + m_timer = pw_loop_add_timer(pw_main_loop_get_loop(m_loop), handleTimeout, this); + pw_loop_update_timer(pw_main_loop_get_loop(m_loop), m_timer, &timeout, &timeout, false); + + auto props = pw_properties_new( + PW_KEY_MEDIA_TYPE, "Audio", PW_KEY_MEDIA_CATEGORY, "Capture", PW_KEY_MEDIA_ROLE, "Music", nullptr); + pw_properties_set(props, PW_KEY_STREAM_CAPTURE_SINK, "true"); + pw_properties_setf( + props, PW_KEY_NODE_LATENCY, "%u/%u", nextPowerOf2(512 * ac::SAMPLE_RATE / 48000), ac::SAMPLE_RATE); + pw_properties_set(props, PW_KEY_NODE_PASSIVE, "true"); + pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); + pw_properties_set(props, PW_KEY_STREAM_DONT_REMIX, "false"); + pw_properties_set(props, "channelmix.upmix", "true"); + + std::vector buffer(ac::CHUNK_SIZE); + spa_pod_builder b; + spa_pod_builder_init(&b, buffer.data(), static_cast(buffer.size())); + + spa_audio_info_raw info{}; + info.format = SPA_AUDIO_FORMAT_S16; + info.rate = ac::SAMPLE_RATE; + info.channels = 1; + + const spa_pod* params[1]; + params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info); + + pw_stream_events events{}; + events.state_changed = [](void* data, pw_stream_state, pw_stream_state state, const char*) { + auto* self = static_cast(data); + self->streamStateChanged(state); + }; + events.process = [](void* data) { + auto* self = static_cast(data); + self->processStream(); + }; + + m_stream = pw_stream_new_simple(pw_main_loop_get_loop(m_loop), "caelestia-shell", props, &events, this); + + const int success = pw_stream_connect(m_stream, PW_DIRECTION_INPUT, PW_ID_ANY, + static_cast( + PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS), + params, 1); + if (success < 0) { + qWarning() << "PipeWireWorker::init: failed to connect stream"; + pw_stream_destroy(m_stream); + pw_main_loop_destroy(m_loop); + pw_deinit(); + return; + } + + pw_main_loop_run(m_loop); + + pw_stream_destroy(m_stream); + pw_main_loop_destroy(m_loop); + pw_deinit(); +} + +void PipeWireWorker::handleTimeout(void* data, uint64_t expirations) { + auto* self = static_cast(data); + + if (self->m_token.stop_requested()) { + pw_main_loop_quit(self->m_loop); + return; + } + + if (!self->m_idle) { + if (expirations < 10) { + self->m_collector->clearBuffer(); + } else { + self->m_idle = true; + timespec timeout = { 0, 500 * SPA_NSEC_PER_MSEC }; + pw_loop_update_timer(pw_main_loop_get_loop(self->m_loop), self->m_timer, &timeout, &timeout, false); + } + } +} + +void PipeWireWorker::streamStateChanged(pw_stream_state state) { + m_idle = false; + switch (state) { + case PW_STREAM_STATE_PAUSED: { + timespec timeout = { 0, 10 * SPA_NSEC_PER_MSEC }; + pw_loop_update_timer(pw_main_loop_get_loop(m_loop), m_timer, &timeout, &timeout, false); + break; + } + case PW_STREAM_STATE_STREAMING: + pw_loop_update_timer(pw_main_loop_get_loop(m_loop), m_timer, nullptr, nullptr, false); + break; + case PW_STREAM_STATE_ERROR: + pw_main_loop_quit(m_loop); + break; + default: + break; + } +} + +void PipeWireWorker::processStream() { + if (m_token.stop_requested()) { + pw_main_loop_quit(m_loop); + return; + } + + pw_buffer* buffer = pw_stream_dequeue_buffer(m_stream); + if (buffer == nullptr) { + return; + } + + const spa_buffer* buf = buffer->buffer; + const qint16* samples = reinterpret_cast(buf->datas[0].data); + if (samples == nullptr) { + return; + } + + const quint32 count = buf->datas[0].chunk->size / 2; + m_collector->loadChunk(samples, count); + + pw_stream_queue_buffer(m_stream, buffer); +} + +unsigned int PipeWireWorker::nextPowerOf2(unsigned int n) { + if (n == 0) { + return 1; + } + + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + + return n; +} + +AudioCollector& AudioCollector::instance() { + static AudioCollector instance; + return instance; +} + +void AudioCollector::clearBuffer() { + auto* writeBuffer = m_writeBuffer.load(std::memory_order_relaxed); + std::fill(writeBuffer->begin(), writeBuffer->end(), 0.0f); + + auto* oldRead = m_readBuffer.exchange(writeBuffer, std::memory_order_acq_rel); + m_writeBuffer.store(oldRead, std::memory_order_release); +} + +void AudioCollector::loadChunk(const qint16* samples, quint32 count) { + if (count > ac::CHUNK_SIZE) { + count = ac::CHUNK_SIZE; + } + + auto* writeBuffer = m_writeBuffer.load(std::memory_order_relaxed); + std::transform(samples, samples + count, writeBuffer->begin(), [](qint16 sample) { + return sample / 32768.0f; + }); + + auto* oldRead = m_readBuffer.exchange(writeBuffer, std::memory_order_acq_rel); + m_writeBuffer.store(oldRead, std::memory_order_release); +} + +quint32 AudioCollector::readChunk(float* out, quint32 count) { + if (count == 0 || count > ac::CHUNK_SIZE) { + count = ac::CHUNK_SIZE; + } + + auto* readBuffer = m_readBuffer.load(std::memory_order_acquire); + std::memcpy(out, readBuffer->data(), count * sizeof(float)); + + return count; +} + +quint32 AudioCollector::readChunk(double* out, quint32 count) { + if (count == 0 || count > ac::CHUNK_SIZE) { + count = ac::CHUNK_SIZE; + } + + auto* readBuffer = m_readBuffer.load(std::memory_order_acquire); + std::transform(readBuffer->begin(), readBuffer->begin() + count, out, [](float sample) { + return static_cast(sample); + }); + + return count; +} + +AudioCollector::AudioCollector(QObject* parent) + : Service(parent) + , m_buffer1(ac::CHUNK_SIZE) + , m_buffer2(ac::CHUNK_SIZE) + , m_readBuffer(&m_buffer1) + , m_writeBuffer(&m_buffer2) {} + +AudioCollector::~AudioCollector() { + stop(); +} + +void AudioCollector::start() { + if (m_thread.joinable()) { + return; + } + + clearBuffer(); + + m_thread = std::jthread([this](std::stop_token token) { + PipeWireWorker worker(token, this); + }); +} + +void AudioCollector::stop() { + if (m_thread.joinable()) { + m_thread.request_stop(); + m_thread.join(); + } +} + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audiocollector.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audiocollector.hpp new file mode 100644 index 0000000..cd63afa --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audiocollector.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include "service.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace caelestia::services { + +namespace ac { + +constexpr quint32 SAMPLE_RATE = 44100; +constexpr quint32 CHUNK_SIZE = 512; + +} // namespace ac + +class AudioCollector; + +class PipeWireWorker { +public: + explicit PipeWireWorker(std::stop_token token, AudioCollector* collector); + + void run(); + +private: + pw_main_loop* m_loop; + pw_stream* m_stream; + spa_source* m_timer; + bool m_idle; + + std::stop_token m_token; + AudioCollector* m_collector; + + static void handleTimeout(void* data, uint64_t expirations); + void streamStateChanged(pw_stream_state state); + void processStream(); + + [[nodiscard]] unsigned int nextPowerOf2(unsigned int n); +}; + +class AudioCollector : public Service { + Q_OBJECT + +public: + AudioCollector(const AudioCollector&) = delete; + AudioCollector& operator=(const AudioCollector&) = delete; + + static AudioCollector& instance(); + + void clearBuffer(); + void loadChunk(const qint16* samples, quint32 count); + quint32 readChunk(float* out, quint32 count = 0); + quint32 readChunk(double* out, quint32 count = 0); + +private: + explicit AudioCollector(QObject* parent = nullptr); + ~AudioCollector(); + + std::jthread m_thread; + std::vector m_buffer1; + std::vector m_buffer2; + std::atomic*> m_readBuffer; + std::atomic*> m_writeBuffer; + quint32 m_sampleCount; + + void reload(); + void start() override; + void stop() override; +}; + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audioprovider.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audioprovider.cpp new file mode 100644 index 0000000..1fac9ee --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audioprovider.cpp @@ -0,0 +1,78 @@ +#include "audioprovider.hpp" + +#include "audiocollector.hpp" +#include "service.hpp" +#include +#include + +namespace caelestia::services { + +AudioProcessor::AudioProcessor(QObject* parent) + : QObject(parent) {} + +AudioProcessor::~AudioProcessor() { + stop(); +} + +void AudioProcessor::init() { + m_timer = new QTimer(this); + m_timer->setInterval(static_cast(ac::CHUNK_SIZE * 1000.0 / ac::SAMPLE_RATE)); + connect(m_timer, &QTimer::timeout, this, &AudioProcessor::process); +} + +void AudioProcessor::start() { + QMetaObject::invokeMethod(&AudioCollector::instance(), &AudioCollector::ref, Qt::QueuedConnection, this); + if (m_timer) { + m_timer->start(); + } +} + +void AudioProcessor::stop() { + if (m_timer) { + m_timer->stop(); + } + QMetaObject::invokeMethod(&AudioCollector::instance(), &AudioCollector::unref, Qt::QueuedConnection, this); +} + +AudioProvider::AudioProvider(QObject* parent) + : Service(parent) + , m_processor(nullptr) + , m_thread(nullptr) {} + +AudioProvider::~AudioProvider() { + if (m_thread) { + m_thread->quit(); + m_thread->wait(); + } +} + +void AudioProvider::init() { + if (!m_processor) { + qWarning() << "AudioProvider::init: attempted to init with no processor set"; + return; + } + + m_thread = new QThread(this); + m_processor->moveToThread(m_thread); + + connect(m_thread, &QThread::started, m_processor, &AudioProcessor::init); + connect(m_thread, &QThread::finished, m_processor, &AudioProcessor::deleteLater); + connect(m_thread, &QThread::finished, m_thread, &QThread::deleteLater); + + m_thread->start(); +} + +void AudioProvider::start() { + if (m_processor) { + AudioCollector::instance(); // Create instance on main thread + QMetaObject::invokeMethod(m_processor, &AudioProcessor::start); + } +} + +void AudioProvider::stop() { + if (m_processor) { + QMetaObject::invokeMethod(m_processor, &AudioProcessor::stop); + } +} + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audioprovider.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audioprovider.hpp new file mode 100644 index 0000000..5bf9bb0 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/audioprovider.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "service.hpp" +#include +#include + +namespace caelestia::services { + +class AudioProcessor : public QObject { + Q_OBJECT + +public: + explicit AudioProcessor(QObject* parent = nullptr); + ~AudioProcessor(); + + void init(); + +public slots: + void start(); + void stop(); + +protected: + virtual void process() = 0; + +private: + QTimer* m_timer; +}; + +class AudioProvider : public Service { + Q_OBJECT + +public: + explicit AudioProvider(QObject* parent = nullptr); + ~AudioProvider(); + +protected: + AudioProcessor* m_processor; + + void init(); + +private: + QThread* m_thread; + + void start() override; + void stop() override; +}; + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/beattracker.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/beattracker.cpp new file mode 100644 index 0000000..93addc6 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/beattracker.cpp @@ -0,0 +1,58 @@ +#include "beattracker.hpp" + +#include "audiocollector.hpp" +#include "audioprovider.hpp" +#include + +namespace caelestia::services { + +BeatProcessor::BeatProcessor(QObject* parent) + : AudioProcessor(parent) + , m_tempo(new_aubio_tempo("default", 1024, ac::CHUNK_SIZE, ac::SAMPLE_RATE)) + , m_in(new_fvec(ac::CHUNK_SIZE)) + , m_out(new_fvec(2)) {}; + +BeatProcessor::~BeatProcessor() { + if (m_tempo) { + del_aubio_tempo(m_tempo); + } + if (m_in) { + del_fvec(m_in); + } + del_fvec(m_out); +} + +void BeatProcessor::process() { + if (!m_tempo || !m_in) { + return; + } + + AudioCollector::instance().readChunk(m_in->data); + + aubio_tempo_do(m_tempo, m_in, m_out); + if (!qFuzzyIsNull(m_out->data[0])) { + emit beat(aubio_tempo_get_bpm(m_tempo)); + } +} + +BeatTracker::BeatTracker(QObject* parent) + : AudioProvider(parent) + , m_bpm(120) { + m_processor = new BeatProcessor(); + init(); + + connect(static_cast(m_processor), &BeatProcessor::beat, this, &BeatTracker::updateBpm); +} + +smpl_t BeatTracker::bpm() const { + return m_bpm; +} + +void BeatTracker::updateBpm(smpl_t bpm) { + if (!qFuzzyCompare(bpm + 1.0f, m_bpm + 1.0f)) { + m_bpm = bpm; + emit bpmChanged(); + } +} + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/beattracker.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/beattracker.hpp new file mode 100644 index 0000000..94738ce --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/beattracker.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "audioprovider.hpp" +#include +#include + +namespace caelestia::services { + +class BeatProcessor : public AudioProcessor { + Q_OBJECT + +public: + explicit BeatProcessor(QObject* parent = nullptr); + ~BeatProcessor(); + +signals: + void beat(smpl_t bpm); + +protected: + void process() override; + +private: + aubio_tempo_t* m_tempo; + fvec_t* m_in; + fvec_t* m_out; +}; + +class BeatTracker : public AudioProvider { + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(smpl_t bpm READ bpm NOTIFY bpmChanged) + +public: + explicit BeatTracker(QObject* parent = nullptr); + + [[nodiscard]] smpl_t bpm() const; + +signals: + void bpmChanged(); + void beat(smpl_t bpm); + +private: + smpl_t m_bpm; + + void updateBpm(smpl_t bpm); +}; + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/cavaprovider.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/cavaprovider.cpp new file mode 100644 index 0000000..7b6cc1f --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/cavaprovider.cpp @@ -0,0 +1,140 @@ +#include "cavaprovider.hpp" + +#include "audiocollector.hpp" +#include "audioprovider.hpp" +#include +#include +#include + +namespace caelestia::services { + +CavaProcessor::CavaProcessor(QObject* parent) + : AudioProcessor(parent) + , m_plan(nullptr) + , m_in(new double[ac::CHUNK_SIZE]) + , m_out(nullptr) + , m_bars(0) {}; + +CavaProcessor::~CavaProcessor() { + cleanup(); + delete[] m_in; +} + +void CavaProcessor::process() { + if (!m_plan || m_bars == 0 || !m_out) { + return; + } + + const int count = static_cast(AudioCollector::instance().readChunk(m_in)); + + // Process in data via cava + cava_execute(m_in, count, m_out, m_plan); + + // Apply monstercat filter + QVector values(m_bars); + + // Left to right pass + const double inv = 1.0 / 1.5; + double carry = 0.0; + for (int i = 0; i < m_bars; ++i) { + carry = std::max(m_out[i], carry * inv); + values[i] = carry; + } + + // Right to left pass and combine + carry = 0.0; + for (int i = m_bars - 1; i >= 0; --i) { + carry = std::max(m_out[i], carry * inv); + values[i] = std::max(values[i], carry); + } + + // Update values + if (values != m_values) { + m_values = std::move(values); + emit valuesChanged(m_values); + } +} + +void CavaProcessor::setBars(int bars) { + if (bars < 0) { + qWarning() << "CavaProcessor::setBars: bars must be greater than 0. Setting to 0."; + bars = 0; + } + + if (m_bars != bars) { + m_bars = bars; + reload(); + } +} + +void CavaProcessor::reload() { + cleanup(); + initCava(); +} + +void CavaProcessor::cleanup() { + if (m_plan) { + cava_destroy(m_plan); + m_plan = nullptr; + } + + if (m_out) { + delete[] m_out; + m_out = nullptr; + } +} + +void CavaProcessor::initCava() { + if (m_plan || m_bars == 0) { + return; + } + + m_plan = cava_init(m_bars, ac::SAMPLE_RATE, 1, 1, 0.85, 50, 10000); + m_out = new double[static_cast(m_bars)]; +} + +CavaProvider::CavaProvider(QObject* parent) + : AudioProvider(parent) + , m_bars(0) + , m_values(m_bars, 0.0) { + m_processor = new CavaProcessor(); + init(); + + connect(static_cast(m_processor), &CavaProcessor::valuesChanged, this, &CavaProvider::updateValues); +} + +int CavaProvider::bars() const { + return m_bars; +} + +void CavaProvider::setBars(int bars) { + if (bars < 0) { + qWarning() << "CavaProvider::setBars: bars must be greater than 0. Setting to 0."; + bars = 0; + } + + if (m_bars == bars) { + return; + } + + m_values.resize(bars, 0.0); + m_bars = bars; + emit barsChanged(); + emit valuesChanged(); + + QMetaObject::invokeMethod( + static_cast(m_processor), &CavaProcessor::setBars, Qt::QueuedConnection, bars); +} + +QVector CavaProvider::values() const { + return m_values; +} + +void CavaProvider::updateValues(QVector values) { + if (values != m_values) { + m_values = values; + emit valuesChanged(); + } +} + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/cavaprovider.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/cavaprovider.hpp new file mode 100644 index 0000000..c45e33f --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/cavaprovider.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include "audioprovider.hpp" +#include +#include + +namespace caelestia::services { + +class CavaProcessor : public AudioProcessor { + Q_OBJECT + +public: + explicit CavaProcessor(QObject* parent = nullptr); + ~CavaProcessor(); + + void setBars(int bars); + +signals: + void valuesChanged(QVector values); + +protected: + void process() override; + +private: + struct cava_plan* m_plan; + double* m_in; + double* m_out; + + int m_bars; + QVector m_values; + + void reload(); + void initCava(); + void cleanup(); +}; + +class CavaProvider : public AudioProvider { + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(int bars READ bars WRITE setBars NOTIFY barsChanged) + + Q_PROPERTY(QVector values READ values NOTIFY valuesChanged) + +public: + explicit CavaProvider(QObject* parent = nullptr); + + [[nodiscard]] int bars() const; + void setBars(int bars); + + [[nodiscard]] QVector values() const; + +signals: + void barsChanged(); + void valuesChanged(); + +private: + int m_bars; + QVector m_values; + + void updateValues(QVector values); +}; + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/service.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/service.cpp new file mode 100644 index 0000000..bc21567 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/service.cpp @@ -0,0 +1,26 @@ +#include "service.hpp" + +#include +#include + +namespace caelestia::services { + +Service::Service(QObject* parent) + : QObject(parent) {} + +void Service::ref(QObject* sender) { + if (m_refs.isEmpty()) { + start(); + } + + QObject::connect(sender, &QObject::destroyed, this, &Service::unref); + m_refs << sender; +} + +void Service::unref(QObject* sender) { + if (m_refs.remove(sender) && m_refs.isEmpty()) { + stop(); + } +} + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/service.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/service.hpp new file mode 100644 index 0000000..f8af03a --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/service.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace caelestia::services { + +class Service : public QObject { + Q_OBJECT + +public: + explicit Service(QObject* parent = nullptr); + + void ref(QObject* sender); + void unref(QObject* sender); + +private: + QSet m_refs; + + virtual void start() = 0; + virtual void stop() = 0; +}; + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/serviceref.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/serviceref.cpp new file mode 100644 index 0000000..db1a3f2 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/serviceref.cpp @@ -0,0 +1,36 @@ +#include "serviceref.hpp" + +#include "service.hpp" + +namespace caelestia::services { + +ServiceRef::ServiceRef(Service* service, QObject* parent) + : QObject(parent) + , m_service(service) { + if (m_service) { + m_service->ref(this); + } +} + +Service* ServiceRef::service() const { + return m_service; +} + +void ServiceRef::setService(Service* service) { + if (m_service == service) { + return; + } + + if (m_service) { + m_service->unref(this); + } + + m_service = service; + emit serviceChanged(); + + if (m_service) { + m_service->ref(this); + } +} + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/Services/serviceref.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/serviceref.hpp new file mode 100644 index 0000000..d4d305c --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/Services/serviceref.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "service.hpp" +#include +#include + +namespace caelestia::services { + +class ServiceRef : public QObject { + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(caelestia::services::Service* service READ service WRITE setService NOTIFY serviceChanged) + +public: + explicit ServiceRef(Service* service = nullptr, QObject* parent = nullptr); + + [[nodiscard]] Service* service() const; + void setService(Service* service); + +signals: + void serviceChanged(); + +private: + QPointer m_service; +}; + +} // namespace caelestia::services diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/appdb.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/appdb.cpp new file mode 100644 index 0000000..b074cf4 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/appdb.cpp @@ -0,0 +1,312 @@ +#include "appdb.hpp" + +#include +#include +#include + +namespace caelestia { + +AppEntry::AppEntry(QObject* entry, unsigned int frequency, QObject* parent) + : QObject(parent) + , m_entry(entry) + , m_frequency(frequency) { + const auto mo = m_entry->metaObject(); + const auto tmo = metaObject(); + + for (const auto& prop : + { "name", "comment", "execString", "startupClass", "genericName", "categories", "keywords" }) { + const auto metaProp = mo->property(mo->indexOfProperty(prop)); + const auto thisMetaProp = tmo->property(tmo->indexOfProperty(prop)); + QObject::connect(m_entry, metaProp.notifySignal(), this, thisMetaProp.notifySignal()); + } + + QObject::connect(m_entry, &QObject::destroyed, this, [this]() { + m_entry = nullptr; + deleteLater(); + }); +} + +QObject* AppEntry::entry() const { + return m_entry; +} + +quint32 AppEntry::frequency() const { + return m_frequency; +} + +void AppEntry::setFrequency(unsigned int frequency) { + if (m_frequency != frequency) { + m_frequency = frequency; + emit frequencyChanged(); + } +} + +void AppEntry::incrementFrequency() { + m_frequency++; + emit frequencyChanged(); +} + +QString AppEntry::id() const { + if (!m_entry) { + return ""; + } + return m_entry->property("id").toString(); +} + +QString AppEntry::name() const { + if (!m_entry) { + return ""; + } + return m_entry->property("name").toString(); +} + +QString AppEntry::comment() const { + if (!m_entry) { + return ""; + } + return m_entry->property("comment").toString(); +} + +QString AppEntry::execString() const { + if (!m_entry) { + return ""; + } + return m_entry->property("execString").toString(); +} + +QString AppEntry::startupClass() const { + if (!m_entry) { + return ""; + } + return m_entry->property("startupClass").toString(); +} + +QString AppEntry::genericName() const { + if (!m_entry) { + return ""; + } + return m_entry->property("genericName").toString(); +} + +QString AppEntry::categories() const { + if (!m_entry) { + return ""; + } + return m_entry->property("categories").toStringList().join(" "); +} + +QString AppEntry::keywords() const { + if (!m_entry) { + return ""; + } + return m_entry->property("keywords").toStringList().join(" "); +} + +AppDb::AppDb(QObject* parent) + : QObject(parent) + , m_timer(new QTimer(this)) + , m_uuid(QUuid::createUuid().toString()) { + m_timer->setSingleShot(true); + m_timer->setInterval(300); + QObject::connect(m_timer, &QTimer::timeout, this, &AppDb::updateApps); + + auto db = QSqlDatabase::addDatabase("QSQLITE", m_uuid); + db.setDatabaseName(":memory:"); + db.open(); + + QSqlQuery query(db); + query.exec("CREATE TABLE IF NOT EXISTS frequencies (id TEXT PRIMARY KEY, frequency INTEGER)"); +} + +QString AppDb::uuid() const { + return m_uuid; +} + +QString AppDb::path() const { + return m_path; +} + +void AppDb::setPath(const QString& path) { + auto newPath = path.isEmpty() ? ":memory:" : path; + + if (m_path == newPath) { + return; + } + + m_path = newPath; + emit pathChanged(); + + auto db = QSqlDatabase::database(m_uuid, false); + db.close(); + db.setDatabaseName(newPath); + db.open(); + + QSqlQuery query(db); + query.exec("CREATE TABLE IF NOT EXISTS frequencies (id TEXT PRIMARY KEY, frequency INTEGER)"); + + updateAppFrequencies(); +} + +QObjectList AppDb::entries() const { + return m_entries; +} + +void AppDb::setEntries(const QObjectList& entries) { + if (m_entries == entries) { + return; + } + + m_entries = entries; + emit entriesChanged(); + + m_timer->start(); +} + +QStringList AppDb::favouriteApps() const { + return m_favouriteApps; +} + +void AppDb::setFavouriteApps(const QStringList& favApps) { + if (m_favouriteApps == favApps) { + return; + } + + m_favouriteApps = favApps; + emit favouriteAppsChanged(); + m_favouriteAppsRegex.clear(); + m_favouriteAppsRegex.reserve(m_favouriteApps.size()); + for (const QString& item : std::as_const(m_favouriteApps)) { + const QRegularExpression re(regexifyString(item)); + if (re.isValid()) { + m_favouriteAppsRegex << re; + } else { + qWarning() << "AppDb::setFavouriteApps: Regular expression is not valid: " << re.pattern(); + } + } + + emit appsChanged(); +} + +QString AppDb::regexifyString(const QString& original) const { + if (original.startsWith('^') && original.endsWith('$')) + return original; + + const QString escaped = QRegularExpression::escape(original); + return QStringLiteral("^%1$").arg(escaped); +} + +QQmlListProperty AppDb::apps() { + return QQmlListProperty(this, &getSortedApps()); +} + +void AppDb::incrementFrequency(const QString& id) { + auto db = QSqlDatabase::database(m_uuid); + QSqlQuery query(db); + + query.prepare("INSERT INTO frequencies (id, frequency) " + "VALUES (:id, 1) " + "ON CONFLICT (id) DO UPDATE SET frequency = frequency + 1"); + query.bindValue(":id", id); + query.exec(); + + auto* app = m_apps.value(id); + if (app) { + const auto before = getSortedApps(); + + app->incrementFrequency(); + + if (before != getSortedApps()) { + emit appsChanged(); + } + } else { + qWarning() << "AppDb::incrementFrequency: could not find app with id" << id; + } +} + +QList& AppDb::getSortedApps() const { + m_sortedApps = m_apps.values(); + std::sort(m_sortedApps.begin(), m_sortedApps.end(), [this](AppEntry* a, AppEntry* b) { + bool aIsFav = isFavourite(a); + bool bIsFav = isFavourite(b); + if (aIsFav != bIsFav) { + return aIsFav; + } + if (a->frequency() != b->frequency()) { + return a->frequency() > b->frequency(); + } + return a->name().localeAwareCompare(b->name()) < 0; + }); + return m_sortedApps; +} + +bool AppDb::isFavourite(const AppEntry* app) const { + for (const QRegularExpression& re : m_favouriteAppsRegex) { + if (re.match(app->id()).hasMatch()) { + return true; + } + } + return false; +} + +quint32 AppDb::getFrequency(const QString& id) const { + auto db = QSqlDatabase::database(m_uuid); + QSqlQuery query(db); + + query.prepare("SELECT frequency FROM frequencies WHERE id = :id"); + query.bindValue(":id", id); + + if (query.exec() && query.next()) { + return query.value(0).toUInt(); + } + + return 0; +} + +void AppDb::updateAppFrequencies() { + const auto before = getSortedApps(); + + for (auto* app : std::as_const(m_apps)) { + app->setFrequency(getFrequency(app->id())); + } + + if (before != getSortedApps()) { + emit appsChanged(); + } +} + +void AppDb::updateApps() { + bool dirty = false; + + for (const auto& entry : std::as_const(m_entries)) { + const auto id = entry->property("id").toString(); + if (!m_apps.contains(id)) { + dirty = true; + auto* const newEntry = new AppEntry(entry, getFrequency(id), this); + QObject::connect(newEntry, &QObject::destroyed, this, [id, this]() { + if (m_apps.remove(id)) { + emit appsChanged(); + } + }); + m_apps.insert(id, newEntry); + } + } + + QSet newIds; + for (const auto& entry : std::as_const(m_entries)) { + newIds.insert(entry->property("id").toString()); + } + + for (auto it = m_apps.keyBegin(); it != m_apps.keyEnd(); ++it) { + const auto& id = *it; + if (!newIds.contains(id)) { + dirty = true; + m_apps.take(id)->deleteLater(); + } + } + + if (dirty) { + emit appsChanged(); + } +} + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/appdb.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/appdb.hpp new file mode 100644 index 0000000..ce5f270 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/appdb.hpp @@ -0,0 +1,116 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace caelestia { + +class AppEntry : public QObject { + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("AppEntry instances can only be retrieved from an AppDb") + + // The actual DesktopEntry, but we don't have access to the type so it's a QObject + Q_PROPERTY(QObject* entry READ entry CONSTANT) + + Q_PROPERTY(quint32 frequency READ frequency NOTIFY frequencyChanged) + Q_PROPERTY(QString id READ id CONSTANT) + Q_PROPERTY(QString name READ name NOTIFY nameChanged) + Q_PROPERTY(QString comment READ comment NOTIFY commentChanged) + Q_PROPERTY(QString execString READ execString NOTIFY execStringChanged) + Q_PROPERTY(QString startupClass READ startupClass NOTIFY startupClassChanged) + Q_PROPERTY(QString genericName READ genericName NOTIFY genericNameChanged) + Q_PROPERTY(QString categories READ categories NOTIFY categoriesChanged) + Q_PROPERTY(QString keywords READ keywords NOTIFY keywordsChanged) + +public: + explicit AppEntry(QObject* entry, quint32 frequency, QObject* parent = nullptr); + + [[nodiscard]] QObject* entry() const; + + [[nodiscard]] quint32 frequency() const; + void setFrequency(quint32 frequency); + void incrementFrequency(); + + [[nodiscard]] QString id() const; + [[nodiscard]] QString name() const; + [[nodiscard]] QString comment() const; + [[nodiscard]] QString execString() const; + [[nodiscard]] QString startupClass() const; + [[nodiscard]] QString genericName() const; + [[nodiscard]] QString categories() const; + [[nodiscard]] QString keywords() const; + +signals: + void frequencyChanged(); + void nameChanged(); + void commentChanged(); + void execStringChanged(); + void startupClassChanged(); + void genericNameChanged(); + void categoriesChanged(); + void keywordsChanged(); + +private: + QObject* m_entry; + quint32 m_frequency; +}; + +class AppDb : public QObject { + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(QString uuid READ uuid CONSTANT) + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged REQUIRED) + Q_PROPERTY(QObjectList entries READ entries WRITE setEntries NOTIFY entriesChanged REQUIRED) + Q_PROPERTY(QStringList favouriteApps READ favouriteApps WRITE setFavouriteApps NOTIFY favouriteAppsChanged REQUIRED) + Q_PROPERTY(QQmlListProperty apps READ apps NOTIFY appsChanged) + +public: + explicit AppDb(QObject* parent = nullptr); + + [[nodiscard]] QString uuid() const; + + [[nodiscard]] QString path() const; + void setPath(const QString& path); + + [[nodiscard]] QObjectList entries() const; + void setEntries(const QObjectList& entries); + + [[nodiscard]] QStringList favouriteApps() const; + void setFavouriteApps(const QStringList& favApps); + + [[nodiscard]] QQmlListProperty apps(); + + Q_INVOKABLE void incrementFrequency(const QString& id); + +signals: + void pathChanged(); + void entriesChanged(); + void favouriteAppsChanged(); + void appsChanged(); + +private: + QTimer* m_timer; + + const QString m_uuid; + QString m_path; + QObjectList m_entries; + QStringList m_favouriteApps; // unedited string list from qml + QList m_favouriteAppsRegex; // pre-regexified m_favouriteApps list + QHash m_apps; + mutable QList m_sortedApps; + + QString regexifyString(const QString& original) const; + QList& getSortedApps() const; + bool isFavourite(const AppEntry* app) const; + quint32 getFrequency(const QString& id) const; + void updateAppFrequencies(); + void updateApps(); +}; + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/cutils.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/cutils.cpp new file mode 100644 index 0000000..6e3bfa9 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/cutils.cpp @@ -0,0 +1,131 @@ +#include "cutils.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace caelestia { + +void CUtils::saveItem(QQuickItem* target, const QUrl& path) { + this->saveItem(target, path, QRect(), QJSValue(), QJSValue()); +} + +void CUtils::saveItem(QQuickItem* target, const QUrl& path, const QRect& rect) { + this->saveItem(target, path, rect, QJSValue(), QJSValue()); +} + +void CUtils::saveItem(QQuickItem* target, const QUrl& path, QJSValue onSaved) { + this->saveItem(target, path, QRect(), onSaved, QJSValue()); +} + +void CUtils::saveItem(QQuickItem* target, const QUrl& path, QJSValue onSaved, QJSValue onFailed) { + this->saveItem(target, path, QRect(), onSaved, onFailed); +} + +void CUtils::saveItem(QQuickItem* target, const QUrl& path, const QRect& rect, QJSValue onSaved) { + this->saveItem(target, path, rect, onSaved, QJSValue()); +} + +void CUtils::saveItem(QQuickItem* target, const QUrl& path, const QRect& rect, QJSValue onSaved, QJSValue onFailed) { + if (!target) { + qWarning() << "CUtils::saveItem: a target is required"; + return; + } + + if (!path.isLocalFile()) { + qWarning() << "CUtils::saveItem:" << path << "is not a local file"; + return; + } + + if (!target->window()) { + qWarning() << "CUtils::saveItem: unable to save target" << target << "without a window"; + return; + } + + auto scaledRect = rect; + const qreal scale = target->window()->devicePixelRatio(); + if (rect.isValid() && !qFuzzyCompare(scale + 1.0, 2.0)) { + scaledRect = + QRectF(rect.left() * scale, rect.top() * scale, rect.width() * scale, rect.height() * scale).toRect(); + } + + const QSharedPointer grabResult = target->grabToImage(); + + QObject::connect(grabResult.data(), &QQuickItemGrabResult::ready, this, + [grabResult, scaledRect, path, onSaved, onFailed, this]() { + const auto future = QtConcurrent::run([=]() { + QImage image = grabResult->image(); + + if (scaledRect.isValid()) { + image = image.copy(scaledRect); + } + + const QString file = path.toLocalFile(); + const QString parent = QFileInfo(file).absolutePath(); + return QDir().mkpath(parent) && image.save(file); + }); + + auto* watcher = new QFutureWatcher(this); + auto* engine = qmlEngine(this); + + QObject::connect(watcher, &QFutureWatcher::finished, this, [=]() { + if (watcher->result()) { + if (onSaved.isCallable()) { + onSaved.call( + { QJSValue(path.toLocalFile()), engine->toScriptValue(QVariant::fromValue(path)) }); + } + } else { + qWarning() << "CUtils::saveItem: failed to save" << path; + if (onFailed.isCallable()) { + onFailed.call({ engine->toScriptValue(QVariant::fromValue(path)) }); + } + } + watcher->deleteLater(); + }); + watcher->setFuture(future); + }); +} + +bool CUtils::copyFile(const QUrl& source, const QUrl& target, bool overwrite) const { + if (!source.isLocalFile()) { + qWarning() << "CUtils::copyFile: source" << source << "is not a local file"; + return false; + } + if (!target.isLocalFile()) { + qWarning() << "CUtils::copyFile: target" << target << "is not a local file"; + return false; + } + + if (overwrite && QFile::exists(target.toLocalFile())) { + if (!QFile::remove(target.toLocalFile())) { + qWarning() << "CUtils::copyFile: overwrite was specified but failed to remove" << target.toLocalFile(); + return false; + } + } + + return QFile::copy(source.toLocalFile(), target.toLocalFile()); +} + +bool CUtils::deleteFile(const QUrl& path) const { + if (!path.isLocalFile()) { + qWarning() << "CUtils::deleteFile: path" << path << "is not a local file"; + return false; + } + + return QFile::remove(path.toLocalFile()); +} + +QString CUtils::toLocalFile(const QUrl& url) const { + if (!url.isLocalFile()) { + qWarning() << "CUtils::toLocalFile: given url is not a local file" << url; + return QString(); + } + + return url.toLocalFile(); +} + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/cutils.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/cutils.hpp new file mode 100644 index 0000000..027226d --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/cutils.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +namespace caelestia { + +class CUtils : public QObject { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + +public: + // clang-format off + Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path); + Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, const QRect& rect); + Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, QJSValue onSaved); + Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, QJSValue onSaved, QJSValue onFailed); + Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, const QRect& rect, QJSValue onSaved); + Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, const QRect& rect, QJSValue onSaved, QJSValue onFailed); + // clang-format on + + Q_INVOKABLE bool copyFile(const QUrl& source, const QUrl& target, bool overwrite = true) const; + Q_INVOKABLE bool deleteFile(const QUrl& path) const; + Q_INVOKABLE QString toLocalFile(const QUrl& url) const; +}; + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/imageanalyser.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/imageanalyser.cpp new file mode 100644 index 0000000..880b078 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/imageanalyser.cpp @@ -0,0 +1,223 @@ +#include "imageanalyser.hpp" + +#include +#include +#include +#include +#include + +namespace caelestia { + +ImageAnalyser::ImageAnalyser(QObject* parent) + : QObject(parent) + , m_futureWatcher(new QFutureWatcher(this)) + , m_source("") + , m_sourceItem(nullptr) + , m_rescaleSize(128) + , m_dominantColour(0, 0, 0) + , m_luminance(0) { + QObject::connect(m_futureWatcher, &QFutureWatcher::finished, this, [this]() { + if (!m_futureWatcher->future().isResultReadyAt(0)) { + return; + } + + const auto result = m_futureWatcher->result(); + if (m_dominantColour != result.first) { + m_dominantColour = result.first; + emit dominantColourChanged(); + } + if (!qFuzzyCompare(m_luminance + 1.0, result.second + 1.0)) { + m_luminance = result.second; + emit luminanceChanged(); + } + }); +} + +QString ImageAnalyser::source() const { + return m_source; +} + +void ImageAnalyser::setSource(const QString& source) { + if (m_source == source) { + return; + } + + m_source = source; + emit sourceChanged(); + + if (m_sourceItem) { + m_sourceItem = nullptr; + emit sourceItemChanged(); + } + + requestUpdate(); +} + +QQuickItem* ImageAnalyser::sourceItem() const { + return m_sourceItem; +} + +void ImageAnalyser::setSourceItem(QQuickItem* sourceItem) { + if (m_sourceItem == sourceItem) { + return; + } + + m_sourceItem = sourceItem; + emit sourceItemChanged(); + + if (!m_source.isEmpty()) { + m_source = ""; + emit sourceChanged(); + } + + requestUpdate(); +} + +int ImageAnalyser::rescaleSize() const { + return m_rescaleSize; +} + +void ImageAnalyser::setRescaleSize(int rescaleSize) { + if (m_rescaleSize == rescaleSize) { + return; + } + + m_rescaleSize = rescaleSize; + emit rescaleSizeChanged(); + + requestUpdate(); +} + +QColor ImageAnalyser::dominantColour() const { + return m_dominantColour; +} + +qreal ImageAnalyser::luminance() const { + return m_luminance; +} + +void ImageAnalyser::requestUpdate() { + if (m_source.isEmpty() && !m_sourceItem) { + return; + } + + if (!m_sourceItem || (m_sourceItem->window() && m_sourceItem->window()->isVisible() && m_sourceItem->width() > 0 && + m_sourceItem->height() > 0)) { + update(); + } else if (m_sourceItem) { + if (!m_sourceItem->window()) { + QObject::connect(m_sourceItem, &QQuickItem::windowChanged, this, &ImageAnalyser::requestUpdate, + Qt::SingleShotConnection); + } else if (!m_sourceItem->window()->isVisible()) { + QObject::connect(m_sourceItem->window(), &QQuickWindow::visibleChanged, this, &ImageAnalyser::requestUpdate, + Qt::SingleShotConnection); + } + if (m_sourceItem->width() <= 0) { + QObject::connect( + m_sourceItem, &QQuickItem::widthChanged, this, &ImageAnalyser::requestUpdate, Qt::SingleShotConnection); + } + if (m_sourceItem->height() <= 0) { + QObject::connect(m_sourceItem, &QQuickItem::heightChanged, this, &ImageAnalyser::requestUpdate, + Qt::SingleShotConnection); + } + } +} + +void ImageAnalyser::update() { + if (m_source.isEmpty() && !m_sourceItem) { + return; + } + + if (m_futureWatcher->isRunning()) { + m_futureWatcher->cancel(); + } + + if (m_sourceItem) { + const QSharedPointer grabResult = m_sourceItem->grabToImage(); + QObject::connect(grabResult.data(), &QQuickItemGrabResult::ready, this, [grabResult, this]() { + m_futureWatcher->setFuture(QtConcurrent::run(&ImageAnalyser::analyse, grabResult->image(), m_rescaleSize)); + }); + } else { + m_futureWatcher->setFuture(QtConcurrent::run([=, this](QPromise& promise) { + const QImage image(m_source); + analyse(promise, image, m_rescaleSize); + })); + } +} + +void ImageAnalyser::analyse(QPromise& promise, const QImage& image, int rescaleSize) { + if (image.isNull()) { + qWarning() << "ImageAnalyser::analyse: image is null"; + return; + } + + QImage img = image; + + if (rescaleSize > 0 && (img.width() > rescaleSize || img.height() > rescaleSize)) { + img = img.scaled(rescaleSize, rescaleSize, Qt::KeepAspectRatio, Qt::FastTransformation); + } + + if (promise.isCanceled()) { + return; + } + + if (img.format() != QImage::Format_ARGB32) { + img = img.convertToFormat(QImage::Format_ARGB32); + } + + if (promise.isCanceled()) { + return; + } + + const uchar* data = img.bits(); + const int width = img.width(); + const int height = img.height(); + const qsizetype bytesPerLine = img.bytesPerLine(); + + std::unordered_map colours; + qreal totalLuminance = 0.0; + int count = 0; + + for (int y = 0; y < height; ++y) { + const uchar* line = data + y * bytesPerLine; + for (int x = 0; x < width; ++x) { + if (promise.isCanceled()) { + return; + } + + const uchar* pixel = line + x * 4; + + if (pixel[3] == 0) { + continue; + } + + const quint32 mr = static_cast(pixel[0] & 0xF8); + const quint32 mg = static_cast(pixel[1] & 0xF8); + const quint32 mb = static_cast(pixel[2] & 0xF8); + ++colours[(mr << 16) | (mg << 8) | mb]; + + const qreal r = pixel[0] / 255.0; + const qreal g = pixel[1] / 255.0; + const qreal b = pixel[2] / 255.0; + totalLuminance += std::sqrt(0.299 * r * r + 0.587 * g * g + 0.114 * b * b); + ++count; + } + } + + quint32 dominantColour = 0; + int maxCount = 0; + for (const auto& [colour, colourCount] : colours) { + if (promise.isCanceled()) { + return; + } + + if (colourCount > maxCount) { + dominantColour = colour; + maxCount = colourCount; + } + } + + promise.addResult(qMakePair(QColor((0xFFu << 24) | dominantColour), count == 0 ? 0.0 : totalLuminance / count)); +} + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/imageanalyser.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/imageanalyser.hpp new file mode 100644 index 0000000..bbea2b3 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/imageanalyser.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace caelestia { + +class ImageAnalyser : public QObject { + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(QQuickItem* sourceItem READ sourceItem WRITE setSourceItem NOTIFY sourceItemChanged) + Q_PROPERTY(int rescaleSize READ rescaleSize WRITE setRescaleSize NOTIFY rescaleSizeChanged) + Q_PROPERTY(QColor dominantColour READ dominantColour NOTIFY dominantColourChanged) + Q_PROPERTY(qreal luminance READ luminance NOTIFY luminanceChanged) + +public: + explicit ImageAnalyser(QObject* parent = nullptr); + + [[nodiscard]] QString source() const; + void setSource(const QString& source); + + [[nodiscard]] QQuickItem* sourceItem() const; + void setSourceItem(QQuickItem* sourceItem); + + [[nodiscard]] int rescaleSize() const; + void setRescaleSize(int rescaleSize); + + [[nodiscard]] QColor dominantColour() const; + [[nodiscard]] qreal luminance() const; + + Q_INVOKABLE void requestUpdate(); + +signals: + void sourceChanged(); + void sourceItemChanged(); + void rescaleSizeChanged(); + void dominantColourChanged(); + void luminanceChanged(); + +private: + using AnalyseResult = QPair; + + QFutureWatcher* const m_futureWatcher; + + QString m_source; + QQuickItem* m_sourceItem; + int m_rescaleSize; + + QColor m_dominantColour; + qreal m_luminance; + + void update(); + static void analyse(QPromise& promise, const QImage& image, int rescaleSize); +}; + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/qalculator.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/qalculator.cpp new file mode 100644 index 0000000..44e8d21 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/qalculator.cpp @@ -0,0 +1,52 @@ +#include "qalculator.hpp" + +#include + +namespace caelestia { + +Qalculator::Qalculator(QObject* parent) + : QObject(parent) { + if (!CALCULATOR) { + new Calculator(); + CALCULATOR->loadExchangeRates(); + CALCULATOR->loadGlobalDefinitions(); + CALCULATOR->loadLocalDefinitions(); + } +} + +QString Qalculator::eval(const QString& expr, bool printExpr) const { + if (expr.isEmpty()) { + return QString(); + } + + EvaluationOptions eo; + PrintOptions po; + + std::string parsed; + std::string result = CALCULATOR->calculateAndPrint( + CALCULATOR->unlocalizeExpression(expr.toStdString(), eo.parse_options), 100, eo, po, &parsed); + + std::string error; + while (CALCULATOR->message()) { + if (!CALCULATOR->message()->message().empty()) { + if (CALCULATOR->message()->type() == MESSAGE_ERROR) { + error += "error: "; + } else if (CALCULATOR->message()->type() == MESSAGE_WARNING) { + error += "warning: "; + } + error += CALCULATOR->message()->message(); + } + CALCULATOR->nextMessage(); + } + if (!error.empty()) { + return QString::fromStdString(error); + } + + if (printExpr) { + return QString("%1 = %2").arg(parsed).arg(result); + } + + return QString::fromStdString(result); +} + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/qalculator.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/qalculator.hpp new file mode 100644 index 0000000..a07a8a2 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/qalculator.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace caelestia { + +class Qalculator : public QObject { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + +public: + explicit Qalculator(QObject* parent = nullptr); + + Q_INVOKABLE QString eval(const QString& expr, bool printExpr = true) const; +}; + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/requests.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/requests.cpp new file mode 100644 index 0000000..2ceddb3 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/requests.cpp @@ -0,0 +1,35 @@ +#include "requests.hpp" + +#include +#include +#include + +namespace caelestia { + +Requests::Requests(QObject* parent) + : QObject(parent) + , m_manager(new QNetworkAccessManager(this)) {} + +void Requests::get(const QUrl& url, QJSValue onSuccess, QJSValue onError) const { + if (!onSuccess.isCallable()) { + qWarning() << "Requests::get: onSuccess is not callable"; + return; + } + + QNetworkRequest request(url); + auto reply = m_manager->get(request); + + QObject::connect(reply, &QNetworkReply::finished, [reply, onSuccess, onError]() { + if (reply->error() == QNetworkReply::NoError) { + onSuccess.call({ QString(reply->readAll()) }); + } else if (onError.isCallable()) { + onError.call({ reply->errorString() }); + } else { + qWarning() << "Requests::get: request failed with error" << reply->errorString(); + } + + reply->deleteLater(); + }); +} + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/requests.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/requests.hpp new file mode 100644 index 0000000..1db2f4c --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/requests.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +namespace caelestia { + +class Requests : public QObject { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + +public: + explicit Requests(QObject* parent = nullptr); + + Q_INVOKABLE void get(const QUrl& url, QJSValue callback, QJSValue onError = QJSValue()) const; + +private: + QNetworkAccessManager* m_manager; +}; + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/toaster.cpp b/.config/quickshell/caelestia/plugin/src/Caelestia/toaster.cpp new file mode 100644 index 0000000..978805d --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/toaster.cpp @@ -0,0 +1,116 @@ +#include "toaster.hpp" + +#include +#include +#include + +namespace caelestia { + +Toast::Toast(const QString& title, const QString& message, const QString& icon, Type type, int timeout, QObject* parent) + : QObject(parent) + , m_closed(false) + , m_title(title) + , m_message(message) + , m_icon(icon) + , m_type(type) + , m_timeout(timeout) { + QTimer::singleShot(timeout, this, &Toast::close); + + if (m_icon.isEmpty()) { + switch (m_type) { + case Type::Success: + m_icon = "check_circle_unread"; + break; + case Type::Warning: + m_icon = "warning"; + break; + case Type::Error: + m_icon = "error"; + break; + default: + m_icon = "info"; + break; + } + } + + if (timeout <= 0) { + switch (m_type) { + case Type::Warning: + m_timeout = 7000; + break; + case Type::Error: + m_timeout = 10000; + break; + default: + m_timeout = 5000; + break; + } + } +} + +bool Toast::closed() const { + return m_closed; +} + +QString Toast::title() const { + return m_title; +} + +QString Toast::message() const { + return m_message; +} + +QString Toast::icon() const { + return m_icon; +} + +int Toast::timeout() const { + return m_timeout; +} + +Toast::Type Toast::type() const { + return m_type; +} + +void Toast::close() { + if (!m_closed) { + m_closed = true; + emit closedChanged(); + } + + if (m_locks.isEmpty()) { + emit finishedClose(); + } +} + +void Toast::lock(QObject* sender) { + m_locks << sender; + QObject::connect(sender, &QObject::destroyed, this, &Toast::unlock); +} + +void Toast::unlock(QObject* sender) { + if (m_locks.remove(sender) && m_closed) { + close(); + } +} + +Toaster::Toaster(QObject* parent) + : QObject(parent) {} + +QQmlListProperty Toaster::toasts() { + return QQmlListProperty(this, &m_toasts); +} + +void Toaster::toast(const QString& title, const QString& message, const QString& icon, Toast::Type type, int timeout) { + auto* toast = new Toast(title, message, icon, type, timeout, this); + QObject::connect(toast, &Toast::finishedClose, this, [toast, this]() { + if (m_toasts.removeOne(toast)) { + emit toastsChanged(); + toast->deleteLater(); + } + }); + m_toasts.push_front(toast); + emit toastsChanged(); +} + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/plugin/src/Caelestia/toaster.hpp b/.config/quickshell/caelestia/plugin/src/Caelestia/toaster.hpp new file mode 100644 index 0000000..1f61734 --- /dev/null +++ b/.config/quickshell/caelestia/plugin/src/Caelestia/toaster.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include +#include + +namespace caelestia { + +class Toast : public QObject { + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("Toast instances can only be retrieved from a Toaster") + + Q_PROPERTY(bool closed READ closed NOTIFY closedChanged) + Q_PROPERTY(QString title READ title CONSTANT) + Q_PROPERTY(QString message READ message CONSTANT) + Q_PROPERTY(QString icon READ icon CONSTANT) + Q_PROPERTY(int timeout READ timeout CONSTANT) + Q_PROPERTY(Type type READ type CONSTANT) + +public: + enum class Type { + Info = 0, + Success, + Warning, + Error + }; + Q_ENUM(Type) + + explicit Toast(const QString& title, const QString& message, const QString& icon, Type type, int timeout, + QObject* parent = nullptr); + + [[nodiscard]] bool closed() const; + [[nodiscard]] QString title() const; + [[nodiscard]] QString message() const; + [[nodiscard]] QString icon() const; + [[nodiscard]] int timeout() const; + [[nodiscard]] Type type() const; + + Q_INVOKABLE void close(); + Q_INVOKABLE void lock(QObject* sender); + Q_INVOKABLE void unlock(QObject* sender); + +signals: + void closedChanged(); + void finishedClose(); + +private: + QSet m_locks; + + bool m_closed; + QString m_title; + QString m_message; + QString m_icon; + Type m_type; + int m_timeout; +}; + +class Toaster : public QObject { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + + Q_PROPERTY(QQmlListProperty toasts READ toasts NOTIFY toastsChanged) + +public: + explicit Toaster(QObject* parent = nullptr); + + [[nodiscard]] QQmlListProperty toasts(); + + Q_INVOKABLE void toast(const QString& title, const QString& message, const QString& icon = QString(), + caelestia::Toast::Type type = Toast::Type::Info, int timeout = 5000); + +signals: + void toastsChanged(); + +private: + QList m_toasts; +}; + +} // namespace caelestia diff --git a/.config/quickshell/caelestia/services/Audio.qml b/.config/quickshell/caelestia/services/Audio.qml new file mode 100644 index 0000000..908d156 --- /dev/null +++ b/.config/quickshell/caelestia/services/Audio.qml @@ -0,0 +1,157 @@ +pragma Singleton + +import qs.config +import Caelestia.Services +import Caelestia +import Quickshell +import Quickshell.Services.Pipewire +import QtQuick + +Singleton { + id: root + + property string previousSinkName: "" + property string previousSourceName: "" + + readonly property var nodes: Pipewire.nodes.values.reduce((acc, node) => { + if (!node.isStream) { + if (node.isSink) + acc.sinks.push(node); + else if (node.audio) + acc.sources.push(node); + } else if (node.isStream && node.audio) { + // Application streams (output streams) + acc.streams.push(node); + } + return acc; + }, { + sources: [], + sinks: [], + streams: [] + }) + + readonly property list sinks: nodes.sinks + readonly property list sources: nodes.sources + readonly property list streams: nodes.streams + + readonly property PwNode sink: Pipewire.defaultAudioSink + readonly property PwNode source: Pipewire.defaultAudioSource + + readonly property bool muted: !!sink?.audio?.muted + readonly property real volume: sink?.audio?.volume ?? 0 + + readonly property bool sourceMuted: !!source?.audio?.muted + readonly property real sourceVolume: source?.audio?.volume ?? 0 + + readonly property alias cava: cava + readonly property alias beatTracker: beatTracker + + function setVolume(newVolume: real): void { + if (sink?.ready && sink?.audio) { + sink.audio.muted = false; + sink.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume)); + } + } + + function incrementVolume(amount: real): void { + setVolume(volume + (amount || Config.services.audioIncrement)); + } + + function decrementVolume(amount: real): void { + setVolume(volume - (amount || Config.services.audioIncrement)); + } + + function setSourceVolume(newVolume: real): void { + if (source?.ready && source?.audio) { + source.audio.muted = false; + source.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume)); + } + } + + function incrementSourceVolume(amount: real): void { + setSourceVolume(sourceVolume + (amount || Config.services.audioIncrement)); + } + + function decrementSourceVolume(amount: real): void { + setSourceVolume(sourceVolume - (amount || Config.services.audioIncrement)); + } + + function setAudioSink(newSink: PwNode): void { + Pipewire.preferredDefaultAudioSink = newSink; + } + + function setAudioSource(newSource: PwNode): void { + Pipewire.preferredDefaultAudioSource = newSource; + } + + function setStreamVolume(stream: PwNode, newVolume: real): void { + if (stream?.ready && stream?.audio) { + stream.audio.muted = false; + stream.audio.volume = Math.max(0, Math.min(Config.services.maxVolume, newVolume)); + } + } + + function setStreamMuted(stream: PwNode, muted: bool): void { + if (stream?.ready && stream?.audio) { + stream.audio.muted = muted; + } + } + + function getStreamVolume(stream: PwNode): real { + return stream?.audio?.volume ?? 0; + } + + function getStreamMuted(stream: PwNode): bool { + return !!stream?.audio?.muted; + } + + function getStreamName(stream: PwNode): string { + if (!stream) + return qsTr("Unknown"); + // Try application name first, then description, then name + return stream.applicationName || stream.description || stream.name || qsTr("Unknown Application"); + } + + onSinkChanged: { + if (!sink?.ready) + return; + + const newSinkName = sink.description || sink.name || qsTr("Unknown Device"); + + if (previousSinkName && previousSinkName !== newSinkName && Config.utilities.toasts.audioOutputChanged) + Toaster.toast(qsTr("Audio output changed"), qsTr("Now using: %1").arg(newSinkName), "volume_up"); + + previousSinkName = newSinkName; + } + + onSourceChanged: { + if (!source?.ready) + return; + + const newSourceName = source.description || source.name || qsTr("Unknown Device"); + + if (previousSourceName && previousSourceName !== newSourceName && Config.utilities.toasts.audioInputChanged) + Toaster.toast(qsTr("Audio input changed"), qsTr("Now using: %1").arg(newSourceName), "mic"); + + previousSourceName = newSourceName; + } + + Component.onCompleted: { + previousSinkName = sink?.description || sink?.name || qsTr("Unknown Device"); + previousSourceName = source?.description || source?.name || qsTr("Unknown Device"); + } + + PwObjectTracker { + objects: [...root.sinks, ...root.sources, ...root.streams] + } + + CavaProvider { + id: cava + + bars: Config.services.visualiserBars + } + + BeatTracker { + id: beatTracker + } +} diff --git a/.config/quickshell/caelestia/services/Brightness.qml b/.config/quickshell/caelestia/services/Brightness.qml new file mode 100644 index 0000000..12920ee --- /dev/null +++ b/.config/quickshell/caelestia/services/Brightness.qml @@ -0,0 +1,226 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import qs.config +import qs.components.misc +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + property list ddcMonitors: [] + readonly property list monitors: variants.instances + property bool appleDisplayPresent: false + + function getMonitorForScreen(screen: ShellScreen): var { + return monitors.find(m => m.modelData === screen); + } + + function getMonitor(query: string): var { + if (query === "active") { + return monitors.find(m => Hypr.monitorFor(m.modelData)?.focused); + } + + if (query.startsWith("model:")) { + const model = query.slice(6); + return monitors.find(m => m.modelData.model === model); + } + + if (query.startsWith("serial:")) { + const serial = query.slice(7); + return monitors.find(m => m.modelData.serialNumber === serial); + } + + if (query.startsWith("id:")) { + const id = parseInt(query.slice(3), 10); + return monitors.find(m => Hypr.monitorFor(m.modelData)?.id === id); + } + + return monitors.find(m => m.modelData.name === query); + } + + function increaseBrightness(): void { + const monitor = getMonitor("active"); + if (monitor) + monitor.setBrightness(monitor.brightness + Config.services.brightnessIncrement); + } + + function decreaseBrightness(): void { + const monitor = getMonitor("active"); + if (monitor) + monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement); + } + + onMonitorsChanged: { + ddcMonitors = []; + ddcProc.running = true; + } + + Variants { + id: variants + + model: Quickshell.screens + + Monitor {} + } + + Process { + running: true + command: ["sh", "-c", "asdbctl get"] // To avoid warnings if asdbctl is not installed + stdout: StdioCollector { + onStreamFinished: root.appleDisplayPresent = text.trim().length > 0 + } + } + + Process { + id: ddcProc + + command: ["ddcutil", "detect", "--brief"] + stdout: StdioCollector { + onStreamFinished: root.ddcMonitors = text.trim().split("\n\n").filter(d => d.startsWith("Display ")).map(d => ({ + busNum: d.match(/I2C bus:[ ]*\/dev\/i2c-([0-9]+)/)[1], + connector: d.match(/DRM connector:\s+(.*)/)[1].replace(/^card\d+-/, "") // strip "card1-" + })) + } + } + + CustomShortcut { + name: "brightnessUp" + description: "Increase brightness" + onPressed: root.increaseBrightness() + } + + CustomShortcut { + name: "brightnessDown" + description: "Decrease brightness" + onPressed: root.decreaseBrightness() + } + + IpcHandler { + target: "brightness" + + function get(): real { + return getFor("active"); + } + + // Allows searching by active/model/serial/id/name + function getFor(query: string): real { + return root.getMonitor(query)?.brightness ?? -1; + } + + function set(value: string): string { + return setFor("active", value); + } + + // Handles brightness value like brightnessctl: 0.1, +0.1, 0.1-, 10%, +10%, 10%- + function setFor(query: string, value: string): string { + const monitor = root.getMonitor(query); + if (!monitor) + return "Invalid monitor: " + query; + + let targetBrightness; + if (value.endsWith("%-")) { + const percent = parseFloat(value.slice(0, -2)); + targetBrightness = monitor.brightness - (percent / 100); + } else if (value.startsWith("+") && value.endsWith("%")) { + const percent = parseFloat(value.slice(1, -1)); + targetBrightness = monitor.brightness + (percent / 100); + } else if (value.endsWith("%")) { + const percent = parseFloat(value.slice(0, -1)); + targetBrightness = percent / 100; + } else if (value.startsWith("+")) { + const increment = parseFloat(value.slice(1)); + targetBrightness = monitor.brightness + increment; + } else if (value.endsWith("-")) { + const decrement = parseFloat(value.slice(0, -1)); + targetBrightness = monitor.brightness - decrement; + } else if (value.includes("%") || value.includes("-") || value.includes("+")) { + return `Invalid brightness format: ${value}\nExpected: 0.1, +0.1, 0.1-, 10%, +10%, 10%-`; + } else { + targetBrightness = parseFloat(value); + } + + if (isNaN(targetBrightness)) + return `Failed to parse value: ${value}\nExpected: 0.1, +0.1, 0.1-, 10%, +10%, 10%-`; + + monitor.setBrightness(targetBrightness); + + return `Set monitor ${monitor.modelData.name} brightness to ${+monitor.brightness.toFixed(2)}`; + } + } + + component Monitor: QtObject { + id: monitor + + required property ShellScreen modelData + readonly property bool isDdc: root.ddcMonitors.some(m => m.connector === modelData.name) + readonly property string busNum: root.ddcMonitors.find(m => m.connector === modelData.name)?.busNum ?? "" + readonly property bool isAppleDisplay: root.appleDisplayPresent && modelData.model.startsWith("StudioDisplay") + property real brightness + property real queuedBrightness: NaN + + readonly property Process initProc: Process { + stdout: StdioCollector { + onStreamFinished: { + if (monitor.isAppleDisplay) { + const val = parseInt(text.trim()); + monitor.brightness = val / 101; + } else { + const [, , , cur, max] = text.split(" "); + monitor.brightness = parseInt(cur) / parseInt(max); + } + } + } + } + + readonly property Timer timer: Timer { + interval: 500 + onTriggered: { + if (!isNaN(monitor.queuedBrightness)) { + monitor.setBrightness(monitor.queuedBrightness); + monitor.queuedBrightness = NaN; + } + } + } + + function setBrightness(value: real): void { + value = Math.max(0, Math.min(1, value)); + const rounded = Math.round(value * 100); + if (Math.round(brightness * 100) === rounded) + return; + + if (isDdc && timer.running) { + queuedBrightness = value; + return; + } + + brightness = value; + + if (isAppleDisplay) + Quickshell.execDetached(["asdbctl", "set", rounded]); + else if (isDdc) + Quickshell.execDetached(["ddcutil", "-b", busNum, "setvcp", "10", rounded]); + else + Quickshell.execDetached(["brightnessctl", "s", `${rounded}%`]); + + if (isDdc) + timer.restart(); + } + + function initBrightness(): void { + if (isAppleDisplay) + initProc.command = ["asdbctl", "get"]; + else if (isDdc) + initProc.command = ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"]; + else + initProc.command = ["sh", "-c", "echo a b c $(brightnessctl g) $(brightnessctl m)"]; + + initProc.running = true; + } + + onBusNumChanged: initBrightness() + Component.onCompleted: initBrightness() + } +} diff --git a/.config/quickshell/caelestia/services/Colours.qml b/.config/quickshell/caelestia/services/Colours.qml new file mode 100644 index 0000000..cd86c8f --- /dev/null +++ b/.config/quickshell/caelestia/services/Colours.qml @@ -0,0 +1,237 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import qs.config +import qs.utils +import Caelestia +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + property bool showPreview + property string scheme + property string flavour + readonly property bool light: showPreview ? previewLight : currentLight + property bool currentLight + property bool previewLight + readonly property M3Palette palette: showPreview ? preview : current + readonly property M3TPalette tPalette: M3TPalette {} + readonly property M3Palette current: M3Palette {} + readonly property M3Palette preview: M3Palette {} + readonly property Transparency transparency: Transparency {} + readonly property alias wallLuminance: analyser.luminance + + function getLuminance(c: color): real { + if (c.r == 0 && c.g == 0 && c.b == 0) + return 0; + return Math.sqrt(0.299 * (c.r ** 2) + 0.587 * (c.g ** 2) + 0.114 * (c.b ** 2)); + } + + function alterColour(c: color, a: real, layer: int): color { + const luminance = getLuminance(c); + + const offset = (!light || layer == 1 ? 1 : -layer / 2) * (light ? 0.2 : 0.3) * (1 - transparency.base) * (1 + wallLuminance * (light ? (layer == 1 ? 3 : 1) : 2.5)); + const scale = (luminance + offset) / luminance; + const r = Math.max(0, Math.min(1, c.r * scale)); + const g = Math.max(0, Math.min(1, c.g * scale)); + const b = Math.max(0, Math.min(1, c.b * scale)); + + return Qt.rgba(r, g, b, a); + } + + function layer(c: color, layer: var): color { + if (!transparency.enabled) + return c; + + return layer === 0 ? Qt.alpha(c, transparency.base) : alterColour(c, transparency.layers, layer ?? 1); + } + + function on(c: color): color { + if (c.hslLightness < 0.5) + return Qt.hsla(c.hslHue, c.hslSaturation, 0.9, 1); + return Qt.hsla(c.hslHue, c.hslSaturation, 0.1, 1); + } + + function load(data: string, isPreview: bool): void { + const colours = isPreview ? preview : current; + const scheme = JSON.parse(data); + + if (!isPreview) { + root.scheme = scheme.name; + flavour = scheme.flavour; + currentLight = scheme.mode === "light"; + } else { + previewLight = scheme.mode === "light"; + } + + for (const [name, colour] of Object.entries(scheme.colours)) { + const propName = name.startsWith("term") ? name : `m3${name}`; + if (colours.hasOwnProperty(propName)) + colours[propName] = `#${colour}`; + } + } + + function setMode(mode: string): void { + Quickshell.execDetached(["caelestia", "scheme", "set", "--notify", "-m", mode]); + } + + FileView { + path: `${Paths.state}/scheme.json` + watchChanges: true + onFileChanged: reload() + onLoaded: root.load(text(), false) + } + + ImageAnalyser { + id: analyser + + source: Wallpapers.current + } + + component Transparency: QtObject { + readonly property bool enabled: Appearance.transparency.enabled + readonly property real base: Appearance.transparency.base - (root.light ? 0.1 : 0) + readonly property real layers: Appearance.transparency.layers + } + + component M3TPalette: QtObject { + readonly property color m3primary_paletteKeyColor: root.layer(root.palette.m3primary_paletteKeyColor) + readonly property color m3secondary_paletteKeyColor: root.layer(root.palette.m3secondary_paletteKeyColor) + readonly property color m3tertiary_paletteKeyColor: root.layer(root.palette.m3tertiary_paletteKeyColor) + readonly property color m3neutral_paletteKeyColor: root.layer(root.palette.m3neutral_paletteKeyColor) + readonly property color m3neutral_variant_paletteKeyColor: root.layer(root.palette.m3neutral_variant_paletteKeyColor) + readonly property color m3background: root.layer(root.palette.m3background, 0) + readonly property color m3onBackground: root.layer(root.palette.m3onBackground) + readonly property color m3surface: root.layer(root.palette.m3surface, 0) + readonly property color m3surfaceDim: root.layer(root.palette.m3surfaceDim, 0) + readonly property color m3surfaceBright: root.layer(root.palette.m3surfaceBright, 0) + readonly property color m3surfaceContainerLowest: root.layer(root.palette.m3surfaceContainerLowest) + readonly property color m3surfaceContainerLow: root.layer(root.palette.m3surfaceContainerLow) + readonly property color m3surfaceContainer: root.layer(root.palette.m3surfaceContainer) + readonly property color m3surfaceContainerHigh: root.layer(root.palette.m3surfaceContainerHigh) + readonly property color m3surfaceContainerHighest: root.layer(root.palette.m3surfaceContainerHighest) + readonly property color m3onSurface: root.layer(root.palette.m3onSurface) + readonly property color m3surfaceVariant: root.layer(root.palette.m3surfaceVariant, 0) + readonly property color m3onSurfaceVariant: root.layer(root.palette.m3onSurfaceVariant) + readonly property color m3inverseSurface: root.layer(root.palette.m3inverseSurface, 0) + readonly property color m3inverseOnSurface: root.layer(root.palette.m3inverseOnSurface) + readonly property color m3outline: root.layer(root.palette.m3outline) + readonly property color m3outlineVariant: root.layer(root.palette.m3outlineVariant) + readonly property color m3shadow: root.layer(root.palette.m3shadow) + readonly property color m3scrim: root.layer(root.palette.m3scrim) + readonly property color m3surfaceTint: root.layer(root.palette.m3surfaceTint) + readonly property color m3primary: root.layer(root.palette.m3primary) + readonly property color m3onPrimary: root.layer(root.palette.m3onPrimary) + readonly property color m3primaryContainer: root.layer(root.palette.m3primaryContainer) + readonly property color m3onPrimaryContainer: root.layer(root.palette.m3onPrimaryContainer) + readonly property color m3inversePrimary: root.layer(root.palette.m3inversePrimary) + readonly property color m3secondary: root.layer(root.palette.m3secondary) + readonly property color m3onSecondary: root.layer(root.palette.m3onSecondary) + readonly property color m3secondaryContainer: root.layer(root.palette.m3secondaryContainer) + readonly property color m3onSecondaryContainer: root.layer(root.palette.m3onSecondaryContainer) + readonly property color m3tertiary: root.layer(root.palette.m3tertiary) + readonly property color m3onTertiary: root.layer(root.palette.m3onTertiary) + readonly property color m3tertiaryContainer: root.layer(root.palette.m3tertiaryContainer) + readonly property color m3onTertiaryContainer: root.layer(root.palette.m3onTertiaryContainer) + readonly property color m3error: root.layer(root.palette.m3error) + readonly property color m3onError: root.layer(root.palette.m3onError) + readonly property color m3errorContainer: root.layer(root.palette.m3errorContainer) + readonly property color m3onErrorContainer: root.layer(root.palette.m3onErrorContainer) + readonly property color m3success: root.layer(root.palette.m3success) + readonly property color m3onSuccess: root.layer(root.palette.m3onSuccess) + readonly property color m3successContainer: root.layer(root.palette.m3successContainer) + readonly property color m3onSuccessContainer: root.layer(root.palette.m3onSuccessContainer) + readonly property color m3primaryFixed: root.layer(root.palette.m3primaryFixed) + readonly property color m3primaryFixedDim: root.layer(root.palette.m3primaryFixedDim) + readonly property color m3onPrimaryFixed: root.layer(root.palette.m3onPrimaryFixed) + readonly property color m3onPrimaryFixedVariant: root.layer(root.palette.m3onPrimaryFixedVariant) + readonly property color m3secondaryFixed: root.layer(root.palette.m3secondaryFixed) + readonly property color m3secondaryFixedDim: root.layer(root.palette.m3secondaryFixedDim) + readonly property color m3onSecondaryFixed: root.layer(root.palette.m3onSecondaryFixed) + readonly property color m3onSecondaryFixedVariant: root.layer(root.palette.m3onSecondaryFixedVariant) + readonly property color m3tertiaryFixed: root.layer(root.palette.m3tertiaryFixed) + readonly property color m3tertiaryFixedDim: root.layer(root.palette.m3tertiaryFixedDim) + readonly property color m3onTertiaryFixed: root.layer(root.palette.m3onTertiaryFixed) + readonly property color m3onTertiaryFixedVariant: root.layer(root.palette.m3onTertiaryFixedVariant) + } + + component M3Palette: QtObject { + property color m3primary_paletteKeyColor: "#a8627b" + property color m3secondary_paletteKeyColor: "#8e6f78" + property color m3tertiary_paletteKeyColor: "#986e4c" + property color m3neutral_paletteKeyColor: "#807477" + property color m3neutral_variant_paletteKeyColor: "#837377" + property color m3background: "#191114" + property color m3onBackground: "#efdfe2" + property color m3surface: "#191114" + property color m3surfaceDim: "#191114" + property color m3surfaceBright: "#403739" + property color m3surfaceContainerLowest: "#130c0e" + property color m3surfaceContainerLow: "#22191c" + property color m3surfaceContainer: "#261d20" + property color m3surfaceContainerHigh: "#31282a" + property color m3surfaceContainerHighest: "#3c3235" + property color m3onSurface: "#efdfe2" + property color m3surfaceVariant: "#514347" + property color m3onSurfaceVariant: "#d5c2c6" + property color m3inverseSurface: "#efdfe2" + property color m3inverseOnSurface: "#372e30" + property color m3outline: "#9e8c91" + property color m3outlineVariant: "#514347" + property color m3shadow: "#000000" + property color m3scrim: "#000000" + property color m3surfaceTint: "#ffb0ca" + property color m3primary: "#ffb0ca" + property color m3onPrimary: "#541d34" + property color m3primaryContainer: "#6f334a" + property color m3onPrimaryContainer: "#ffd9e3" + property color m3inversePrimary: "#8b4a62" + property color m3secondary: "#e2bdc7" + property color m3onSecondary: "#422932" + property color m3secondaryContainer: "#5a3f48" + property color m3onSecondaryContainer: "#ffd9e3" + property color m3tertiary: "#f0bc95" + property color m3onTertiary: "#48290c" + property color m3tertiaryContainer: "#b58763" + property color m3onTertiaryContainer: "#000000" + property color m3error: "#ffb4ab" + property color m3onError: "#690005" + property color m3errorContainer: "#93000a" + property color m3onErrorContainer: "#ffdad6" + property color m3success: "#B5CCBA" + property color m3onSuccess: "#213528" + property color m3successContainer: "#374B3E" + property color m3onSuccessContainer: "#D1E9D6" + property color m3primaryFixed: "#ffd9e3" + property color m3primaryFixedDim: "#ffb0ca" + property color m3onPrimaryFixed: "#39071f" + property color m3onPrimaryFixedVariant: "#6f334a" + property color m3secondaryFixed: "#ffd9e3" + property color m3secondaryFixedDim: "#e2bdc7" + property color m3onSecondaryFixed: "#2b151d" + property color m3onSecondaryFixedVariant: "#5a3f48" + property color m3tertiaryFixed: "#ffdcc3" + property color m3tertiaryFixedDim: "#f0bc95" + property color m3onTertiaryFixed: "#2f1500" + property color m3onTertiaryFixedVariant: "#623f21" + property color term0: "#353434" + property color term1: "#ff4c8a" + property color term2: "#ffbbb7" + property color term3: "#ffdedf" + property color term4: "#b3a2d5" + property color term5: "#e98fb0" + property color term6: "#ffba93" + property color term7: "#eed1d2" + property color term8: "#b39e9e" + property color term9: "#ff80a3" + property color term10: "#ffd3d0" + property color term11: "#fff1f0" + property color term12: "#dcbc93" + property color term13: "#f9a8c2" + property color term14: "#ffd1c0" + property color term15: "#ffffff" + } +} diff --git a/.config/quickshell/caelestia/services/GameMode.qml b/.config/quickshell/caelestia/services/GameMode.qml new file mode 100644 index 0000000..83770b7 --- /dev/null +++ b/.config/quickshell/caelestia/services/GameMode.qml @@ -0,0 +1,76 @@ +pragma Singleton + +import qs.services +import qs.config +import Caelestia +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + property alias enabled: props.enabled + + function setDynamicConfs(): void { + Hypr.extras.applyOptions({ + "animations:enabled": 0, + "decoration:shadow:enabled": 0, + "decoration:blur:enabled": 0, + "general:gaps_in": 0, + "general:gaps_out": 0, + "general:border_size": 1, + "decoration:rounding": 0, + "general:allow_tearing": 1 + }); + } + + onEnabledChanged: { + if (enabled) { + setDynamicConfs(); + if (Config.utilities.toasts.gameModeChanged) + Toaster.toast(qsTr("Game mode enabled"), qsTr("Disabled Hyprland animations, blur, gaps and shadows"), "gamepad"); + } else { + Hypr.extras.message("reload"); + if (Config.utilities.toasts.gameModeChanged) + Toaster.toast(qsTr("Game mode disabled"), qsTr("Hyprland settings restored"), "gamepad"); + } + } + + PersistentProperties { + id: props + + property bool enabled: Hypr.options["animations:enabled"] === 0 + + reloadableId: "gameMode" + } + + Connections { + target: Hypr + + function onConfigReloaded(): void { + if (props.enabled) + root.setDynamicConfs(); + } + } + + IpcHandler { + target: "gameMode" + + function isEnabled(): bool { + return props.enabled; + } + + function toggle(): void { + props.enabled = !props.enabled; + } + + function enable(): void { + props.enabled = true; + } + + function disable(): void { + props.enabled = false; + } + } +} diff --git a/.config/quickshell/caelestia/services/Hypr.qml b/.config/quickshell/caelestia/services/Hypr.qml new file mode 100644 index 0000000..a26c24d --- /dev/null +++ b/.config/quickshell/caelestia/services/Hypr.qml @@ -0,0 +1,213 @@ +pragma Singleton + +import qs.components.misc +import qs.config +import Caelestia +import Caelestia.Internal +import Quickshell +import Quickshell.Hyprland +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + readonly property var toplevels: Hyprland.toplevels + readonly property var workspaces: Hyprland.workspaces + readonly property var monitors: Hyprland.monitors + + readonly property HyprlandToplevel activeToplevel: Hyprland.activeToplevel?.wayland?.activated ? Hyprland.activeToplevel : null + readonly property HyprlandWorkspace focusedWorkspace: Hyprland.focusedWorkspace + readonly property HyprlandMonitor focusedMonitor: Hyprland.focusedMonitor + readonly property int activeWsId: focusedWorkspace?.id ?? 1 + + readonly property HyprKeyboard keyboard: extras.devices.keyboards.find(kb => kb.main) ?? null + readonly property bool capsLock: keyboard?.capsLock ?? false + readonly property bool numLock: keyboard?.numLock ?? false + readonly property string defaultKbLayout: keyboard?.layout.split(",")[0] ?? "??" + readonly property string kbLayoutFull: keyboard?.activeKeymap ?? "Unknown" + readonly property string kbLayout: kbMap.get(kbLayoutFull) ?? "??" + readonly property var kbMap: new Map() + + readonly property alias extras: extras + readonly property alias options: extras.options + readonly property alias devices: extras.devices + + property bool hadKeyboard + property string lastSpecialWorkspace: "" + + signal configReloaded + + function dispatch(request: string): void { + Hyprland.dispatch(request); + } + + function cycleSpecialWorkspace(direction: string): void { + const openSpecials = workspaces.values.filter(w => w.name.startsWith("special:") && w.lastIpcObject.windows > 0); + + if (openSpecials.length === 0) + return; + + const activeSpecial = focusedMonitor.lastIpcObject.specialWorkspace.name ?? ""; + + if (!activeSpecial) { + if (lastSpecialWorkspace) { + const workspace = workspaces.values.find(w => w.name === lastSpecialWorkspace); + if (workspace && workspace.lastIpcObject.windows > 0) { + dispatch(`workspace ${lastSpecialWorkspace}`); + return; + } + } + dispatch(`workspace ${openSpecials[0].name}`); + return; + } + + const currentIndex = openSpecials.findIndex(w => w.name === activeSpecial); + let nextIndex = 0; + + if (currentIndex !== -1) { + if (direction === "next") + nextIndex = (currentIndex + 1) % openSpecials.length; + else + nextIndex = (currentIndex - 1 + openSpecials.length) % openSpecials.length; + } + + dispatch(`workspace ${openSpecials[nextIndex].name}`); + } + + function monitorFor(screen: ShellScreen): HyprlandMonitor { + return Hyprland.monitorFor(screen); + } + + function reloadDynamicConfs(): void { + extras.batchMessage(["keyword bindlni ,Caps_Lock,global,caelestia:refreshDevices", "keyword bindlni ,Num_Lock,global,caelestia:refreshDevices"]); + } + + Component.onCompleted: reloadDynamicConfs() + + onCapsLockChanged: { + if (!Config.utilities.toasts.capsLockChanged) + return; + + if (capsLock) + Toaster.toast(qsTr("Caps lock enabled"), qsTr("Caps lock is currently enabled"), "keyboard_capslock_badge"); + else + Toaster.toast(qsTr("Caps lock disabled"), qsTr("Caps lock is currently disabled"), "keyboard_capslock"); + } + + onNumLockChanged: { + if (!Config.utilities.toasts.numLockChanged) + return; + + if (numLock) + Toaster.toast(qsTr("Num lock enabled"), qsTr("Num lock is currently enabled"), "looks_one"); + else + Toaster.toast(qsTr("Num lock disabled"), qsTr("Num lock is currently disabled"), "timer_1"); + } + + onKbLayoutFullChanged: { + if (hadKeyboard && Config.utilities.toasts.kbLayoutChanged) + Toaster.toast(qsTr("Keyboard layout changed"), qsTr("Layout changed to: %1").arg(kbLayoutFull), "keyboard"); + + hadKeyboard = !!keyboard; + } + + Connections { + target: Hyprland + + function onRawEvent(event: HyprlandEvent): void { + const n = event.name; + if (n.endsWith("v2")) + return; + + if (n === "configreloaded") { + root.configReloaded(); + root.reloadDynamicConfs(); + } else if (["workspace", "moveworkspace", "activespecial", "focusedmon"].includes(n)) { + Hyprland.refreshWorkspaces(); + Hyprland.refreshMonitors(); + } else if (["openwindow", "closewindow", "movewindow"].includes(n)) { + Hyprland.refreshToplevels(); + Hyprland.refreshWorkspaces(); + } else if (n.includes("mon")) { + Hyprland.refreshMonitors(); + } else if (n.includes("workspace")) { + Hyprland.refreshWorkspaces(); + } else if (n.includes("window") || n.includes("group") || ["pin", "fullscreen", "changefloatingmode", "minimize"].includes(n)) { + Hyprland.refreshToplevels(); + } + } + } + + Connections { + target: root.focusedMonitor + + function onLastIpcObjectChanged(): void { + const specialName = root.focusedMonitor.lastIpcObject.specialWorkspace.name; + + if (specialName && specialName.startsWith("special:")) { + root.lastSpecialWorkspace = specialName; + } + } + } + + FileView { + id: kbLayoutFile + + path: Quickshell.env("CAELESTIA_XKB_RULES_PATH") || "/usr/share/X11/xkb/rules/base.lst" + onLoaded: { + const layoutMatch = text().match(/! layout\n([\s\S]*?)\n\n/); + if (layoutMatch) { + const lines = layoutMatch[1].split("\n"); + for (const line of lines) { + if (!line.trim() || line.trim().startsWith("!")) + continue; + + const match = line.match(/^\s*([a-z]{2,})\s+([a-zA-Z() ]+)$/); + if (match) + root.kbMap.set(match[2], match[1]); + } + } + + const variantMatch = text().match(/! variant\n([\s\S]*?)\n\n/); + if (variantMatch) { + const lines = variantMatch[1].split("\n"); + for (const line of lines) { + if (!line.trim() || line.trim().startsWith("!")) + continue; + + const match = line.match(/^\s*([a-zA-Z0-9_-]+)\s+([a-z]{2,}): (.+)$/); + if (match) + root.kbMap.set(match[3], match[2]); + } + } + } + } + + IpcHandler { + target: "hypr" + + function refreshDevices(): void { + extras.refreshDevices(); + } + + function cycleSpecialWorkspace(direction: string): void { + root.cycleSpecialWorkspace(direction); + } + + function listSpecialWorkspaces(): string { + return root.workspaces.values.filter(w => w.name.startsWith("special:") && w.lastIpcObject.windows > 0).map(w => w.name).join("\n"); + } + } + + CustomShortcut { + name: "refreshDevices" + description: "Reload devices" + onPressed: extras.refreshDevices() + onReleased: extras.refreshDevices() + } + + HyprExtras { + id: extras + } +} diff --git a/.config/quickshell/caelestia/services/IdleInhibitor.qml b/.config/quickshell/caelestia/services/IdleInhibitor.qml new file mode 100644 index 0000000..29409ab --- /dev/null +++ b/.config/quickshell/caelestia/services/IdleInhibitor.qml @@ -0,0 +1,56 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import Quickshell.Wayland + +Singleton { + id: root + + property alias enabled: props.enabled + readonly property alias enabledSince: props.enabledSince + + onEnabledChanged: { + if (enabled) + props.enabledSince = new Date(); + } + + PersistentProperties { + id: props + + property bool enabled + property date enabledSince + + reloadableId: "idleInhibitor" + } + + IdleInhibitor { + enabled: props.enabled + window: PanelWindow { + implicitWidth: 0 + implicitHeight: 0 + color: "transparent" + mask: Region {} + } + } + + IpcHandler { + target: "idleInhibitor" + + function isEnabled(): bool { + return props.enabled; + } + + function toggle(): void { + props.enabled = !props.enabled; + } + + function enable(): void { + props.enabled = true; + } + + function disable(): void { + props.enabled = false; + } + } +} diff --git a/.config/quickshell/caelestia/services/Network.qml b/.config/quickshell/caelestia/services/Network.qml new file mode 100644 index 0000000..f3dfc3e --- /dev/null +++ b/.config/quickshell/caelestia/services/Network.qml @@ -0,0 +1,324 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import QtQuick +import qs.services + +Singleton { + id: root + + Component.onCompleted: { + // Trigger ethernet device detection after initialization + Qt.callLater(() => { + getEthernetDevices(); + }); + // Load saved connections on startup + Nmcli.loadSavedConnections(() => { + root.savedConnections = Nmcli.savedConnections; + root.savedConnectionSsids = Nmcli.savedConnectionSsids; + }); + // Get initial WiFi status + Nmcli.getWifiStatus(enabled => { + root.wifiEnabled = enabled; + }); + // Sync networks from Nmcli on startup + Qt.callLater(() => { + syncNetworksFromNmcli(); + }, 100); + } + + readonly property list networks: [] + readonly property AccessPoint active: networks.find(n => n.active) ?? null + property bool wifiEnabled: true + readonly property bool scanning: Nmcli.scanning + + property list ethernetDevices: [] + readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null + property int ethernetDeviceCount: 0 + property bool ethernetProcessRunning: false + property var ethernetDeviceDetails: null + property var wirelessDeviceDetails: null + + function enableWifi(enabled: bool): void { + Nmcli.enableWifi(enabled, result => { + if (result.success) { + root.getWifiStatus(); + Nmcli.getNetworks(() => { + syncNetworksFromNmcli(); + }); + } + }); + } + + function toggleWifi(): void { + Nmcli.toggleWifi(result => { + if (result.success) { + root.getWifiStatus(); + Nmcli.getNetworks(() => { + syncNetworksFromNmcli(); + }); + } + }); + } + + function rescanWifi(): void { + Nmcli.rescanWifi(); + } + + property var pendingConnection: null + signal connectionFailed(string ssid) + + function connectToNetwork(ssid: string, password: string, bssid: string, callback: var): void { + // Set up pending connection tracking if callback provided + if (callback) { + const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0; + root.pendingConnection = { + ssid: ssid, + bssid: hasBssid ? bssid : "", + callback: callback + }; + } + + Nmcli.connectToNetwork(ssid, password, bssid, result => { + if (result && result.success) { + // Connection successful + if (callback) + callback(result); + root.pendingConnection = null; + } else if (result && result.needsPassword) { + // Password needed - callback will handle showing dialog + if (callback) + callback(result); + } else { + // Connection failed + if (result && result.error) { + root.connectionFailed(ssid); + } + if (callback) + callback(result); + root.pendingConnection = null; + } + }); + } + + function connectToNetworkWithPasswordCheck(ssid: string, isSecure: bool, callback: var, bssid: string): void { + // Set up pending connection tracking + const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0; + root.pendingConnection = { + ssid: ssid, + bssid: hasBssid ? bssid : "", + callback: callback + }; + + Nmcli.connectToNetworkWithPasswordCheck(ssid, isSecure, result => { + if (result && result.success) { + // Connection successful + if (callback) + callback(result); + root.pendingConnection = null; + } else if (result && result.needsPassword) { + // Password needed - callback will handle showing dialog + if (callback) + callback(result); + } else { + // Connection failed + if (result && result.error) { + root.connectionFailed(ssid); + } + if (callback) + callback(result); + root.pendingConnection = null; + } + }, bssid); + } + + function disconnectFromNetwork(): void { + // Try to disconnect - use connection name if available, otherwise use device + Nmcli.disconnectFromNetwork(); + // Refresh network list after disconnection + Qt.callLater(() => { + Nmcli.getNetworks(() => { + syncNetworksFromNmcli(); + }); + }, 500); + } + + function forgetNetwork(ssid: string): void { + // Delete the connection profile for this network + // This will remove the saved password and connection settings + Nmcli.forgetNetwork(ssid, result => { + if (result.success) { + // Refresh network list after deletion + Qt.callLater(() => { + Nmcli.getNetworks(() => { + syncNetworksFromNmcli(); + }); + }, 500); + } + }); + } + + property list savedConnections: [] + property list savedConnectionSsids: [] + + // Sync saved connections from Nmcli when they're updated + Connections { + target: Nmcli + function onSavedConnectionsChanged() { + root.savedConnections = Nmcli.savedConnections; + } + function onSavedConnectionSsidsChanged() { + root.savedConnectionSsids = Nmcli.savedConnectionSsids; + } + } + + function syncNetworksFromNmcli(): void { + const rNetworks = root.networks; + const nNetworks = Nmcli.networks; + + // Build a map of existing networks by key + const existingMap = new Map(); + for (const rn of rNetworks) { + const key = `${rn.frequency}:${rn.ssid}:${rn.bssid}`; + existingMap.set(key, rn); + } + + // Build a map of new networks by key + const newMap = new Map(); + for (const nn of nNetworks) { + const key = `${nn.frequency}:${nn.ssid}:${nn.bssid}`; + newMap.set(key, nn); + } + + // Remove networks that no longer exist + for (const [key, network] of existingMap) { + if (!newMap.has(key)) { + const index = rNetworks.indexOf(network); + if (index >= 0) { + rNetworks.splice(index, 1); + network.destroy(); + } + } + } + + // Add or update networks from Nmcli + for (const [key, nNetwork] of newMap) { + const existing = existingMap.get(key); + if (existing) { + // Update existing network's lastIpcObject + existing.lastIpcObject = nNetwork.lastIpcObject; + } else { + // Create new AccessPoint from Nmcli's data + rNetworks.push(apComp.createObject(root, { + lastIpcObject: nNetwork.lastIpcObject + })); + } + } + } + + component AccessPoint: QtObject { + required property var lastIpcObject + readonly property string ssid: lastIpcObject.ssid + readonly property string bssid: lastIpcObject.bssid + readonly property int strength: lastIpcObject.strength + readonly property int frequency: lastIpcObject.frequency + readonly property bool active: lastIpcObject.active + readonly property string security: lastIpcObject.security + readonly property bool isSecure: security.length > 0 + } + + Component { + id: apComp + AccessPoint {} + } + + function hasSavedProfile(ssid: string): bool { + // Use Nmcli's hasSavedProfile which has the same logic + return Nmcli.hasSavedProfile(ssid); + } + + function getWifiStatus(): void { + Nmcli.getWifiStatus(enabled => { + root.wifiEnabled = enabled; + }); + } + + function getEthernetDevices(): void { + root.ethernetProcessRunning = true; + Nmcli.getEthernetInterfaces(interfaces => { + root.ethernetDevices = Nmcli.ethernetDevices; + root.ethernetDeviceCount = Nmcli.ethernetDevices.length; + root.ethernetProcessRunning = false; + }); + } + + function connectEthernet(connectionName: string, interfaceName: string): void { + Nmcli.connectEthernet(connectionName, interfaceName, result => { + if (result.success) { + getEthernetDevices(); + // Refresh device details after connection + Qt.callLater(() => { + const activeDevice = root.ethernetDevices.find(function (d) { + return d.connected; + }); + if (activeDevice && activeDevice.interface) { + updateEthernetDeviceDetails(activeDevice.interface); + } + }, 1000); + } + }); + } + + function disconnectEthernet(connectionName: string): void { + Nmcli.disconnectEthernet(connectionName, result => { + if (result.success) { + getEthernetDevices(); + // Clear device details after disconnection + Qt.callLater(() => { + root.ethernetDeviceDetails = null; + }); + } + }); + } + + function updateEthernetDeviceDetails(interfaceName: string): void { + Nmcli.getEthernetDeviceDetails(interfaceName, details => { + root.ethernetDeviceDetails = details; + }); + } + + function updateWirelessDeviceDetails(): void { + // Find the wireless interface by looking for wifi devices + // Pass empty string to let Nmcli find the active interface automatically + Nmcli.getWirelessDeviceDetails("", details => { + root.wirelessDeviceDetails = details; + }); + } + + function cidrToSubnetMask(cidr: string): string { + // Convert CIDR notation (e.g., "24") to subnet mask (e.g., "255.255.255.0") + const cidrNum = parseInt(cidr); + if (isNaN(cidrNum) || cidrNum < 0 || cidrNum > 32) { + return ""; + } + + const mask = (0xffffffff << (32 - cidrNum)) >>> 0; + const octets = [(mask >>> 24) & 0xff, (mask >>> 16) & 0xff, (mask >>> 8) & 0xff, mask & 0xff]; + + return octets.join("."); + } + + Process { + running: true + command: ["nmcli", "m"] + stdout: SplitParser { + onRead: { + Nmcli.getNetworks(() => { + syncNetworksFromNmcli(); + }); + getEthernetDevices(); + } + } + } +} diff --git a/.config/quickshell/caelestia/services/NetworkUsage.qml b/.config/quickshell/caelestia/services/NetworkUsage.qml new file mode 100644 index 0000000..502ec3a --- /dev/null +++ b/.config/quickshell/caelestia/services/NetworkUsage.qml @@ -0,0 +1,233 @@ +pragma Singleton + +import qs.config + +import Quickshell +import Quickshell.Io + +import QtQuick + +Singleton { + id: root + + property int refCount: 0 + + // Current speeds in bytes per second + readonly property real downloadSpeed: _downloadSpeed + readonly property real uploadSpeed: _uploadSpeed + + // Total bytes transferred since tracking started + readonly property real downloadTotal: _downloadTotal + readonly property real uploadTotal: _uploadTotal + + // History of speeds for sparkline (most recent at end) + readonly property var downloadHistory: _downloadHistory + readonly property var uploadHistory: _uploadHistory + readonly property int historyLength: 30 + + // Private properties + property real _downloadSpeed: 0 + property real _uploadSpeed: 0 + property real _downloadTotal: 0 + property real _uploadTotal: 0 + property var _downloadHistory: [] + property var _uploadHistory: [] + + // Previous readings for calculating speed + property real _prevRxBytes: 0 + property real _prevTxBytes: 0 + property real _prevTimestamp: 0 + + // Initial readings for calculating totals + property real _initialRxBytes: 0 + property real _initialTxBytes: 0 + property bool _initialized: false + + function formatBytes(bytes: real): var { + // Handle negative or invalid values + if (bytes < 0 || isNaN(bytes) || !isFinite(bytes)) { + return { + value: 0, + unit: "B/s" + }; + } + + if (bytes < 1024) { + return { + value: bytes, + unit: "B/s" + }; + } else if (bytes < 1024 * 1024) { + return { + value: bytes / 1024, + unit: "KB/s" + }; + } else if (bytes < 1024 * 1024 * 1024) { + return { + value: bytes / (1024 * 1024), + unit: "MB/s" + }; + } else { + return { + value: bytes / (1024 * 1024 * 1024), + unit: "GB/s" + }; + } + } + + function formatBytesTotal(bytes: real): var { + // Handle negative or invalid values + if (bytes < 0 || isNaN(bytes) || !isFinite(bytes)) { + return { + value: 0, + unit: "B" + }; + } + + if (bytes < 1024) { + return { + value: bytes, + unit: "B" + }; + } else if (bytes < 1024 * 1024) { + return { + value: bytes / 1024, + unit: "KB" + }; + } else if (bytes < 1024 * 1024 * 1024) { + return { + value: bytes / (1024 * 1024), + unit: "MB" + }; + } else { + return { + value: bytes / (1024 * 1024 * 1024), + unit: "GB" + }; + } + } + + function parseNetDev(content: string): var { + const lines = content.split("\n"); + let totalRx = 0; + let totalTx = 0; + + for (let i = 2; i < lines.length; i++) { + const line = lines[i].trim(); + if (!line) + continue; + + const parts = line.split(/\s+/); + if (parts.length < 10) + continue; + + const iface = parts[0].replace(":", ""); + // Skip loopback interface + if (iface === "lo") + continue; + + const rxBytes = parseFloat(parts[1]) || 0; + const txBytes = parseFloat(parts[9]) || 0; + + totalRx += rxBytes; + totalTx += txBytes; + } + + return { + rx: totalRx, + tx: totalTx + }; + } + + FileView { + id: netDevFile + path: "/proc/net/dev" + } + + Timer { + interval: Config.dashboard.resourceUpdateInterval + running: root.refCount > 0 + repeat: true + triggeredOnStart: true + + onTriggered: { + netDevFile.reload(); + const content = netDevFile.text(); + if (!content) + return; + + const data = root.parseNetDev(content); + const now = Date.now(); + + if (!root._initialized) { + root._initialRxBytes = data.rx; + root._initialTxBytes = data.tx; + root._prevRxBytes = data.rx; + root._prevTxBytes = data.tx; + root._prevTimestamp = now; + root._initialized = true; + return; + } + + const timeDelta = (now - root._prevTimestamp) / 1000; // seconds + if (timeDelta > 0) { + // Calculate byte deltas + let rxDelta = data.rx - root._prevRxBytes; + let txDelta = data.tx - root._prevTxBytes; + + // Handle counter overflow (when counters wrap around from max to 0) + // This happens when counters exceed 32-bit or 64-bit limits + if (rxDelta < 0) { + // Counter wrapped around - assume 64-bit counter + rxDelta += Math.pow(2, 64); + } + if (txDelta < 0) { + txDelta += Math.pow(2, 64); + } + + // Calculate speeds + root._downloadSpeed = rxDelta / timeDelta; + root._uploadSpeed = txDelta / timeDelta; + + const maxHistory = root.historyLength + 1; + + if (root._downloadSpeed >= 0 && isFinite(root._downloadSpeed)) { + let newDownHist = root._downloadHistory.slice(); + newDownHist.push(root._downloadSpeed); + if (newDownHist.length > maxHistory) { + newDownHist.shift(); + } + root._downloadHistory = newDownHist; + } + + if (root._uploadSpeed >= 0 && isFinite(root._uploadSpeed)) { + let newUpHist = root._uploadHistory.slice(); + newUpHist.push(root._uploadSpeed); + if (newUpHist.length > maxHistory) { + newUpHist.shift(); + } + root._uploadHistory = newUpHist; + } + } + + // Calculate totals with overflow handling + let downTotal = data.rx - root._initialRxBytes; + let upTotal = data.tx - root._initialTxBytes; + + // Handle counter overflow for totals + if (downTotal < 0) { + downTotal += Math.pow(2, 64); + } + if (upTotal < 0) { + upTotal += Math.pow(2, 64); + } + + root._downloadTotal = downTotal; + root._uploadTotal = upTotal; + + root._prevRxBytes = data.rx; + root._prevTxBytes = data.tx; + root._prevTimestamp = now; + } + } +} diff --git a/.config/quickshell/caelestia/services/Nmcli.qml b/.config/quickshell/caelestia/services/Nmcli.qml new file mode 100644 index 0000000..36bd3e6 --- /dev/null +++ b/.config/quickshell/caelestia/services/Nmcli.qml @@ -0,0 +1,1352 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + property var deviceStatus: null + property var wirelessInterfaces: [] + property var ethernetInterfaces: [] + property bool isConnected: false + property string activeInterface: "" + property string activeConnection: "" + property bool wifiEnabled: true + readonly property bool scanning: rescanProc.running + readonly property list networks: [] + readonly property AccessPoint active: networks.find(n => n.active) ?? null + property list savedConnections: [] + property list savedConnectionSsids: [] + + property var wifiConnectionQueue: [] + property int currentSsidQueryIndex: 0 + property var pendingConnection: null + signal connectionFailed(string ssid) + property var wirelessDeviceDetails: null + property var ethernetDeviceDetails: null + property list ethernetDevices: [] + readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null + + property list activeProcesses: [] + + // Constants + readonly property string deviceTypeWifi: "wifi" + readonly property string deviceTypeEthernet: "ethernet" + readonly property string connectionTypeWireless: "802-11-wireless" + readonly property string nmcliCommandDevice: "device" + readonly property string nmcliCommandConnection: "connection" + readonly property string nmcliCommandWifi: "wifi" + readonly property string nmcliCommandRadio: "radio" + readonly property string deviceStatusFields: "DEVICE,TYPE,STATE,CONNECTION" + readonly property string connectionListFields: "NAME,TYPE" + readonly property string wirelessSsidField: "802-11-wireless.ssid" + readonly property string networkListFields: "SSID,SIGNAL,SECURITY" + readonly property string networkDetailFields: "ACTIVE,SIGNAL,FREQ,SSID,BSSID,SECURITY" + readonly property string securityKeyMgmt: "802-11-wireless-security.key-mgmt" + readonly property string securityPsk: "802-11-wireless-security.psk" + readonly property string keyMgmtWpaPsk: "wpa-psk" + readonly property string connectionParamType: "type" + readonly property string connectionParamConName: "con-name" + readonly property string connectionParamIfname: "ifname" + readonly property string connectionParamSsid: "ssid" + readonly property string connectionParamPassword: "password" + readonly property string connectionParamBssid: "802-11-wireless.bssid" + + function detectPasswordRequired(error: string): bool { + if (!error || error.length === 0) { + return false; + } + + return (error.includes("Secrets were required") || error.includes("Secrets were required, but not provided") || error.includes("No secrets provided") || error.includes("802-11-wireless-security.psk") || error.includes("password for") || (error.includes("password") && !error.includes("Connection activated") && !error.includes("successfully")) || (error.includes("Secrets") && !error.includes("Connection activated") && !error.includes("successfully")) || (error.includes("802.11") && !error.includes("Connection activated") && !error.includes("successfully"))) && !error.includes("Connection activated") && !error.includes("successfully"); + } + + function parseNetworkOutput(output: string): list { + if (!output || output.length === 0) { + return []; + } + + const PLACEHOLDER = "STRINGWHICHHOPEFULLYWONTBEUSED"; + const rep = new RegExp("\\\\:", "g"); + const rep2 = new RegExp(PLACEHOLDER, "g"); + + const allNetworks = output.trim().split("\n").filter(line => line && line.length > 0).map(n => { + const net = n.replace(rep, PLACEHOLDER).split(":"); + return { + active: net[0] === "yes", + strength: parseInt(net[1] || "0", 10) || 0, + frequency: parseInt(net[2] || "0", 10) || 0, + ssid: (net[3]?.replace(rep2, ":") ?? "").trim(), + bssid: (net[4]?.replace(rep2, ":") ?? "").trim(), + security: (net[5] ?? "").trim() + }; + }).filter(n => n.ssid && n.ssid.length > 0); + + return allNetworks; + } + + function deduplicateNetworks(networks: list): list { + if (!networks || networks.length === 0) { + return []; + } + + const networkMap = new Map(); + for (const network of networks) { + const existing = networkMap.get(network.ssid); + if (!existing) { + networkMap.set(network.ssid, network); + } else { + if (network.active && !existing.active) { + networkMap.set(network.ssid, network); + } else if (!network.active && !existing.active) { + if (network.strength > existing.strength) { + networkMap.set(network.ssid, network); + } + } + } + } + + return Array.from(networkMap.values()); + } + + function isConnectionCommand(command: list): bool { + if (!command || command.length === 0) { + return false; + } + + return command.includes(root.nmcliCommandWifi) || command.includes(root.nmcliCommandConnection); + } + + function parseDeviceStatusOutput(output: string, filterType: string): list { + if (!output || output.length === 0) { + return []; + } + + const interfaces = []; + const lines = output.trim().split("\n"); + + for (const line of lines) { + const parts = line.split(":"); + if (parts.length >= 2) { + const deviceType = parts[1]; + let shouldInclude = false; + + if (filterType === root.deviceTypeWifi && deviceType === root.deviceTypeWifi) { + shouldInclude = true; + } else if (filterType === root.deviceTypeEthernet && deviceType === root.deviceTypeEthernet) { + shouldInclude = true; + } else if (filterType === "both" && (deviceType === root.deviceTypeWifi || deviceType === root.deviceTypeEthernet)) { + shouldInclude = true; + } + + if (shouldInclude) { + interfaces.push({ + device: parts[0] || "", + type: parts[1] || "", + state: parts[2] || "", + connection: parts[3] || "" + }); + } + } + } + + return interfaces; + } + + function isConnectedState(state: string): bool { + if (!state || state.length === 0) { + return false; + } + + return state === "100 (connected)" || state === "connected" || state.startsWith("connected"); + } + + function executeCommand(args: list, callback: var): void { + const proc = commandProc.createObject(root); + proc.command = ["nmcli", ...args]; + proc.callback = callback; + + activeProcesses.push(proc); + + proc.processFinished.connect(() => { + const index = activeProcesses.indexOf(proc); + if (index >= 0) { + activeProcesses.splice(index, 1); + } + }); + + Qt.callLater(() => { + proc.exec(proc.command); + }); + } + + function getDeviceStatus(callback: var): void { + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { + if (callback) + callback(result.output); + }); + } + + function getWirelessInterfaces(callback: var): void { + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { + const interfaces = parseDeviceStatusOutput(result.output, root.deviceTypeWifi); + root.wirelessInterfaces = interfaces; + if (callback) + callback(interfaces); + }); + } + + function getEthernetInterfaces(callback: var): void { + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { + const interfaces = parseDeviceStatusOutput(result.output, root.deviceTypeEthernet); + const devices = []; + + for (const iface of interfaces) { + const connected = isConnectedState(iface.state); + + devices.push({ + interface: iface.device, + type: iface.type, + state: iface.state, + connection: iface.connection, + connected: connected, + ipAddress: "", + gateway: "", + dns: [], + subnet: "", + macAddress: "", + speed: "" + }); + } + + root.ethernetInterfaces = interfaces; + root.ethernetDevices = devices; + if (callback) + callback(interfaces); + }); + } + + function connectEthernet(connectionName: string, interfaceName: string, callback: var): void { + if (connectionName && connectionName.length > 0) { + executeCommand([root.nmcliCommandConnection, "up", connectionName], result => { + if (result.success) { + Qt.callLater(() => { + getEthernetInterfaces(() => {}); + if (interfaceName && interfaceName.length > 0) { + Qt.callLater(() => { + getEthernetDeviceDetails(interfaceName, () => {}); + }, 1000); + } + }, 500); + } + if (callback) + callback(result); + }); + } else if (interfaceName && interfaceName.length > 0) { + executeCommand([root.nmcliCommandDevice, "connect", interfaceName], result => { + if (result.success) { + Qt.callLater(() => { + getEthernetInterfaces(() => {}); + Qt.callLater(() => { + getEthernetDeviceDetails(interfaceName, () => {}); + }, 1000); + }, 500); + } + if (callback) + callback(result); + }); + } else { + if (callback) + callback({ + success: false, + output: "", + error: "No connection name or interface specified", + exitCode: -1 + }); + } + } + + function disconnectEthernet(connectionName: string, callback: var): void { + if (!connectionName || connectionName.length === 0) { + if (callback) + callback({ + success: false, + output: "", + error: "No connection name specified", + exitCode: -1 + }); + return; + } + + executeCommand([root.nmcliCommandConnection, "down", connectionName], result => { + if (result.success) { + root.ethernetDeviceDetails = null; + Qt.callLater(() => { + getEthernetInterfaces(() => {}); + }, 500); + } + if (callback) + callback(result); + }); + } + + function getAllInterfaces(callback: var): void { + executeCommand(["-t", "-f", root.deviceStatusFields, root.nmcliCommandDevice, "status"], result => { + const interfaces = parseDeviceStatusOutput(result.output, "both"); + if (callback) + callback(interfaces); + }); + } + + function isInterfaceConnected(interfaceName: string, callback: var): void { + executeCommand([root.nmcliCommandDevice, "status"], result => { + const lines = result.output.trim().split("\n"); + for (const line of lines) { + const parts = line.split(/\s+/); + if (parts.length >= 3 && parts[0] === interfaceName) { + const connected = isConnectedState(parts[2]); + if (callback) + callback(connected); + return; + } + } + if (callback) + callback(false); + }); + } + + function connectToNetworkWithPasswordCheck(ssid: string, isSecure: bool, callback: var, bssid: string): void { + if (isSecure) { + const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0; + connectWireless(ssid, "", bssid, result => { + if (result.success) { + if (callback) + callback({ + success: true, + usedSavedPassword: true, + output: result.output, + error: "", + exitCode: 0 + }); + } else if (result.needsPassword) { + if (callback) + callback({ + success: false, + needsPassword: true, + output: result.output, + error: result.error, + exitCode: result.exitCode + }); + } else { + if (callback) + callback(result); + } + }); + } else { + connectWireless(ssid, "", bssid, callback); + } + } + + function connectToNetwork(ssid: string, password: string, bssid: string, callback: var): void { + connectWireless(ssid, password, bssid, callback); + } + + function connectWireless(ssid: string, password: string, bssid: string, callback: var, retryCount: int): void { + const hasBssid = bssid !== undefined && bssid !== null && bssid.length > 0; + const retries = retryCount !== undefined ? retryCount : 0; + const maxRetries = 2; + + if (callback) { + root.pendingConnection = { + ssid: ssid, + bssid: hasBssid ? bssid : "", + callback: callback, + retryCount: retries + }; + connectionCheckTimer.start(); + immediateCheckTimer.checkCount = 0; + immediateCheckTimer.start(); + } + + if (password && password.length > 0 && hasBssid) { + const bssidUpper = bssid.toUpperCase(); + createConnectionWithPassword(ssid, bssidUpper, password, callback); + return; + } + + let cmd = [root.nmcliCommandDevice, root.nmcliCommandWifi, "connect", ssid]; + if (password && password.length > 0) { + cmd.push(root.connectionParamPassword, password); + } + executeCommand(cmd, result => { + if (result.needsPassword && callback) { + if (callback) + callback(result); + return; + } + + if (!result.success && root.pendingConnection && retries < maxRetries) { + console.warn("[NMCLI] Connection failed, retrying... (attempt " + (retries + 1) + "/" + maxRetries + ")"); + Qt.callLater(() => { + connectWireless(ssid, password, bssid, callback, retries + 1); + }, 1000); + } else if (!result.success && root.pendingConnection) {} else if (result.success && callback) {} else if (!result.success && !root.pendingConnection) { + if (callback) + callback(result); + } + }); + } + + function createConnectionWithPassword(ssid: string, bssidUpper: string, password: string, callback: var): void { + checkAndDeleteConnection(ssid, () => { + const cmd = [root.nmcliCommandConnection, "add", root.connectionParamType, root.deviceTypeWifi, root.connectionParamConName, ssid, root.connectionParamIfname, "*", root.connectionParamSsid, ssid, root.connectionParamBssid, bssidUpper, root.securityKeyMgmt, root.keyMgmtWpaPsk, root.securityPsk, password]; + + executeCommand(cmd, result => { + if (result.success) { + loadSavedConnections(() => {}); + activateConnection(ssid, callback); + } else { + const hasDuplicateWarning = result.error && (result.error.includes("another connection with the name") || result.error.includes("Reference the connection by its uuid")); + + if (hasDuplicateWarning || (result.exitCode > 0 && result.exitCode < 10)) { + loadSavedConnections(() => {}); + activateConnection(ssid, callback); + } else { + console.warn("[NMCLI] Connection profile creation failed, trying fallback..."); + let fallbackCmd = [root.nmcliCommandDevice, root.nmcliCommandWifi, "connect", ssid, root.connectionParamPassword, password]; + executeCommand(fallbackCmd, fallbackResult => { + if (callback) + callback(fallbackResult); + }); + } + } + }); + }); + } + + function checkAndDeleteConnection(ssid: string, callback: var): void { + executeCommand([root.nmcliCommandConnection, "show", ssid], result => { + if (result.success) { + executeCommand([root.nmcliCommandConnection, "delete", ssid], deleteResult => { + Qt.callLater(() => { + if (callback) + callback(); + }, 300); + }); + } else { + if (callback) + callback(); + } + }); + } + + function activateConnection(connectionName: string, callback: var): void { + executeCommand([root.nmcliCommandConnection, "up", connectionName], result => { + if (callback) + callback(result); + }); + } + + function loadSavedConnections(callback: var): void { + executeCommand(["-t", "-f", root.connectionListFields, root.nmcliCommandConnection, "show"], result => { + if (!result.success) { + root.savedConnections = []; + root.savedConnectionSsids = []; + if (callback) + callback([]); + return; + } + + parseConnectionList(result.output, callback); + }); + } + + function parseConnectionList(output: string, callback: var): void { + const lines = output.trim().split("\n").filter(line => line.length > 0); + const wifiConnections = []; + const connections = []; + + for (const line of lines) { + const parts = line.split(":"); + if (parts.length >= 2) { + const name = parts[0]; + const type = parts[1]; + connections.push(name); + + if (type === root.connectionTypeWireless) { + wifiConnections.push(name); + } + } + } + + root.savedConnections = connections; + + if (wifiConnections.length > 0) { + root.wifiConnectionQueue = wifiConnections; + root.currentSsidQueryIndex = 0; + root.savedConnectionSsids = []; + queryNextSsid(callback); + } else { + root.savedConnectionSsids = []; + root.wifiConnectionQueue = []; + if (callback) + callback(root.savedConnectionSsids); + } + } + + function queryNextSsid(callback: var): void { + if (root.currentSsidQueryIndex < root.wifiConnectionQueue.length) { + const connectionName = root.wifiConnectionQueue[root.currentSsidQueryIndex]; + root.currentSsidQueryIndex++; + + executeCommand(["-t", "-f", root.wirelessSsidField, root.nmcliCommandConnection, "show", connectionName], result => { + if (result.success) { + processSsidOutput(result.output); + } + queryNextSsid(callback); + }); + } else { + root.wifiConnectionQueue = []; + root.currentSsidQueryIndex = 0; + if (callback) + callback(root.savedConnectionSsids); + } + } + + function processSsidOutput(output: string): void { + const lines = output.trim().split("\n"); + for (const line of lines) { + if (line.startsWith("802-11-wireless.ssid:")) { + const ssid = line.substring("802-11-wireless.ssid:".length).trim(); + if (ssid && ssid.length > 0) { + const ssidLower = ssid.toLowerCase(); + const exists = root.savedConnectionSsids.some(s => s && s.toLowerCase() === ssidLower); + if (!exists) { + const newList = root.savedConnectionSsids.slice(); + newList.push(ssid); + root.savedConnectionSsids = newList; + } + } + } + } + } + + function hasSavedProfile(ssid: string): bool { + if (!ssid || ssid.length === 0) { + return false; + } + const ssidLower = ssid.toLowerCase().trim(); + + if (root.active && root.active.ssid) { + const activeSsidLower = root.active.ssid.toLowerCase().trim(); + if (activeSsidLower === ssidLower) { + return true; + } + } + + const hasSsid = root.savedConnectionSsids.some(savedSsid => savedSsid && savedSsid.toLowerCase().trim() === ssidLower); + + if (hasSsid) { + return true; + } + + const hasConnectionName = root.savedConnections.some(connName => connName && connName.toLowerCase().trim() === ssidLower); + + return hasConnectionName; + } + + function forgetNetwork(ssid: string, callback: var): void { + if (!ssid || ssid.length === 0) { + if (callback) + callback({ + success: false, + output: "", + error: "No SSID specified", + exitCode: -1 + }); + return; + } + + const connectionName = root.savedConnections.find(conn => conn && conn.toLowerCase().trim() === ssid.toLowerCase().trim()) || ssid; + + executeCommand([root.nmcliCommandConnection, "delete", connectionName], result => { + if (result.success) { + Qt.callLater(() => { + loadSavedConnections(() => {}); + }, 500); + } + if (callback) + callback(result); + }); + } + + function disconnect(interfaceName: string, callback: var): void { + if (interfaceName && interfaceName.length > 0) { + executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], result => { + if (callback) + callback(result.success ? result.output : ""); + }); + } else { + executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], result => { + if (callback) + callback(result.success ? result.output : ""); + }); + } + } + + function disconnectFromNetwork(): void { + if (active && active.ssid) { + executeCommand([root.nmcliCommandConnection, "down", active.ssid], result => { + if (result.success) { + getNetworks(() => {}); + } + }); + } else { + executeCommand([root.nmcliCommandDevice, "disconnect", root.deviceTypeWifi], result => { + if (result.success) { + getNetworks(() => {}); + } + }); + } + } + + function getDeviceDetails(interfaceName: string, callback: var): void { + executeCommand([root.nmcliCommandDevice, "show", interfaceName], result => { + if (callback) + callback(result.output); + }); + } + + function refreshStatus(callback: var): void { + getDeviceStatus(output => { + const lines = output.trim().split("\n"); + let connected = false; + let activeIf = ""; + let activeConn = ""; + + for (const line of lines) { + const parts = line.split(":"); + if (parts.length >= 4) { + const state = parts[2] || ""; + if (isConnectedState(state)) { + connected = true; + activeIf = parts[0] || ""; + activeConn = parts[3] || ""; + break; + } + } + } + + root.isConnected = connected; + root.activeInterface = activeIf; + root.activeConnection = activeConn; + + if (callback) + callback({ + connected, + interface: activeIf, + connection: activeConn + }); + }); + } + + function bringInterfaceUp(interfaceName: string, callback: var): void { + if (interfaceName && interfaceName.length > 0) { + executeCommand([root.nmcliCommandDevice, "connect", interfaceName], result => { + if (callback) { + callback(result); + } + }); + } else { + if (callback) + callback({ + success: false, + output: "", + error: "No interface specified", + exitCode: -1 + }); + } + } + + function bringInterfaceDown(interfaceName: string, callback: var): void { + if (interfaceName && interfaceName.length > 0) { + executeCommand([root.nmcliCommandDevice, "disconnect", interfaceName], result => { + if (callback) { + callback(result); + } + }); + } else { + if (callback) + callback({ + success: false, + output: "", + error: "No interface specified", + exitCode: -1 + }); + } + } + + function scanWirelessNetworks(interfaceName: string, callback: var): void { + let cmd = [root.nmcliCommandDevice, root.nmcliCommandWifi, "rescan"]; + if (interfaceName && interfaceName.length > 0) { + cmd.push(root.connectionParamIfname, interfaceName); + } + executeCommand(cmd, result => { + if (callback) { + callback(result); + } + }); + } + + function rescanWifi(): void { + rescanProc.running = true; + } + + function enableWifi(enabled: bool, callback: var): void { + const cmd = enabled ? "on" : "off"; + executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi, cmd], result => { + if (result.success) { + getWifiStatus(status => { + root.wifiEnabled = status; + if (callback) + callback(result); + }); + } else { + if (callback) + callback(result); + } + }); + } + + function toggleWifi(callback: var): void { + const newState = !root.wifiEnabled; + enableWifi(newState, callback); + } + + function getWifiStatus(callback: var): void { + executeCommand([root.nmcliCommandRadio, root.nmcliCommandWifi], result => { + if (result.success) { + const enabled = result.output.trim() === "enabled"; + root.wifiEnabled = enabled; + if (callback) + callback(enabled); + } else { + if (callback) + callback(root.wifiEnabled); + } + }); + } + + function getNetworks(callback: var): void { + executeCommand(["-g", root.networkDetailFields, "d", "w"], result => { + if (!result.success) { + if (callback) + callback([]); + return; + } + + const allNetworks = parseNetworkOutput(result.output); + const networks = deduplicateNetworks(allNetworks); + const rNetworks = root.networks; + + const destroyed = rNetworks.filter(rn => !networks.find(n => n.frequency === rn.frequency && n.ssid === rn.ssid && n.bssid === rn.bssid)); + for (const network of destroyed) { + const index = rNetworks.indexOf(network); + if (index >= 0) { + rNetworks.splice(index, 1); + network.destroy(); + } + } + + for (const network of networks) { + const match = rNetworks.find(n => n.frequency === network.frequency && n.ssid === network.ssid && n.bssid === network.bssid); + if (match) { + match.lastIpcObject = network; + } else { + rNetworks.push(apComp.createObject(root, { + lastIpcObject: network + })); + } + } + + if (callback) + callback(root.networks); + checkPendingConnection(); + }); + } + + function getWirelessSSIDs(interfaceName: string, callback: var): void { + let cmd = ["-t", "-f", root.networkListFields, root.nmcliCommandDevice, root.nmcliCommandWifi, "list"]; + if (interfaceName && interfaceName.length > 0) { + cmd.push(root.connectionParamIfname, interfaceName); + } + executeCommand(cmd, result => { + if (!result.success) { + if (callback) + callback([]); + return; + } + + const ssids = []; + const lines = result.output.trim().split("\n"); + const seenSSIDs = new Set(); + + for (const line of lines) { + if (!line || line.length === 0) + continue; + + const parts = line.split(":"); + if (parts.length >= 1) { + const ssid = parts[0].trim(); + if (ssid && ssid.length > 0 && !seenSSIDs.has(ssid)) { + seenSSIDs.add(ssid); + const signalStr = parts.length >= 2 ? parts[1].trim() : ""; + const signal = signalStr ? parseInt(signalStr, 10) : 0; + const security = parts.length >= 3 ? parts[2].trim() : ""; + ssids.push({ + ssid: ssid, + signal: signalStr, + signalValue: isNaN(signal) ? 0 : signal, + security: security + }); + } + } + } + + ssids.sort((a, b) => { + return b.signalValue - a.signalValue; + }); + + if (callback) + callback(ssids); + }); + } + + function handlePasswordRequired(proc: var, error: string, output: string, exitCode: int): bool { + if (!proc || !error || error.length === 0) { + return false; + } + + if (!isConnectionCommand(proc.command) || !root.pendingConnection || !root.pendingConnection.callback) { + return false; + } + + const needsPassword = detectPasswordRequired(error); + + if (needsPassword && !proc.callbackCalled && root.pendingConnection) { + connectionCheckTimer.stop(); + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + const pending = root.pendingConnection; + root.pendingConnection = null; + proc.callbackCalled = true; + const result = { + success: false, + output: output || "", + error: error, + exitCode: exitCode, + needsPassword: true + }; + if (pending.callback) { + pending.callback(result); + } + if (proc.callback && proc.callback !== pending.callback) { + proc.callback(result); + } + return true; + } + + return false; + } + + component CommandProcess: Process { + id: proc + + property var callback: null + property list command: [] + property bool callbackCalled: false + property int exitCode: 0 + + signal processFinished + + environment: ({ + LANG: "C.UTF-8", + LC_ALL: "C.UTF-8" + }) + + stdout: StdioCollector { + id: stdoutCollector + } + + stderr: StdioCollector { + id: stderrCollector + + onStreamFinished: { + const error = text.trim(); + if (error && error.length > 0) { + const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : ""; + root.handlePasswordRequired(proc, error, output, -1); + } + } + } + + onExited: code => { + exitCode = code; + + Qt.callLater(() => { + if (callbackCalled) { + processFinished(); + return; + } + + if (proc.callback) { + const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : ""; + const error = (stderrCollector && stderrCollector.text) ? stderrCollector.text : ""; + const success = exitCode === 0; + const cmdIsConnection = isConnectionCommand(proc.command); + + if (root.handlePasswordRequired(proc, error, output, exitCode)) { + processFinished(); + return; + } + + const needsPassword = cmdIsConnection && root.detectPasswordRequired(error); + + if (!success && cmdIsConnection && root.pendingConnection) { + const failedSsid = root.pendingConnection.ssid; + root.connectionFailed(failedSsid); + } + + callbackCalled = true; + callback({ + success: success, + output: output, + error: error, + exitCode: proc.exitCode, + needsPassword: needsPassword || false + }); + processFinished(); + } else { + processFinished(); + } + }); + } + } + + Component { + id: commandProc + + CommandProcess {} + } + + component AccessPoint: QtObject { + required property var lastIpcObject + readonly property string ssid: lastIpcObject.ssid + readonly property string bssid: lastIpcObject.bssid + readonly property int strength: lastIpcObject.strength + readonly property int frequency: lastIpcObject.frequency + readonly property bool active: lastIpcObject.active + readonly property string security: lastIpcObject.security + readonly property bool isSecure: security.length > 0 + } + + Component { + id: apComp + + AccessPoint {} + } + + Timer { + id: connectionCheckTimer + + interval: 4000 + onTriggered: { + if (root.pendingConnection) { + const connected = root.active && root.active.ssid === root.pendingConnection.ssid; + + if (!connected && root.pendingConnection.callback) { + let foundPasswordError = false; + for (let i = 0; i < root.activeProcesses.length; i++) { + const proc = root.activeProcesses[i]; + if (proc && proc.stderr && proc.stderr.text) { + const error = proc.stderr.text.trim(); + if (error && error.length > 0) { + if (root.isConnectionCommand(proc.command)) { + const needsPassword = root.detectPasswordRequired(error); + + if (needsPassword && !proc.callbackCalled && root.pendingConnection) { + const pending = root.pendingConnection; + root.pendingConnection = null; + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + proc.callbackCalled = true; + const result = { + success: false, + output: (proc.stdout && proc.stdout.text) ? proc.stdout.text : "", + error: error, + exitCode: -1, + needsPassword: true + }; + if (pending.callback) { + pending.callback(result); + } + if (proc.callback && proc.callback !== pending.callback) { + proc.callback(result); + } + foundPasswordError = true; + break; + } + } + } + } + } + + if (!foundPasswordError) { + const pending = root.pendingConnection; + const failedSsid = pending.ssid; + root.pendingConnection = null; + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + root.connectionFailed(failedSsid); + pending.callback({ + success: false, + output: "", + error: "Connection timeout", + exitCode: -1, + needsPassword: false + }); + } + } else if (connected) { + root.pendingConnection = null; + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + } + } + } + } + + Timer { + id: immediateCheckTimer + + property int checkCount: 0 + + interval: 500 + repeat: true + triggeredOnStart: false + + onTriggered: { + if (root.pendingConnection) { + checkCount++; + const connected = root.active && root.active.ssid === root.pendingConnection.ssid; + + if (connected) { + connectionCheckTimer.stop(); + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + if (root.pendingConnection.callback) { + root.pendingConnection.callback({ + success: true, + output: "Connected", + error: "", + exitCode: 0 + }); + } + root.pendingConnection = null; + } else { + for (let i = 0; i < root.activeProcesses.length; i++) { + const proc = root.activeProcesses[i]; + if (proc && proc.stderr && proc.stderr.text) { + const error = proc.stderr.text.trim(); + if (error && error.length > 0) { + if (root.isConnectionCommand(proc.command)) { + const needsPassword = root.detectPasswordRequired(error); + + if (needsPassword && !proc.callbackCalled && root.pendingConnection && root.pendingConnection.callback) { + connectionCheckTimer.stop(); + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + const pending = root.pendingConnection; + root.pendingConnection = null; + proc.callbackCalled = true; + const result = { + success: false, + output: (proc.stdout && proc.stdout.text) ? proc.stdout.text : "", + error: error, + exitCode: -1, + needsPassword: true + }; + if (pending.callback) { + pending.callback(result); + } + if (proc.callback && proc.callback !== pending.callback) { + proc.callback(result); + } + return; + } + } + } + } + } + + if (checkCount >= 6) { + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + } + } + } else { + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + } + } + } + + function checkPendingConnection(): void { + if (root.pendingConnection) { + Qt.callLater(() => { + const connected = root.active && root.active.ssid === root.pendingConnection.ssid; + if (connected) { + connectionCheckTimer.stop(); + immediateCheckTimer.stop(); + immediateCheckTimer.checkCount = 0; + if (root.pendingConnection.callback) { + root.pendingConnection.callback({ + success: true, + output: "Connected", + error: "", + exitCode: 0 + }); + } + root.pendingConnection = null; + } else { + if (!immediateCheckTimer.running) { + immediateCheckTimer.start(); + } + } + }); + } + } + + function cidrToSubnetMask(cidr: string): string { + const cidrNum = parseInt(cidr, 10); + if (isNaN(cidrNum) || cidrNum < 0 || cidrNum > 32) { + return ""; + } + + const mask = (0xffffffff << (32 - cidrNum)) >>> 0; + const octet1 = (mask >>> 24) & 0xff; + const octet2 = (mask >>> 16) & 0xff; + const octet3 = (mask >>> 8) & 0xff; + const octet4 = mask & 0xff; + + return `${octet1}.${octet2}.${octet3}.${octet4}`; + } + + function getWirelessDeviceDetails(interfaceName: string, callback: var): void { + if (!interfaceName || interfaceName.length === 0) { + const activeInterface = root.wirelessInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeInterface && activeInterface.device) { + interfaceName = activeInterface.device; + } else { + if (callback) + callback(null); + return; + } + } + + executeCommand(["device", "show", interfaceName], result => { + if (!result.success || !result.output) { + root.wirelessDeviceDetails = null; + if (callback) + callback(null); + return; + } + + const details = parseDeviceDetails(result.output, false); + root.wirelessDeviceDetails = details; + if (callback) + callback(details); + }); + } + + function getEthernetDeviceDetails(interfaceName: string, callback: var): void { + if (!interfaceName || interfaceName.length === 0) { + const activeInterface = root.ethernetInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeInterface && activeInterface.device) { + interfaceName = activeInterface.device; + } else { + if (callback) + callback(null); + return; + } + } + + executeCommand(["device", "show", interfaceName], result => { + if (!result.success || !result.output) { + root.ethernetDeviceDetails = null; + if (callback) + callback(null); + return; + } + + const details = parseDeviceDetails(result.output, true); + root.ethernetDeviceDetails = details; + if (callback) + callback(details); + }); + } + + function parseDeviceDetails(output: string, isEthernet: bool): var { + const details = { + ipAddress: "", + gateway: "", + dns: [], + subnet: "", + macAddress: "", + speed: "" + }; + + if (!output || output.length === 0) { + return details; + } + + const lines = output.trim().split("\n"); + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const parts = line.split(":"); + if (parts.length >= 2) { + const key = parts[0].trim(); + const value = parts.slice(1).join(":").trim(); + + if (key.startsWith("IP4.ADDRESS")) { + const ipParts = value.split("/"); + details.ipAddress = ipParts[0] || ""; + if (ipParts[1]) { + details.subnet = cidrToSubnetMask(ipParts[1]); + } else { + details.subnet = ""; + } + } else if (key === "IP4.GATEWAY") { + if (value !== "--") { + details.gateway = value; + } + } else if (key.startsWith("IP4.DNS")) { + if (value !== "--" && value.length > 0) { + details.dns.push(value); + } + } else if (isEthernet && key === "WIRED-PROPERTIES.MAC") { + details.macAddress = value; + } else if (isEthernet && key === "WIRED-PROPERTIES.SPEED") { + details.speed = value; + } else if (!isEthernet && key === "GENERAL.HWADDR") { + details.macAddress = value; + } + } + } + + return details; + } + + Process { + id: rescanProc + + command: ["nmcli", "dev", root.nmcliCommandWifi, "list", "--rescan", "yes"] + onExited: root.getNetworks() + } + + Process { + id: monitorProc + + running: true + command: ["nmcli", "monitor"] + environment: ({ + LANG: "C.UTF-8", + LC_ALL: "C.UTF-8" + }) + stdout: SplitParser { + onRead: root.refreshOnConnectionChange() + } + onExited: monitorRestartTimer.start() + } + + Timer { + id: monitorRestartTimer + interval: 2000 + onTriggered: { + monitorProc.running = true; + } + } + + function refreshOnConnectionChange(): void { + getNetworks(networks => { + const newActive = root.active; + + if (newActive && newActive.active) { + Qt.callLater(() => { + if (root.wirelessInterfaces.length > 0) { + const activeWireless = root.wirelessInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeWireless && activeWireless.device) { + getWirelessDeviceDetails(activeWireless.device, () => {}); + } + } + + if (root.ethernetInterfaces.length > 0) { + const activeEthernet = root.ethernetInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeEthernet && activeEthernet.device) { + getEthernetDeviceDetails(activeEthernet.device, () => {}); + } + } + }, 500); + } else { + root.wirelessDeviceDetails = null; + root.ethernetDeviceDetails = null; + } + + getWirelessInterfaces(() => {}); + getEthernetInterfaces(() => { + if (root.activeEthernet && root.activeEthernet.connected) { + Qt.callLater(() => { + getEthernetDeviceDetails(root.activeEthernet.interface, () => {}); + }, 500); + } + }); + }); + } + + Component.onCompleted: { + getWifiStatus(() => {}); + getNetworks(() => {}); + loadSavedConnections(() => {}); + getEthernetInterfaces(() => {}); + + Qt.callLater(() => { + if (root.wirelessInterfaces.length > 0) { + const activeWireless = root.wirelessInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeWireless && activeWireless.device) { + getWirelessDeviceDetails(activeWireless.device, () => {}); + } + } + + if (root.ethernetInterfaces.length > 0) { + const activeEthernet = root.ethernetInterfaces.find(iface => { + return isConnectedState(iface.state); + }); + if (activeEthernet && activeEthernet.device) { + getEthernetDeviceDetails(activeEthernet.device, () => {}); + } + } + }, 2000); + } +} diff --git a/.config/quickshell/caelestia/services/Notifs.qml b/.config/quickshell/caelestia/services/Notifs.qml new file mode 100644 index 0000000..2ebc32d --- /dev/null +++ b/.config/quickshell/caelestia/services/Notifs.qml @@ -0,0 +1,338 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import qs.components.misc +import qs.config +import qs.utils +import Caelestia +import Quickshell +import Quickshell.Io +import Quickshell.Services.Notifications +import QtQuick + +Singleton { + id: root + + property list list: [] + readonly property list notClosed: list.filter(n => !n.closed) + readonly property list popups: list.filter(n => n.popup) + property alias dnd: props.dnd + + property bool loaded + + onDndChanged: { + if (!Config.utilities.toasts.dndChanged) + return; + + if (dnd) + Toaster.toast(qsTr("Do not disturb enabled"), qsTr("Popup notifications are now disabled"), "do_not_disturb_on"); + else + Toaster.toast(qsTr("Do not disturb disabled"), qsTr("Popup notifications are now enabled"), "do_not_disturb_off"); + } + + onListChanged: { + if (loaded) + saveTimer.restart(); + } + + Timer { + id: saveTimer + + interval: 1000 + onTriggered: storage.setText(JSON.stringify(root.notClosed.map(n => ({ + time: n.time, + id: n.id, + summary: n.summary, + body: n.body, + appIcon: n.appIcon, + appName: n.appName, + image: n.image, + expireTimeout: n.expireTimeout, + urgency: n.urgency, + resident: n.resident, + hasActionIcons: n.hasActionIcons, + actions: n.actions + })))) + } + + PersistentProperties { + id: props + + property bool dnd + + reloadableId: "notifs" + } + + NotificationServer { + id: server + + keepOnReload: false + actionsSupported: true + bodyHyperlinksSupported: true + bodyImagesSupported: true + bodyMarkupSupported: true + imageSupported: true + persistenceSupported: true + + onNotification: notif => { + notif.tracked = true; + + const comp = notifComp.createObject(root, { + popup: !props.dnd && ![...Visibilities.screens.values()].some(v => v.sidebar), + notification: notif + }); + root.list = [comp, ...root.list]; + } + } + + FileView { + id: storage + + path: `${Paths.state}/notifs.json` + onLoaded: { + const data = JSON.parse(text()); + for (const notif of data) + root.list.push(notifComp.createObject(root, notif)); + root.list.sort((a, b) => b.time - a.time); + root.loaded = true; + } + onLoadFailed: err => { + if (err === FileViewError.FileNotFound) { + root.loaded = true; + setText("[]"); + } + } + } + + CustomShortcut { + name: "clearNotifs" + description: "Clear all notifications" + onPressed: { + for (const notif of root.list.slice()) + notif.close(); + } + } + + IpcHandler { + target: "notifs" + + function clear(): void { + for (const notif of root.list.slice()) + notif.close(); + } + + function isDndEnabled(): bool { + return props.dnd; + } + + function toggleDnd(): void { + props.dnd = !props.dnd; + } + + function enableDnd(): void { + props.dnd = true; + } + + function disableDnd(): void { + props.dnd = false; + } + } + + component Notif: QtObject { + id: notif + + property bool popup + property bool closed + property var locks: new Set() + + property date time: new Date() + readonly property string timeStr: { + const diff = Time.date.getTime() - time.getTime(); + const m = Math.floor(diff / 60000); + + if (m < 1) + return qsTr("now"); + + const h = Math.floor(m / 60); + const d = Math.floor(h / 24); + + if (d > 0) + return `${d}d`; + if (h > 0) + return `${h}h`; + return `${m}m`; + } + + property Notification notification + property string id + property string summary + property string body + property string appIcon + property string appName + property string image + property real expireTimeout: Config.notifs.defaultExpireTimeout + property int urgency: NotificationUrgency.Normal + property bool resident + property bool hasActionIcons + property list actions + + readonly property Timer timer: Timer { + running: true + interval: notif.expireTimeout > 0 ? notif.expireTimeout : Config.notifs.defaultExpireTimeout + onTriggered: { + if (Config.notifs.expire) + notif.popup = false; + } + } + + readonly property LazyLoader dummyImageLoader: LazyLoader { + active: false + + PanelWindow { + implicitWidth: Config.notifs.sizes.image + implicitHeight: Config.notifs.sizes.image + color: "transparent" + mask: Region {} + + Image { + function tryCache(): void { + if (status !== Image.Ready || width != Config.notifs.sizes.image || height != Config.notifs.sizes.image) + return; + + const cacheKey = notif.appName + notif.summary + notif.id; + let h1 = 0xdeadbeef, h2 = 0x41c6ce57, ch; + for (let i = 0; i < cacheKey.length; i++) { + ch = cacheKey.charCodeAt(i); + h1 = Math.imul(h1 ^ ch, 2654435761); + h2 = Math.imul(h2 ^ ch, 1597334677); + } + h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507); + h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909); + h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507); + h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909); + const hash = (h2 >>> 0).toString(16).padStart(8, 0) + (h1 >>> 0).toString(16).padStart(8, 0); + + const cache = `${Paths.notifimagecache}/${hash}.png`; + CUtils.saveItem(this, Qt.resolvedUrl(cache), () => { + notif.image = cache; + notif.dummyImageLoader.active = false; + }); + } + + anchors.fill: parent + source: Qt.resolvedUrl(notif.image) + fillMode: Image.PreserveAspectCrop + cache: false + asynchronous: true + opacity: 0 + + onStatusChanged: tryCache() + onWidthChanged: tryCache() + onHeightChanged: tryCache() + } + } + } + + readonly property Connections conn: Connections { + target: notif.notification + + function onClosed(): void { + notif.close(); + } + + function onSummaryChanged(): void { + notif.summary = notif.notification.summary; + } + + function onBodyChanged(): void { + notif.body = notif.notification.body; + } + + function onAppIconChanged(): void { + notif.appIcon = notif.notification.appIcon; + } + + function onAppNameChanged(): void { + notif.appName = notif.notification.appName; + } + + function onImageChanged(): void { + notif.image = notif.notification.image; + if (notif.notification?.image) + notif.dummyImageLoader.active = true; + } + + function onExpireTimeoutChanged(): void { + notif.expireTimeout = notif.notification.expireTimeout; + } + + function onUrgencyChanged(): void { + notif.urgency = notif.notification.urgency; + } + + function onResidentChanged(): void { + notif.resident = notif.notification.resident; + } + + function onHasActionIconsChanged(): void { + notif.hasActionIcons = notif.notification.hasActionIcons; + } + + function onActionsChanged(): void { + notif.actions = notif.notification.actions.map(a => ({ + identifier: a.identifier, + text: a.text, + invoke: () => a.invoke() + })); + } + } + + function lock(item: Item): void { + locks.add(item); + } + + function unlock(item: Item): void { + locks.delete(item); + if (closed) + close(); + } + + function close(): void { + closed = true; + if (locks.size === 0 && root.list.includes(this)) { + root.list = root.list.filter(n => n !== this); + notification?.dismiss(); + destroy(); + } + } + + Component.onCompleted: { + if (!notification) + return; + + id = notification.id; + summary = notification.summary; + body = notification.body; + appIcon = notification.appIcon; + appName = notification.appName; + image = notification.image; + if (notification?.image) + dummyImageLoader.active = true; + expireTimeout = notification.expireTimeout; + urgency = notification.urgency; + resident = notification.resident; + hasActionIcons = notification.hasActionIcons; + actions = notification.actions.map(a => ({ + identifier: a.identifier, + text: a.text, + invoke: () => a.invoke() + })); + } + } + + Component { + id: notifComp + + Notif {} + } +} diff --git a/.config/quickshell/caelestia/services/Players.qml b/.config/quickshell/caelestia/services/Players.qml new file mode 100644 index 0000000..1191696 --- /dev/null +++ b/.config/quickshell/caelestia/services/Players.qml @@ -0,0 +1,126 @@ +pragma Singleton + +import qs.components.misc +import qs.config +import Quickshell +import Quickshell.Io +import Quickshell.Services.Mpris +import QtQml +import Caelestia + +Singleton { + id: root + + readonly property list list: Mpris.players.values + readonly property MprisPlayer active: props.manualActive ?? list.find(p => getIdentity(p) === Config.services.defaultPlayer) ?? list[0] ?? null + property alias manualActive: props.manualActive + + function getIdentity(player: MprisPlayer): string { + const alias = Config.services.playerAliases.find(a => a.from === player.identity); + return alias?.to ?? player.identity; + } + + Connections { + target: active + + function onPostTrackChanged() { + if (!Config.utilities.toasts.nowPlaying) { + return; + } + if (active.trackArtist != "" && active.trackTitle != "") { + Toaster.toast(qsTr("Now Playing"), qsTr("%1 - %2").arg(active.trackArtist).arg(active.trackTitle), "music_note"); + } + } + } + + PersistentProperties { + id: props + + property MprisPlayer manualActive + + reloadableId: "players" + } + + CustomShortcut { + name: "mediaToggle" + description: "Toggle media playback" + onPressed: { + const active = root.active; + if (active && active.canTogglePlaying) + active.togglePlaying(); + } + } + + CustomShortcut { + name: "mediaPrev" + description: "Previous track" + onPressed: { + const active = root.active; + if (active && active.canGoPrevious) + active.previous(); + } + } + + CustomShortcut { + name: "mediaNext" + description: "Next track" + onPressed: { + const active = root.active; + if (active && active.canGoNext) + active.next(); + } + } + + CustomShortcut { + name: "mediaStop" + description: "Stop media playback" + onPressed: root.active?.stop() + } + + IpcHandler { + target: "mpris" + + function getActive(prop: string): string { + const active = root.active; + return active ? active[prop] ?? "Invalid property" : "No active player"; + } + + function list(): string { + return root.list.map(p => root.getIdentity(p)).join("\n"); + } + + function play(): void { + const active = root.active; + if (active?.canPlay) + active.play(); + } + + function pause(): void { + const active = root.active; + if (active?.canPause) + active.pause(); + } + + function playPause(): void { + const active = root.active; + if (active?.canTogglePlaying) + active.togglePlaying(); + } + + function previous(): void { + const active = root.active; + if (active?.canGoPrevious) + active.previous(); + } + + function next(): void { + const active = root.active; + if (active?.canGoNext) + active.next(); + } + + function stop(): void { + root.active?.stop(); + } + } +} diff --git a/.config/quickshell/caelestia/services/Recorder.qml b/.config/quickshell/caelestia/services/Recorder.qml new file mode 100644 index 0000000..6eddce9 --- /dev/null +++ b/.config/quickshell/caelestia/services/Recorder.qml @@ -0,0 +1,82 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + readonly property alias running: props.running + readonly property alias paused: props.paused + readonly property alias elapsed: props.elapsed + property bool needsStart + property list startArgs + property bool needsStop + property bool needsPause + + function start(extraArgs = []): void { + needsStart = true; + startArgs = extraArgs; + checkProc.running = true; + } + + function stop(): void { + needsStop = true; + checkProc.running = true; + } + + function togglePause(): void { + needsPause = true; + checkProc.running = true; + } + + PersistentProperties { + id: props + + property bool running: false + property bool paused: false + property real elapsed: 0 // Might get too large for int + + reloadableId: "recorder" + } + + Process { + id: checkProc + + running: true + command: ["pidof", "gpu-screen-recorder"] + onExited: code => { + props.running = code === 0; + + if (code === 0) { + if (root.needsStop) { + Quickshell.execDetached(["caelestia", "record"]); + props.running = false; + props.paused = false; + } else if (root.needsPause) { + Quickshell.execDetached(["caelestia", "record", "-p"]); + props.paused = !props.paused; + } + } else if (root.needsStart) { + Quickshell.execDetached(["caelestia", "record", ...root.startArgs]); + props.running = true; + props.paused = false; + props.elapsed = 0; + } + + root.needsStart = false; + root.needsStop = false; + root.needsPause = false; + } + } + + Connections { + target: Time + // enabled: props.running && !props.paused + + function onSecondsChanged(): void { + props.elapsed++; + } + } +} diff --git a/.config/quickshell/caelestia/services/SystemUsage.qml b/.config/quickshell/caelestia/services/SystemUsage.qml new file mode 100644 index 0000000..ce62017 --- /dev/null +++ b/.config/quickshell/caelestia/services/SystemUsage.qml @@ -0,0 +1,342 @@ +pragma Singleton + +import qs.config +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + // CPU properties + property string cpuName: "" + property real cpuPerc + property real cpuTemp + + // GPU properties + readonly property string gpuType: Config.services.gpuType.toUpperCase() || autoGpuType + property string autoGpuType: "NONE" + property string gpuName: "" + property real gpuPerc + property real gpuTemp + + // Memory properties + property real memUsed + property real memTotal + readonly property real memPerc: memTotal > 0 ? memUsed / memTotal : 0 + + // Storage properties (aggregated) + readonly property real storagePerc: { + let totalUsed = 0; + let totalSize = 0; + for (const disk of disks) { + totalUsed += disk.used; + totalSize += disk.total; + } + return totalSize > 0 ? totalUsed / totalSize : 0; + } + + // Individual disks: Array of { mount, used, total, free, perc } + property var disks: [] + + property real lastCpuIdle + property real lastCpuTotal + + property int refCount + + function cleanCpuName(name: string): string { + return name.replace(/\(R\)/gi, "").replace(/\(TM\)/gi, "").replace(/CPU/gi, "").replace(/\d+th Gen /gi, "").replace(/\d+nd Gen /gi, "").replace(/\d+rd Gen /gi, "").replace(/\d+st Gen /gi, "").replace(/Core /gi, "").replace(/Processor/gi, "").replace(/\s+/g, " ").trim(); + } + + function cleanGpuName(name: string): string { + return name.replace(/\(R\)/gi, "").replace(/\(TM\)/gi, "").replace(/Graphics/gi, "").replace(/\s+/g, " ").trim(); + } + + function formatKib(kib: real): var { + const mib = 1024; + const gib = 1024 ** 2; + const tib = 1024 ** 3; + + if (kib >= tib) + return { + value: kib / tib, + unit: "TiB" + }; + if (kib >= gib) + return { + value: kib / gib, + unit: "GiB" + }; + if (kib >= mib) + return { + value: kib / mib, + unit: "MiB" + }; + return { + value: kib, + unit: "KiB" + }; + } + + Timer { + running: root.refCount > 0 + interval: Config.dashboard.resourceUpdateInterval + repeat: true + triggeredOnStart: true + onTriggered: { + stat.reload(); + meminfo.reload(); + storage.running = true; + gpuUsage.running = true; + sensors.running = true; + } + } + + // One-time CPU info detection (name) + FileView { + id: cpuinfoInit + + path: "/proc/cpuinfo" + onLoaded: { + const nameMatch = text().match(/model name\s*:\s*(.+)/); + if (nameMatch) + root.cpuName = root.cleanCpuName(nameMatch[1]); + } + } + + FileView { + id: stat + + path: "/proc/stat" + onLoaded: { + const data = text().match(/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/); + if (data) { + const stats = data.slice(1).map(n => parseInt(n, 10)); + const total = stats.reduce((a, b) => a + b, 0); + const idle = stats[3] + (stats[4] ?? 0); + + const totalDiff = total - root.lastCpuTotal; + const idleDiff = idle - root.lastCpuIdle; + root.cpuPerc = totalDiff > 0 ? (1 - idleDiff / totalDiff) : 0; + + root.lastCpuTotal = total; + root.lastCpuIdle = idle; + } + } + } + + FileView { + id: meminfo + + path: "/proc/meminfo" + onLoaded: { + const data = text(); + root.memTotal = parseInt(data.match(/MemTotal: *(\d+)/)[1], 10) || 1; + root.memUsed = (root.memTotal - parseInt(data.match(/MemAvailable: *(\d+)/)[1], 10)) || 0; + } + } + + Process { + id: storage + + // Get physical disks with aggregated usage from their partitions + // lsblk outputs: NAME SIZE TYPE FSUSED FSSIZE in bytes + command: ["lsblk", "-b", "-o", "NAME,SIZE,TYPE,FSUSED,FSSIZE", "-P"] + stdout: StdioCollector { + onStreamFinished: { + const diskMap = {}; // Map disk name -> { name, totalSize, used, fsTotal } + const lines = text.trim().split("\n"); + + for (const line of lines) { + if (line.trim() === "") + continue; + + // Parse KEY="VALUE" format + const nameMatch = line.match(/NAME="([^"]+)"/); + const sizeMatch = line.match(/SIZE="([^"]+)"/); + const typeMatch = line.match(/TYPE="([^"]+)"/); + const fsusedMatch = line.match(/FSUSED="([^"]*)"/); + const fssizeMatch = line.match(/FSSIZE="([^"]*)"/); + + if (!nameMatch || !typeMatch) + continue; + + const name = nameMatch[1]; + const type = typeMatch[1]; + const size = parseInt(sizeMatch?.[1] || "0", 10); + const fsused = parseInt(fsusedMatch?.[1] || "0", 10); + const fssize = parseInt(fssizeMatch?.[1] || "0", 10); + + if (type === "disk") { + // Skip zram (swap) devices + if (name.startsWith("zram")) + continue; + + // Initialize disk entry + if (!diskMap[name]) { + diskMap[name] = { + name: name, + totalSize: size, + used: 0, + fsTotal: 0 + }; + } + } else if (type === "part") { + // Find parent disk (remove trailing numbers/p+numbers) + let parentDisk = name.replace(/p?\d+$/, ""); + // For nvme devices like nvme0n1p1, parent is nvme0n1 + if (name.match(/nvme\d+n\d+p\d+/)) + parentDisk = name.replace(/p\d+$/, ""); + + // Aggregate partition usage to parent disk + if (diskMap[parentDisk]) { + diskMap[parentDisk].used += fsused; + diskMap[parentDisk].fsTotal += fssize; + } + } + } + + // Convert map to sorted array + const diskList = []; + let totalUsed = 0; + let totalSize = 0; + + for (const diskName of Object.keys(diskMap).sort()) { + const disk = diskMap[diskName]; + // Use filesystem total if available, otherwise use disk size + const total = disk.fsTotal > 0 ? disk.fsTotal : disk.totalSize; + const used = disk.used; + const perc = total > 0 ? used / total : 0; + + // Convert bytes to KiB for consistency with formatKib + diskList.push({ + mount: disk.name // Using 'mount' property for compatibility + , + used: used / 1024, + total: total / 1024, + free: (total - used) / 1024, + perc: perc + }); + + totalUsed += used; + totalSize += total; + } + + root.disks = diskList; + } + } + } + + // GPU name detection (one-time) + Process { + id: gpuNameDetect + + running: true + command: ["sh", "-c", "nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null || glxinfo -B 2>/dev/null | grep 'Device:' | cut -d':' -f2 | cut -d'(' -f1 || lspci 2>/dev/null | grep -i 'vga\\|3d controller\\|display' | head -1"] + stdout: StdioCollector { + onStreamFinished: { + const output = text.trim(); + if (!output) + return; + + // Check if it's from nvidia-smi (clean GPU name) + if (output.toLowerCase().includes("nvidia") || output.toLowerCase().includes("geforce") || output.toLowerCase().includes("rtx") || output.toLowerCase().includes("gtx")) { + root.gpuName = root.cleanGpuName(output); + } else if (output.toLowerCase().includes("rx")) { + root.gpuName = root.cleanGpuName(output); + } else { + // Parse lspci output: extract name from brackets or after colon + // Handles cases like [AMD/ATI] Navi 21 [Radeon RX 6800/6800 XT / 6900 XT] (rev c0) + const bracketMatch = output.match(/\[([^\]]+)\][^\[]*$/); + if (bracketMatch) { + root.gpuName = root.cleanGpuName(bracketMatch[1]); + } else { + const colonMatch = output.match(/:\s*(.+)/); + if (colonMatch) + root.gpuName = root.cleanGpuName(colonMatch[1]); + } + } + } + } + } + + Process { + id: gpuTypeCheck + + running: !Config.services.gpuType + command: ["sh", "-c", "if command -v nvidia-smi &>/dev/null && nvidia-smi -L &>/dev/null; then echo NVIDIA; elif ls /sys/class/drm/card*/device/gpu_busy_percent 2>/dev/null | grep -q .; then echo GENERIC; else echo NONE; fi"] + stdout: StdioCollector { + onStreamFinished: root.autoGpuType = text.trim() + } + } + + Process { + id: gpuUsage + + command: root.gpuType === "GENERIC" ? ["sh", "-c", "cat /sys/class/drm/card*/device/gpu_busy_percent"] : root.gpuType === "NVIDIA" ? ["nvidia-smi", "--query-gpu=utilization.gpu,temperature.gpu", "--format=csv,noheader,nounits"] : ["echo"] + stdout: StdioCollector { + onStreamFinished: { + if (root.gpuType === "GENERIC") { + const percs = text.trim().split("\n"); + const sum = percs.reduce((acc, d) => acc + parseInt(d, 10), 0); + root.gpuPerc = sum / percs.length / 100; + } else if (root.gpuType === "NVIDIA") { + const [usage, temp] = text.trim().split(","); + root.gpuPerc = parseInt(usage, 10) / 100; + root.gpuTemp = parseInt(temp, 10); + } else { + root.gpuPerc = 0; + root.gpuTemp = 0; + } + } + } + } + + Process { + id: sensors + + command: ["sensors"] + environment: ({ + LANG: "C.UTF-8", + LC_ALL: "C.UTF-8" + }) + stdout: StdioCollector { + onStreamFinished: { + let cpuTemp = text.match(/(?:Package id [0-9]+|Tdie):\s+((\+|-)[0-9.]+)(°| )C/); + if (!cpuTemp) + // If AMD Tdie pattern failed, try fallback on Tctl + cpuTemp = text.match(/Tctl:\s+((\+|-)[0-9.]+)(°| )C/); + + if (cpuTemp) + root.cpuTemp = parseFloat(cpuTemp[1]); + + if (root.gpuType !== "GENERIC") + return; + + let eligible = false; + let sum = 0; + let count = 0; + + for (const line of text.trim().split("\n")) { + if (line === "Adapter: PCI adapter") + eligible = true; + else if (line === "") + eligible = false; + else if (eligible) { + let match = line.match(/^(temp[0-9]+|GPU core|edge)+:\s+\+([0-9]+\.[0-9]+)(°| )C/); + if (!match) + // Fall back to junction/mem if GPU doesn't have edge temp (for AMD GPUs) + match = line.match(/^(junction|mem)+:\s+\+([0-9]+\.[0-9]+)(°| )C/); + + if (match) { + sum += parseFloat(match[2]); + count++; + } + } + } + + root.gpuTemp = count > 0 ? sum / count : 0; + } + } + } +} diff --git a/.config/quickshell/caelestia/services/Time.qml b/.config/quickshell/caelestia/services/Time.qml new file mode 100644 index 0000000..a07d9ef --- /dev/null +++ b/.config/quickshell/caelestia/services/Time.qml @@ -0,0 +1,28 @@ +pragma Singleton + +import qs.config +import Quickshell +import QtQuick + +Singleton { + property alias enabled: clock.enabled + readonly property date date: clock.date + readonly property int hours: clock.hours + readonly property int minutes: clock.minutes + readonly property int seconds: clock.seconds + + readonly property string timeStr: format(Config.services.useTwelveHourClock ? "hh:mm:A" : "hh:mm") + readonly property list timeComponents: timeStr.split(":") + readonly property string hourStr: timeComponents[0] ?? "" + readonly property string minuteStr: timeComponents[1] ?? "" + readonly property string amPmStr: timeComponents[2] ?? "" + + function format(fmt: string): string { + return Qt.formatDateTime(clock.date, fmt); + } + + SystemClock { + id: clock + precision: SystemClock.Seconds + } +} diff --git a/.config/quickshell/caelestia/services/VPN.qml b/.config/quickshell/caelestia/services/VPN.qml new file mode 100644 index 0000000..2d08631 --- /dev/null +++ b/.config/quickshell/caelestia/services/VPN.qml @@ -0,0 +1,179 @@ +pragma Singleton + +import Quickshell +import Quickshell.Io +import QtQuick +import qs.config +import Caelestia + +Singleton { + id: root + + property bool connected: false + + readonly property bool connecting: connectProc.running || disconnectProc.running + readonly property bool enabled: Config.utilities.vpn.provider.some(p => typeof p === "object" ? (p.enabled === true) : false) + readonly property var providerInput: { + const enabledProvider = Config.utilities.vpn.provider.find(p => typeof p === "object" ? (p.enabled === true) : false); + return enabledProvider || "wireguard"; + } + readonly property bool isCustomProvider: typeof providerInput === "object" + readonly property string providerName: isCustomProvider ? (providerInput.name || "custom") : String(providerInput) + readonly property string interfaceName: isCustomProvider ? (providerInput.interface || "") : "" + readonly property var currentConfig: { + const name = providerName; + const iface = interfaceName; + const defaults = getBuiltinDefaults(name, iface); + + if (isCustomProvider) { + const custom = providerInput; + return { + connectCmd: custom.connectCmd || defaults.connectCmd, + disconnectCmd: custom.disconnectCmd || defaults.disconnectCmd, + interface: custom.interface || defaults.interface, + displayName: custom.displayName || defaults.displayName + }; + } + + return defaults; + } + + function getBuiltinDefaults(name, iface) { + const builtins = { + "wireguard": { + connectCmd: ["pkexec", "wg-quick", "up", iface], + disconnectCmd: ["pkexec", "wg-quick", "down", iface], + interface: iface, + displayName: iface + }, + "warp": { + connectCmd: ["warp-cli", "connect"], + disconnectCmd: ["warp-cli", "disconnect"], + interface: "CloudflareWARP", + displayName: "Warp" + }, + "netbird": { + connectCmd: ["netbird", "up"], + disconnectCmd: ["netbird", "down"], + interface: "wt0", + displayName: "NetBird" + }, + "tailscale": { + connectCmd: ["tailscale", "up"], + disconnectCmd: ["tailscale", "down"], + interface: "tailscale0", + displayName: "Tailscale" + } + }; + + return builtins[name] || { + connectCmd: [name, "up"], + disconnectCmd: [name, "down"], + interface: iface || name, + displayName: name + }; + } + + function connect(): void { + if (!connected && !connecting && root.currentConfig && root.currentConfig.connectCmd) { + connectProc.exec(root.currentConfig.connectCmd); + } + } + + function disconnect(): void { + if (connected && !connecting && root.currentConfig && root.currentConfig.disconnectCmd) { + disconnectProc.exec(root.currentConfig.disconnectCmd); + } + } + + function toggle(): void { + if (connected) { + disconnect(); + } else { + connect(); + } + } + + function checkStatus(): void { + if (root.enabled) { + statusProc.running = true; + } + } + + onConnectedChanged: { + if (!Config.utilities.toasts.vpnChanged) + return; + + const displayName = root.currentConfig ? (root.currentConfig.displayName || "VPN") : "VPN"; + if (connected) { + Toaster.toast(qsTr("VPN connected"), qsTr("Connected to %1").arg(displayName), "vpn_key"); + } else { + Toaster.toast(qsTr("VPN disconnected"), qsTr("Disconnected from %1").arg(displayName), "vpn_key_off"); + } + } + + Component.onCompleted: root.enabled && statusCheckTimer.start() + + Process { + id: nmMonitor + + running: root.enabled + command: ["nmcli", "monitor"] + stdout: SplitParser { + onRead: statusCheckTimer.restart() + } + } + + Process { + id: statusProc + + command: ["ip", "link", "show"] + environment: ({ + LANG: "C.UTF-8", + LC_ALL: "C.UTF-8" + }) + stdout: StdioCollector { + onStreamFinished: { + const iface = root.currentConfig ? root.currentConfig.interface : ""; + root.connected = iface && text.includes(iface + ":"); + } + } + } + + Process { + id: connectProc + + onExited: statusCheckTimer.start() + stderr: StdioCollector { + onStreamFinished: { + const error = text.trim(); + if (error && !error.includes("[#]") && !error.includes("already exists")) { + console.warn("VPN connection error:", error); + } else if (error.includes("already exists")) { + root.connected = true; + } + } + } + } + + Process { + id: disconnectProc + + onExited: statusCheckTimer.start() + stderr: StdioCollector { + onStreamFinished: { + const error = text.trim(); + if (error && !error.includes("[#]")) { + console.warn("VPN disconnection error:", error); + } + } + } + } + + Timer { + id: statusCheckTimer + + interval: 500 + onTriggered: root.checkStatus() + } +} diff --git a/.config/quickshell/caelestia/services/Visibilities.qml b/.config/quickshell/caelestia/services/Visibilities.qml new file mode 100644 index 0000000..5ddde0c --- /dev/null +++ b/.config/quickshell/caelestia/services/Visibilities.qml @@ -0,0 +1,16 @@ +pragma Singleton + +import Quickshell + +Singleton { + property var screens: new Map() + property var bars: new Map() + + function load(screen: ShellScreen, visibilities: var): void { + screens.set(Hypr.monitorFor(screen), visibilities); + } + + function getForActive(): PersistentProperties { + return screens.get(Hypr.focusedMonitor); + } +} diff --git a/.config/quickshell/caelestia/services/Wallpapers.qml b/.config/quickshell/caelestia/services/Wallpapers.qml new file mode 100644 index 0000000..cb96bc5 --- /dev/null +++ b/.config/quickshell/caelestia/services/Wallpapers.qml @@ -0,0 +1,93 @@ +pragma Singleton + +import qs.config +import qs.utils +import Caelestia.Models +import Quickshell +import Quickshell.Io +import QtQuick + +Searcher { + id: root + + readonly property string currentNamePath: `${Paths.state}/wallpaper/path.txt` + readonly property list smartArg: Config.services.smartScheme ? [] : ["--no-smart"] + + property bool showPreview: false + readonly property string current: showPreview ? previewPath : actualCurrent + property string previewPath + property string actualCurrent + property bool previewColourLock + + function setWallpaper(path: string): void { + actualCurrent = path; + Quickshell.execDetached(["caelestia", "wallpaper", "-f", path, ...smartArg]); + } + + function preview(path: string): void { + previewPath = path; + showPreview = true; + + if (Colours.scheme === "dynamic") + getPreviewColoursProc.running = true; + } + + function stopPreview(): void { + showPreview = false; + if (!previewColourLock) + Colours.showPreview = false; + } + + list: wallpapers.entries + key: "relativePath" + useFuzzy: Config.launcher.useFuzzy.wallpapers + extraOpts: useFuzzy ? ({}) : ({ + forward: false + }) + + IpcHandler { + target: "wallpaper" + + function get(): string { + return root.actualCurrent; + } + + function set(path: string): void { + root.setWallpaper(path); + } + + function list(): string { + return root.list.map(w => w.path).join("\n"); + } + } + + FileView { + path: root.currentNamePath + watchChanges: true + onFileChanged: reload() + onLoaded: { + root.actualCurrent = text().trim(); + root.previewColourLock = false; + } + } + + FileSystemModel { + id: wallpapers + + recursive: true + path: Paths.wallsdir + filter: FileSystemModel.Images + } + + Process { + id: getPreviewColoursProc + + command: ["caelestia", "wallpaper", "-p", root.previewPath, ...root.smartArg] + stdout: StdioCollector { + onStreamFinished: { + Colours.load(text, true); + Colours.showPreview = true; + } + } + } +} diff --git a/.config/quickshell/caelestia/services/Weather.qml b/.config/quickshell/caelestia/services/Weather.qml new file mode 100644 index 0000000..a309542 --- /dev/null +++ b/.config/quickshell/caelestia/services/Weather.qml @@ -0,0 +1,206 @@ +pragma Singleton + +import qs.config +import qs.utils +import Caelestia +import Quickshell +import QtQuick + +Singleton { + id: root + + property string city + property string loc + property var cc + property list forecast + property list hourlyForecast + + readonly property string icon: cc ? Icons.getWeatherIcon(cc.weatherCode) : "cloud_alert" + readonly property string description: cc?.weatherDesc ?? qsTr("No weather") + readonly property string temp: Config.services.useFahrenheit ? `${cc?.tempF ?? 0}°F` : `${cc?.tempC ?? 0}°C` + readonly property string feelsLike: Config.services.useFahrenheit ? `${cc?.feelsLikeF ?? 0}°F` : `${cc?.feelsLikeC ?? 0}°C` + readonly property int humidity: cc?.humidity ?? 0 + readonly property real windSpeed: cc?.windSpeed ?? 0 + readonly property string sunrise: cc ? Qt.formatDateTime(new Date(cc.sunrise), Config.services.useTwelveHourClock ? "h:mm A" : "h:mm") : "--:--" + readonly property string sunset: cc ? Qt.formatDateTime(new Date(cc.sunset), Config.services.useTwelveHourClock ? "h:mm A" : "h:mm") : "--:--" + + readonly property var cachedCities: new Map() + + function reload(): void { + const configLocation = Config.services.weatherLocation; + + if (configLocation) { + if (configLocation.indexOf(",") !== -1 && !isNaN(parseFloat(configLocation.split(",")[0]))) { + loc = configLocation; + fetchCityFromCoords(configLocation); + } else { + fetchCoordsFromCity(configLocation); + } + } else if (!loc || timer.elapsed() > 900) { + Requests.get("https://ipinfo.io/json", text => { + const response = JSON.parse(text); + if (response.loc) { + loc = response.loc; + city = response.city ?? ""; + timer.restart(); + } + }); + } + } + + function fetchCityFromCoords(coords: string): void { + if (cachedCities.has(coords)) { + city = cachedCities.get(coords); + return; + } + + const [lat, lon] = coords.split(","); + const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=geocodejson`; + Requests.get(url, text => { + const geo = JSON.parse(text).features?.[0]?.properties.geocoding; + if (geo) { + const geoCity = geo.type === "city" ? geo.name : geo.city; + city = geoCity; + cachedCities.set(coords, geoCity); + } else { + city = "Unknown City"; + } + }); + } + + function fetchCoordsFromCity(cityName: string): void { + const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(cityName)}&count=1&language=en&format=json`; + + Requests.get(url, text => { + const json = JSON.parse(text); + if (json.results && json.results.length > 0) { + const result = json.results[0]; + loc = result.latitude + "," + result.longitude; + city = result.name; + } else { + loc = ""; + reload(); + } + }); + } + + function fetchWeatherData(): void { + const url = getWeatherUrl(); + if (url === "") + return; + + Requests.get(url, text => { + const json = JSON.parse(text); + if (!json.current || !json.daily) + return; + + cc = { + weatherCode: json.current.weather_code, + weatherDesc: getWeatherCondition(json.current.weather_code), + tempC: Math.round(json.current.temperature_2m), + tempF: Math.round(toFahrenheit(json.current.temperature_2m)), + feelsLikeC: Math.round(json.current.apparent_temperature), + feelsLikeF: Math.round(toFahrenheit(json.current.apparent_temperature)), + humidity: json.current.relative_humidity_2m, + windSpeed: json.current.wind_speed_10m, + isDay: json.current.is_day, + sunrise: json.daily.sunrise[0], + sunset: json.daily.sunset[0] + }; + + const forecastList = []; + for (let i = 0; i < json.daily.time.length; i++) + forecastList.push({ + date: json.daily.time[i], + maxTempC: Math.round(json.daily.temperature_2m_max[i]), + maxTempF: Math.round(toFahrenheit(json.daily.temperature_2m_max[i])), + minTempC: Math.round(json.daily.temperature_2m_min[i]), + minTempF: Math.round(toFahrenheit(json.daily.temperature_2m_min[i])), + weatherCode: json.daily.weather_code[i], + icon: Icons.getWeatherIcon(json.daily.weather_code[i]) + }); + forecast = forecastList; + + const hourlyList = []; + const now = new Date(); + for (let i = 0; i < json.hourly.time.length; i++) { + const time = new Date(json.hourly.time[i]); + if (time < now) + continue; + + hourlyList.push({ + timestamp: json.hourly.time[i], + hour: time.getHours(), + tempC: Math.round(json.hourly.temperature_2m[i]), + tempF: Math.round(toFahrenheit(json.hourly.temperature_2m[i])), + weatherCode: json.hourly.weather_code[i], + icon: Icons.getWeatherIcon(json.hourly.weather_code[i]) + }); + } + hourlyForecast = hourlyList; + }); + } + + function toFahrenheit(celcius: real): real { + return celcius * 9 / 5 + 32; + } + + function getWeatherUrl(): string { + if (!loc || loc.indexOf(",") === -1) + return ""; + + const [lat, lon] = loc.split(","); + const baseUrl = "https://api.open-meteo.com/v1/forecast"; + const params = ["latitude=" + lat, "longitude=" + lon, "hourly=weather_code,temperature_2m", "daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset", "current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,weather_code,wind_speed_10m", "timezone=auto", "forecast_days=7"]; + + return baseUrl + "?" + params.join("&"); + } + + function getWeatherCondition(code: string): string { + const conditions = { + "0": "Clear", + "1": "Clear", + "2": "Partly cloudy", + "3": "Overcast", + "45": "Fog", + "48": "Fog", + "51": "Drizzle", + "53": "Drizzle", + "55": "Drizzle", + "56": "Freezing drizzle", + "57": "Freezing drizzle", + "61": "Light rain", + "63": "Rain", + "65": "Heavy rain", + "66": "Light rain", + "67": "Heavy rain", + "71": "Light snow", + "73": "Snow", + "75": "Heavy snow", + "77": "Snow", + "80": "Light rain", + "81": "Rain", + "82": "Heavy rain", + "85": "Light snow showers", + "86": "Heavy snow showers", + "95": "Thunderstorm", + "96": "Thunderstorm with hail", + "99": "Thunderstorm with hail" + }; + return conditions[code] || "Unknown"; + } + + onLocChanged: fetchWeatherData() + + // Refresh current location hourly + Timer { + interval: 3600000 // 1 hour + running: true + repeat: true + onTriggered: fetchWeatherData() + } + + ElapsedTimer { + id: timer + } +} diff --git a/.config/quickshell/caelestia/shell.qml b/.config/quickshell/caelestia/shell.qml new file mode 100644 index 0000000..3ce7776 --- /dev/null +++ b/.config/quickshell/caelestia/shell.qml @@ -0,0 +1,25 @@ +//@ pragma Env QS_NO_RELOAD_POPUP=1 +//@ pragma Env QSG_RENDER_LOOP=threaded +//@ pragma Env QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000 + +import "modules" +import "modules/drawers" +import "modules/background" +import "modules/areapicker" +import "modules/lock" +import Quickshell + +ShellRoot { + Background {} + Drawers {} + AreaPicker {} + Lock { + id: lock + } + + Shortcuts {} + BatteryMonitor {} + IdleMonitors { + lock: lock + } +} diff --git a/.config/quickshell/caelestia/utils/Icons.qml b/.config/quickshell/caelestia/utils/Icons.qml new file mode 100644 index 0000000..c06cbf8 --- /dev/null +++ b/.config/quickshell/caelestia/utils/Icons.qml @@ -0,0 +1,221 @@ +pragma Singleton + +import qs.config +import Quickshell +import Quickshell.Services.Notifications +import QtQuick + +Singleton { + id: root + + readonly 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" + }) + + readonly property var categoryIcons: ({ + WebBrowser: "web", + Printing: "print", + Security: "security", + Network: "chat", + Archiving: "archive", + Compression: "archive", + Development: "code", + IDE: "code", + TextEditor: "edit_note", + Audio: "music_note", + Music: "music_note", + Player: "music_note", + Recorder: "mic", + Game: "sports_esports", + FileTools: "files", + FileManager: "files", + Filesystem: "files", + FileTransfer: "files", + Settings: "settings", + DesktopSettings: "settings", + HardwareSettings: "settings", + TerminalEmulator: "terminal", + ConsoleOnly: "terminal", + Utility: "build", + Monitor: "monitor_heart", + Midi: "graphic_eq", + Mixer: "graphic_eq", + AudioVideoEditing: "video_settings", + AudioVideo: "music_video", + Video: "videocam", + Building: "construction", + Graphics: "photo_library", + "2DGraphics": "photo_library", + RasterGraphics: "photo_library", + TV: "tv", + System: "host", + Office: "content_paste" + }) + + function getAppIcon(name: string, fallback: string): string { + const icon = DesktopEntries.heuristicLookup(name)?.icon; + if (fallback !== "undefined") + return Quickshell.iconPath(icon, fallback); + return Quickshell.iconPath(icon); + } + + function getAppCategoryIcon(name: string, fallback: string): string { + const categories = DesktopEntries.heuristicLookup(name)?.categories; + + if (categories) + for (const [key, value] of Object.entries(categoryIcons)) + if (categories.includes(key)) + return value; + return fallback; + } + + function getNetworkIcon(strength: int, isSecure = false): string { + if (isSecure) { + if (strength >= 80) + return "network_wifi_locked"; + if (strength >= 60) + return "network_wifi_3_bar_locked"; + if (strength >= 40) + return "network_wifi_2_bar_locked"; + if (strength >= 20) + return "network_wifi_1_bar_locked"; + return "signal_wifi_0_bar"; + } else { + if (strength >= 80) + return "network_wifi"; + if (strength >= 60) + return "network_wifi_3_bar"; + if (strength >= 40) + return "network_wifi_2_bar"; + if (strength >= 20) + return "network_wifi_1_bar"; + return "signal_wifi_0_bar"; + } + } + + function getBluetoothIcon(icon: string): string { + if (icon.includes("headset") || icon.includes("headphones")) + return "headphones"; + if (icon.includes("audio")) + return "speaker"; + if (icon.includes("phone")) + return "smartphone"; + if (icon.includes("mouse")) + return "mouse"; + if (icon.includes("keyboard")) + return "keyboard"; + return "bluetooth"; + } + + function getWeatherIcon(code: string): string { + if (weatherIcons.hasOwnProperty(code)) + return weatherIcons[code]; + return "air"; + } + + function getNotifIcon(summary: string, urgency: int): string { + summary = summary.toLowerCase(); + if (summary.includes("reboot")) + return "restart_alt"; + if (summary.includes("recording")) + return "screen_record"; + if (summary.includes("battery")) + return "power"; + if (summary.includes("screenshot")) + return "screenshot_monitor"; + if (summary.includes("welcome")) + return "waving_hand"; + if (summary.includes("time") || summary.includes("a break")) + return "schedule"; + if (summary.includes("installed")) + return "download"; + if (summary.includes("update")) + return "update"; + if (summary.includes("unable to")) + return "deployed_code_alert"; + if (summary.includes("profile")) + return "person"; + if (summary.includes("file")) + return "folder_copy"; + if (urgency === NotificationUrgency.Critical) + return "release_alert"; + return "chat"; + } + + function getVolumeIcon(volume: real, isMuted: bool): string { + if (isMuted) + return "no_sound"; + if (volume >= 0.5) + return "volume_up"; + if (volume > 0) + return "volume_down"; + return "volume_mute"; + } + + function getMicVolumeIcon(volume: real, isMuted: bool): string { + if (!isMuted && volume > 0) + return "mic"; + return "mic_off"; + } + + function getSpecialWsIcon(name: string): string { + name = name.toLowerCase().slice("special:".length); + + for (const iconConfig of Config.bar.workspaces.specialWorkspaceIcons) { + if (iconConfig.name === name) { + return iconConfig.icon; + } + } + + if (name === "special") + return "star"; + if (name === "communication") + return "forum"; + if (name === "music") + return "music_cast"; + if (name === "todo") + return "checklist"; + if (name === "sysmon") + return "monitor_heart"; + return name[0].toUpperCase(); + } + + function getTrayIcon(id: string, icon: string): string { + for (const sub of Config.bar.tray.iconSubs) + if (sub.id === id) + return sub.image ? Qt.resolvedUrl(sub.image) : Quickshell.iconPath(sub.icon); + + if (icon.includes("?path=")) { + const [name, path] = icon.split("?path="); + icon = Qt.resolvedUrl(`${path}/${name.slice(name.lastIndexOf("/") + 1)}`); + } + return icon; + } +} diff --git a/.config/quickshell/caelestia/utils/Images.qml b/.config/quickshell/caelestia/utils/Images.qml new file mode 100644 index 0000000..ac76f51 --- /dev/null +++ b/.config/quickshell/caelestia/utils/Images.qml @@ -0,0 +1,12 @@ +pragma Singleton + +import Quickshell + +Singleton { + readonly property list validImageTypes: ["jpeg", "png", "webp", "tiff", "svg"] + readonly property list validImageExtensions: ["jpg", "jpeg", "png", "webp", "tif", "tiff", "svg"] + + function isValidImageByName(name: string): bool { + return validImageExtensions.some(t => name.endsWith(`.${t}`)); + } +} diff --git a/.config/quickshell/caelestia/utils/NetworkConnection.qml b/.config/quickshell/caelestia/utils/NetworkConnection.qml new file mode 100644 index 0000000..e55b87b --- /dev/null +++ b/.config/quickshell/caelestia/utils/NetworkConnection.qml @@ -0,0 +1,116 @@ +pragma Singleton + +import qs.services +import QtQuick + +/** + * NetworkConnection + * + * Centralized utility for network connection logic. Provides a single source of truth + * for connecting to wireless networks, eliminating code duplication across + * controlcenter components and bar popouts. + * + * Usage: + * ```qml + * import qs.utils + * + * // With Session object (controlcenter) + * NetworkConnection.handleConnect(network, session); + * + * // Without Session object (bar popouts) - provide password dialog callback + * NetworkConnection.handleConnect(network, null, (network) => { + * // Show password dialog + * root.passwordNetwork = network; + * root.showPasswordDialog = true; + * }); + * ``` + */ +QtObject { + id: root + + /** + * Handle network connection with automatic disconnection if needed. + * If there's an active network different from the target, disconnects first, + * then connects to the target network. + * + * @param network The network object to connect to (must have ssid property) + * @param session Optional Session object (for controlcenter - must have network property with showPasswordDialog and pendingNetwork) + * @param onPasswordNeeded Optional callback function(network) called when password is needed (for bar popouts) + */ + function handleConnect(network, session, onPasswordNeeded): void { + if (!network) { + return; + } + + if (Nmcli.active && Nmcli.active.ssid !== network.ssid) { + Nmcli.disconnectFromNetwork(); + Qt.callLater(() => { + root.connectToNetwork(network, session, onPasswordNeeded); + }); + } else { + root.connectToNetwork(network, session, onPasswordNeeded); + } + } + + /** + * Connect to a wireless network. + * Handles both secured and open networks, checks for saved profiles, + * and shows password dialog if needed. + * + * @param network The network object to connect to (must have ssid, isSecure, bssid properties) + * @param session Optional Session object (for controlcenter - must have network property with showPasswordDialog and pendingNetwork) + * @param onPasswordNeeded Optional callback function(network) called when password is needed (for bar popouts) + */ + function connectToNetwork(network, session, onPasswordNeeded): void { + if (!network) { + return; + } + + if (network.isSecure) { + const hasSavedProfile = Nmcli.hasSavedProfile(network.ssid); + + if (hasSavedProfile) { + Nmcli.connectToNetwork(network.ssid, "", network.bssid, null); + } else { + // Use password check with callback + Nmcli.connectToNetworkWithPasswordCheck(network.ssid, network.isSecure, result => { + if (result.needsPassword) { + // Clear pending connection if exists + if (Nmcli.pendingConnection) { + Nmcli.connectionCheckTimer.stop(); + Nmcli.immediateCheckTimer.stop(); + Nmcli.immediateCheckTimer.checkCount = 0; + Nmcli.pendingConnection = null; + } + + // Handle password dialog - use session if available, otherwise use callback + if (session && session.network) { + session.network.showPasswordDialog = true; + session.network.pendingNetwork = network; + } else if (onPasswordNeeded) { + onPasswordNeeded(network); + } + } + }, network.bssid); + } + } else { + Nmcli.connectToNetwork(network.ssid, "", network.bssid, null); + } + } + + /** + * Connect to a wireless network with a provided password. + * Used by password dialogs when the user has already entered a password. + * + * @param network The network object to connect to (must have ssid, bssid properties) + * @param password The password to use for connection + * @param onResult Optional callback function(result) called with connection result + */ + function connectWithPassword(network, password, onResult): void { + if (!network) { + return; + } + + Nmcli.connectToNetwork(network.ssid, password || "", network.bssid || "", onResult || null); + } +} diff --git a/.config/quickshell/caelestia/utils/Paths.qml b/.config/quickshell/caelestia/utils/Paths.qml new file mode 100644 index 0000000..bc89770 --- /dev/null +++ b/.config/quickshell/caelestia/utils/Paths.qml @@ -0,0 +1,37 @@ +pragma Singleton + +import qs.config +import Caelestia +import Quickshell + +Singleton { + id: root + + readonly property string home: Quickshell.env("HOME") + readonly property string pictures: Quickshell.env("XDG_PICTURES_DIR") || `${home}/Pictures` + readonly property string videos: Quickshell.env("XDG_VIDEOS_DIR") || `${home}/Videos` + + readonly property string data: `${Quickshell.env("XDG_DATA_HOME") || `${home}/.local/share`}/caelestia` + readonly property string state: `${Quickshell.env("XDG_STATE_HOME") || `${home}/.local/state`}/caelestia` + readonly property string cache: `${Quickshell.env("XDG_CACHE_HOME") || `${home}/.cache`}/caelestia` + readonly property string config: `${Quickshell.env("XDG_CONFIG_HOME") || `${home}/.config`}/caelestia` + + readonly property string imagecache: `${cache}/imagecache` + readonly property string notifimagecache: `${imagecache}/notifs` + readonly property string wallsdir: Quickshell.env("CAELESTIA_WALLPAPERS_DIR") || absolutePath(Config.paths.wallpaperDir) + readonly property string recsdir: Quickshell.env("CAELESTIA_RECORDINGS_DIR") || `${videos}/Recordings` + readonly property string libdir: Quickshell.env("CAELESTIA_LIB_DIR") || "/usr/lib/caelestia" + + function toLocalFile(path: url): string { + path = Qt.resolvedUrl(path); + return path.toString() ? CUtils.toLocalFile(path) : ""; + } + + function absolutePath(path: string): string { + return toLocalFile(path.replace(/~|(\$({?)HOME(}?))+/, home)); + } + + function shortenHome(path: string): string { + return path.replace(home, "~"); + } +} diff --git a/.config/quickshell/caelestia/utils/Searcher.qml b/.config/quickshell/caelestia/utils/Searcher.qml new file mode 100644 index 0000000..053b73b --- /dev/null +++ b/.config/quickshell/caelestia/utils/Searcher.qml @@ -0,0 +1,56 @@ +import Quickshell + +import "scripts/fzf.js" as Fzf +import "scripts/fuzzysort.js" as Fuzzy +import QtQuick + +Singleton { + required property list list + property string key: "name" + property bool useFuzzy: false + property var extraOpts: ({}) + + // Extra stuff for fuzzy + property list keys: [key] + property list weights: [1] + + readonly property var fzf: useFuzzy ? [] : new Fzf.Finder(list, Object.assign({ + selector + }, extraOpts)) + readonly property list fuzzyPrepped: useFuzzy ? list.map(e => { + const obj = { + _item: e + }; + for (const k of keys) + obj[k] = Fuzzy.prepare(e[k]); + return obj; + }) : [] + + function transformSearch(search: string): string { + return search; + } + + function selector(item: var): string { + // Only for fzf + return item[key]; + } + + function query(search: string): list { + search = transformSearch(search); + if (!search) + return [...list]; + + if (useFuzzy) + return Fuzzy.go(search, fuzzyPrepped, Object.assign({ + all: true, + keys, + scoreFn: r => weights.reduce((a, w, i) => a + r[i].score * w, 0) + }, extraOpts)).map(r => r.obj._item); + + return fzf.find(search).sort((a, b) => { + if (a.score === b.score) + return selector(a.item).trim().length - selector(b.item).trim().length; + return b.score - a.score; + }).map(r => r.item); + } +} diff --git a/.config/quickshell/caelestia/utils/Strings.qml b/.config/quickshell/caelestia/utils/Strings.qml new file mode 100644 index 0000000..1d0cc76 --- /dev/null +++ b/.config/quickshell/caelestia/utils/Strings.qml @@ -0,0 +1,20 @@ +pragma Singleton + +import Quickshell + +Singleton { + function testRegexList(filterList: list, target: string): bool { + const regexChecker = /^\^.*\$$/; + for (const filter of filterList) { + // If filter is a regex + if (regexChecker.test(filter)) { + if ((new RegExp(filter)).test(target)) + return true; + } else { + if (filter === target) + return true; + } + } + return false; + } +} diff --git a/.config/quickshell/caelestia/utils/SysInfo.qml b/.config/quickshell/caelestia/utils/SysInfo.qml new file mode 100644 index 0000000..19aa4a7 --- /dev/null +++ b/.config/quickshell/caelestia/utils/SysInfo.qml @@ -0,0 +1,88 @@ +pragma Singleton + +import qs.config +import qs.utils +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + property string osName + property string osPrettyName + property string osId + property list osIdLike + property string osLogo: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/logo.svg`) + property bool isDefaultLogo: true + + property string uptime + readonly property string user: Quickshell.env("USER") + readonly property string wm: Quickshell.env("XDG_CURRENT_DESKTOP") || Quickshell.env("XDG_SESSION_DESKTOP") + readonly property string shell: Quickshell.env("SHELL").split("/").pop() + + FileView { + id: osRelease + + path: "/etc/os-release" + onLoaded: { + const lines = text().split("\n"); + + const fd = key => lines.find(l => l.startsWith(`${key}=`))?.split("=")[1].replace(/"/g, "") ?? ""; + + root.osName = fd("NAME"); + root.osPrettyName = fd("PRETTY_NAME"); + root.osId = fd("ID"); + root.osIdLike = fd("ID_LIKE").split(" "); + + const logo = Quickshell.iconPath(fd("LOGO"), true); + if (Config.general.logo === "caelestia") { + root.osLogo = Qt.resolvedUrl(`${Quickshell.shellDir}/assets/logo.svg`); + root.isDefaultLogo = true; + } else if (Config.general.logo) { + root.osLogo = Quickshell.iconPath(Config.general.logo, true) || "file://" + Paths.absolutePath(Config.general.logo); + root.isDefaultLogo = false; + } else if (logo) { + root.osLogo = logo; + root.isDefaultLogo = false; + } + } + } + + Connections { + target: Config.general + + function onLogoChanged(): void { + osRelease.reload(); + } + } + + Timer { + running: true + repeat: true + interval: 15000 + onTriggered: fileUptime.reload() + } + + FileView { + id: fileUptime + + path: "/proc/uptime" + onLoaded: { + const up = parseInt(text().split(" ")[0] ?? 0); + + const days = Math.floor(up / 86400); + const hours = Math.floor((up % 86400) / 3600); + const minutes = Math.floor((up % 3600) / 60); + + let str = ""; + if (days > 0) + str += `${days} day${days === 1 ? "" : "s"}`; + if (hours > 0) + str += `${str ? ", " : ""}${hours} hour${hours === 1 ? "" : "s"}`; + if (minutes > 0 || !str) + str += `${str ? ", " : ""}${minutes} minute${minutes === 1 ? "" : "s"}`; + root.uptime = str; + } + } +} diff --git a/.config/quickshell/caelestia/utils/scripts/fuzzysort.js b/.config/quickshell/caelestia/utils/scripts/fuzzysort.js new file mode 100644 index 0000000..94308ff --- /dev/null +++ b/.config/quickshell/caelestia/utils/scripts/fuzzysort.js @@ -0,0 +1,705 @@ +.pragma library + +/* +https://github.com/farzher/fuzzysort + +MIT License + +Copyright (c) 2018 Stephen Kamenar + +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. +*/ + +var single = (search, target) => { + if(!search || !target) return NULL + + var preparedSearch = getPreparedSearch(search) + if(!isPrepared(target)) target = getPrepared(target) + + var searchBitflags = preparedSearch.bitflags + if((searchBitflags & target._bitflags) !== searchBitflags) return NULL + + return algorithm(preparedSearch, target) +} + +var go = (search, targets, options) => { + if(!search) return options?.all ? all(targets, options) : noResults + + var preparedSearch = getPreparedSearch(search) + var searchBitflags = preparedSearch.bitflags + var containsSpace = preparedSearch.containsSpace + + var threshold = denormalizeScore( options?.threshold || 0 ) + var limit = options?.limit || INFINITY + + var resultsLen = 0; var limitedCount = 0 + var targetsLen = targets.length + + function push_result(result) { + if(resultsLen < limit) { q.add(result); ++resultsLen } + else { + ++limitedCount + if(result._score > q.peek()._score) q.replaceTop(result) + } + } + + // This code is copy/pasted 3 times for performance reasons [options.key, options.keys, no keys] + + // options.key + if(options?.key) { + var key = options.key + for(var i = 0; i < targetsLen; ++i) { var obj = targets[i] + var target = getValue(obj, key) + if(!target) continue + if(!isPrepared(target)) target = getPrepared(target) + + if((searchBitflags & target._bitflags) !== searchBitflags) continue + var result = algorithm(preparedSearch, target) + if(result === NULL) continue + if(result._score < threshold) continue + + result.obj = obj + push_result(result) + } + + // options.keys + } else if(options?.keys) { + var keys = options.keys + var keysLen = keys.length + + outer: for(var i = 0; i < targetsLen; ++i) { var obj = targets[i] + + { // early out based on bitflags + var keysBitflags = 0 + for (var keyI = 0; keyI < keysLen; ++keyI) { + var key = keys[keyI] + var target = getValue(obj, key) + if(!target) { tmpTargets[keyI] = noTarget; continue } + if(!isPrepared(target)) target = getPrepared(target) + tmpTargets[keyI] = target + + keysBitflags |= target._bitflags + } + + if((searchBitflags & keysBitflags) !== searchBitflags) continue + } + + if(containsSpace) for(let i=0; i -1000) { + if(keysSpacesBestScores[i] > NEGATIVE_INFINITY) { + var tmp = (keysSpacesBestScores[i] + allowPartialMatchScores[i]) / 4/*bonus score for having multiple matches*/ + if(tmp > keysSpacesBestScores[i]) keysSpacesBestScores[i] = tmp + } + } + if(allowPartialMatchScores[i] > keysSpacesBestScores[i]) keysSpacesBestScores[i] = allowPartialMatchScores[i] + } + } + + if(containsSpace) { + for(let i=0; i -1000) { + if(score > NEGATIVE_INFINITY) { + var tmp = (score + result._score) / 4/*bonus score for having multiple matches*/ + if(tmp > score) score = tmp + } + } + if(result._score > score) score = result._score + } + } + + objResults.obj = obj + objResults._score = score + if(options?.scoreFn) { + score = options.scoreFn(objResults) + if(!score) continue + score = denormalizeScore(score) + objResults._score = score + } + + if(score < threshold) continue + push_result(objResults) + } + + // no keys + } else { + for(var i = 0; i < targetsLen; ++i) { var target = targets[i] + if(!target) continue + if(!isPrepared(target)) target = getPrepared(target) + + if((searchBitflags & target._bitflags) !== searchBitflags) continue + var result = algorithm(preparedSearch, target) + if(result === NULL) continue + if(result._score < threshold) continue + + push_result(result) + } + } + + if(resultsLen === 0) return noResults + var results = new Array(resultsLen) + for(var i = resultsLen - 1; i >= 0; --i) results[i] = q.poll() + results.total = resultsLen + limitedCount + return results +} + + +// this is written as 1 function instead of 2 for minification. perf seems fine ... +// except when minified. the perf is very slow +var highlight = (result, open='', close='') => { + var callback = typeof open === 'function' ? open : undefined + + var target = result.target + var targetLen = target.length + var indexes = result.indexes + var highlighted = '' + var matchI = 0 + var indexesI = 0 + var opened = false + var parts = [] + + for(var i = 0; i < targetLen; ++i) { var char = target[i] + if(indexes[indexesI] === i) { + ++indexesI + if(!opened) { opened = true + if(callback) { + parts.push(highlighted); highlighted = '' + } else { + highlighted += open + } + } + + if(indexesI === indexes.length) { + if(callback) { + highlighted += char + parts.push(callback(highlighted, matchI++)); highlighted = '' + parts.push(target.substr(i+1)) + } else { + highlighted += char + close + target.substr(i+1) + } + break + } + } else { + if(opened) { opened = false + if(callback) { + parts.push(callback(highlighted, matchI++)); highlighted = '' + } else { + highlighted += close + } + } + } + highlighted += char + } + + return callback ? parts : highlighted +} + + +var prepare = (target) => { + if(typeof target === 'number') target = ''+target + else if(typeof target !== 'string') target = '' + var info = prepareLowerInfo(target) + return new_result(target, {_targetLower:info._lower, _targetLowerCodes:info.lowerCodes, _bitflags:info.bitflags}) +} + +var cleanup = () => { preparedCache.clear(); preparedSearchCache.clear() } + + +// Below this point is only internal code +// Below this point is only internal code +// Below this point is only internal code +// Below this point is only internal code + + +class Result { + get ['indexes']() { return this._indexes.slice(0, this._indexes.len).sort((a,b)=>a-b) } + set ['indexes'](indexes) { return this._indexes = indexes } + ['highlight'](open, close) { return highlight(this, open, close) } + get ['score']() { return normalizeScore(this._score) } + set ['score'](score) { this._score = denormalizeScore(score) } +} + +class KeysResult extends Array { + get ['score']() { return normalizeScore(this._score) } + set ['score'](score) { this._score = denormalizeScore(score) } +} + +var new_result = (target, options) => { + const result = new Result() + result['target'] = target + result['obj'] = options.obj ?? NULL + result._score = options._score ?? NEGATIVE_INFINITY + result._indexes = options._indexes ?? [] + result._targetLower = options._targetLower ?? '' + result._targetLowerCodes = options._targetLowerCodes ?? NULL + result._nextBeginningIndexes = options._nextBeginningIndexes ?? NULL + result._bitflags = options._bitflags ?? 0 + return result +} + + +var normalizeScore = score => { + if(score === NEGATIVE_INFINITY) return 0 + if(score > 1) return score + return Math.E ** ( ((-score + 1)**.04307 - 1) * -2) +} +var denormalizeScore = normalizedScore => { + if(normalizedScore === 0) return NEGATIVE_INFINITY + if(normalizedScore > 1) return normalizedScore + return 1 - Math.pow((Math.log(normalizedScore) / -2 + 1), 1 / 0.04307) +} + + +var prepareSearch = (search) => { + if(typeof search === 'number') search = ''+search + else if(typeof search !== 'string') search = '' + search = search.trim() + var info = prepareLowerInfo(search) + + var spaceSearches = [] + if(info.containsSpace) { + var searches = search.split(/\s+/) + searches = [...new Set(searches)] // distinct + for(var i=0; i { + if(target.length > 999) return prepare(target) // don't cache huge targets + var targetPrepared = preparedCache.get(target) + if(targetPrepared !== undefined) return targetPrepared + targetPrepared = prepare(target) + preparedCache.set(target, targetPrepared) + return targetPrepared +} +var getPreparedSearch = (search) => { + if(search.length > 999) return prepareSearch(search) // don't cache huge searches + var searchPrepared = preparedSearchCache.get(search) + if(searchPrepared !== undefined) return searchPrepared + searchPrepared = prepareSearch(search) + preparedSearchCache.set(search, searchPrepared) + return searchPrepared +} + + +var all = (targets, options) => { + var results = []; results.total = targets.length // this total can be wrong if some targets are skipped + + var limit = options?.limit || INFINITY + + if(options?.key) { + for(var i=0;i= limit) return results + } + } else if(options?.keys) { + for(var i=0;i= 0; --keyI) { + var target = getValue(obj, options.keys[keyI]) + if(!target) { objResults[keyI] = noTarget; continue } + if(!isPrepared(target)) target = getPrepared(target) + target._score = NEGATIVE_INFINITY + target._indexes.len = 0 + objResults[keyI] = target + } + objResults.obj = obj + objResults._score = NEGATIVE_INFINITY + results.push(objResults); if(results.length >= limit) return results + } + } else { + for(var i=0;i= limit) return results + } + } + + return results +} + + +var algorithm = (preparedSearch, prepared, allowSpaces=false, allowPartialMatch=false) => { + if(allowSpaces===false && preparedSearch.containsSpace) return algorithmSpaces(preparedSearch, prepared, allowPartialMatch) + + var searchLower = preparedSearch._lower + var searchLowerCodes = preparedSearch.lowerCodes + var searchLowerCode = searchLowerCodes[0] + var targetLowerCodes = prepared._targetLowerCodes + var searchLen = searchLowerCodes.length + var targetLen = targetLowerCodes.length + var searchI = 0 // where we at + var targetI = 0 // where you at + var matchesSimpleLen = 0 + + // very basic fuzzy match; to remove non-matching targets ASAP! + // walk through target. find sequential matches. + // if all chars aren't found then exit + for(;;) { + var isMatch = searchLowerCode === targetLowerCodes[targetI] + if(isMatch) { + matchesSimple[matchesSimpleLen++] = targetI + ++searchI; if(searchI === searchLen) break + searchLowerCode = searchLowerCodes[searchI] + } + ++targetI; if(targetI >= targetLen) return NULL // Failed to find searchI + } + + var searchI = 0 + var successStrict = false + var matchesStrictLen = 0 + + var nextBeginningIndexes = prepared._nextBeginningIndexes + if(nextBeginningIndexes === NULL) nextBeginningIndexes = prepared._nextBeginningIndexes = prepareNextBeginningIndexes(prepared.target) + targetI = matchesSimple[0]===0 ? 0 : nextBeginningIndexes[matchesSimple[0]-1] + + // Our target string successfully matched all characters in sequence! + // Let's try a more advanced and strict test to improve the score + // only count it as a match if it's consecutive or a beginning character! + var backtrackCount = 0 + if(targetI !== targetLen) for(;;) { + if(targetI >= targetLen) { + // We failed to find a good spot for this search char, go back to the previous search char and force it forward + if(searchI <= 0) break // We failed to push chars forward for a better match + + ++backtrackCount; if(backtrackCount > 200) break // exponential backtracking is taking too long, just give up and return a bad match + + --searchI + var lastMatch = matchesStrict[--matchesStrictLen] + targetI = nextBeginningIndexes[lastMatch] + + } else { + var isMatch = searchLowerCodes[searchI] === targetLowerCodes[targetI] + if(isMatch) { + matchesStrict[matchesStrictLen++] = targetI + ++searchI; if(searchI === searchLen) { successStrict = true; break } + ++targetI + } else { + targetI = nextBeginningIndexes[targetI] + } + } + } + + // check if it's a substring match + var substringIndex = searchLen <= 1 ? -1 : prepared._targetLower.indexOf(searchLower, matchesSimple[0]) // perf: this is slow + var isSubstring = !!~substringIndex + var isSubstringBeginning = !isSubstring ? false : substringIndex===0 || prepared._nextBeginningIndexes[substringIndex-1] === substringIndex + + // if it's a substring match but not at a beginning index, let's try to find a substring starting at a beginning index for a better score + if(isSubstring && !isSubstringBeginning) { + for(var i=0; i { + var score = 0 + + var extraMatchGroupCount = 0 + for(var i = 1; i < searchLen; ++i) { + if(matches[i] - matches[i-1] !== 1) {score -= matches[i]; ++extraMatchGroupCount} + } + var unmatchedDistance = matches[searchLen-1] - matches[0] - (searchLen-1) + + score -= (12+unmatchedDistance) * extraMatchGroupCount // penality for more groups + + if(matches[0] !== 0) score -= matches[0]*matches[0]*.2 // penality for not starting near the beginning + + if(!successStrict) { + score *= 1000 + } else { + // successStrict on a target with too many beginning indexes loses points for being a bad target + var uniqueBeginningIndexes = 1 + for(var i = nextBeginningIndexes[0]; i < targetLen; i=nextBeginningIndexes[i]) ++uniqueBeginningIndexes + + if(uniqueBeginningIndexes > 24) score *= (uniqueBeginningIndexes-24)*10 // quite arbitrary numbers here ... + } + + score -= (targetLen - searchLen)/2 // penality for longer targets + + if(isSubstring) score /= 1+searchLen*searchLen*1 // bonus for being a full substring + if(isSubstringBeginning) score /= 1+searchLen*searchLen*1 // bonus for substring starting on a beginningIndex + + score -= (targetLen - searchLen)/2 // penality for longer targets + + return score + } + + if(!successStrict) { + if(isSubstring) for(var i=0; i { + var seen_indexes = new Set() + var score = 0 + var result = NULL + + var first_seen_index_last_search = 0 + var searches = preparedSearch.spaceSearches + var searchesLen = searches.length + var changeslen = 0 + + // Return _nextBeginningIndexes back to its normal state + var resetNextBeginningIndexes = () => { + for(let i=changeslen-1; i>=0; i--) target._nextBeginningIndexes[nextBeginningIndexesChanges[i*2 + 0]] = nextBeginningIndexesChanges[i*2 + 1] + } + + var hasAtLeast1Match = false + for(var i=0; i=0; i--) { + if(toReplace !== target._nextBeginningIndexes[i]) break + target._nextBeginningIndexes[i] = newBeginningIndex + nextBeginningIndexesChanges[changeslen*2 + 0] = i + nextBeginningIndexesChanges[changeslen*2 + 1] = toReplace + changeslen++ + } + } + } + + score += result._score / searchesLen + allowPartialMatchScores[i] = result._score / searchesLen + + // dock points based on order otherwise "c man" returns Manifest.cpp instead of CheatManager.h + if(result._indexes[0] < first_seen_index_last_search) { + score -= (first_seen_index_last_search - result._indexes[0]) * 2 + } + first_seen_index_last_search = result._indexes[0] + + for(var j=0; j score) { + if(allowPartialMatch) { + for(var i=0; i str.replace(/\p{Script=Latin}+/gu, match => match.normalize('NFD')).replace(/[\u0300-\u036f]/g, '') + +var prepareLowerInfo = (str) => { + str = remove_accents(str) + var strLen = str.length + var lower = str.toLowerCase() + var lowerCodes = [] // new Array(strLen) sparse array is too slow + var bitflags = 0 + var containsSpace = false // space isn't stored in bitflags because of how searching with a space works + + for(var i = 0; i < strLen; ++i) { + var lowerCode = lowerCodes[i] = lower.charCodeAt(i) + + if(lowerCode === 32) { + containsSpace = true + continue // it's important that we don't set any bitflags for space + } + + var bit = lowerCode>=97&&lowerCode<=122 ? lowerCode-97 // alphabet + : lowerCode>=48&&lowerCode<=57 ? 26 // numbers + // 3 bits available + : lowerCode<=127 ? 30 // other ascii + : 31 // other utf8 + bitflags |= 1< { + var targetLen = target.length + var beginningIndexes = []; var beginningIndexesLen = 0 + var wasUpper = false + var wasAlphanum = false + for(var i = 0; i < targetLen; ++i) { + var targetCode = target.charCodeAt(i) + var isUpper = targetCode>=65&&targetCode<=90 + var isAlphanum = isUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57 + var isBeginning = isUpper && !wasUpper || !wasAlphanum || !isAlphanum + wasUpper = isUpper + wasAlphanum = isAlphanum + if(isBeginning) beginningIndexes[beginningIndexesLen++] = i + } + return beginningIndexes +} +var prepareNextBeginningIndexes = (target) => { + target = remove_accents(target) + var targetLen = target.length + var beginningIndexes = prepareBeginningIndexes(target) + var nextBeginningIndexes = [] // new Array(targetLen) sparse array is too slow + var lastIsBeginning = beginningIndexes[0] + var lastIsBeginningI = 0 + for(var i = 0; i < targetLen; ++i) { + if(lastIsBeginning > i) { + nextBeginningIndexes[i] = lastIsBeginning + } else { + lastIsBeginning = beginningIndexes[++lastIsBeginningI] + nextBeginningIndexes[i] = lastIsBeginning===undefined ? targetLen : lastIsBeginning + } + } + return nextBeginningIndexes +} + +var preparedCache = new Map() +var preparedSearchCache = new Map() + +// the theory behind these being globals is to reduce garbage collection by not making new arrays +var matchesSimple = []; var matchesStrict = [] +var nextBeginningIndexesChanges = [] // allows straw berry to match strawberry well, by modifying the end of a substring to be considered a beginning index for the rest of the search +var keysSpacesBestScores = []; var allowPartialMatchScores = [] +var tmpTargets = []; var tmpResults = [] + +// prop = 'key' 2.5ms optimized for this case, seems to be about as fast as direct obj[prop] +// prop = 'key1.key2' 10ms +// prop = ['key1', 'key2'] 27ms +// prop = obj => obj.tags.join() ??ms +var getValue = (obj, prop) => { + var tmp = obj[prop]; if(tmp !== undefined) return tmp + if(typeof prop === 'function') return prop(obj) // this should run first. but that makes string props slower + var segs = prop + if(!Array.isArray(prop)) segs = prop.split('.') + var len = segs.length + var i = -1 + while (obj && (++i < len)) obj = obj[segs[i]] + return obj +} + +var isPrepared = (x) => { return typeof x === 'object' && typeof x._bitflags === 'number' } +var INFINITY = Infinity; var NEGATIVE_INFINITY = -INFINITY +var noResults = []; noResults.total = 0 +var NULL = null + +var noTarget = prepare('') + +// Hacked version of https://github.com/lemire/FastPriorityQueue.js +var fastpriorityqueue=r=>{var e=[],o=0,a={},v=r=>{for(var a=0,v=e[a],c=1;c>1]=e[a],c=1+(a<<1)}for(var f=a-1>>1;a>0&&v._score>1)e[a]=e[f];e[a]=v};return a.add=(r=>{var a=o;e[o++]=r;for(var v=a-1>>1;a>0&&r._score>1)e[a]=e[v];e[a]=r}),a.poll=(r=>{if(0!==o){var a=e[0];return e[0]=e[--o],v(),a}}),a.peek=(r=>{if(0!==o)return e[0]}),a.replaceTop=(r=>{e[0]=r,v()}),a} +var q = fastpriorityqueue() // reuse this + diff --git a/.config/quickshell/caelestia/utils/scripts/fzf.js b/.config/quickshell/caelestia/utils/scripts/fzf.js new file mode 100644 index 0000000..995a093 --- /dev/null +++ b/.config/quickshell/caelestia/utils/scripts/fzf.js @@ -0,0 +1,1307 @@ +.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) { + 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/.config/quickshell/nucleus-shell/CMakeLists.txt b/.config/quickshell/nucleus-shell/CMakeLists.txt new file mode 100644 index 0000000..0d10d08 --- /dev/null +++ b/.config/quickshell/nucleus-shell/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.16) + +project(nucleus-shell VERSION 1.0.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 6.5 COMPONENTS Quick REQUIRED) + +qt_standard_project_setup(REQUIRES 6.5) + +qt_add_executable(nucleus-shell + main.cpp +) + +qt_add_qml_module(nucleus-shell + URI nucleus-shell + QML_FILES + shell.qml + RESOURCES + img/world.png +) + +target_link_libraries(nucleus-shell PRIVATE Qt6::Quick) diff --git a/.config/quickshell/nucleus-shell/assets/gifs/bongo-cat.gif b/.config/quickshell/nucleus-shell/assets/gifs/bongo-cat.gif new file mode 100644 index 0000000000000000000000000000000000000000..146c3587fae4baa13b48702a8b7c59005e86ff31 GIT binary patch literal 23125 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 literal 0 HcmV?d00001 diff --git a/.config/quickshell/nucleus-shell/config/Appearance.qml b/.config/quickshell/nucleus-shell/config/Appearance.qml new file mode 100644 index 0000000..6d82425 --- /dev/null +++ b/.config/quickshell/nucleus-shell/config/Appearance.qml @@ -0,0 +1,262 @@ +import qs.modules.functions +import QtQuick +import Quickshell +pragma Singleton +pragma ComponentBehavior: Bound + +Singleton { + id: root + property QtObject m3colors + property QtObject colors + property QtObject rounding + property QtObject font + property QtObject margin + property QtObject moduleLayouts + property QtObject animation + property string syntaxHighlightingTheme + + readonly property bool darkmode: Config.runtime.appearance.theme === "dark" + readonly property bool transparentize: Config.runtime.appearance.transparency.enabled + readonly property double alpha: Config.runtime.appearance.transparency.alpha + + colors: QtObject { + property color colSubtext: m3colors.m3outline + property color colLayer0: m3colors.m3background + property color colLayer0Border: ColorUtils.mix(root.m3colors.m3outlineVariant, colLayer0, 0.4) + property color colLayer1: m3colors.m3surfaceContainerLow + property color colOnLayer1: m3colors.m3onSurfaceVariant + property color colOnLayer1Inactive: ColorUtils.mix(colOnLayer1, colLayer1, 0.45) + property color colLayer1Hover: ColorUtils.mix(colLayer1, colOnLayer1, 0.92) + property color colLayer1Active: ColorUtils.mix(colLayer1, colOnLayer1, 0.85) + property color colLayer2: m3colors.m3surfaceContainer + property color colOnLayer2: m3colors.m3onSurface + property color colLayer2Hover: ColorUtils.mix(colLayer2, colOnLayer2, 0.90) + property color colLayer2Active: ColorUtils.mix(colLayer2, colOnLayer2, 0.80) + property color colPrimary: m3colors.m3primary + property color colOnPrimary: m3colors.m3onPrimary + property color colSecondary: m3colors.m3secondary + property color colSecondaryContainer: m3colors.m3secondaryContainer + property color colOnSecondaryContainer: m3colors.m3onSecondaryContainer + property color colTooltip: m3colors.m3inverseSurface + property color colOnTooltip: m3colors.m3inverseOnSurface + property color colShadow: ColorUtils.transparentize(m3colors.m3shadow, 0.7) + property color colOutline: m3colors.m3outline + } + + m3colors: QtObject { + function t(c) { + return root.transparentize + ? ColorUtils.transparentize(c, root.alpha) + : c + } + + function tH(c) { + return root.transparentize + ? ColorUtils.transparentize(c, root.alpha + 1) // Totally transparent + : c + } + + readonly property color m3background: t(MaterialColors.colors.background) + readonly property color m3paddingContainer: t(Config.runtime.bar.modules.paddingColor) + readonly property color m3surface: t(MaterialColors.colors.surface) + readonly property color m3surfaceDim: t(MaterialColors.colors.surface_dim) + readonly property color m3surfaceBright: t(MaterialColors.colors.surface_bright) + + readonly property color m3surfaceContainerLowest: tH(MaterialColors.colors.surface_container_lowest) + readonly property color m3surfaceContainerLow: tH(MaterialColors.colors.surface_container_low) + readonly property color m3surfaceContainer: tH(MaterialColors.colors.surface_container) + readonly property color m3surfaceContainerHigh: tH(MaterialColors.colors.surface_container_high) + readonly property color m3surfaceContainerHighest: tH(MaterialColors.colors.surface_container_highest) + + readonly property color m3onSurface: t(MaterialColors.colors.on_surface) + readonly property color m3surfaceVariant: t(MaterialColors.colors.surface_variant) + readonly property color m3onSurfaceVariant: t(MaterialColors.colors.on_surface_variant) + + readonly property color m3inverseSurface: t(MaterialColors.colors.inverse_surface) + readonly property color m3inverseOnSurface: t(MaterialColors.colors.inverse_on_surface) + + readonly property color m3outline: t(MaterialColors.colors.outline) + readonly property color m3outlineVariant: t(MaterialColors.colors.outline_variant) + readonly property color m3shadow: t(MaterialColors.colors.shadow) + readonly property color m3scrim: t(MaterialColors.colors.scrim) + readonly property color m3surfaceTint: t(MaterialColors.colors.surface_tint) + + readonly property color m3primary: t(MaterialColors.colors.primary) + readonly property color m3onPrimary: t(MaterialColors.colors.on_primary) + readonly property color m3primaryContainer: t(MaterialColors.colors.primary_container) + readonly property color m3onPrimaryContainer: t(MaterialColors.colors.on_primary_container) + readonly property color m3inversePrimary: t(MaterialColors.colors.inverse_primary) + + readonly property color m3secondary: t(MaterialColors.colors.secondary) + readonly property color m3onSecondary: t(MaterialColors.colors.on_secondary) + readonly property color m3secondaryContainer: t(MaterialColors.colors.secondary_container) + readonly property color m3onSecondaryContainer: t(MaterialColors.colors.on_secondary_container) + + readonly property color m3tertiary: t(MaterialColors.colors.tertiary) + readonly property color m3onTertiary: t(MaterialColors.colors.on_tertiary) + readonly property color m3tertiaryContainer: t(MaterialColors.colors.tertiary_container) + readonly property color m3onTertiaryContainer: t(MaterialColors.colors.on_tertiary_container) + + readonly property color m3error: t(MaterialColors.colors.error) + readonly property color m3onError: t(MaterialColors.colors.on_error) + readonly property color m3errorContainer: t(MaterialColors.colors.error_container) + readonly property color m3onErrorContainer: t(MaterialColors.colors.on_error_container) + + readonly property color m3primaryFixed: t(MaterialColors.colors.primary_fixed) + readonly property color m3primaryFixedDim: t(MaterialColors.colors.primary_fixed_dim) + readonly property color m3onPrimaryFixed: t(MaterialColors.colors.on_primary_fixed) + readonly property color m3onPrimaryFixedVariant: t(MaterialColors.colors.on_primary_fixed_variant) + + readonly property color m3secondaryFixed: t(MaterialColors.colors.secondary_fixed) + readonly property color m3secondaryFixedDim: t(MaterialColors.colors.secondary_fixed_dim) + readonly property color m3onSecondaryFixed: t(MaterialColors.colors.on_secondary_fixed) + readonly property color m3onSecondaryFixedVariant: t(MaterialColors.colors.on_secondary_fixed_variant) + + readonly property color m3tertiaryFixed: t(MaterialColors.colors.tertiary_fixed) + readonly property color m3tertiaryFixedDim: t(MaterialColors.colors.tertiary_fixed_dim) + readonly property color m3onTertiaryFixed: t(MaterialColors.colors.on_tertiary_fixed) + readonly property color m3onTertiaryFixedVariant: t(MaterialColors.colors.on_tertiary_fixed_variant) + + } + + + margin: QtObject { + property int supertiny: 2 + property int tinier: 3 + property int tiny: 6 + property int verysmall: 8 + property int small: 12 + property int normal: 16 + property int large: 22 + property int verylarge: 30 + property int extraLarge: 35 + } + + animation: QtObject { + + property var easing: Easing.OutExpo + + property QtObject durations: QtObject { + property int supershort: 100 + property int small: 200 + property int normal: 400 + property int large: 600 + property int extraLarge: 1000 + property int expressiveFastSpatial: 350 + property int expressiveDefaultSpatial: 500 + property int expressiveEffects: 200 + } + + property QtObject curves: QtObject { + readonly property list expressiveFastSpatial: [0.42, 1.67, 0.21, 0.90, 1, 1] // Default, 350ms + readonly property list expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1.00, 1, 1] // Default, 500ms + readonly property list expressiveSlowSpatial: [0.39, 1.29, 0.35, 0.98, 1, 1] // Default, 650ms + readonly property list expressiveEffects: [0.34, 0.80, 0.34, 1.00, 1, 1] // Default, 200ms + 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 emphasizedFirstHalf: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82] + readonly property list emphasizedLastHalf: [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 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 real expressiveFastSpatialDuration: 350 + readonly property real expressiveDefaultSpatialDuration: 500 + readonly property real expressiveSlowSpatialDuration: 650 + readonly property real expressiveEffectsDuration: 200 + } + + property QtObject elementMove: QtObject { + property int duration: animation.curves.expressiveDefaultSpatialDuration + property int type: Easing.BezierSpline + property list bezierCurve: animation.curves.expressiveDefaultSpatial + property Component numberAnimation: Component { + NumberAnimation { + duration: root.animation.elementMove.duration + easing.type: root.animation.elementMove.type + easing.bezierCurve: root.animation.elementMove.bezierCurve + } + } + } + + property QtObject elementMoveEnter: QtObject { + property int duration: 400 + property int type: Easing.BezierSpline + property list bezierCurve: animation.curves.emphasizedDecel + property Component numberAnimation: Component { + NumberAnimation { + duration: root.animation.elementMoveEnter.duration + easing.type: root.animation.elementMoveEnter.type + easing.bezierCurve: root.animation.elementMoveEnter.bezierCurve + } + } + } + + property QtObject elementMoveFast: QtObject { + property int duration: animation.curves.expressiveEffectsDuration + property int type: Easing.BezierSpline + property list bezierCurve: animation.curves.expressiveEffects + property Component numberAnimation: Component { + NumberAnimation { + duration: root.animation.elementMoveFast.duration + easing.type: root.animation.elementMoveFast.type + easing.bezierCurve: root.animation.elementMoveFast.bezierCurve + } + } + } + + } + + rounding: QtObject { + property int unsharpen: 2 * Config.runtime.appearance.rounding.factor + property int unsharpenmore: 6 * Config.runtime.appearance.rounding.factor + property int verysmall: 8 * Config.runtime.appearance.rounding.factor + property int small: 12 * Config.runtime.appearance.rounding.factor + property int normal: 17 * Config.runtime.appearance.rounding.factor + property int large: 23 * Config.runtime.appearance.rounding.factor + property int verylarge: 30 * Config.runtime.appearance.rounding.factor + property int childish: 50 * Config.runtime.appearance.rounding.factor // Idk why did I named this childish + property int full: 9999 + property int screenRounding: large + property int windowRounding: 18 * Config.runtime.appearance.rounding.factor + } + + font: QtObject { + property QtObject family: QtObject { + property string main: Config.runtime.appearance.font.families.main + property string title: Config.runtime.appearance.font.families.title + property string materialIcons: Config.runtime.appearance.font.families.materialIcons + property string nerdIcons: Config.runtime.appearance.font.families.nerdFonts + property string monospace: Config.runtime.appearance.font.families.monospace + property string reading: Config.runtime.appearance.font.families.reading + property string expressive: Config.runtime.appearance.font.families.expressive + } + property QtObject size: QtObject { + property int smallest: 10 + property int smaller: 12 + property int smallie: 13 + property int small: 15 + property int normal: 16 + property int large: 17 + property int larger: 19 + property int big: 21 + property int huge: 22 + property int hugeass: 23 + property int wildass: 40 + property int title: huge + + property QtObject icon: QtObject { + property int smallest: 10 + property int smaller: 12 + property int small: 14 + property int normal: 16 + property int large: 17 + property int larger: 19 + property int huge: 22 + property int hugeass: 23 + } + } + } + + syntaxHighlightingTheme: darkmode ? '#f1ebeb' : "#141333" +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/config/Config.qml b/.config/quickshell/nucleus-shell/config/Config.qml new file mode 100644 index 0000000..8feb50e --- /dev/null +++ b/.config/quickshell/nucleus-shell/config/Config.qml @@ -0,0 +1,282 @@ +pragma Singleton +pragma ComponentBehavior: Bound +import QtQuick +import QtCore +import Quickshell +import Quickshell.Io +import qs.plugins +import qs.services + +Singleton { + id: root + property string filePath: Directories.shellConfigPath + property alias runtime: configOptionsJsonAdapter + property bool initialized: false + property int readWriteDelay: 50 + property bool blockWrites: false + + function updateKey(nestedKey, value) { + let keys = nestedKey.split(".") + let obj = root.runtime + if (!obj) { + console.warn("Config.updateKey: adapter not available for key", nestedKey) + return + } + + for (let i = 0; i < keys.length - 1; ++i) { + let k = keys[i] + if (obj[k] === undefined || obj[k] === null || typeof obj[k] !== "object") { + obj[k] = {} // Use Plain JS for serialization + } + obj = obj[k] + if (!obj) { + console.warn("Config.updateKey: failed to resolve", k) + return + } + } + + let convertedValue = value + if (typeof value === "string") { + let trimmed = value.trim() + if (trimmed === "true" || trimmed === "false" || (!isNaN(Number(trimmed)) && trimmed !== "")) { + try { + convertedValue = JSON.parse(trimmed) + } catch (e) { + convertedValue = value + } + } + } + + obj[keys[keys.length - 1]] = convertedValue + configFileView.adapterUpdated() + } + + function loadPluginConfigs(plugins) { + console.log("Loading plugins:", plugins) + + if (!root.runtime) + return + + if (!root.runtime.plugins) + root.runtime.plugins = {} + + function mergeDefaults(target, defaults) { + let changed = false + + for (let key in defaults) { + const defVal = defaults[key] + const tgtVal = target[key] + + if (tgtVal === undefined) { + target[key] = defVal + changed = true + } else if ( + typeof tgtVal === "object" && + typeof defVal === "object" && + tgtVal !== null && + defVal !== null + ) { + if (mergeDefaults(tgtVal, defVal)) + changed = true + } + } + + return changed + } + + let anyChange = false + + for (let i = 0; i < plugins.length; i++) { + const name = plugins[i] + const path = Directories.shellConfig + "/plugins/" + name + "/PluginConfigData.qml" + + const component = Qt.createComponent(path) + if (component.status === Component.Error) { + console.warn("Plugin failed:", path, component.errorString()) + continue + } + + if (component.status !== Component.Ready) + continue + + const pluginObj = component.createObject(root) + if (!pluginObj) { + console.warn("Failed to create plugin object:", name) + component.destroy() + continue + } + + if (!pluginObj.defaults) + pluginObj.defaults = { enabled: false } + + if (!root.runtime.plugins[name]) { + root.runtime.plugins[name] = {} + anyChange = true + } + + if (mergeDefaults(root.runtime.plugins[name], pluginObj.defaults)) + anyChange = true + + console.log("Plugin config injected:", name) + + pluginObj.destroy() + component.destroy() + } + + if (anyChange) { + console.log("Plugin defaults merged, writing config") + configFileView.adapterUpdated() + } else { + console.log("Plugin configs already up to date") + } + } + + Timer { id: fileReloadTimer; interval: root.readWriteDelay; repeat: false; onTriggered: configFileView.reload() } + Timer { id: fileWriteTimer; interval: root.readWriteDelay; repeat: false; onTriggered: configFileView.writeAdapter() } + + Timer { // Used to output all log/debug to the terminal + interval: 1200 + running: true + repeat: false + onTriggered: { + console.log("Injecting plugin configs") + root.loadPluginConfigs(PluginLoader.plugins) + console.log("Detected Compositor:", Compositor.detectedCompositor) + } + } + + FileView { + id: configFileView + path: root.filePath + watchChanges: true + blockWrites: root.blockWrites + onFileChanged: fileReloadTimer.restart() + onAdapterUpdated: fileWriteTimer.restart() + onLoaded: { root.initialized = true } + onLoadFailed: error => { + if (error == FileViewError.FileNotFound) writeAdapter() + } + + JsonAdapter { + id: configOptionsJsonAdapter + + property var plugins: ({}) // dynamic plugins config variable + property var monitors: ({}) // per-monitor configuration for bars and wallpapers + + property JsonObject appearance: JsonObject { + property string theme: "dark" + property bool tintIcons: false + property JsonObject animations: JsonObject { property bool enabled: true; property double durationScale: 1 } + property JsonObject transparency: JsonObject { property bool enabled: false; property double alpha: 0.2 } + property JsonObject rounding: JsonObject { property double factor: 1 } + property JsonObject font: JsonObject { + property double scale: 1 + property JsonObject families: JsonObject { + property string main: "JetBrains Mono" + property string title: "Gabarito" + property string materialIcons: "Material Symbols Rounded" + property string nerdFonts: "JetBrains Mono NF" + property string monospace: "JetBrains Mono NF" + property string reading: "Readex Pro" + property string expressive: "Space Grotesk" + } + } + property JsonObject colors: JsonObject { + property string scheme: "catppuccin-lavender" + property string matugenScheme: "scheme-neutral" + property bool autogenerated: true + property bool runMatugenUserWide: false + } + property JsonObject background: JsonObject { + property bool enabled: true + property url defaultPath: Directories.defaultsPath + "/default.jpg" + property JsonObject parallax: JsonObject { + property bool enabled: true + property bool enableSidebarLeft: true + property bool enableSidebarRight: true + property real zoom: 1.10 + } + property JsonObject clock: JsonObject { + property bool enabled: true + property bool isAnalog: true + property bool rotatePolygonBg: false + property int rotationDuration: 18 // lower the faster + property int edgeSpacing: 50 + property int shape: 1 + property int xPos: 0 + property int yPos: 0 + property bool animateHands: false + } + property JsonObject slideshow: JsonObject { + property bool enabled: false + property bool includeSubfolders: true + property int interval: 5 + property string folder: "" + } + } + } + + property JsonObject misc: JsonObject { + property url pfp: Quickshell.env("HOME") + "/.face.icon" + property JsonObject intelligence: JsonObject { + property bool enabled: true + property string apiKey: "" + } + } + + property JsonObject notifications: JsonObject { + property bool enabled: true + property bool doNotDisturb: false + property string position: "center" + } + property JsonObject shell: JsonObject { + property string version: "0.7.7" + property string releaseChannel: "stable" + property string qsVersion: "0.0.0" + } + property JsonObject overlays: JsonObject { + property bool enabled: true + property bool volumeOverlayEnabled: true + property bool brightnessOverlayEnabled: true + property string volumeOverlayPosition: "top" + property string brightnessOverlayPosition: "top" + } + property JsonObject launcher: JsonObject { + property bool fuzzySearchEnabled: true + property string webSearchEngine: "google" + } + property JsonObject bar: JsonObject { + property string position: "top" + property bool enabled: true + property bool merged: false + property bool floating: false + property bool gothCorners: true + property int radius: Appearance.rounding.large + property int margins: Appearance.margin.normal + property int density: 50 + property JsonObject modules: JsonObject { + property color paddingColor: Appearance.m3colors.m3surfaceContainer + property int radius: Appearance.rounding.normal + property int height: 34 + property JsonObject workspaces: JsonObject { + property bool enabled: true + property int workspaceIndicators: 8 + property bool showAppIcons: true + property bool showJapaneseNumbers: false + } + property JsonObject statusIcons: JsonObject { + property bool enabled: true + property bool networkStatusEnabled: true + property bool bluetoothStatusEnabled: true + } + property JsonObject systemUsage: JsonObject { + property bool enabled: true + property bool cpuStatsEnabled: true + property bool memoryStatsEnabled: true + property bool tempStatsEnabled: true + } + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/config/Directories.qml b/.config/quickshell/nucleus-shell/config/Directories.qml new file mode 100644 index 0000000..3f2f3c4 --- /dev/null +++ b/.config/quickshell/nucleus-shell/config/Directories.qml @@ -0,0 +1,39 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import qs.modules.functions +import QtCore +import QtQuick +import Quickshell + +Singleton { + // XDG Dirs, with "file://" + readonly property string home: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0] + readonly property string config: StandardPaths.standardLocations(StandardPaths.ConfigLocation)[0] + readonly property string state: StandardPaths.standardLocations(StandardPaths.StateLocation)[0] + readonly property string cache: StandardPaths.standardLocations(StandardPaths.CacheLocation)[0] + readonly property string genericCache: StandardPaths.standardLocations(StandardPaths.GenericCacheLocation)[0] + readonly property string documents: StandardPaths.standardLocations(StandardPaths.DocumentsLocation)[0] + readonly property string downloads: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0] + readonly property string pictures: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0] + readonly property string music: StandardPaths.standardLocations(StandardPaths.MusicLocation)[0] + readonly property string videos: StandardPaths.standardLocations(StandardPaths.MoviesLocation)[0] + + property string shellConfig: FileUtils.trimFileProtocol(`${Directories.config}/nucleus-shell`) + property string shellConfigName: "configuration.json" + property string shellConfigPath: `${Directories.shellConfig}/config/${Directories.shellConfigName}` + property string generatedMaterialThemePath: FileUtils.trimFileProtocol(`${Directories.config}/nucleus-shell/config/colors.json`) + property string defaultsPath: Quickshell.shellPath("defaults") + property string scriptsPath: Quickshell.shellPath("scripts") + property string assetsPath: Quickshell.shellPath("assets") + // Cleanup on init + Component.onCompleted: { + Quickshell.execDetached(["mkdir", "-p", `${shellConfig}`]) + Quickshell.execDetached(["mkdir", "-p", `${shellConfig}/config`]) + Quickshell.execDetached(["mkdir", "-p", `${shellConfig}/plugins`]) + Quickshell.execDetached(["mkdir", "-p", `${FileUtils.trimFileProtocol(Directories.pictures)}/Screenshots`]) + // Create dirs for intelligence shit + Quickshell.execDetached(["mkdir", "-p", FileUtils.trimFileProtocol(`${config}/zenith/`), FileUtils.trimFileProtocol(`${config}/zenith/chats`)]) + Quickshell.execDetached(["touch", FileUtils.trimFileProtocol(`${config}/zenith/chats/default.txt`)]) + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/config/Globals.qml b/.config/quickshell/nucleus-shell/config/Globals.qml new file mode 100644 index 0000000..653c9a9 --- /dev/null +++ b/.config/quickshell/nucleus-shell/config/Globals.qml @@ -0,0 +1,23 @@ +import QtQuick +pragma Singleton +pragma ComponentBehavior: Bound +import Quickshell + +Singleton { + id: root + property QtObject visiblility + property QtObject states + + visiblility: QtObject { + property bool powermenu: false + property bool launcher: false + property bool sidebarRight: false + property bool sidebarLeft: false + } + + states: QtObject { + property bool settingsOpen: false + property bool intelligenceWindowOpen: false + } + +} diff --git a/.config/quickshell/nucleus-shell/config/Ipc.qml b/.config/quickshell/nucleus-shell/config/Ipc.qml new file mode 100644 index 0000000..78841c4 --- /dev/null +++ b/.config/quickshell/nucleus-shell/config/Ipc.qml @@ -0,0 +1,97 @@ +import QtQuick +import Quickshell +import Quickshell.Io +import qs.services +import qs.modules.interface.settings + +Scope { + id: global + + // Track if notification has already been shown + property bool themeNotificationShown: false + + // Function to show notification once + function notifyPredefinedTheme() { + if (!themeNotificationShown) { + themeNotificationShown = true + Quickshell.execDetached([ + "notify-send", + "Nucleus Shell", + `You are using a predefined theme ${Config.runtime.appearance.colors.scheme}. Color generation/Light Theme is not supported for this theme.`, + "--urgency=normal", + "--expire-time=5000" + ]) + } + } + + // Handle Global IPCs + IpcHandler { + target: "global" + + function toggleTheme() { + const currentTheme = Config.runtime.appearance.theme + const newTheme = currentTheme === "light" ? "dark" : "light" + + // Predefined themes: validate variant BEFORE changing theme + if (!Config.runtime.appearance.colors.autogenerated) { + const scheme = Config.runtime.appearance.colors.scheme + const file = Theme.map[scheme]?.[newTheme] + + if (!file) { + Theme.notifyMissingVariant(scheme, newTheme) + return + } + + Config.updateKey("appearance.theme", newTheme) + + Quickshell.execDetached([ + "bash", + Directories.scriptsPath + "/interface/switchTheme.sh", + file + ]) + return + } + + // Autogenerated themes: safe to toggle freely + Config.updateKey("appearance.theme", newTheme) + genThemeColors.running = true + } + + function regenColors() { + if (Config.runtime.appearance.colors.autogenerated) { + genThemeColors.running = true + } else { + notifyPredefinedTheme() + } + } + } + + property var genColorsCmd: Config.runtime.appearance.colors.runMatugenUserWide + ? [ + "bash", + Directories.scriptsPath + "/interface/gencolors.sh", + "--user-wide", + Config.runtime.appearance.background.path, + Config.runtime.appearance.colors.matugenScheme, + Config.runtime.appearance.theme, + Quickshell.shellPath("extras/matugen/config.toml") + ] + : [ + "bash", + Directories.scriptsPath + "/interface/gencolors.sh", + Config.runtime.appearance.background.path, + Config.runtime.appearance.colors.matugenScheme, + Config.runtime.appearance.theme, + Quickshell.shellPath("extras/matugen/config.toml") + ]; + + + + // Process to generate colors + Process { + id: genThemeColors + + command: genColorsCmd + } + +} diff --git a/.config/quickshell/nucleus-shell/config/MaterialColors.qml b/.config/quickshell/nucleus-shell/config/MaterialColors.qml new file mode 100644 index 0000000..4fe949a --- /dev/null +++ b/.config/quickshell/nucleus-shell/config/MaterialColors.qml @@ -0,0 +1,89 @@ +pragma Singleton +pragma ComponentBehavior: Bound +import QtQuick +import QtCore +import Quickshell +import Quickshell.Io + +Singleton { + id: m3colors + property string filePath: Directories.generatedMaterialThemePath + property alias colors: colorsJsonAdapter + property bool ready: false + + FileView { + id: colorsFileView + path: m3colors.filePath + watchChanges: true + onLoaded: m3colors.ready = true + onFileChanged: colorsFileView.reload() + onLoadFailed: error => { + if (error === FileViewError.FileNotFound) { + console.warn("MaterialColors: colors.json not found, writing defaults") + writeAdapter() + } else { + console.error("MaterialColors: failed to load colors.json:", error) + } + } + + JsonAdapter { + id: colorsJsonAdapter + + // === Default Matugen color scheme === + property string background: "#131313" + property string error: "#ffb4ab" + property string error_container: "#93000a" + property string inverse_on_surface: "#303030" + property string inverse_primary: "#00677f" + property string inverse_surface: "#e2e2e2" + property string on_background: "#e2e2e2" + property string on_error: "#690005" + property string on_error_container: "#ffdad6" + property string on_primary: "#003543" + property string on_primary_container: "#b7eaff" + property string on_primary_fixed: "#001f28" + property string on_primary_fixed_variant: "#004e60" + property string on_secondary: "#1e333b" + property string on_secondary_container: "#cfe6f1" + property string on_secondary_fixed: "#071e26" + property string on_secondary_fixed_variant: "#344a52" + property string on_surface: "#e2e2e2" + property string on_surface_variant: "#c6c6c6" + property string on_tertiary: "#2c2e4d" + property string on_tertiary_container: "#e0e0ff" + property string on_tertiary_fixed: "#171937" + property string on_tertiary_fixed_variant: "#424465" + property string outline: "#919191" + property string outline_variant: "#474747" + property string primary: '#a571f2' + property string primary_container: "#004e60" + property string primary_fixed: "#b7eaff" + property string primary_fixed_dim: "#5cd5fb" + property string scrim: "#000000" + property string secondary: "#b3cad4" + property string secondary_container: "#344a52" + property string secondary_fixed: "#cfe6f1" + property string secondary_fixed_dim: "#b3cad4" + property string shadow: "#000000" + property string source_color: "#829aa4" + property string surface: "#131313" + property string surface_bright: "#393939" + property string surface_container: "#1f1f1f" + property string surface_container_high: "#2a2a2a" + property string surface_container_highest: "#353535" + property string surface_container_low: "#1b1b1b" + property string surface_container_lowest: "#0e0e0e" + property string surface_dim: "#131313" + property string surface_tint: "#5cd5fb" + property string surface_variant: "#474747" + property string tertiary: "#c3c3eb" + property string tertiary_container: "#424465" + property string tertiary_fixed: "#e0e0ff" + property string tertiary_fixed_dim: "#c3c3eb" + } + } + + function reload() { + colorsFileView.reload() + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/config/Metrics.qml b/.config/quickshell/nucleus-shell/config/Metrics.qml new file mode 100644 index 0000000..cc063ac --- /dev/null +++ b/.config/quickshell/nucleus-shell/config/Metrics.qml @@ -0,0 +1,133 @@ +import QtQuick +import Quickshell +pragma Singleton +pragma ComponentBehavior: Bound + +Singleton { + id: root + + readonly property double durationScale: Config.runtime.appearance.animations.durationScale + readonly property double roundingScale: Config.runtime.appearance.rounding.factor + readonly property double fontScale: Config.runtime.appearance.font.scale + + function spacing(value) { // These will be used with a scale later on... + return value + } + + function padding(value) { + return value + } + + function chronoDuration(value) { + if (typeof value === "number") + return value * durationScale + + switch (value) { + case "supershort": return Appearance.animation.durations.supershort * durationScale + case "small": return Appearance.animation.durations.small * durationScale + case "normal": return Appearance.animation.durations.normal * durationScale + case "large": return Appearance.animation.durations.large * durationScale + case "extraLarge": return Appearance.animation.durations.extraLarge * durationScale + case "expressiveFastSpatial": return Appearance.animation.durations.expressiveFastSpatial * durationScale + case "expressiveDefaultSpatial": return Appearance.animation.durations.expressiveDefaultSpatial * durationScale + case "expressiveEffects": return Appearance.animation.durations.expressiveEffects * durationScale + default: return 0 + } + } + + function margin(value) { + if (typeof value === "number") + return value + + switch (value) { + case "supertiny": return Appearance.margin.supertiny + case "tinier": return Appearance.margin.tinier + case "tiny": return Appearance.margin.tiny + case "verysmall": return Appearance.margin.verysmall + case "small": return Appearance.margin.small + case "normal": return Appearance.margin.normal + case "large": return Appearance.margin.large + case "verylarge": return Appearance.margin.verylarge + case "extraLarge": return Appearance.margin.extraLarge + default: return 0 + } + } + + function radius(value) { + if (typeof value === "number") + return value * roundingScale + + switch (value) { + case "unsharpen": return Appearance.rounding.unsharpen * roundingScale + case "unsharpenmore": return Appearance.rounding.unsharpenmore * roundingScale + case "verysmall": return Appearance.rounding.verysmall * roundingScale + case "small": return Appearance.rounding.small * roundingScale + case "normal": return Appearance.rounding.normal * roundingScale + case "large": return Appearance.rounding.large * roundingScale + case "verylarge": return Appearance.rounding.verylarge * roundingScale + case "childish": return Appearance.rounding.childish * roundingScale + case "full": return Appearance.rounding.full * roundingScale + case "screenRounding": return Appearance.rounding.screenRounding * roundingScale + case "windowRounding": return Appearance.rounding.windowRounding * roundingScale + default: return 0 + } + } + + function fontSize(value) { + if (typeof value === "number") + return value * fontScale + + switch (value) { + case "smallest": return Appearance.font.size.smallest * fontScale + case "smaller": return Appearance.font.size.smaller * fontScale + case "smallie": return Appearance.font.size.smallie * fontScale + case "small": return Appearance.font.size.small * fontScale + case "normal": return Appearance.font.size.normal * fontScale + case "large": return Appearance.font.size.large * fontScale + case "larger": return Appearance.font.size.larger * fontScale + case "big": return Appearance.font.size.big * fontScale + case "huge": return Appearance.font.size.huge * fontScale + case "hugeass": return Appearance.font.size.hugeass * fontScale + case "wildass": return Appearance.font.size.wildass * fontScale + case "title": return Appearance.font.size.title * fontScale + default: return Appearance.font.size.normal * fontScale + } + } + + function iconSize(value) { + if (typeof value === "number") + return value * fontScale + + switch (value) { + case "smallest": return Appearance.font.size.icon.smallest * fontScale + case "smaller": return Appearance.font.size.icon.smaller * fontScale + case "smallie": return Appearance.font.size.icon.smallie * fontScale + case "small": return Appearance.font.size.icon.small * fontScale + case "normal": return Appearance.font.size.icon.normal * fontScale + case "large": return Appearance.font.size.icon.large * fontScale + case "larger": return Appearance.font.size.icon.larger * fontScale + case "big": return Appearance.font.size.icon.big * fontScale + case "huge": return Appearance.font.size.icon.huge * fontScale + case "hugeass": return Appearance.font.size.icon.hugeass * fontScale + case "wildass": return Appearance.font.size.icon.wildass * fontScale + case "title": return Appearance.font.size.icon.title * fontScale + default: return Appearance.font.size.icon.normal * fontScale + } + } + + function fontFamily(value) { + if (typeof value === "string") { + switch (value) { + case "main": return Appearance.font.family.main + case "title": return Appearance.font.family.title + case "materialIcons": return Appearance.font.family.materialIcons + case "nerdIcons": return Appearance.font.family.nerdIcons + case "monospace": return Appearance.font.family.monospace + case "reading": return Appearance.font.family.reading + case "expressive": return Appearance.font.family.expressive + default: return value + } + } + return Appearance.font.family.main + } +} diff --git a/.config/quickshell/nucleus-shell/defaults/default.jpg b/.config/quickshell/nucleus-shell/defaults/default.jpg new file mode 100644 index 0000000000000000000000000000000000000000..50b694d79c83ba12de1c223c1c35eaa9214eb297 GIT binary patch literal 2148034 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%0Ay$8ZW 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

5TkwmGUF$R&Fke`Mey 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

&yFg5Nd!J2WFQWxbMi^rm!$ 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

iDtnZT~X&cnF1O2k-2+?9b}UL`Fa|s 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�^?5LkOmV&4b9Uq-5KV&qE*706vxY`F|31HSm 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%0A@6`8yB^_9q&e$|w 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

ogJXRC=IpbVj&>kyP2Rb~pvz7#R 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

@$(0{m^$f+w*tGZUGTR$!~gXEpX6aYNvJX@9Q_{ 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—M2hcoi_yonGsOI^Y9!UB;-VF?(4$4L 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

p|aQFcwu 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

1Mc(K8e6G0eIwoEW+LcNaFMy%{&W^ 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�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­5|e<*e8~hxZ)wcsYCEU7CH-kwXPUq>xe)xGjdAmWeM#?Ho-6x)?q(pcA z@Ap_zfw+11L8tLCu&S1YX^R_gQd4?CyqCQZu5V^*8`G=V;S8RK3 zxIZw)vjKsTVkdaUd2moU_WaJmL)}!~)`?lI?O!v51xk1jO|twRP-0QkkS`a6z#+P7 zP5WI)hzF7w_h1fXnu!nPY<<1Xv1Lq(F$_rWBoPlpT#C6do!5k{7qGkYnwC~O2T=h^ z-jNN1>%w$iITUm}JKx4fqdSS1V|JDXwo1?Ns!(OOGGW z!LgxX*MAw=vY7YBIm4HJ^!icHv>v#memgNqdE4Dr0r#Juyzpo&bA^=+z!>Jb$Ni_3 z6u%ALyJk0zvjNA#WeFZ?PEWRH5bn$_bx5nWc_2>CFrE89Fd5GGA;((%nVRI^9==mf zhgc$0x>VT9fb8R zI%m+Cf}LDzM79-|9HLZ*_zt}M;wU7?eKQrje(6s5tx+2Syt$R7s8Sd&Lc(l%rxzsV zb#5YQAHYTU?E=HE+l-1G_^OTB4T;em`$$93bx$LY;OL#gXtw--G@3ZNoJ(73360tL zIa6PuA99Q8ro^xTz>;i~;pcudpH$(O0blmfWPT41!*41InN`6G#pOHCUdt0q!xO|J z25GR6kp01`WgO&Qt#;47O!1kRfsMp7?m*>aPJMu{VtLMPPaJ(lI00P&K)vsir9SSH zs!~;^CwaVCQM-^d-?>`ODHpI8%{?QZ1t>*=G&&!y7^8|cS zRX{nETio?+Wi+;lq~izN>#q@c^`-hzFBN#3@~>L*{y}Zs(*t>(6kaYRS48-3h2?w7H&v>Q zks}2gfSLec(h!6^;N5`krD*$kH_LkmVA-b@r^zGi1?QEn$G#x?^p*gQK7Y<5Up5o? zQ=Z9}?FxZ<9GQ(g%7+?Kjgm$_HXTNNRV`#r`7SLRIMX^Wv6g(9e6VH644SFxA5&m- zTJURu5LCd4waCJ$FmZGpB=JmUL9?;|mu6o9v7Fr^Nx{R~^kY80^=uVW0BFB>EV+Tt za8w4g6Fp=fX0y=2r7)~u4)K|+T;ZE8Jt~n=d!n8%FBM~mKsZTi!ZaK$mjJq8BwZbv zXzzE4DF#kM@aCd(YdtP;Glp~=lp?>?3xKil0IbyF0)q@Rh;VlN*Y@sQPk+?N1=FWZ zn1LLKNZ3rg@9T1x3`16ufJ%K<`J}$k?ynmtAjkKiJh4+&pSPo{`j6(0uzMSW2T+)e zHZSy10z52O1+&j@LsS4DiYSgwrH9)nNL2inpAeU5NsV^h3Yg zi@axum+ny~X3DShFG``A(wC%WeJ78T#cf`?swNc&T#0x2;%+#ubhV~|BN)erWYPf2AzW^B}9rghu-5tf2&JrLB35t+$DYeT_Tu8`s< zotkpyS4J`}YO-v{0nkLz@9-4xnk{TB2tIvxmM0)_8Z+l3idH_X{b4^5KE|kO5+b-Z zff$~1*BdHDhuz(eQ2qa!M)!+m;le|-$l!85i_V!LY-3cyHA{gtAMq7()wi|L?LpjeyJ+a*%$tW2hBO&`n^m+i~DOa3=eA6kWJu&R(lEj+SX;QMa# zQ9hA+`uZ@Av)Smgck~myx6YBEP;v>kNNJO}#j5-iLo9B%AhZT_#g=ASEM5YWs#Shz!k{R?hC z21`kk9MwU2H$YaNwh+_vZ}IGydRQ?)*b1*F3R6^K%lW#FX;u6$G!mKjd z>b{XwhLj-7B1~mNu;EGlZ0PQ}Qa2?D}l7TgvI6ZUE z_KbtHHX;YmZs-C2M1`gf5wB0x3~*bI@Z?Wb za5H)UB?{pCGve}d+}V|t%4Xy4m&tK6H&-+!8gPJUVCIV{ERwS9IiblmU^@l&GVwT! z(bP;~OsRB06ZK|Y;an|ec8|f2=ct+DDddVHEZ7Di|ALBc?ATzY3K*8KR(hpV>eg%t z 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 z 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 z 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 literal 0 HcmV?d00001 diff --git a/.config/quickshell/nucleus-shell/extras/matugen/config.toml b/.config/quickshell/nucleus-shell/extras/matugen/config.toml new file mode 100644 index 0000000..113ca5e --- /dev/null +++ b/.config/quickshell/nucleus-shell/extras/matugen/config.toml @@ -0,0 +1,6 @@ +[config] +reload = false + +[templates.nucleus] +input_path = './templates/colors.json' +output_path = '~/.config/nucleus-shell/config/colors.json' \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/extras/matugen/templates/colors.json b/.config/quickshell/nucleus-shell/extras/matugen/templates/colors.json new file mode 100644 index 0000000..ab420fe --- /dev/null +++ b/.config/quickshell/nucleus-shell/extras/matugen/templates/colors.json @@ -0,0 +1,6 @@ +{ + "_comment": "Material Colors generated with Matugen" +<* for name, value in colors *> + , "{{ name }}": "{{ value.default.hex }}" +<* endfor *> +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/CircularProgressBar.qml b/.config/quickshell/nucleus-shell/modules/components/CircularProgressBar.qml new file mode 100644 index 0000000..1276f8c --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/CircularProgressBar.qml @@ -0,0 +1,57 @@ +import QtQuick +import Quickshell +import qs.config + +Item { + id: root + + property real value: 0.65 // 0.0 → 1.0 + property real strokeWidth: 2 + property color bgColor: Appearance.m3colors.m3secondaryContainer + property color fgColor: Appearance.m3colors.m3primary + property string icon: "battery_full" + property int iconSize: Metrics.iconSize(20) + property bool fillIcon: false + + width: 22 + height: 24 + onValueChanged: canvas.requestPaint() + + Canvas { + id: canvas + + anchors.fill: parent + onPaint: { + const ctx = getContext("2d"); + ctx.clearRect(0, 0, width, height); + const cx = width / 2; + const cy = height / 2; + const r = (width - root.strokeWidth) / 2; + const start = -Math.PI / 2; + const end = start + 2 * Math.PI * root.value; + ctx.lineWidth = root.strokeWidth; + ctx.lineCap = "round"; + // background ring + ctx.strokeStyle = root.bgColor; + ctx.beginPath(); + ctx.arc(cx, cy, r, 0, 2 * Math.PI); + ctx.stroke(); + // progress ring + ctx.strokeStyle = root.fgColor; + ctx.beginPath(); + ctx.arc(cx, cy, r, start, end); + ctx.stroke(); + } + } + + // CENTER ICON + MaterialSymbol { + anchors.centerIn: parent + icon: root.icon + iconSize: root.iconSize + font.variableAxes: { + "FILL": root.fillIcon ? 1 : 0 + } + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/components/ContentCard.qml b/.config/quickshell/nucleus-shell/modules/components/ContentCard.qml new file mode 100644 index 0000000..a6f5601 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/ContentCard.qml @@ -0,0 +1,38 @@ +import qs.config +import QtQuick +import QtQuick.Layouts + +Item { + id: contentCard + implicitWidth: parent ? parent.width : 600 + implicitHeight: contentArea.implicitHeight + verticalPadding + + default property alias content: contentArea.data + property alias color: bg.color + property alias radius: bg.radius + property int cardMargin: Metrics.margin("normal") + property int cardSpacing: Metrics.margin("small") + property int verticalPadding: Metrics.margin("verylarge") + property bool useAnims: true + + Rectangle { + id: bg + anchors.fill: parent + radius: Metrics.radius("normal") + color: Appearance.colors.colLayer1 + + Behavior on color { + enabled: Config.runtime.appearance.animations.enabled + ColorAnimation { + duration: !contentCard.useAnims ? 0 : Metrics.chronoDuration("fast") + } + } + } + + ColumnLayout { + id: contentArea + anchors.fill: parent + anchors.margins: cardMargin + spacing: cardSpacing + } +} diff --git a/.config/quickshell/nucleus-shell/modules/components/ContentMenu.qml b/.config/quickshell/nucleus-shell/modules/components/ContentMenu.qml new file mode 100644 index 0000000..c80fd1f --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/ContentMenu.qml @@ -0,0 +1,101 @@ +import qs.config +import QtQuick +import QtQuick.Layouts + +Item { + id: contentMenu + Layout.fillWidth: true + Layout.fillHeight: true + + opacity: visible ? 1 : 0 + scale: visible ? 1 : 0.95 + + Behavior on opacity { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.curves.standard[0] // using standard easing + } + } + Behavior on scale { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.curves.standard[0] + } + } + + property string title: "" + property string description: "" + default property alias content: stackedSections.data + + Item { + id: headerArea + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.topMargin: Metrics.margin("verylarge") + anchors.leftMargin: Metrics.margin("verylarge") + anchors.rightMargin: Metrics.margin("verylarge") + width: parent.width + + ColumnLayout { + id: headerContent + anchors.left: parent.left + anchors.right: parent.right + spacing: Metrics.margin("small") + + ColumnLayout { + StyledText { + text: contentMenu.title + font.pixelSize: Metrics.fontSize("huge") + font.bold: true + font.family: Metrics.fontFamily("title") + } + StyledText { + text: contentMenu.description + font.pixelSize: Metrics.fontSize("small") + } + } + + Rectangle { + id: hr + Layout.alignment: Qt.AlignLeft | Qt.AlignRight + implicitHeight: 1 + } + } + + height: headerContent.implicitHeight + } + + Flickable { + id: mainScroll + anchors.left: parent.left + anchors.right: parent.right + anchors.top: headerArea.bottom + anchors.bottom: parent.bottom + anchors.leftMargin: Metrics.margin("verylarge") + anchors.rightMargin: Metrics.margin("verylarge") + anchors.topMargin: Metrics.margin("normal") + clip: true + interactive: true + boundsBehavior: Flickable.StopAtBounds + flickableDirection: Flickable.VerticalFlick + + contentHeight: mainContent.childrenRect.height + Appearance.margin.small + contentWidth: width + + Item { + id: mainContent + width: mainScroll.width + height: mainContent.childrenRect.height + + Column { + id: stackedSections + width: Math.min(mainScroll.width, 1000) + x: (mainContent.width - width) / 2 + spacing: Appearance.margin.normal + } + } + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/ContentRowCard.qml b/.config/quickshell/nucleus-shell/modules/components/ContentRowCard.qml new file mode 100644 index 0000000..467fbeb --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/ContentRowCard.qml @@ -0,0 +1,51 @@ +import qs.config +import QtQuick +import QtQuick.Layouts + +Item { + id: baseCard + + Layout.fillWidth: true + + implicitHeight: wpBG.implicitHeight + + default property alias content: contentArea.data + property alias color: wpBG.color + + property int cardMargin: Metrics.margin(20) + property int cardSpacing: Metrics.spacing(10) + property int radius: Metrics.radius("large") + property int verticalPadding: Metrics.padding(40) + + Rectangle { + id: wpBG + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: contentArea.implicitHeight + baseCard.verticalPadding + Behavior on implicitHeight { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Easing.InOutExpo + } + } + color: Appearance.m3colors.m3surfaceContainerLow + Behavior on color { + enabled: Config.runtime.appearance.animations.enabled + ColorAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Easing.InOutExpo + } + } + radius: baseCard.radius + } + + RowLayout { + id: contentArea + anchors.top: wpBG.top + anchors.left: wpBG.left + anchors.right: wpBG.right + anchors.margins: baseCard.cardMargin + spacing: baseCard.cardSpacing + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/InfoCard.qml b/.config/quickshell/nucleus-shell/modules/components/InfoCard.qml new file mode 100644 index 0000000..d3f4116 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/InfoCard.qml @@ -0,0 +1,58 @@ +import qs.config +import QtQuick +import QtQuick.Layouts + +ContentRowCard { + id: infoCard + + // --- Properties --- + property string icon: "info" + property color backgroundColor: Appearance.m3colors.darkMode ? Qt.lighter(Appearance.m3colors.m3error, 3.5) : Qt.lighter(Appearance.m3colors.m3error, 1) + property color contentColor: Appearance.m3colors.m3onPrimary + property string title: "Title" + property string description: "Description" + + color: backgroundColor + cardSpacing: Metrics.spacing(12) // nice spacing between elements + + RowLayout { + id: mainLayout + Layout.fillHeight: true + Layout.fillWidth: true + + spacing: Metrics.spacing(16) + Layout.alignment: Qt.AlignVCenter + + // --- Icon --- + MaterialSymbol { + id: infoIcon + icon: infoCard.icon + iconSize: Metrics.iconSize(26) + color: contentColor + Layout.alignment: Qt.AlignVCenter + } + + // --- Text column --- + ColumnLayout { + spacing: Metrics.spacing(2) + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + + StyledText { + text: infoCard.title + font.bold: true + color: contentColor + font.pixelSize: Metrics.fontSize(14) + Layout.fillWidth: true + } + + StyledText { + text: infoCard.description + color: contentColor + font.pixelSize: Metrics.fontSize(12) + Layout.fillWidth: true + wrapMode: Text.WordWrap + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/components/LoadingIcon.qml b/.config/quickshell/nucleus-shell/modules/components/LoadingIcon.qml new file mode 100644 index 0000000..6e0aac1 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/LoadingIcon.qml @@ -0,0 +1,26 @@ +import QtQuick +import qs.config + +Item { + id: root + property alias icon: mIcon.icon + property real size: Metrics.iconSize(28) + width: size + height: size + MaterialSymbol { + id: mIcon + anchors.centerIn: parent + icon: "progress_activity" + font.pixelSize: root.size + color: Appearance.m3colors.m3primary + renderType: Text.QtRendering + } + RotationAnimator on rotation { + target: mIcon + running: true + loops: Animation.Infinite + from: 0 + to: 360 + duration: Metrics.chronoDuration(1000) + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/MaterialSymbol.qml b/.config/quickshell/nucleus-shell/modules/components/MaterialSymbol.qml new file mode 100644 index 0000000..229d6bc --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/MaterialSymbol.qml @@ -0,0 +1,15 @@ +import QtQuick +import qs.config + +StyledText { + property string icon: "" + property int fill: 0 + property int iconSize: Metrics.iconSize("large") + + font.family: Appearance.font.family.materialIcons + font.pixelSize: iconSize + text: icon + font.variableAxes: { + "FILL": fill + } +} diff --git a/.config/quickshell/nucleus-shell/modules/components/MaterialSymbolButton.qml b/.config/quickshell/nucleus-shell/modules/components/MaterialSymbolButton.qml new file mode 100644 index 0000000..39b5ee8 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/MaterialSymbolButton.qml @@ -0,0 +1,56 @@ +import QtQuick +import Quickshell +import qs.config + +MaterialSymbol { + id: root + + // Expose mouse props + property alias enabled: ma.enabled + property alias hoverEnabled: ma.hoverEnabled + property alias pressed: ma.pressed + property string tooltipText: "" + + // Renamed signals (no collisions possible) + signal buttonClicked() + signal buttonEntered() + signal buttonExited() + signal buttonPressAndHold() + signal buttonPressedChanged(bool pressed) + + MouseArea { + id: ma + + anchors.fill: parent + hoverEnabled: true + onClicked: root.buttonClicked() + onEntered: root.buttonEntered() + onExited: root.buttonExited() + onPressAndHold: root.buttonPressAndHold() + onPressedChanged: root.buttonPressedChanged(pressed) + } + + HoverHandler { + id: hover + + enabled: root.tooltipText !== "" + } + + LazyLoader { + active: root.tooltipText !== "" + StyledPopout { + hoverTarget: hover + hoverDelay: Metrics.chronoDuration(500) + + Component { + StyledText { + text: root.tooltipText + } + + } + + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/components/NumberStepper.qml b/.config/quickshell/nucleus-shell/modules/components/NumberStepper.qml new file mode 100644 index 0000000..521b601 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/NumberStepper.qml @@ -0,0 +1,88 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs.config + +RowLayout { + id: root + + property string label: "" + property string description: "" + property string prefField: "" + property double step: 1.0 + property double minimum: -2.14748e+09 // Largest num I could find and type ig + property double maximum: 2.14748e+09 + + // Floating-point value + property double value: readValue() + + function readValue() { + if (!prefField) + return 0; + + var parts = prefField.split('.'); + var cur = Config.runtime; + + for (var i = 0; i < parts.length; ++i) { + if (cur === undefined || cur === null) + return 0; + cur = cur[parts[i]]; + } + + var n = Number(cur); + return isNaN(n) ? 0 : n; + } + + function writeValue(v) { + if (!prefField) + return; + + var nv = Math.max(minimum, Math.min(maximum, v)); + nv = Number(nv.toFixed(2)); // precision control (adjust if needed) + Config.updateKey(prefField, nv); + } + + spacing: Metrics.spacing(8) + Layout.alignment: Qt.AlignVCenter + + ColumnLayout { + spacing: Metrics.spacing(2) + + StyledText { + text: root.label + font.pixelSize: Metrics.fontSize(14) + } + + StyledText { + text: root.description + font.pixelSize: Metrics.fontSize(10) + } + } + + Item { Layout.fillWidth: true } + + RowLayout { + spacing: Metrics.spacing(6) + + StyledButton { + text: "-" + implicitWidth: 36 + onClicked: writeValue(readValue() - step) + } + + StyledText { + text: value.toFixed(2) + font.pixelSize: Metrics.fontSize(14) + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + width: 72 + elide: Text.ElideRight + } + + StyledButton { + text: "+" + implicitWidth: 36 + onClicked: writeValue(readValue() + step) + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/components/StyledButton.qml b/.config/quickshell/nucleus-shell/modules/components/StyledButton.qml new file mode 100644 index 0000000..2ab1aa2 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/StyledButton.qml @@ -0,0 +1,185 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import qs.config +import qs.modules.functions + +Control { + id: root + + property alias text: label.text + property string icon: "" + property int iconSize: Metrics.iconSize(20) + property alias radius: background.radius + property alias topLeftRadius: background.topLeftRadius + property alias topRightRadius: background.topRightRadius + property alias bottomLeftRadius: background.bottomLeftRadius + property alias bottomRightRadius: background.bottomRightRadius + property bool checkable: false + property bool checked: true + property bool secondary: false + property string tooltipText: "" + property bool usePrimary: secondary ? false : checked + property color base_bg: usePrimary ? Appearance.m3colors.m3primary : Appearance.m3colors.m3secondaryContainer + property color base_fg: usePrimary ? Appearance.m3colors.m3onPrimary : Appearance.m3colors.m3onSecondaryContainer + property color disabled_bg: ColorUtils.transparentize(base_bg, 0.4) + property color disabled_fg: ColorUtils.transparentize(base_fg, 0.4) + property color hover_bg: Qt.lighter(base_bg, 1.1) + property color pressed_bg: Qt.darker(base_bg, 1.2) + property color backgroundColor: !root.enabled ? disabled_bg : mouse_area.pressed ? pressed_bg : mouse_area.containsMouse ? hover_bg : base_bg + property color textColor: !root.enabled ? disabled_fg : base_fg + property bool beingHovered: mouse_area.containsMouse + + signal clicked() + signal toggled(bool checked) + + implicitWidth: (label.text === "" && icon !== "") ? implicitHeight : row.implicitWidth + implicitHeight + implicitHeight: 40 + + MouseArea { + id: mouse_area + + anchors.fill: parent + hoverEnabled: root.enabled + cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ForbiddenCursor + onClicked: { + if (!root.enabled) + return ; + + if (root.checkable) { + root.checked = !root.checked; + root.toggled(root.checked); + } + root.clicked(); + } + } + + HoverHandler { + id: hover + + enabled: root.tooltipText !== "" + } + + LazyLoader { + active: root.tooltipText !== "" + + StyledPopout { + hoverTarget: hover + hoverDelay: Metrics.chronoDuration(500) + + Component { + StyledText { + text: root.tooltipText + } + + } + + } + + } + + contentItem: Item { + anchors.fill: parent + + Row { + id: row + + anchors.centerIn: parent + spacing: root.icon !== "" && label.text !== "" ? 5 : 0 + + MaterialSymbol { + visible: root.icon !== "" + icon: root.icon + font.pixelSize: root.iconSize + color: root.textColor + anchors.verticalCenter: parent.verticalCenter + + Behavior on color { + ColorAnimation { + duration: Metrics.chronoDuration("small") / 2 + easing.type: Appearance.animation.easing + } + + } + + } + + StyledText { + id: label + + color: root.textColor + anchors.verticalCenter: parent.verticalCenter + elide: Text.ElideRight + + Behavior on color { + ColorAnimation { + duration: Metrics.chronoDuration("small") / 2 + easing.type: Appearance.animation.easing + } + + } + + } + + } + + } + + background: Rectangle { + id: background + + radius: Metrics.radius("large") + color: root.backgroundColor + + Behavior on color { + ColorAnimation { + duration: Metrics.chronoDuration("small") / 2 + easing.type: Appearance.animation.easing + } + + } + + Behavior on radius { + NumberAnimation { + duration: Metrics.chronoDuration("small") / 2 + easing.type: Appearance.animation.easing + } + + } + + Behavior on topLeftRadius { + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + + } + + Behavior on topRightRadius { + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + + } + + Behavior on bottomLeftRadius { + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + + } + + Behavior on bottomRightRadius { + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/components/StyledDropDown.qml b/.config/quickshell/nucleus-shell/modules/components/StyledDropDown.qml new file mode 100644 index 0000000..ae7080d --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/StyledDropDown.qml @@ -0,0 +1,196 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Effects +import qs.config +import qs.modules.functions + +Item { + id: root + width: 200 + height: 56 + + property string label: "Select option" + property var model: ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5"] + property int currentIndex: -1 + property string currentText: { + if (currentIndex < 0) + return "" + + if (textRole && model && model.get) + return model.get(currentIndex)[textRole] ?? "" + + return model[currentIndex] ?? "" + } + property bool enabled: true + property string textRole: "" + + signal selectedIndexChanged(int index) + + Rectangle { + id: container + anchors.fill: parent + color: "transparent" + border.color: dropdown.activeFocus ? Appearance.m3colors.m3primary : Appearance.m3colors.m3outline + border.width: dropdown.activeFocus ? 2 : 1 + radius: Metrics.radius("unsharpen") + + Behavior on border.color { + enabled: Config.runtime.appearance.animations.enabled + ColorAnimation { duration: Metrics.chronoDuration("small") ; easing.type: Easing.InOutCubic } + } + Behavior on border.width { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { duration: Metrics.chronoDuration("small") ; easing.type: Easing.InOutCubic } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + enabled: root.enabled + hoverEnabled: true + onClicked: dropdown.popup.visible ? dropdown.popup.close() : dropdown.popup.open() + + Rectangle { + anchors.fill: parent + radius: parent.parent.radius + color: Appearance.m3colors.m3primary + opacity: mouseArea.pressed ? 0.12 : mouseArea.containsMouse ? 0.08 : 0 + + Behavior on opacity { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { duration: Metrics.chronoDuration("small") ; easing.type: Easing.InOutCubic } + } + } + } + + RowLayout { + anchors.fill: parent + anchors.leftMargin: Metrics.margin(16) + anchors.rightMargin: Metrics.margin(12) + spacing: Metrics.spacing(12) + + StyledText { + id: labelText + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + text: root.currentIndex >= 0 ? root.currentText : root.label + color: root.currentIndex >= 0 + ? Appearance.m3colors.m3onSurface + : ColorUtils.transparentize(Appearance.m3colors.m3onSurfaceVariant, 0.7) + font.pixelSize: Metrics.fontSize(16) + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + + MaterialSymbol { + id: dropdownIcon + Layout.alignment: Qt.AlignVCenter + icon: dropdown.popup.visible ? "arrow_drop_up" : "arrow_drop_down" + iconSize: Metrics.iconSize(20) + color: Appearance.m3colors.m3onSurfaceVariant + } + } + } + + ComboBox { + id: dropdown + visible: false + model: root.model + currentIndex: root.currentIndex >= 0 ? root.currentIndex : -1 + enabled: root.enabled + textRole: root.textRole + + onCurrentIndexChanged: { + if (currentIndex >= 0) { + root.currentIndex = currentIndex + root.selectedIndexChanged(currentIndex) + } + } + + popup: Popup { + y: root.height + 4 + width: root.width + padding: 0 + + background: Rectangle { + color: Appearance.m3colors.m3surfaceContainer + radius: Metrics.radius(4) + border.color: Appearance.m3colors.m3outline + border.width: 1 + layer.enabled: true + layer.effect: MultiEffect { + shadowEnabled: true + shadowColor: ColorUtils.transparentize(Appearance.m3colors.m3shadow, 0.25) + shadowBlur: 0.4 + shadowVerticalOffset: 8 + shadowHorizontalOffset: 0 + } + } + + contentItem: ListView { + id: listView + clip: true + implicitHeight: Math.min(contentHeight, 300) + model: dropdown.popup.visible ? dropdown.model : [] + currentIndex: Math.max(0, dropdown.currentIndex) + + ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } + + delegate: ItemDelegate { + width: listView.width + height: 48 + + background: Rectangle { + color: { + if (itemMouse.pressed) return ColorUtils.transparentize(Appearance.m3colors.m3primaryContainer, 0.12) + if (itemMouse.containsMouse) return ColorUtils.transparentize(Appearance.m3colors.m3primaryContainer, 0.08) + if (index === root.currentIndex) return ColorUtils.transparentize(Appearance.m3colors.m3primaryContainer, 0.08) + return "transparent" + } + Behavior on color { + ColorAnimation { duration: Metrics.chronoDuration("small") ; easing.type: Easing.InOutCubic } + } + } + + contentItem: StyledText { + text: modelData + color: index === root.currentIndex ? Appearance.m3colors.m3primary : Appearance.m3colors.m3onSurface + font.pixelSize: Metrics.fontSize(16) + verticalAlignment: Text.AlignVCenter + leftPadding: Metrics.fontSize(16) + } + + MouseArea { + id: itemMouse + anchors.fill: parent + hoverEnabled: true + onClicked: { + dropdown.currentIndex = index + dropdown.popup.close() + } + } + } + } + + enter: Transition { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation {property: "opacity"; from: 0.0; to: 1.0; duration: Metrics.chronoDuration("small") ; easing.type: Easing.InOutCubic } + NumberAnimation {property: "scale"; from: 0.9; to: 1.0; duration: Metrics.chronoDuration("small") ; easing.type: Easing.InOutCubic } + } + + exit: Transition { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation {property: "opacity"; from: 1.0; to: 0.0; duration: Metrics.chronoDuration(Appearance.animation.fast * 0.67); easing.type: Easing.InOutCubic } + } + } + } + + focus: true + Keys.onPressed: (event) => { + if (event.key === Qt.Key_Space || event.key === Qt.Key_Return) { + dropdown.popup.visible ? dropdown.popup.close() : dropdown.popup.open() + event.accepted = true + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/components/StyledImage.qml b/.config/quickshell/nucleus-shell/modules/components/StyledImage.qml new file mode 100644 index 0000000..e46e48e --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/StyledImage.qml @@ -0,0 +1,13 @@ +import QtQuick +import qs.services +import qs.config + +Image { + asynchronous: true + retainWhileLoading: true + visible: opacity > 0 + opacity: (status === Image.Ready) ? 1 : 0 + Behavior on opacity { + animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/StyledPopout.qml b/.config/quickshell/nucleus-shell/modules/components/StyledPopout.qml new file mode 100644 index 0000000..d53339d --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/StyledPopout.qml @@ -0,0 +1,327 @@ +import qs.config +import QtQuick +import QtQuick.Effects +import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets +import Quickshell.Wayland + +LazyLoader { + id: root + + property string displayName: screen?.name ?? "" + property PanelWindow instance: null + property HoverHandler hoverTarget + property real margin: Metrics.margin(10) + default property list content + property bool startAnim: false + property bool isVisible: false + property bool keepAlive: false + property bool interactable: false + property bool hasHitbox: true + property bool hCenterOnItem: false + property bool followMouse: false + property list childPopouts: [] + + property bool requiresHover: true + property bool _manualControl: false + property int hoverDelay: Metrics.chronoDuration(250) + + property bool targetHovered: hoverTarget && hoverTarget.hovered + property bool containerHovered: interactable && root.item && root.item.containerHovered + property bool selfHovered: targetHovered || containerHovered + + property bool childrenHovered: { + for (let i = 0; i < childPopouts.length; i++) { + if (childPopouts[i].selfHovered) + return true; + } + return false; + } + + property bool hoverActive: selfHovered || childrenHovered + + property Timer showDelayTimer: Timer { + interval: root.hoverDelay + repeat: false + onTriggered: { + root.keepAlive = true; + root.isVisible = true; + root.startAnim = true; + } + } + + property Timer hangTimer: Timer { + interval: Metrics.chronoDuration(200) + repeat: false + onTriggered: { + root.startAnim = false; + cleanupTimer.restart(); + } + } + + property Timer cleanupTimer: Timer { + interval: Metrics.chronoDuration("small") + repeat: false + onTriggered: { + root.isVisible = false; + root.keepAlive = false; + root._manualControl = false; + root.instance = null; + } + } + + onHoverActiveChanged: { + if (_manualControl) + return; + if (!requiresHover) + return; + if (hoverActive) { + hangTimer.stop(); + cleanupTimer.stop(); + if (hoverDelay > 0) { + showDelayTimer.restart(); + } else { + root.keepAlive = true; + root.isVisible = true; + root.startAnim = true; + } + } else { + showDelayTimer.stop(); + hangTimer.restart(); + } + } + + function show() { + hangTimer.stop(); + cleanupTimer.stop(); + showDelayTimer.stop(); + _manualControl = true; + keepAlive = true; + isVisible = true; + startAnim = true; + } + + function hide() { + _manualControl = true; + showDelayTimer.stop(); + startAnim = false; + hangTimer.stop(); + cleanupTimer.restart(); + } + + active: keepAlive + + component: PanelWindow { + id: popoutWindow + + color: "transparent" + visible: root.isVisible + + WlrLayershell.namespace: "whisker:popout" + WlrLayershell.layer: WlrLayer.Overlay + exclusionMode: ExclusionMode.Ignore + exclusiveZone: 0 + + anchors { + left: true + top: true + right: true + bottom: true + } + + property bool exceedingHalf: false + property var parentPopoutWindow: null + property point mousePos: Qt.point(0, 0) + property bool containerHovered: root.interactable && containerHoverHandler.hovered + + HoverHandler { + id: windowHover + onPointChanged: point => { + if (root.followMouse) + popoutWindow.mousePos = point.position; + } + } + + mask: Region { + x: !root.hasHitbox ? 0 : !requiresHover ? 0 : container.x + y: !root.hasHitbox ? 0 : !requiresHover ? 0 : container.y + width: !root.hasHitbox ? 0 : !requiresHover ? popoutWindow.width : container.implicitWidth + height: !root.hasHitbox ? 0 : !requiresHover ? popoutWindow.height : container.implicitHeight + } + MouseArea { + id: mouseArea + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + hoverEnabled: false + + onPressed: mouse => { + if (!containerHoverHandler.containsMouse && root.isVisible) { + root.hide(); + } + } + } + Item { + id: container + + implicitWidth: contentArea.implicitWidth + root.margin * 2 + implicitHeight: contentArea.implicitHeight + root.margin * 2 + + x: { + let xValue; + + if (root.followMouse) + xValue = mousePos.x + 10; + else { + let targetItem = hoverTarget?.parent; + if (!targetItem) + xValue = 0; + else { + let baseX = targetItem.mapToGlobal(Qt.point(0, 0)).x; + if (parentPopoutWindow) + baseX += parentPopoutWindow.x; + + let targetWidth = targetItem.width; + let popupWidth = container.implicitWidth; + + if (root.hCenterOnItem) { + let centeredX = baseX + (targetWidth - popupWidth) / 2; + if (centeredX + popupWidth > screen.width) + centeredX = screen.width - popupWidth - 10; + if (centeredX < 10) + centeredX = 10; + xValue = centeredX; + } else { + let xPos = baseX - ((ConfigResolver.bar(root.displayName).position === "top" || ConfigResolver.bar(root.displayName).position === "top") ? 20 : -40); + if (xPos + popupWidth > screen.width) { + exceedingHalf = true; + xValue = baseX - popupWidth; + } else { + exceedingHalf = false; + xValue = xPos; + } + } + } + } + + return root.cleanupTimer.running ? xValue : Math.round(xValue); + } + + y: { + let yValue; + + if (root.followMouse) + yValue = mousePos.y + 10; + else { + let targetItem = hoverTarget?.parent; + if (!targetItem) + yValue = 0; + else { + let baseY = targetItem.mapToGlobal(Qt.point(0, 0)).y; + if (parentPopoutWindow) + baseY += parentPopoutWindow.y; + + let targetHeight = targetItem.height; + let popupHeight = container.implicitHeight; + + let yPos = baseY + ((ConfigResolver.bar(root.displayName).position === "top" || ConfigResolver.bar(root.displayName).position === "top") ? targetHeight : 0); + + if (yPos > screen.height / 2) + yPos = baseY - popupHeight; + + if (yPos + popupHeight > screen.height) + yPos = screen.height - popupHeight - 10; + if (yPos < 10) + yPos = 10; + + yValue = yPos; + } + } + + return root.cleanupTimer.running ? yValue : Math.round(yValue); + } + + + + opacity: root.startAnim ? 1 : 0 + scale: root.interactable ? 1 : root.startAnim ? 1 : 0.9 + + layer.enabled: true + layer.effect: MultiEffect { + shadowEnabled: true + shadowOpacity: 1 + shadowColor: Appearance.m3colors.m3shadow + shadowBlur: 1 + shadowScale: 1 + } + + Behavior on opacity { + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + } + Behavior on scale { + enabled: !root.interactable + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + } + Behavior on implicitWidth { + enabled: root.interactable + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + } + Behavior on implicitHeight { + enabled: root.interactable + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + } + + ClippingRectangle { + id: popupBackground + anchors.fill: parent + color: Appearance.m3colors.m3surface + radius: Appearance.rounding.normal + + ColumnLayout { + id: contentArea + anchors.fill: parent + anchors.margins: root.margin + } + } + + HoverHandler { + id: containerHoverHandler + enabled: root.interactable + } + } + + Component.onCompleted: { + root.instance = popoutWindow; + for (let i = 0; i < root.content.length; i++) { + const comp = root.content[i]; + if (comp && comp.createObject) { + comp.createObject(contentArea); + } else { + console.warn("StyledPopout: invalid content:", comp); + } + } + + let parentPopout = root.parent; + while (parentPopout && !parentPopout.childPopouts) + parentPopout = parentPopout.parent; + + if (parentPopout) { + parentPopout.childPopouts.push(root); + if (parentPopout.item) + popoutWindow.parentPopoutWindow = parentPopout.item; + } + } + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/StyledRect.qml b/.config/quickshell/nucleus-shell/modules/components/StyledRect.qml new file mode 100644 index 0000000..20fe500 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/StyledRect.qml @@ -0,0 +1,15 @@ +import qs.config +import QtQuick + +Rectangle { + id: root + + Behavior on color { + enabled: Config.runtime.appearance.animations.enabled + ColorAnimation { + duration: Metrics.chronoDuration(600) + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.curves.standard + } + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/StyledSlider.qml b/.config/quickshell/nucleus-shell/modules/components/StyledSlider.qml new file mode 100644 index 0000000..fd6f485 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/StyledSlider.qml @@ -0,0 +1,118 @@ +import qs.config +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +Slider { + id: root + + property real trackHeightDiff: 15 + property real handleGap: Metrics.spacing(4) + property real trackDotSize: Metrics.iconSize(4) + property real trackNearHandleRadius: Appearance.rounding.unsharpen + property bool useAnim: true + property int iconSize: Appearance.font.size.large + property string icon: "" + + Layout.fillWidth: true + + implicitWidth: 200 + implicitHeight: 40 + from: 0 + to: 100 + value: 0 + stepSize: 0 + snapMode: stepSize > 0 ? Slider.SnapAlways : Slider.NoSnap + + + MouseArea { + anchors.fill: parent + onPressed: (mouse) => mouse.accepted = false + cursorShape: root.pressed ? Qt.ClosedHandCursor : Qt.PointingHandCursor + } + + MaterialSymbol { + id: icon + icon: root.icon + iconSize: root.iconSize + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.rightMargin: Metrics.margin(16) + } + + background: Item { + anchors.verticalCenter: parent.verticalCenter + width: parent.width + height: parent.height + + // Filled Left Segment + Rectangle { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + + width: root.handleGap + (root.visualPosition * (root.width - root.handleGap * 2)) + - ((root.pressed ? 1.5 : 3) / 2 + root.handleGap) + + height: root.height - root.trackHeightDiff + color: Appearance.colors.colPrimary + radius: Metrics.radius("small") + topRightRadius: root.trackNearHandleRadius + bottomRightRadius: root.trackNearHandleRadius + + Behavior on width { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: !root.useAnim ? 0 : Metrics.chronoDuration("small") + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.curves.expressiveEffects + } + } + } + + // Remaining Right Segment + Rectangle { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + + width: root.handleGap + ((1 - root.visualPosition) * (root.width - root.handleGap * 2)) + - ((root.pressed ? 1.5 : 3) / 2 + root.handleGap) + + height: root.height - root.trackHeightDiff + color: Appearance.colors.colSecondaryContainer + radius: Metrics.radius("small") + topLeftRadius: root.trackNearHandleRadius + bottomLeftRadius: root.trackNearHandleRadius + + Behavior on width { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: !root.useAnim ? 0 : Metrics.chronoDuration("small") + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.curves.expressiveEffects + } + } + } + } + + + handle: Rectangle { + width: 5 + height: root.height + radius: (width / 2) * Config.runtime.appearance.rounding.factor + + x: root.handleGap + (root.visualPosition * (root.width - root.handleGap * 2)) - width / 2 + anchors.verticalCenter: parent.verticalCenter + + color: Appearance.colors.colPrimary + + Behavior on x { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: !root.useAnim ? 0 : Appearance.animation.elementMoveFast.duration + easing.type: Appearance.animation.elementMoveFast.type + easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/components/StyledSwitch.qml b/.config/quickshell/nucleus-shell/modules/components/StyledSwitch.qml new file mode 100644 index 0000000..c19b903 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/StyledSwitch.qml @@ -0,0 +1,138 @@ +import qs.config +import QtQuick +import QtQuick.Controls + +Item { + id: root + width: 60 + height: 34 + + property bool checked: false + signal toggled(bool checked) + + // Colors + property color trackOn: Appearance.colors.colPrimary + property color trackOff: Appearance.colors.colLayer2 + property color outline: Appearance.colors.colOutline + + property color thumbOn: Appearance.colors.colOnPrimary + property color thumbOff: Appearance.colors.colOnLayer2 + + property color iconOn: Appearance.colors.colPrimary + property color iconOff: Appearance.colors.colOnPrimary + + // Dimensions + property int trackRadius: (height / 2) * Config.runtime.appearance.rounding.factor + property int thumbSize: height - (checked ? 10 : 14) + + Behavior on thumbSize { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration("normal") + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.curves.expressiveEffects + } + } + + // TRACK + Rectangle { + id: track + anchors.fill: parent + radius: trackRadius + + color: root.checked ? trackOn : trackOff + border.width: root.checked ? 0 : 2 + border.color: outline + + Behavior on color { + enabled: Config.runtime.appearance.animations.enabled + ColorAnimation { + duration: Metrics.chronoDuration("normal") + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.curves.expressiveEffects + } + } + } + + // THUMB + Rectangle { + id: thumb + width: thumbSize + height: thumbSize + radius: (thumbSize / 2) * Config.runtime.appearance.rounding.factor + + anchors.verticalCenter: parent.verticalCenter + x: root.checked ? parent.width - width - 6 : 6 + + color: root.checked ? thumbOn : thumbOff + + Behavior on x { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.curves.expressiveEffects + } + } + + Behavior on color { + enabled: Config.runtime.appearance.animations.enabled + ColorAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.curves.expressiveEffects + } + } + + // ✓ CHECK ICON + MaterialSymbol { + anchors.centerIn: parent + icon: "check" + iconSize: parent.width * 0.7 + color: iconOn + + opacity: root.checked ? 1 : 0 + scale: root.checked ? 1 : 0.6 + + Behavior on opacity { NumberAnimation { duration: 120 } } + + Behavior on scale { + NumberAnimation { + duration: 160 + easing.type: Easing.OutBack + } + } + } + + // ✕ CROSS ICON (more visible) + MaterialSymbol { + anchors.centerIn: parent + icon: "close" + iconSize: parent.width * 0.72 + color: iconOff + + opacity: root.checked ? 0 : 1 + scale: root.checked ? 0.6 : 1 + + Behavior on opacity { NumberAnimation { duration: 120 } } + + Behavior on scale { + NumberAnimation { + duration: 160 + easing.type: Easing.OutBack + } + } + } + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + + onClicked: { + root.checked = !root.checked + root.toggled(root.checked) + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/components/StyledSwitchOption.qml b/.config/quickshell/nucleus-shell/modules/components/StyledSwitchOption.qml new file mode 100644 index 0000000..1ae90b7 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/StyledSwitchOption.qml @@ -0,0 +1,37 @@ +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +RowLayout { + id: main + property string title: "Title" + property string description: "Description" + property string prefField: '' + + ColumnLayout { + StyledText { text: main.title; font.pixelSize: Metrics.fontSize(16); } + StyledText { text: main.description; font.pixelSize: Metrics.fontSize(12); } + } + Item { Layout.fillWidth: true } + + StyledSwitch { + // Safely resolve nested key (e.g. "background.showClock" or "bar.modules.some.setting") + checked: { + if (!main.prefField) return false; + var parts = main.prefField.split('.'); + var cur = Config.runtime; + for (var i = 0; i < parts.length; ++i) { + if (cur === undefined || cur === null) return false; + cur = cur[parts[i]]; + } + // If the config value is undefined, default to false + return cur === undefined || cur === null ? false : cur; + } + + onToggled: { + // Persist change (updateKey will create missing objects) + Config.updateKey(main.prefField, checked); + } + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/StyledText.qml b/.config/quickshell/nucleus-shell/modules/components/StyledText.qml new file mode 100644 index 0000000..90b3ba6 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/StyledText.qml @@ -0,0 +1,54 @@ +pragma ComponentBehavior: Bound + +import qs.config +import QtQuick + +Text { + id: root + + // from github.com/yannpelletier/twinshell with modifications + + property bool animate: true + property string animateProp: "scale" + property real animateFrom: 0 + property real animateTo: 1 + property int animateDuration: Metrics.chronoDuration("small") + + renderType: Text.NativeRendering + textFormat: Text.PlainText + color: Appearance.syntaxHighlightingTheme + font.family: Metrics.fontFamily("main") + font.pixelSize: Metrics.fontSize("normal") + + Behavior on color { + enabled: Config.runtime.appearance.animations.enabled + ColorAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.curves.standard + } + } + + Behavior on text { + enabled: Config.runtime.appearance.animations.enabled && root.animate + + SequentialAnimation { + Anim { + to: root.animateFrom + easing.bezierCurve: Appearance.animation.curves.standardAccel + } + PropertyAction {} + Anim { + to: root.animateTo + easing.bezierCurve: Appearance.animation.curves.standardDecel + } + } + } + + component Anim: NumberAnimation { + target: root + property: root.animateProp + duration: root.animateDuration / 2 + easing.type: Easing.BezierSpline + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/StyledTextField.qml b/.config/quickshell/nucleus-shell/modules/components/StyledTextField.qml new file mode 100755 index 0000000..9e64290 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/StyledTextField.qml @@ -0,0 +1,195 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Effects +import qs.config +import qs.modules.functions + +TextField { + id: control + + property string icon: "" + property color iconColor: Appearance.m3colors.m3onSurfaceVariant + property string placeholder: "" + property real iconSize: Metrics.iconSize(24) + property alias radius: bg.radius + property bool outline: true + property alias topLeftRadius: bg.topLeftRadius + property alias topRightRadius: bg.topRightRadius + property alias bottomLeftRadius: bg.bottomLeftRadius + property alias bottomRightRadius: bg.bottomRightRadius + property color backgroundColor: filled ? Appearance.m3colors.m3surfaceContainerHigh : "transparent" + property int fieldPadding: Metrics.padding(20) + property int iconSpacing: Metrics.spacing(14) + property int iconMargin: Metrics.margin(20) + property bool filled: true + property bool highlight: true + + width: parent ? parent.width - 40 : 300 + placeholderText: placeholder + leftPadding: icon !== "" ? iconSize + iconSpacing + iconMargin : fieldPadding + padding: fieldPadding + verticalAlignment: TextInput.AlignVCenter + color: Appearance.m3colors.m3onSurface + placeholderTextColor: Appearance.m3colors.m3onSurfaceVariant + font.family: "Outfit" + font.pixelSize: Metrics.fontSize(14) + cursorVisible: control.focus + + MaterialSymbol { + icon: control.icon + anchors.left: parent.left + anchors.leftMargin: icon !== "" ? iconMargin : 0 + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: control.iconSize + color: control.iconColor + visible: control.icon !== "" + + Behavior on color { + ColorAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + + } + + } + + cursorDelegate: Rectangle { + width: 2 + color: Appearance.m3colors.m3primary + visible: control.focus + + SequentialAnimation on opacity { + loops: Animation.Infinite + running: control.focus && Config.runtime.appearance.animations.enabled + + NumberAnimation { + from: 1 + to: 0 + duration: Metrics.chronoDuration("lrage") * 2 + } + + NumberAnimation { + from: 0 + to: 1 + duration: Metrics.chronoDuration("lrage") * 2 + } + + } + + } + + background: Item { + Rectangle { + id: bg + + anchors.fill: parent + radius: Metrics.radius("unsharpenmore") + color: control.backgroundColor + + Rectangle { + anchors.fill: parent + radius: parent.radius + color: { + if (control.activeFocus && control.highlight) + return ColorUtils.transparentize(Appearance.m3colors.m3primary, 0.8); + + if (control.hovered && control.highlight) + return ColorUtils.transparentize(Appearance.m3colors.m3onSurface, 0.9); + + return "transparent"; + } + + Behavior on color { + enabled: Config.runtime.appearance.animations.enabled + + ColorAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + + } + + } + + } + + Rectangle { + id: indicator + + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + height: control.activeFocus ? 2 : 1 + color: { + if (control.activeFocus) + return Appearance.m3colors.m3primary; + + if (control.hovered) + return Appearance.m3colors.m3onSurface; + + return Appearance.m3colors.m3onSurface; + } + visible: filled + + Behavior on height { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + + } + + Behavior on color { + enabled: Config.runtime.appearance.animations.enabled + ColorAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + + } + + } + + Rectangle { + id: outline + + anchors.fill: parent + radius: bg.radius + color: "transparent" + border.width: control.activeFocus ? 2 : 1 + border.color: { + if (control.activeFocus) + return Appearance.m3colors.m3primary; + + if (control.hovered) + return Appearance.m3colors.m3onSurface; + + return Appearance.m3colors.m3outline; + } + visible: !filled && control.outline + + Behavior on border.width { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + + } + + Behavior on border.color { + enabled: Config.runtime.appearance.animations.enabled + ColorAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + + } + + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/components/Tint.qml b/.config/quickshell/nucleus-shell/modules/components/Tint.qml new file mode 100644 index 0000000..e88a59a --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/Tint.qml @@ -0,0 +1,22 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Effects +import qs.config + +Item { + property var sourceItem: null + + Loader { + active: Config.runtime.appearance.tintIcons + anchors.fill: parent + sourceComponent: MultiEffect { + source: sourceItem + + saturation: -1.0 + contrast: 0.10 + brightness: -0.08 + blur: 0.0 + } + + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/MorphedPolygon.qml b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/MorphedPolygon.qml new file mode 100644 index 0000000..11409f9 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/MorphedPolygon.qml @@ -0,0 +1,103 @@ +import QtQuick +import "shapes/morph.js" as Morph +import qs.config + +// From github.com/end-4/rounded-polygons-qmljs + +Canvas { + id: root + property color color: "#685496" + property var roundedPolygon: null + property bool polygonIsNormalized: true + property real borderWidth: 0 + property color borderColor: color + property bool debug: false + + // Internals: size + property var bounds: roundedPolygon.calculateBounds() + implicitWidth: bounds[2] - bounds[0] + implicitHeight: bounds[3] - bounds[1] + + // Internals: anim + property var prevRoundedPolygon: null + property double progress: 1 + property var morph: new Morph.Morph(roundedPolygon, roundedPolygon) + property Animation animation: NumberAnimation { + duration: Metrics.chronoDuration(350) + easing.type: Easing.BezierSpline + easing.bezierCurve: [0.42, 1.67, 0.21, 0.90, 1, 1] // Material 3 Expressive fast spatial (https://m3.material.io/styles/motion/overview/specs) + } + + onRoundedPolygonChanged: { + delete root.morph + root.morph = new Morph.Morph(root.prevRoundedPolygon ?? root.roundedPolygon, root.roundedPolygon) + morphBehavior.enabled = false; + root.progress = 0 + morphBehavior.enabled = true; + root.progress = 1 + root.prevRoundedPolygon = root.roundedPolygon + } + + Behavior on progress { + id: morphBehavior + animation: root.animation + } + + onProgressChanged: requestPaint() + onColorChanged: requestPaint() + onBorderWidthChanged: requestPaint() + onBorderColorChanged: requestPaint() + onDebugChanged: requestPaint() + onPaint: { + var ctx = getContext("2d") + ctx.fillStyle = root.color + ctx.clearRect(0, 0, width, height) + if (!root.morph) return + const cubics = root.morph.asCubics(root.progress) + if (cubics.length === 0) return + + const size = Math.min(root.width, root.height) + + ctx.save() + if (root.polygonIsNormalized) ctx.scale(size, size) + + ctx.beginPath() + ctx.moveTo(cubics[0].anchor0X, cubics[0].anchor0Y) + for (const cubic of cubics) { + ctx.bezierCurveTo( + cubic.control0X, cubic.control0Y, + cubic.control1X, cubic.control1Y, + cubic.anchor1X, cubic.anchor1Y + ) + } + ctx.closePath() + ctx.fill() + + if (root.borderWidth > 0) { + ctx.strokeStyle = root.borderColor + ctx.lineWidth = root.borderWidth + ctx.stroke() + } + + if (root.debug) { + const points = [] + for (let i = 0; i < cubics.length; ++i) { + const c = cubics[i] + if (i === 0) + points.push({ x: c.anchor0X, y: c.anchor0Y }) + points.push({ x: c.anchor1X, y: c.anchor1Y }) + } + + let radius = Metrics.radius(2) + + ctx.fillStyle = "red" + for (const p of points) { + ctx.beginPath() + ctx.arc(p.x, p.y, radius, 0, Math.PI * 2) + ctx.fill() + } + } + + ctx.restore() + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/geometry/offset.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/geometry/offset.js new file mode 100644 index 0000000..6066605 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/geometry/offset.js @@ -0,0 +1,177 @@ +.pragma library + +/** + * @param {number} x + * @param {number} y + * @returns {Offset} + */ +function createOffset(x, y) { + return new Offset(x, y); +} + +class Offset { + /** + * @param {number} x + * @param {number} y + */ + constructor(x, y) { + this.x = x; + this.y = y; + } + + /** + * @param {number} x + * @param {number} y + * @returns {Offset} + */ + copy(x = this.x, y = this.y) { + return new Offset(x, y); + } + + /** + * @returns {number} + */ + getDistance() { + return Math.sqrt(this.x * this.x + this.y * this.y); + } + + /** + * @returns {number} + */ + getDistanceSquared() { + return this.x * this.x + this.y * this.y; + } + + /** + * @returns {boolean} + */ + isValid() { + return isFinite(this.x) && isFinite(this.y); + } + + /** + * @returns {boolean} + */ + get isFinite() { + return isFinite(this.x) && isFinite(this.y); + } + + /** + * @returns {boolean} + */ + get isSpecified() { + return !this.isUnspecified; + } + + /** + * @returns {boolean} + */ + get isUnspecified() { + return Object.is(this.x, NaN) && Object.is(this.y, NaN); + } + + /** + * @returns {Offset} + */ + negate() { + return new Offset(-this.x, -this.y); + } + + /** + * @param {Offset} other + * @returns {Offset} + */ + minus(other) { + return new Offset(this.x - other.x, this.y - other.y); + } + + /** + * @param {Offset} other + * @returns {Offset} + */ + plus(other) { + return new Offset(this.x + other.x, this.y + other.y); + } + + /** + * @param {number} operand + * @returns {Offset} + */ + times(operand) { + return new Offset(this.x * operand, this.y * operand); + } + + /** + * @param {number} operand + * @returns {Offset} + */ + div(operand) { + return new Offset(this.x / operand, this.y / operand); + } + + /** + * @param {number} operand + * @returns {Offset} + */ + rem(operand) { + return new Offset(this.x % operand, this.y % operand); + } + + /** + * @returns {string} + */ + toString() { + if (this.isSpecified) { + return `Offset(${this.x.toFixed(1)}, ${this.y.toFixed(1)})`; + } else { + return 'Offset.Unspecified'; + } + } + + /** + * @param {Offset} start + * @param {Offset} stop + * @param {number} fraction + * @returns {Offset} + */ + static lerp(start, stop, fraction) { + return new Offset( + start.x + (stop.x - start.x) * fraction, + start.y + (stop.y - start.y) * fraction + ); + } + + /** + * @param {function(): Offset} block + * @returns {Offset} + */ + takeOrElse(block) { + return this.isSpecified ? this : block(); + } + + /** + * @returns {number} + */ + angleDegrees() { + return Math.atan2(this.y, this.x) * 180 / Math.PI; + } + + /** + * @param {number} angle + * @param {Offset} center + * @returns {Offset} + */ + rotateDegrees(angle, center = Offset.Zero) { + const a = angle * Math.PI / 180; + const off = this.minus(center); + const cosA = Math.cos(a); + const sinA = Math.sin(a); + const newX = off.x * cosA - off.y * sinA; + const newY = off.x * sinA + off.y * cosA; + return new Offset(newX, newY).plus(center); + } +} + +Offset.Zero = new Offset(0, 0); +Offset.Infinite = new Offset(Infinity, Infinity); +Offset.Unspecified = new Offset(NaN, NaN); diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/graphics/matrix.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/graphics/matrix.js new file mode 100644 index 0000000..4c8181c --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/graphics/matrix.js @@ -0,0 +1,198 @@ +.pragma library + +.import "../geometry/offset.js" as Offset + +class Matrix { + constructor(values = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]) { + this.values = values; + } + + get(row, column) { + return this.values[(row * 4) + column]; + } + + set(row, column, v) { + this.values[(row * 4) + column] = v; + } + + /** Does the 3D transform on [point] and returns the `x` and `y` values in an [Offset]. */ + map(point) { + if (this.values.length < 16) return point; + + const v00 = this.get(0, 0); + const v01 = this.get(0, 1); + const v03 = this.get(0, 3); + const v10 = this.get(1, 0); + const v11 = this.get(1, 1); + const v13 = this.get(1, 3); + const v30 = this.get(3, 0); + const v31 = this.get(3, 1); + const v33 = this.get(3, 3); + + const x = point.x; + const y = point.y; + const z = v03 * x + v13 * y + v33; + const inverseZ = 1 / z; + const pZ = isFinite(inverseZ) ? inverseZ : 0; + + return new Offset.Offset(pZ * (v00 * x + v10 * y + v30), pZ * (v01 * x + v11 * y + v31)); + } + + /** Multiply this matrix by [m] and assign the result to this matrix. */ + timesAssign(m) { + const v = this.values; + if (v.length < 16) return; + if (m.values.length < 16) return; + + const v00 = this.dot(0, m, 0); + const v01 = this.dot(0, m, 1); + const v02 = this.dot(0, m, 2); + const v03 = this.dot(0, m, 3); + const v10 = this.dot(1, m, 0); + const v11 = this.dot(1, m, 1); + const v12 = this.dot(1, m, 2); + const v13 = this.dot(1, m, 3); + const v20 = this.dot(2, m, 0); + const v21 = this.dot(2, m, 1); + const v22 = this.dot(2, m, 2); + const v23 = this.dot(2, m, 3); + const v30 = this.dot(3, m, 0); + const v31 = this.dot(3, m, 1); + const v32 = this.dot(3, m, 2); + const v33 = this.dot(3, m, 3); + + v[0] = v00; + v[1] = v01; + v[2] = v02; + v[3] = v03; + v[4] = v10; + v[5] = v11; + v[6] = v12; + v[7] = v13; + v[8] = v20; + v[9] = v21; + v[10] = v22; + v[11] = v23; + v[12] = v30; + v[13] = v31; + v[14] = v32; + v[15] = v33; + } + + dot(row, m, column) { + return this.get(row, 0) * m.get(0, column) + + this.get(row, 1) * m.get(1, column) + + this.get(row, 2) * m.get(2, column) + + this.get(row, 3) * m.get(3, column); + } + + /** Resets the `this` to the identity matrix. */ + reset() { + const v = this.values; + if (v.length < 16) return; + v[0] = 1; + v[1] = 0; + v[2] = 0; + v[3] = 0; + v[4] = 0; + v[5] = 1; + v[6] = 0; + v[7] = 0; + v[8] = 0; + v[9] = 0; + v[10] = 1; + v[11] = 0; + v[12] = 0; + v[13] = 0; + v[14] = 0; + v[15] = 1; + } + + /** Applies a [degrees] rotation around Z to `this`. */ + rotateZ(degrees) { + if (this.values.length < 16) return; + + const r = degrees * (Math.PI / 180.0); + const s = Math.sin(r); + const c = Math.cos(r); + + const a00 = this.get(0, 0); + const a10 = this.get(1, 0); + const v00 = c * a00 + s * a10; + const v10 = -s * a00 + c * a10; + + const a01 = this.get(0, 1); + const a11 = this.get(1, 1); + const v01 = c * a01 + s * a11; + const v11 = -s * a01 + c * a11; + + const a02 = this.get(0, 2); + const a12 = this.get(1, 2); + const v02 = c * a02 + s * a12; + const v12 = -s * a02 + c * a12; + + const a03 = this.get(0, 3); + const a13 = this.get(1, 3); + const v03 = c * a03 + s * a13; + const v13 = -s * a03 + c * a13; + + this.set(0, 0, v00); + this.set(0, 1, v01); + this.set(0, 2, v02); + this.set(0, 3, v03); + this.set(1, 0, v10); + this.set(1, 1, v11); + this.set(1, 2, v12); + this.set(1, 3, v13); + } + + /** Scale this matrix by [x], [y], [z] */ + scale(x = 1, y = 1, z = 1) { + if (this.values.length < 16) return; + this.set(0, 0, this.get(0, 0) * x); + this.set(0, 1, this.get(0, 1) * x); + this.set(0, 2, this.get(0, 2) * x); + this.set(0, 3, this.get(0, 3) * x); + this.set(1, 0, this.get(1, 0) * y); + this.set(1, 1, this.get(1, 1) * y); + this.set(1, 2, this.get(1, 2) * y); + this.set(1, 3, this.get(1, 3) * y); + this.set(2, 0, this.get(2, 0) * z); + this.set(2, 1, this.get(2, 1) * z); + this.set(2, 2, this.get(2, 2) * z); + this.set(2, 3, this.get(2, 3) * z); + } + + /** Translate this matrix by [x], [y], [z] */ + translate(x = 0, y = 0, z = 0) { + if (this.values.length < 16) return; + const t1 = this.get(0, 0) * x + this.get(1, 0) * y + this.get(2, 0) * z + this.get(3, 0); + const t2 = this.get(0, 1) * x + this.get(1, 1) * y + this.get(2, 1) * z + this.get(3, 1); + const t3 = this.get(0, 2) * x + this.get(1, 2) * y + this.get(2, 2) * z + this.get(3, 2); + const t4 = this.get(0, 3) * x + this.get(1, 3) * y + this.get(2, 3) * z + this.get(3, 3); + this.set(3, 0, t1); + this.set(3, 1, t2); + this.set(3, 2, t3); + this.set(3, 3, t4); + } + + toString() { + return `${this.get(0, 0)} ${this.get(0, 1)} ${this.get(0, 2)} ${this.get(0, 3)}\n` + + `${this.get(1, 0)} ${this.get(1, 1)} ${this.get(1, 2)} ${this.get(1, 3)}\n` + + `${this.get(2, 0)} ${this.get(2, 1)} ${this.get(2, 2)} ${this.get(2, 3)}\n` + + `${this.get(3, 0)} ${this.get(3, 1)} ${this.get(3, 2)} ${this.get(3, 3)}`; + } +} + +// Companion object constants +Matrix.ScaleX = 0; +Matrix.SkewY = 1; +Matrix.Perspective0 = 3; +Matrix.SkewX = 4; +Matrix.ScaleY = 5; +Matrix.Perspective1 = 7; +Matrix.ScaleZ = 10; +Matrix.TranslateX = 12; +Matrix.TranslateY = 13; +Matrix.TranslateZ = 14; +Matrix.Perspective2 = 15; diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/material-shapes.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/material-shapes.js new file mode 100644 index 0000000..8743f37 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/material-shapes.js @@ -0,0 +1,712 @@ +.pragma library + +.import "shapes/point.js" as Point +.import "shapes/rounded-polygon.js" as RoundedPolygon +.import "shapes/corner-rounding.js" as CornerRounding +.import "geometry/offset.js" as Offset +.import "graphics/matrix.js" as Matrix + +var _circle = null +var _square = null +var _slanted = null +var _arch = null +var _fan = null +var _arrow = null +var _semiCircle = null +var _oval = null +var _pill = null +var _triangle = null +var _diamond = null +var _clamShell = null +var _pentagon = null +var _gem = null +var _verySunny = null +var _sunny = null +var _cookie4Sided = null +var _cookie6Sided = null +var _cookie7Sided = null +var _cookie9Sided = null +var _cookie12Sided = null +var _ghostish = null +var _clover4Leaf = null +var _clover8Leaf = null +var _burst = null +var _softBurst = null +var _boom = null +var _softBoom = null +var _flower = null +var _puffy = null +var _puffyDiamond = null +var _pixelCircle = null +var _pixelTriangle = null +var _bun = null +var _heart = null + +var cornerRound15 = new CornerRounding.CornerRounding(0.15) +var cornerRound20 = new CornerRounding.CornerRounding(0.2) +var cornerRound30 = new CornerRounding.CornerRounding(0.3) +var cornerRound50 = new CornerRounding.CornerRounding(0.5) +var cornerRound100 = new CornerRounding.CornerRounding(1.0) + +var rotateNeg30 = new Matrix.Matrix(); +rotateNeg30.rotateZ(-30); +var rotateNeg45 = new Matrix.Matrix(); +rotateNeg45.rotateZ(-45); +var rotateNeg90 = new Matrix.Matrix(); +rotateNeg90.rotateZ(-90); +var rotateNeg135 = new Matrix.Matrix(); +rotateNeg135.rotateZ(-135); +var rotate30 = new Matrix.Matrix(); +rotate30.rotateZ(30); +var rotate45 = new Matrix.Matrix(); +rotate45.rotateZ(45); +var rotate60 = new Matrix.Matrix(); +rotate60.rotateZ(60); +var rotate90 = new Matrix.Matrix(); +rotate90.rotateZ(90); +var rotate120 = new Matrix.Matrix(); +rotate120.rotateZ(120); +var rotate135 = new Matrix.Matrix(); +rotate135.rotateZ(135); +var rotate180 = new Matrix.Matrix(); +rotate180.rotateZ(180); + +var rotate28th = new Matrix.Matrix(); +rotate28th.rotateZ(360/28); +var rotateNeg16th = new Matrix.Matrix(); +rotateNeg16th.rotateZ(-360/16); + +function getCircle() { + if (_circle !== null) return _circle; + _circle = circle(); + return _circle; +} + +function getSquare() { + if (_square !== null) return _square; + _square = square(); + return _square; +} + +function getSlanted() { + if (_slanted !== null) return _slanted; + _slanted = slanted(); + return _slanted; +} + +function getArch() { + if (_arch !== null) return _arch; + _arch = arch(); + return _arch; +} + +function getFan() { + if (_fan !== null) return _fan; + _fan = fan(); + return _fan; +} + +function getArrow() { + if (_arrow !== null) return _arrow; + _arrow = arrow(); + return _arrow; +} + +function getSemiCircle() { + if (_semiCircle !== null) return _semiCircle; + _semiCircle = semiCircle(); + return _semiCircle; +} + +function getOval() { + if (_oval !== null) return _oval; + _oval = oval(); + return _oval; +} + +function getPill() { + if (_pill !== null) return _pill; + _pill = pill(); + return _pill; +} + +function getTriangle() { + if (_triangle !== null) return _triangle; + _triangle = triangle(); + return _triangle; +} + +function getDiamond() { + if (_diamond !== null) return _diamond; + _diamond = diamond(); + return _diamond; +} + +function getClamShell() { + if (_clamShell !== null) return _clamShell; + _clamShell = clamShell(); + return _clamShell; +} + +function getPentagon() { + if (_pentagon !== null) return _pentagon; + _pentagon = pentagon(); + return _pentagon; +} + +function getGem() { + if (_gem !== null) return _gem; + _gem = gem(); + return _gem; +} + +function getSunny() { + if (_sunny !== null) return _sunny; + _sunny = sunny(); + return _sunny; +} + +function getVerySunny() { + if (_verySunny !== null) return _verySunny; + _verySunny = verySunny(); + return _verySunny; +} + +function getCookie4Sided() { + if (_cookie4Sided !== null) return _cookie4Sided; + _cookie4Sided = cookie4(); + return _cookie4Sided; +} + +function getCookie6Sided() { + if (_cookie6Sided !== null) return _cookie6Sided; + _cookie6Sided = cookie6(); + return _cookie6Sided; +} + +function getCookie7Sided() { + if (_cookie7Sided !== null) return _cookie7Sided; + _cookie7Sided = cookie7(); + return _cookie7Sided; +} + +function getCookie9Sided() { + if (_cookie9Sided !== null) return _cookie9Sided; + _cookie9Sided = cookie9(); + return _cookie9Sided; +} + +function getCookie12Sided() { + if (_cookie12Sided !== null) return _cookie12Sided; + _cookie12Sided = cookie12(); + return _cookie12Sided; +} + +function getGhostish() { + if (_ghostish !== null) return _ghostish; + _ghostish = ghostish(); + return _ghostish; +} + +function getClover4Leaf() { + if (_clover4Leaf !== null) return _clover4Leaf; + _clover4Leaf = clover4(); + return _clover4Leaf; +} + +function getClover8Leaf() { + if (_clover8Leaf !== null) return _clover8Leaf; + _clover8Leaf = clover8(); + return _clover8Leaf; +} + +function getBurst() { + if (_burst !== null) return _burst; + _burst = burst(); + return _burst; +} + +function getSoftBurst() { + if (_softBurst !== null) return _softBurst; + _softBurst = softBurst(); + return _softBurst; +} + +function getBoom() { + if (_boom !== null) return _boom; + _boom = boom(); + return _boom; +} + +function getSoftBoom() { + if (_softBoom !== null) return _softBoom; + _softBoom = softBoom(); + return _softBoom; +} + +function getFlower() { + if (_flower !== null) return _flower; + _flower = flower(); + return _flower; +} + +function getPuffy() { + if (_puffy !== null) return _puffy; + _puffy = puffy(); + return _puffy; +} + +function getPuffyDiamond() { + if (_puffyDiamond !== null) return _puffyDiamond; + _puffyDiamond = puffyDiamond(); + return _puffyDiamond; +} + +function getPixelCircle() { + if (_pixelCircle !== null) return _pixelCircle; + _pixelCircle = pixelCircle(); + return _pixelCircle; +} + +function getPixelTriangle() { + if (_pixelTriangle !== null) return _pixelTriangle; + _pixelTriangle = pixelTriangle(); + return _pixelTriangle; +} + +function getBun() { + if (_bun !== null) return _bun; + _bun = bun(); + return _bun; +} + +function getHeart() { + if (_heart !== null) return _heart; + _heart = heart(); + return _heart; +} + +function circle() { + return RoundedPolygon.RoundedPolygon.circle(10) + .transformed((x, y) => rotate45.map(new Offset.Offset(x, y))) + .normalized(); +} + +function square() { + return RoundedPolygon.RoundedPolygon.rectangle(1, 1, cornerRound30).normalized(); +} + +function slanted() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.926, 0.970), new CornerRounding.CornerRounding(0.189, 0.811)), + new PointNRound(new Offset.Offset(-0.021, 0.967), new CornerRounding.CornerRounding(0.187, 0.057)), + ], 2).normalized(); +} + +function arch() { + return RoundedPolygon.RoundedPolygon.rectangle(1, 1, CornerRounding.Unrounded, [cornerRound20, cornerRound20, cornerRound100, cornerRound100]) + .normalized(); +} + +function fan() { + return customPolygon([ + new PointNRound(new Offset.Offset(1.004, 1.000), new CornerRounding.CornerRounding(0.148, 0.417)), + new PointNRound(new Offset.Offset(0.000, 1.000), new CornerRounding.CornerRounding(0.151)), + new PointNRound(new Offset.Offset(0.000, -0.003), new CornerRounding.CornerRounding(0.148)), + new PointNRound(new Offset.Offset(0.978, 0.020), new CornerRounding.CornerRounding(0.803)), + ], 1).normalized(); +} + +function arrow() { + return customPolygon([ + new PointNRound(new Offset.Offset(1.225, 1.060), new CornerRounding.CornerRounding(0.211)), + new PointNRound(new Offset.Offset(0.500, 0.892), new CornerRounding.CornerRounding(0.313)), + new PointNRound(new Offset.Offset(-0.216, 1.050), new CornerRounding.CornerRounding(0.207)), + new PointNRound(new Offset.Offset(0.499, -0.160), new CornerRounding.CornerRounding(0.215, 1.000)), + ], 1).normalized(); +} + +function semiCircle() { + return RoundedPolygon.RoundedPolygon.rectangle(1.6, 1, CornerRounding.Unrounded, [cornerRound20, cornerRound20, cornerRound100, cornerRound100]).normalized(); +} + +function oval() { + const scaleMatrix = new Matrix.Matrix(); + scaleMatrix.scale(1, 0.64); + return RoundedPolygon.RoundedPolygon.circle() + .transformed((x, y) => rotateNeg90.map(new Offset.Offset(x, y))) + .transformed((x, y) => scaleMatrix.map(new Offset.Offset(x, y))) + .transformed((x, y) => rotate135.map(new Offset.Offset(x, y))) + .normalized(); +} + +function pill() { + return customPolygon([ + // new PointNRound(new Offset.Offset(0.609, 0.000), new CornerRounding.CornerRounding(1.000)), + new PointNRound(new Offset.Offset(0.428, -0.001), new CornerRounding.CornerRounding(0.426)), + new PointNRound(new Offset.Offset(0.961, 0.039), new CornerRounding.CornerRounding(0.426)), + new PointNRound(new Offset.Offset(1.001, 0.428)), + new PointNRound(new Offset.Offset(1.000, 0.609), new CornerRounding.CornerRounding(1.000)), + ], 2) + .transformed((x, y) => rotate180.map(new Offset.Offset(x, y))) + .normalized(); +} + +function triangle() { + return RoundedPolygon.RoundedPolygon.fromNumVertices(3, 1, 0.5, 0.5, cornerRound20) + .transformed((x, y) => rotate30.map(new Offset.Offset(x, y))) + .normalized() +} + +function diamond() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.500, 1.096), new CornerRounding.CornerRounding(0.151, 0.524)), + new PointNRound(new Offset.Offset(0.040, 0.500), new CornerRounding.CornerRounding(0.159)), + ], 2).normalized(); +} + +function clamShell() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.829, 0.841), new CornerRounding.CornerRounding(0.159)), + new PointNRound(new Offset.Offset(0.171, 0.841), new CornerRounding.CornerRounding(0.159)), + new PointNRound(new Offset.Offset(-0.020, 0.500), new CornerRounding.CornerRounding(0.140)), + ], 2).normalized(); +} + +function pentagon() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.828, 0.970), new CornerRounding.CornerRounding(0.169)), + new PointNRound(new Offset.Offset(0.172, 0.970), new CornerRounding.CornerRounding(0.169)), + new PointNRound(new Offset.Offset(-0.030, 0.365), new CornerRounding.CornerRounding(0.164)), + new PointNRound(new Offset.Offset(0.500, -0.009), new CornerRounding.CornerRounding(0.172)), + new PointNRound(new Offset.Offset(1.030, 0.365), new CornerRounding.CornerRounding(0.164)), + ], 1).normalized(); +} + +function gem() { + return customPolygon([ + new PointNRound(new Offset.Offset(1.005, 0.792), new CornerRounding.CornerRounding(0.208)), + new PointNRound(new Offset.Offset(0.5, 1.023), new CornerRounding.CornerRounding(0.241, 0.778)), + new PointNRound(new Offset.Offset(-0.005, 0.792), new CornerRounding.CornerRounding(0.208)), + new PointNRound(new Offset.Offset(0.073, 0.258), new CornerRounding.CornerRounding(0.228)), + new PointNRound(new Offset.Offset(0.5, 0.000), new CornerRounding.CornerRounding(0.241, 0.778)), + new PointNRound(new Offset.Offset(0.927, 0.258), new CornerRounding.CornerRounding(0.228)), + ], 1).normalized(); +} + +function sunny() { + return RoundedPolygon.RoundedPolygon.star(8, 1, 0.8, cornerRound15) + .transformed((x, y) => rotate45.map(new Offset.Offset(x, y))) + .normalized(); +} + +function verySunny() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.500, 1.080), new CornerRounding.CornerRounding(0.085)), + new PointNRound(new Offset.Offset(0.358, 0.843), new CornerRounding.CornerRounding(0.085)), + ], 8) + .transformed((x, y) => rotateNeg45.map(new Offset.Offset(x, y))) + .normalized(); +} + +function cookie4() { + return customPolygon([ + new PointNRound(new Offset.Offset(1.237, 1.236), new CornerRounding.CornerRounding(0.258)), + new PointNRound(new Offset.Offset(0.500, 0.918), new CornerRounding.CornerRounding(0.233)), + ], 4).normalized(); +} + +function cookie6() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.723, 0.884), new CornerRounding.CornerRounding(0.394)), + new PointNRound(new Offset.Offset(0.500, 1.099), new CornerRounding.CornerRounding(0.398)), + ], 6).normalized(); +} + +function cookie7() { + return RoundedPolygon.RoundedPolygon.star(7, 1, 0.75, cornerRound50) + .normalized() + .transformed((x, y) => rotate28th.map(new Offset.Offset(x, y))) + .transformed((x, y) => rotate28th.map(new Offset.Offset(x, y))) + .transformed((x, y) => rotate28th.map(new Offset.Offset(x, y))) + .transformed((x, y) => rotate28th.map(new Offset.Offset(x, y))) + .transformed((x, y) => rotate28th.map(new Offset.Offset(x, y))) + .normalized(); +} + +function cookie9() { + return RoundedPolygon.RoundedPolygon.star(9, 1, 0.8, cornerRound50) + .transformed((x, y) => rotate30.map(new Offset.Offset(x, y))) + .normalized(); +} + +function cookie12() { + return RoundedPolygon.RoundedPolygon.star(12, 1, 0.8, cornerRound50) + .transformed((x, y) => rotate30.map(new Offset.Offset(x, y))) + .normalized(); +} + +function ghostish() { + return customPolygon([ + new PointNRound(new Offset.Offset(1.000, 1.140), new CornerRounding.CornerRounding(0.254, 0.106)), + new PointNRound(new Offset.Offset(0.575, 0.906), new CornerRounding.CornerRounding(0.253)), + new PointNRound(new Offset.Offset(0.425, 0.906), new CornerRounding.CornerRounding(0.253)), + new PointNRound(new Offset.Offset(0.000, 1.140), new CornerRounding.CornerRounding(0.254, 0.106)), + new PointNRound(new Offset.Offset(0.000, 0.000), new CornerRounding.CornerRounding(1.0)), + new PointNRound(new Offset.Offset(0.500, 0.000), new CornerRounding.CornerRounding(1.0)), + new PointNRound(new Offset.Offset(1.000, 0.000), new CornerRounding.CornerRounding(1.0)), + ], 1).normalized(); +} + +function clover4() { + return customPolygon([ + new PointNRound(new Offset.Offset(1.099, 0.725), new CornerRounding.CornerRounding(0.476)), + new PointNRound(new Offset.Offset(0.725, 1.099), new CornerRounding.CornerRounding(0.476)), + new PointNRound(new Offset.Offset(0.500, 0.926)), + ], 4).normalized(); +} + +function clover8() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.758, 1.101), new CornerRounding.CornerRounding(0.209)), + new PointNRound(new Offset.Offset(0.500, 0.964)), + ], 8).normalized(); +} + +function burst() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.592, 0.842), new CornerRounding.CornerRounding(0.006)), + new PointNRound(new Offset.Offset(0.500, 1.006), new CornerRounding.CornerRounding(0.006)), + ], 12) + .transformed((x, y) => rotateNeg30.map(new Offset.Offset(x, y))) + .transformed((x, y) => rotateNeg30.map(new Offset.Offset(x, y))) + .normalized(); +} + +function softBurst() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.193, 0.277), new CornerRounding.CornerRounding(0.053)), + new PointNRound(new Offset.Offset(0.176, 0.055), new CornerRounding.CornerRounding(0.053)), + ], 10) + .transformed((x, y) => rotate180.map(new Offset.Offset(x, y))) + .normalized(); +} + +function boom() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.457, 0.296), new CornerRounding.CornerRounding(0.007)), + new PointNRound(new Offset.Offset(0.500, -0.051), new CornerRounding.CornerRounding(0.007)), + ], 15) + .transformed((x, y) => rotate120.map(new Offset.Offset(x, y))) + .normalized(); +} + +function softBoom() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.733, 0.454)), + new PointNRound(new Offset.Offset(0.839, 0.437), new CornerRounding.CornerRounding(0.532)), + new PointNRound(new Offset.Offset(0.949, 0.449), new CornerRounding.CornerRounding(0.439, 1.000)), + new PointNRound(new Offset.Offset(0.998, 0.478), new CornerRounding.CornerRounding(0.174)), + // mirrored points + new PointNRound(new Offset.Offset(0.998, 0.522), new CornerRounding.CornerRounding(0.174)), + new PointNRound(new Offset.Offset(0.949, 0.551), new CornerRounding.CornerRounding(0.439, 1.000)), + new PointNRound(new Offset.Offset(0.839, 0.563), new CornerRounding.CornerRounding(0.532)), + new PointNRound(new Offset.Offset(0.733, 0.546)), + ], 16) + .transformed((x, y) => rotate45.map(new Offset.Offset(x, y))) + .transformed((x, y) => rotateNeg16th.map(new Offset.Offset(x, y))) + .normalized(); +} + +function flower() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.370, 0.187)), + new PointNRound(new Offset.Offset(0.416, 0.049), new CornerRounding.CornerRounding(0.381)), + new PointNRound(new Offset.Offset(0.479, 0.001), new CornerRounding.CornerRounding(0.095)), + // mirrored points + new PointNRound(new Offset.Offset(0.521, 0.001), new CornerRounding.CornerRounding(0.095)), + new PointNRound(new Offset.Offset(0.584, 0.049), new CornerRounding.CornerRounding(0.381)), + new PointNRound(new Offset.Offset(0.630, 0.187)), + ], 8) + .transformed((x, y) => rotate135.map(new Offset.Offset(x, y))) + .normalized(); +} + +function puffy() { + const m = new Matrix.Matrix(); + m.scale(1, 0.742); + const shape = customPolygon([ + // mirrored points + new PointNRound(new Offset.Offset(1.003, 0.563), new CornerRounding.CornerRounding(0.255)), + new PointNRound(new Offset.Offset(0.940, 0.656), new CornerRounding.CornerRounding(0.126)), + new PointNRound(new Offset.Offset(0.881, 0.654)), + new PointNRound(new Offset.Offset(0.926, 0.711), new CornerRounding.CornerRounding(0.660)), + new PointNRound(new Offset.Offset(0.914, 0.851), new CornerRounding.CornerRounding(0.660)), + new PointNRound(new Offset.Offset(0.777, 0.998), new CornerRounding.CornerRounding(0.360)), + new PointNRound(new Offset.Offset(0.722, 0.872)), + new PointNRound(new Offset.Offset(0.717, 0.934), new CornerRounding.CornerRounding(0.574)), + new PointNRound(new Offset.Offset(0.670, 1.035), new CornerRounding.CornerRounding(0.426)), + new PointNRound(new Offset.Offset(0.545, 1.040), new CornerRounding.CornerRounding(0.405)), + new PointNRound(new Offset.Offset(0.500, 0.947)), + // original points + new PointNRound(new Offset.Offset(0.500, 1-0.053)), + new PointNRound(new Offset.Offset(1-0.545, 1+0.040), new CornerRounding.CornerRounding(0.405)), + new PointNRound(new Offset.Offset(1-0.670, 1+0.035), new CornerRounding.CornerRounding(0.426)), + new PointNRound(new Offset.Offset(1-0.717, 1-0.066), new CornerRounding.CornerRounding(0.574)), + new PointNRound(new Offset.Offset(1-0.722, 1-0.128)), + new PointNRound(new Offset.Offset(1-0.777, 1-0.002), new CornerRounding.CornerRounding(0.360)), + new PointNRound(new Offset.Offset(1-0.914, 1-0.149), new CornerRounding.CornerRounding(0.660)), + new PointNRound(new Offset.Offset(1-0.926, 1-0.289), new CornerRounding.CornerRounding(0.660)), + new PointNRound(new Offset.Offset(1-0.881, 1-0.346)), + new PointNRound(new Offset.Offset(1-0.940, 1-0.344), new CornerRounding.CornerRounding(0.126)), + new PointNRound(new Offset.Offset(1-1.003, 1-0.437), new CornerRounding.CornerRounding(0.255)), + ], 2); + return shape.transformed((x, y) => m.map(new Offset.Offset(x, y))).normalized(); +} + +function puffyDiamond() { + return customPolygon([ + // original points + new PointNRound(new Offset.Offset(0.870, 0.130), new CornerRounding.CornerRounding(0.146)), + new PointNRound(new Offset.Offset(0.818, 0.357)), + new PointNRound(new Offset.Offset(1.000, 0.332), new CornerRounding.CornerRounding(0.853)), + // mirrored points + new PointNRound(new Offset.Offset(1.000, 1-0.332), new CornerRounding.CornerRounding(0.853)), + new PointNRound(new Offset.Offset(0.818, 1-0.357)), + ], 4) + .transformed((x, y) => rotate90.map(new Offset.Offset(x, y))) + .normalized(); +} + +function pixelCircle() { + return customPolygon([ + new PointNRound(new Offset.Offset(1.000, 0.704)), + new PointNRound(new Offset.Offset(0.926, 0.704)), + new PointNRound(new Offset.Offset(0.926, 0.852)), + new PointNRound(new Offset.Offset(0.843, 0.852)), + new PointNRound(new Offset.Offset(0.843, 0.935)), + new PointNRound(new Offset.Offset(0.704, 0.935)), + new PointNRound(new Offset.Offset(0.704, 1.000)), + new PointNRound(new Offset.Offset(0.500, 1.000)), + new PointNRound(new Offset.Offset(1-0.704, 1.000)), + new PointNRound(new Offset.Offset(1-0.704, 0.935)), + new PointNRound(new Offset.Offset(1-0.843, 0.935)), + new PointNRound(new Offset.Offset(1-0.843, 0.852)), + new PointNRound(new Offset.Offset(1-0.926, 0.852)), + new PointNRound(new Offset.Offset(1-0.926, 0.704)), + new PointNRound(new Offset.Offset(1-1.000, 0.704)), + ], 2) + .normalized(); +} + +function pixelTriangle() { + return customPolygon([ + // mirrored points + new PointNRound(new Offset.Offset(0.888, 1-0.439)), + new PointNRound(new Offset.Offset(0.789, 1-0.439)), + new PointNRound(new Offset.Offset(0.789, 1-0.344)), + new PointNRound(new Offset.Offset(0.675, 1-0.344)), + new PointNRound(new Offset.Offset(0.674, 1-0.265)), + new PointNRound(new Offset.Offset(0.560, 1-0.265)), + new PointNRound(new Offset.Offset(0.560, 1-0.170)), + new PointNRound(new Offset.Offset(0.421, 1-0.170)), + new PointNRound(new Offset.Offset(0.421, 1-0.087)), + new PointNRound(new Offset.Offset(0.287, 1-0.087)), + new PointNRound(new Offset.Offset(0.287, 1-0.000)), + new PointNRound(new Offset.Offset(0.113, 1-0.000)), + // original points + new PointNRound(new Offset.Offset(0.110, 0.500)), + new PointNRound(new Offset.Offset(0.113, 0.000)), + new PointNRound(new Offset.Offset(0.287, 0.000)), + new PointNRound(new Offset.Offset(0.287, 0.087)), + new PointNRound(new Offset.Offset(0.421, 0.087)), + new PointNRound(new Offset.Offset(0.421, 0.170)), + new PointNRound(new Offset.Offset(0.560, 0.170)), + new PointNRound(new Offset.Offset(0.560, 0.265)), + new PointNRound(new Offset.Offset(0.674, 0.265)), + new PointNRound(new Offset.Offset(0.675, 0.344)), + new PointNRound(new Offset.Offset(0.789, 0.344)), + new PointNRound(new Offset.Offset(0.789, 0.439)), + new PointNRound(new Offset.Offset(0.888, 0.439)), + ], 1).normalized(); +} + +function bun() { + return customPolygon([ + // original points + new PointNRound(new Offset.Offset(0.796, 0.500)), + new PointNRound(new Offset.Offset(0.853, 0.518), cornerRound100), + new PointNRound(new Offset.Offset(0.992, 0.631), cornerRound100), + new PointNRound(new Offset.Offset(0.968, 1.000), cornerRound100), + // mirrored points + new PointNRound(new Offset.Offset(0.032, 1-0.000), cornerRound100), + new PointNRound(new Offset.Offset(0.008, 1-0.369), cornerRound100), + new PointNRound(new Offset.Offset(0.147, 1-0.482), cornerRound100), + new PointNRound(new Offset.Offset(0.204, 1-0.500)), + ], 2).normalized(); +} + +function heart() { + return customPolygon([ + new PointNRound(new Offset.Offset(0.782, 0.611)), + new PointNRound(new Offset.Offset(0.499, 0.946), new CornerRounding.CornerRounding(0.000)), + new PointNRound(new Offset.Offset(0.2175, 0.611)), + new PointNRound(new Offset.Offset(-0.064, 0.276), new CornerRounding.CornerRounding(1.000)), + new PointNRound(new Offset.Offset(0.208, -0.066), new CornerRounding.CornerRounding(0.958)), + new PointNRound(new Offset.Offset(0.500, 0.268), new CornerRounding.CornerRounding(0.016)), + new PointNRound(new Offset.Offset(0.792, -0.066), new CornerRounding.CornerRounding(0.958)), + new PointNRound(new Offset.Offset(1.064, 0.276), new CornerRounding.CornerRounding(1.000)), + ], 1) + .normalized(); +} + +class PointNRound { + constructor(o, r = CornerRounding.Unrounded) { + this.o = o; + this.r = r; + } +} + +function doRepeat(points, reps, center, mirroring) { + if (mirroring) { + const result = []; + const angles = points.map(p => p.o.minus(center).angleDegrees()); + const distances = points.map(p => p.o.minus(center).getDistance()); + const actualReps = reps * 2; + const sectionAngle = 360 / actualReps; + for (let it = 0; it < actualReps; it++) { + for (let index = 0; index < points.length; index++) { + const i = (it % 2 === 0) ? index : points.length - 1 - index; + if (i > 0 || it % 2 === 0) { + const baseAngle = angles[i]; + const angle = it * sectionAngle + (it % 2 === 0 ? baseAngle : (2 * angles[0] - baseAngle)); + const dist = distances[i]; + const rad = angle * Math.PI / 180; + const x = center.x + dist * Math.cos(rad); + const y = center.y + dist * Math.sin(rad); + result.push(new PointNRound(new Offset.Offset(x, y), points[i].r)); + } + } + } + return result; + } else { + const np = points.length; + const result = []; + for (let i = 0; i < np * reps; i++) { + const point = points[i % np].o.rotateDegrees(Math.floor(i / np) * 360 / reps, center); + result.push(new PointNRound(point, points[i % np].r)); + } + return result; + } +} + +function customPolygon(pnr, reps = 1, center = new Offset.Offset(0.5, 0.5), mirroring = false) { + const actualPoints = doRepeat(pnr, reps, center, mirroring); + const vertices = []; + for (const p of actualPoints) { + vertices.push(p.o.x); + vertices.push(p.o.y); + } + const perVertexRounding = actualPoints.map(p => p.r); + return RoundedPolygon.RoundedPolygon.fromVertices(vertices, CornerRounding.Unrounded, perVertexRounding, center.x, center.y); +} diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/corner-rounding.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/corner-rounding.js new file mode 100644 index 0000000..da456fa --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/corner-rounding.js @@ -0,0 +1,18 @@ +.pragma library + +/** + * Represents corner rounding configuration + */ +class CornerRounding { + /** + * @param {float} [radius=0] + * @param {float} [smoothing=0] + */ + constructor(radius = 0, smoothing = 0) { + this.radius = radius; + this.smoothing = smoothing; + } +} + +// Static property +CornerRounding.Unrounded = new CornerRounding(); \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/cubic.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/cubic.js new file mode 100644 index 0000000..1e3b0bd --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/cubic.js @@ -0,0 +1,371 @@ +.pragma library +.import "point.js" as PointModule +.import "utils.js" as UtilsModule + +var Point = PointModule.Point; +var DistanceEpsilon = UtilsModule.DistanceEpsilon; +var interpolate = UtilsModule.interpolate; +var directionVector = UtilsModule.directionVector; +var distance = UtilsModule.distance; + +/** + * Represents a cubic Bézier curve with anchor and control points + */ +class Cubic { + /** + * @param {Array} points Array of 8 numbers [anchor0X, anchor0Y, control0X, control0Y, control1X, control1Y, anchor1X, anchor1Y] + */ + constructor(points) { + this.points = points; + } + + get anchor0X() { return this.points[0]; } + get anchor0Y() { return this.points[1]; } + get control0X() { return this.points[2]; } + get control0Y() { return this.points[3]; } + get control1X() { return this.points[4]; } + get control1Y() { return this.points[5]; } + get anchor1X() { return this.points[6]; } + get anchor1Y() { return this.points[7]; } + + /** + * @param {Point} anchor0 + * @param {Point} control0 + * @param {Point} control1 + * @param {Point} anchor1 + * @returns {Cubic} + */ + static create(anchor0, control0, control1, anchor1) { + return new Cubic([ + anchor0.x, anchor0.y, + control0.x, control0.y, + control1.x, control1.y, + anchor1.x, anchor1.y + ]); + } + + /** + * @param {float} t + * @returns {Point} + */ + pointOnCurve(t) { + const u = 1 - t; + return new Point( + this.anchor0X * (u * u * u) + + this.control0X * (3 * t * u * u) + + this.control1X * (3 * t * t * u) + + this.anchor1X * (t * t * t), + this.anchor0Y * (u * u * u) + + this.control0Y * (3 * t * u * u) + + this.control1Y * (3 * t * t * u) + + this.anchor1Y * (t * t * t) + ); + } + + /** + * @returns {boolean} + */ + zeroLength() { + return Math.abs(this.anchor0X - this.anchor1X) < DistanceEpsilon && + Math.abs(this.anchor0Y - this.anchor1Y) < DistanceEpsilon; + } + + /** + * @param {Cubic} next + * @returns {boolean} + */ + convexTo(next) { + const prevVertex = new Point(this.anchor0X, this.anchor0Y); + const currVertex = new Point(this.anchor1X, this.anchor1Y); + const nextVertex = new Point(next.anchor1X, next.anchor1Y); + return convex(prevVertex, currVertex, nextVertex); + } + + /** + * @param {float} value + * @returns {boolean} + */ + zeroIsh(value) { + return Math.abs(value) < DistanceEpsilon; + } + + /** + * @param {Array} bounds + * @param {boolean} [approximate=false] + */ + calculateBounds(bounds, approximate = false) { + if (this.zeroLength()) { + bounds[0] = this.anchor0X; + bounds[1] = this.anchor0Y; + bounds[2] = this.anchor0X; + bounds[3] = this.anchor0Y; + return; + } + + let minX = Math.min(this.anchor0X, this.anchor1X); + let minY = Math.min(this.anchor0Y, this.anchor1Y); + let maxX = Math.max(this.anchor0X, this.anchor1X); + let maxY = Math.max(this.anchor0Y, this.anchor1Y); + + if (approximate) { + bounds[0] = Math.min(minX, Math.min(this.control0X, this.control1X)); + bounds[1] = Math.min(minY, Math.min(this.control0Y, this.control1Y)); + bounds[2] = Math.max(maxX, Math.max(this.control0X, this.control1X)); + bounds[3] = Math.max(maxY, Math.max(this.control0Y, this.control1Y)); + return; + } + + // Find extrema using derivatives + const xa = -this.anchor0X + 3 * this.control0X - 3 * this.control1X + this.anchor1X; + const xb = 2 * this.anchor0X - 4 * this.control0X + 2 * this.control1X; + const xc = -this.anchor0X + this.control0X; + + if (this.zeroIsh(xa)) { + if (xb != 0) { + const t = 2 * xc / (-2 * xb); + if (t >= 0 && t <= 1) { + const it = this.pointOnCurve(t).x; + if (it < minX) minX = it; + if (it > maxX) maxX = it; + } + } + } else { + const xs = xb * xb - 4 * xa * xc; + if (xs >= 0) { + const t1 = (-xb + Math.sqrt(xs)) / (2 * xa); + if (t1 >= 0 && t1 <= 1) { + const it = this.pointOnCurve(t1).x; + if (it < minX) minX = it; + if (it > maxX) maxX = it; + } + + const t2 = (-xb - Math.sqrt(xs)) / (2 * xa); + if (t2 >= 0 && t2 <= 1) { + const it = this.pointOnCurve(t2).x; + if (it < minX) minX = it; + if (it > maxX) maxX = it; + } + } + } + + // Repeat for y coord + const ya = -this.anchor0Y + 3 * this.control0Y - 3 * this.control1Y + this.anchor1Y; + const yb = 2 * this.anchor0Y - 4 * this.control0Y + 2 * this.control1Y; + const yc = -this.anchor0Y + this.control0Y; + + if (this.zeroIsh(ya)) { + if (yb != 0) { + const t = 2 * yc / (-2 * yb); + if (t >= 0 && t <= 1) { + const it = this.pointOnCurve(t).y; + if (it < minY) minY = it; + if (it > maxY) maxY = it; + } + } + } else { + const ys = yb * yb - 4 * ya * yc; + if (ys >= 0) { + const t1 = (-yb + Math.sqrt(ys)) / (2 * ya); + if (t1 >= 0 && t1 <= 1) { + const it = this.pointOnCurve(t1).y; + if (it < minY) minY = it; + if (it > maxY) maxY = it; + } + + const t2 = (-yb - Math.sqrt(ys)) / (2 * ya); + if (t2 >= 0 && t2 <= 1) { + const it = this.pointOnCurve(t2).y; + if (it < minY) minY = it; + if (it > maxY) maxY = it; + } + } + } + bounds[0] = minX; + bounds[1] = minY; + bounds[2] = maxX; + bounds[3] = maxY; + } + + /** + * @param {float} t + * @returns {{a: Cubic, b: Cubic}} + */ + split(t) { + const u = 1 - t; + const pointOnCurve = this.pointOnCurve(t); + return { + a: new Cubic([ + this.anchor0X, + this.anchor0Y, + this.anchor0X * u + this.control0X * t, + this.anchor0Y * u + this.control0Y * t, + this.anchor0X * (u * u) + this.control0X * (2 * u * t) + this.control1X * (t * t), + this.anchor0Y * (u * u) + this.control0Y * (2 * u * t) + this.control1Y * (t * t), + pointOnCurve.x, + pointOnCurve.y + ]), + b: new Cubic([ + pointOnCurve.x, + pointOnCurve.y, + this.control0X * (u * u) + this.control1X * (2 * u * t) + this.anchor1X * (t * t), + this.control0Y * (u * u) + this.control1Y * (2 * u * t) + this.anchor1Y * (t * t), + this.control1X * u + this.anchor1X * t, + this.control1Y * u + this.anchor1Y * t, + this.anchor1X, + this.anchor1Y + ]) + }; + } + + /** + * @returns {Cubic} + */ + reverse() { + return new Cubic([ + this.anchor1X, this.anchor1Y, + this.control1X, this.control1Y, + this.control0X, this.control0Y, + this.anchor0X, this.anchor0Y + ]); + } + + /** + * @param {Cubic} other + * @returns {Cubic} + */ + plus(other) { + return new Cubic(other.points.map((_, index) => this.points[index] + other.points[index])); + } + + /** + * @param {float} x + * @returns {Cubic} + */ + times(x) { + return new Cubic(this.points.map(v => v * x)); + } + + /** + * @param {float} x + * @returns {Cubic} + */ + div(x) { + return this.times(1 / x); + } + + /** + * @param {Cubic} other + * @returns {boolean} + */ + equals(other) { + return this.points.every((p, i) => other.points[i] === p); + } + + /** + * @param {function(float, float): Point} f + * @returns {Cubic} + */ + transformed(f) { + const newCubic = new MutableCubic([...this.points]); + newCubic.transform(f); + return newCubic; + } + + /** + * @param {float} x0 + * @param {float} y0 + * @param {float} x1 + * @param {float} y1 + * @returns {Cubic} + */ + static straightLine(x0, y0, x1, y1) { + return new Cubic([ + x0, + y0, + interpolate(x0, x1, 1/3), + interpolate(y0, y1, 1/3), + interpolate(x0, x1, 2/3), + interpolate(y0, y1, 2/3), + x1, + y1 + ]); + } + + /** + * @param {float} centerX + * @param {float} centerY + * @param {float} x0 + * @param {float} y0 + * @param {float} x1 + * @param {float} y1 + * @returns {Cubic} + */ + static circularArc(centerX, centerY, x0, y0, x1, y1) { + const p0d = directionVector(x0 - centerX, y0 - centerY); + const p1d = directionVector(x1 - centerX, y1 - centerY); + const rotatedP0 = p0d.rotate90(); + const rotatedP1 = p1d.rotate90(); + const clockwise = rotatedP0.dotProductScalar(x1 - centerX, y1 - centerY) >= 0; + const cosa = p0d.dotProduct(p1d); + + if (cosa > 0.999) { + return Cubic.straightLine(x0, y0, x1, y1); + } + + const k = distance(x0 - centerX, y0 - centerY) * 4/3 * + (Math.sqrt(2 * (1 - cosa)) - Math.sqrt(1 - cosa * cosa)) / + (1 - cosa) * (clockwise ? 1 : -1); + + return new Cubic([ + x0, y0, + x0 + rotatedP0.x * k, + y0 + rotatedP0.y * k, + x1 - rotatedP1.x * k, + y1 - rotatedP1.y * k, + x1, y1 + ]); + } + + /** + * @param {float} x0 + * @param {float} y0 + * @returns {Cubic} + */ + static empty(x0, y0) { + return new Cubic([x0, y0, x0, y0, x0, y0, x0, y0]); + } +} + +class MutableCubic extends Cubic { + /** + * @param {function(float, float): Point} f + */ + transform(f) { + this.transformOnePoint(f, 0); + this.transformOnePoint(f, 2); + this.transformOnePoint(f, 4); + this.transformOnePoint(f, 6); + } + + /** + * @param {Cubic} c1 + * @param {Cubic} c2 + * @param {float} progress + */ + interpolate(c1, c2, progress) { + for (let i = 0; i < 8; i++) { + this.points[i] = interpolate(c1.points[i], c2.points[i], progress); + } + } + + /** + * @private + * @param {function(float, float): Point} f + * @param {number} ix + */ + transformOnePoint(f, ix) { + const result = f(this.points[ix], this.points[ix + 1]); + this.points[ix] = result.x; + this.points[ix + 1] = result.y; + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/feature-mapping.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/feature-mapping.js new file mode 100644 index 0000000..16db92c --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/feature-mapping.js @@ -0,0 +1,166 @@ +.pragma library +.import "feature.js" as FeatureModule +.import "float-mapping.js" as MappingModule +.import "point.js" as PointModule +.import "utils.js" as UtilsModule + +var Feature = FeatureModule.Feature; +var Corner = FeatureModule.Corner; +var Point = PointModule.Point; +var DoubleMapper = MappingModule.DoubleMapper; +var progressInRange = MappingModule.progressInRange; +var DistanceEpsilon = UtilsModule.DistanceEpsilon; + +var IdentityMapping = [{ a: 0, b: 0 }, { a: 0.5, b: 0.5 }]; + +class ProgressableFeature { + /** + * @param {float} progress + * @param {Feature} feature + */ + constructor(progress, feature) { + this.progress = progress; + this.feature = feature; + } +} + +class DistanceVertex { + /** + * @param {float} distance + * @param {ProgressableFeature} f1 + * @param {ProgressableFeature} f2 + */ + constructor(distance, f1, f2) { + this.distance = distance; + this.f1 = f1; + this.f2 = f2; + } +} + +class MappingHelper { + constructor() { + this.mapping = []; + this.usedF1 = new Set(); + this.usedF2 = new Set(); + } + + /** + * @param {ProgressableFeature} f1 + * @param {ProgressableFeature} f2 + */ + addMapping(f1, f2) { + if (this.usedF1.has(f1) || this.usedF2.has(f2)) { + return; + } + + const index = this.mapping.findIndex(x => x.a === f1.progress); + const insertionIndex = -index - 1; + const n = this.mapping.length; + + if (n >= 1) { + const { a: before1, b: before2 } = this.mapping[(insertionIndex + n - 1) % n]; + const { a: after1, b: after2 } = this.mapping[insertionIndex % n]; + + if ( + progressDistance(f1.progress, before1) < DistanceEpsilon || + progressDistance(f1.progress, after1) < DistanceEpsilon || + progressDistance(f2.progress, before2) < DistanceEpsilon || + progressDistance(f2.progress, after2) < DistanceEpsilon + ) { + return; + } + + if (n > 1 && !progressInRange(f2.progress, before2, after2)) { + return; + } + } + + this.mapping.splice(insertionIndex, 0, { a: f1.progress, b: f2.progress }); + this.usedF1.add(f1); + this.usedF2.add(f2); + } +} + +/** + * @param {Array} features1 + * @param {Array} features2 + * @returns {DoubleMapper} + */ +function featureMapper(features1, features2) { + const filteredFeatures1 = features1.filter(f => f.feature instanceof Corner); + const filteredFeatures2 = features2.filter(f => f.feature instanceof Corner); + + const featureProgressMapping = doMapping(filteredFeatures1, filteredFeatures2); + return new DoubleMapper(...featureProgressMapping); +} + +/** + * @param {Array} features1 + * @param {Array} features2 + * @returns {Array<{a: float, b: float}>} + */ +function doMapping(features1, features2) { + const distanceVertexList = []; + + for (const f1 of features1) { + for (const f2 of features2) { + const d = featureDistSquared(f1.feature, f2.feature); + if (d !== Number.MAX_VALUE) { + distanceVertexList.push(new DistanceVertex(d, f1, f2)); + } + } + } + + distanceVertexList.sort((a, b) => a.distance - b.distance); + + // Special cases + if (distanceVertexList.length === 0) { + return IdentityMapping; + } else if (distanceVertexList.length === 1) { + const { f1, f2 } = distanceVertexList[0]; + const p1 = f1.progress; + const p2 = f2.progress; + return [ + { a: p1, b: p2 }, + { a: (p1 + 0.5) % 1, b: (p2 + 0.5) % 1 } + ]; + } + + const helper = new MappingHelper(); + distanceVertexList.forEach(({ f1, f2 }) => helper.addMapping(f1, f2)); + return helper.mapping; +} + +/** + * @param {Feature} f1 + * @param {Feature} f2 + * @returns {float} + */ +function featureDistSquared(f1, f2) { + if (f1 instanceof Corner && f2 instanceof Corner && f1.convex != f2.convex) { + return Number.MAX_VALUE; + } + return featureRepresentativePoint(f1).minus(featureRepresentativePoint(f2)).getDistanceSquared(); +} + +/** + * @param {Feature} feature + * @returns {Point} + */ +function featureRepresentativePoint(feature) { + const firstCubic = feature.cubics[0]; + const lastCubic = feature.cubics[feature.cubics.length - 1]; + const x = (firstCubic.anchor0X + lastCubic.anchor1X) / 2; + const y = (firstCubic.anchor0Y + lastCubic.anchor1Y) / 2; + return new Point(x, y); +} + +/** + * @param {float} p1 + * @param {float} p2 + * @returns {float} + */ +function progressDistance(p1, p2) { + const it = Math.abs(p1 - p2); + return Math.min(it, 1 - it); +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/feature.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/feature.js new file mode 100644 index 0000000..afd5ee5 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/feature.js @@ -0,0 +1,103 @@ +.pragma library +.import "cubic.js" as CubicModule + +var Cubic = CubicModule.Cubic; + +/** + * Base class for shape features (edges and corners) + */ +class Feature { + /** + * @param {Array} cubics + */ + constructor(cubics) { + this.cubics = cubics; + } + + /** + * @param {Array} cubics + * @returns {Edge} + */ + buildIgnorableFeature(cubics) { + return new Edge(cubics); + } + + /** + * @param {Cubic} cubic + * @returns {Edge} + */ + buildEdge(cubic) { + return new Edge([cubic]); + } + + /** + * @param {Array} cubics + * @returns {Corner} + */ + buildConvexCorner(cubics) { + return new Corner(cubics, true); + } + + /** + * @param {Array} cubics + * @returns {Corner} + */ + buildConcaveCorner(cubics) { + return new Corner(cubics, false); + } +} + +class Edge extends Feature { + constructor(cubics) { + super(cubics); + this.isIgnorableFeature = true; + this.isEdge = true; + this.isConvexCorner = false; + this.isConcaveCorner = false; + } + + /** + * @param {function(float, float): Point} f + * @returns {Feature} + */ + transformed(f) { + return new Edge(this.cubics.map(c => c.transformed(f))); + } + + /** + * @returns {Feature} + */ + reversed() { + return new Edge(this.cubics.map(c => c.reverse())); + } +} + +class Corner extends Feature { + /** + * @param {Array} cubics + * @param {boolean} convex + */ + constructor(cubics, convex) { + super(cubics); + this.convex = convex; + this.isIgnorableFeature = false; + this.isEdge = false; + this.isConvexCorner = convex; + this.isConcaveCorner = !convex; + } + + /** + * @param {function(float, float): Point} f + * @returns {Feature} + */ + transformed(f) { + return new Corner(this.cubics.map(c => c.transformed(f)), this.convex); + } + + /** + * @returns {Feature} + */ + reversed() { + return new Corner(this.cubics.map(c => c.reverse()), !this.convex); + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/float-mapping.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/float-mapping.js new file mode 100644 index 0000000..dc9c94a --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/float-mapping.js @@ -0,0 +1,86 @@ +.pragma library +.import "utils.js" as UtilsModule + +var positiveModulo = UtilsModule.positiveModulo; + +/** + * Maps values between two ranges + */ +class DoubleMapper { + constructor(...mappings) { + this.sourceValues = []; + this.targetValues = []; + + for (const mapping of mappings) { + this.sourceValues.push(mapping.a); + this.targetValues.push(mapping.b); + } + } + + /** + * @param {float} x + * @returns {float} + */ + map(x) { + return linearMap(this.sourceValues, this.targetValues, x); + } + + /** + * @param {float} x + * @returns {float} + */ + mapBack(x) { + return linearMap(this.targetValues, this.sourceValues, x); + } +} + +// Static property +DoubleMapper.Identity = new DoubleMapper({ a: 0, b: 0 }, { a: 0.5, b: 0.5 }); + +/** + * @param {Array} xValues + * @param {Array} yValues + * @param {float} x + * @returns {float} + */ +function linearMap(xValues, yValues, x) { + let segmentStartIndex = -1; + for (let i = 0; i < xValues.length; i++) { + const nextIndex = (i + 1) % xValues.length; + if (progressInRange(x, xValues[i], xValues[nextIndex])) { + segmentStartIndex = i; + break; + } + } + + if (segmentStartIndex === -1) { + throw new Error("No valid segment found"); + } + + const segmentEndIndex = (segmentStartIndex + 1) % xValues.length; + const segmentSizeX = positiveModulo(xValues[segmentEndIndex] - xValues[segmentStartIndex], 1); + const segmentSizeY = positiveModulo(yValues[segmentEndIndex] - yValues[segmentStartIndex], 1); + + let positionInSegment; + if (segmentSizeX < 0.001) { + positionInSegment = 0.5; + } else { + positionInSegment = positiveModulo(x - xValues[segmentStartIndex], 1) / segmentSizeX; + } + + return positiveModulo(yValues[segmentStartIndex] + segmentSizeY * positionInSegment, 1); +} + +/** + * @param {float} progress + * @param {float} progressFrom + * @param {float} progressTo + * @returns {boolean} + */ +function progressInRange(progress, progressFrom, progressTo) { + if (progressTo >= progressFrom) { + return progress >= progressFrom && progress <= progressTo; + } else { + return progress >= progressFrom || progress <= progressTo; + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/morph.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/morph.js new file mode 100644 index 0000000..ae149b9 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/morph.js @@ -0,0 +1,94 @@ +.pragma library + +.import "rounded-polygon.js" as RoundedPolygon +.import "cubic.js" as Cubic +.import "polygon-measure.js" as PolygonMeasure +.import "feature-mapping.js" as FeatureMapping +.import "utils.js" as Utils + +class Morph { + constructor(start, end) { + this.morphMatch = this.match(start, end) + } + + asCubics(progress) { + const ret = [] + + // The first/last mechanism here ensures that the final anchor point in the shape + // exactly matches the first anchor point. There can be rendering artifacts introduced + // by those points being slightly off, even by much less than a pixel + let firstCubic = null + let lastCubic = null + for (let i = 0; i < this.morphMatch.length; i++) { + const cubic = new Cubic.Cubic(Array.from({ length: 8 }).map((_, it) => Utils.interpolate( + this.morphMatch[i].a.points[it], + this.morphMatch[i].b.points[it], + progress, + ))) + if (firstCubic == null) + firstCubic = cubic + if (lastCubic != null) + ret.push(lastCubic) + lastCubic = cubic + } + if (lastCubic != null && firstCubic != null) + ret.push( + new Cubic.Cubic([ + lastCubic.anchor0X, + lastCubic.anchor0Y, + lastCubic.control0X, + lastCubic.control0Y, + lastCubic.control1X, + lastCubic.control1Y, + firstCubic.anchor0X, + firstCubic.anchor0Y, + ]) + ) + return ret + } + + forEachCubic(progress, mutableCubic, callback) { + for (let i = 0; i < this.morphMatch.length; i++) { + mutableCubic.interpolate(this.morphMatch[i].a, this.morphMatch[i].b, progress) + callback(mutableCubic) + } + } + + match(p1, p2) { + const measurer = new PolygonMeasure.LengthMeasurer() + const measuredPolygon1 = PolygonMeasure.MeasuredPolygon.measurePolygon(measurer, p1) + const measuredPolygon2 = PolygonMeasure.MeasuredPolygon.measurePolygon(measurer, p2) + + const features1 = measuredPolygon1.features + const features2 = measuredPolygon2.features + + const doubleMapper = FeatureMapping.featureMapper(features1, features2) + + const polygon2CutPoint = doubleMapper.map(0) + + const bs1 = measuredPolygon1 + const bs2 = measuredPolygon2.cutAndShift(polygon2CutPoint) + + const ret = [] + + let i1 = 0 + let i2 = 0 + + let b1 = bs1.cubics[i1++] + let b2 = bs2.cubics[i2++] + + while (b1 != null && b2 != null) { + const b1a = (i1 == bs1.cubics.length) ? 1 : b1.endOutlineProgress + const b2a = (i2 == bs2.cubics.length) ? 1 : doubleMapper.mapBack(Utils.positiveModulo(b2.endOutlineProgress + polygon2CutPoint, 1)) + const minb = Math.min(b1a, b2a) + const { a: seg1, b: newb1 } = b1a > minb + Utils.AngleEpsilon ? b1.cutAtProgress(minb) : { a: b1, b: bs1.cubics[i1++] } + const { a: seg2, b: newb2 } = b2a > minb + Utils.AngleEpsilon ? b2.cutAtProgress(Utils.positiveModulo(doubleMapper.map(minb) - polygon2CutPoint, 1)) : { a: b2, b: bs2.cubics[i2++] } + + ret.push({ a: seg1.cubic, b: seg2.cubic }) + b1 = newb1 + b2 = newb2 + } + + return ret + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/point.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/point.js new file mode 100644 index 0000000..d301974 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/point.js @@ -0,0 +1,154 @@ +.pragma library + +/** + * @param {number} x + * @param {number} y + * @returns {Point} + */ +function createPoint(x, y) { + return new Point(x, y); +} + +class Point { + /** + * @param {float} x + * @param {float} y + */ + constructor(x, y) { + this.x = x; + this.y = y; + } + + /** + * @param {float} x + * @param {float} y + * @returns {Point} + */ + copy(x = this.x, y = this.y) { + return new Point(x, y); + } + + /** + * @returns {float} + */ + getDistance() { + return Math.sqrt(this.x * this.x + this.y * this.y); + } + + /** + * @returns {float} + */ + getDistanceSquared() { + return this.x * this.x + this.y * this.y; + } + + /** + * @param {Point} other + * @returns {float} + */ + dotProduct(other) { + return this.x * other.x + this.y * other.y; + } + + /** + * @param {float} otherX + * @param {float} otherY + * @returns {float} + */ + dotProductScalar(otherX, otherY) { + return this.x * otherX + this.y * otherY; + } + + /** + * @param {Point} other + * @returns {boolean} + */ + clockwise(other) { + return this.x * other.y - this.y * other.x > 0; + } + + /** + * @returns {Point} + */ + getDirection() { + const d = this.getDistance(); + return this.div(d); + } + + /** + * @returns {Point} + */ + negate() { + return new Point(-this.x, -this.y); + } + + /** + * @param {Point} other + * @returns {Point} + */ + minus(other) { + return new Point(this.x - other.x, this.y - other.y); + } + + /** + * @param {Point} other + * @returns {Point} + */ + plus(other) { + return new Point(this.x + other.x, this.y + other.y); + } + + /** + * @param {float} operand + * @returns {Point} + */ + times(operand) { + return new Point(this.x * operand, this.y * operand); + } + + /** + * @param {float} operand + * @returns {Point} + */ + div(operand) { + return new Point(this.x / operand, this.y / operand); + } + + /** + * @param {float} operand + * @returns {Point} + */ + rem(operand) { + return new Point(this.x % operand, this.y % operand); + } + + /** + * @param {Point} start + * @param {Point} stop + * @param {float} fraction + * @returns {Point} + */ + static interpolate(start, stop, fraction) { + return new Point( + start.x + (stop.x - start.x) * fraction, + start.y + (stop.y - start.y) * fraction + ); + } + + /** + * @param {function(float, float): Point} f + * @returns {Point} + */ + transformed(f) { + const result = f(this.x, this.y); + return new Point(result.x, result.y); + } + + /** + * @returns {Point} + */ + rotate90() { + return new Point(-this.y, this.x); + } +} + diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/polygon-measure.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/polygon-measure.js new file mode 100644 index 0000000..bbcd7b4 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/polygon-measure.js @@ -0,0 +1,192 @@ +.pragma library + +.import "cubic.js" as Cubic +.import "point.js" as Point +.import "feature-mapping.js" as FeatureMapping +.import "utils.js" as Utils +.import "feature.js" as Feature + +class MeasuredPolygon { + constructor(measurer, features, cubics, outlineProgress) { + this.measurer = measurer + this.features = features + this.outlineProgress = outlineProgress + this.cubics = [] + + const measuredCubics = [] + let startOutlineProgress = 0 + for(let i = 0; i < cubics.length; i++) { + if ((outlineProgress[i + 1] - outlineProgress[i]) > Utils.DistanceEpsilon) { + measuredCubics.push( + new MeasuredCubic(this, cubics[i], startOutlineProgress, outlineProgress[i + 1]) + ) + // The next measured cubic will start exactly where this one ends. + startOutlineProgress = outlineProgress[i + 1] + } + } + + measuredCubics[measuredCubics.length - 1].updateProgressRange(measuredCubics[measuredCubics.length - 1].startOutlineProgress, 1) + this.cubics = measuredCubics + } + + cutAndShift(cuttingPoint) { + if (cuttingPoint < Utils.DistanceEpsilon) return this + + // Find the index of cubic we want to cut + const targetIndex = this.cubics.findIndex(it => cuttingPoint >= it.startOutlineProgress && cuttingPoint <= it.endOutlineProgress) + const target = this.cubics[targetIndex] + // Cut the target cubic. + // b1, b2 are two resulting cubics after cut + const { a: b1, b: b2 } = target.cutAtProgress(cuttingPoint) + + // Construct the list of the cubics we need: + // * The second part of the target cubic (after the cut) + // * All cubics after the target, until the end + All cubics from the start, before the + // target cubic + // * The first part of the target cubic (before the cut) + const retCubics = [b2.cubic] + for(let i = 1; i < this.cubics.length; i++) { + retCubics.push(this.cubics[(i + targetIndex) % this.cubics.length].cubic) + } + retCubics.push(b1.cubic) + + // Construct the array of outline progress. + // For example, if we have 3 cubics with outline progress [0 .. 0.3], [0.3 .. 0.8] & + // [0.8 .. 1.0], and we cut + shift at 0.6: + // 0. 0123456789 + // |--|--/-|-| + // The outline progresses will start at 0 (the cutting point, that shifs to 0.0), + // then 0.8 - 0.6 = 0.2, then 1 - 0.6 = 0.4, then 0.3 - 0.6 + 1 = 0.7, + // then 1 (the cutting point again), + // all together: (0.0, 0.2, 0.4, 0.7, 1.0) + const retOutlineProgress = [] + for (let i = 0; i < this.cubics.length + 2; i++) { + if (i === 0) { + retOutlineProgress.push(0) + } else if(i === this.cubics.length + 1) { + retOutlineProgress.push(1) + } else { + const cubicIndex = (targetIndex + i - 1) % this.cubics.length + retOutlineProgress.push(Utils.positiveModulo(this.cubics[cubicIndex].endOutlineProgress - cuttingPoint, 1)) + } + } + + // Shift the feature's outline progress too. + const newFeatures = [] + for(let i = 0; i < this.features.length; i++) { + newFeatures.push(new FeatureMapping.ProgressableFeature(Utils.positiveModulo(this.features[i].progress - cuttingPoint, 1), this.features[i].feature)) + } + + // Filter out all empty cubics (i.e. start and end anchor are (almost) the same point.) + return new MeasuredPolygon(this.measurer, newFeatures, retCubics, retOutlineProgress) + } + + static measurePolygon(measurer, polygon) { + const cubics = [] + const featureToCubic = [] + + for (let featureIndex = 0; featureIndex < polygon.features.length; featureIndex++) { + const feature = polygon.features[featureIndex] + for (let cubicIndex = 0; cubicIndex < feature.cubics.length; cubicIndex++) { + if (feature instanceof Feature.Corner && cubicIndex == feature.cubics.length / 2) { + featureToCubic.push({ a: feature, b: cubics.length }) + } + cubics.push(feature.cubics[cubicIndex]) + } + } + + const measures = [0] // Initialize with 0 like in Kotlin's scan + for (const cubic of cubics) { + const measurement = measurer.measureCubic(cubic) + if (measurement < 0) { + throw new Error("Measured cubic is expected to be greater or equal to zero") + } + const lastMeasure = measures[measures.length - 1] + measures.push(lastMeasure + measurement) + } + const totalMeasure = measures[measures.length - 1] + + const outlineProgress = [] + for (let i = 0; i < measures.length; i++) { + outlineProgress.push(measures[i] / totalMeasure) + } + + const features = [] + for (let i = 0; i < featureToCubic.length; i++) { + const ix = featureToCubic[i].b + features.push( + new FeatureMapping.ProgressableFeature(Utils.positiveModulo((outlineProgress[ix] + outlineProgress[ix + 1]) / 2, 1), featureToCubic[i].a)) + } + + return new MeasuredPolygon(measurer, features, cubics, outlineProgress) + } +} + +class MeasuredCubic { + constructor(polygon, cubic, startOutlineProgress, endOutlineProgress) { + this.polygon = polygon + this.cubic = cubic + this.startOutlineProgress = startOutlineProgress + this.endOutlineProgress = endOutlineProgress + this.measuredSize = this.polygon.measurer.measureCubic(cubic) + } + + updateProgressRange( + startOutlineProgress = this.startOutlineProgress, + endOutlineProgress = this.endOutlineProgress, + ) { + this.startOutlineProgress = startOutlineProgress + this.endOutlineProgress = endOutlineProgress + } + + cutAtProgress(cutOutlineProgress) { + const boundedCutOutlineProgress = Utils.coerceIn(cutOutlineProgress, this.startOutlineProgress, this.endOutlineProgress) + const outlineProgressSize = this.endOutlineProgress - this.startOutlineProgress + const progressFromStart = boundedCutOutlineProgress - this.startOutlineProgress + + const relativeProgress = progressFromStart / outlineProgressSize + const t = this.polygon.measurer.findCubicCutPoint(this.cubic, relativeProgress * this.measuredSize) + + const {a: c1, b: c2} = this.cubic.split(t) + return { + a: new MeasuredCubic(this.polygon, c1, this.startOutlineProgress, boundedCutOutlineProgress), + b: new MeasuredCubic(this.polygon, c2, boundedCutOutlineProgress, this.endOutlineProgress) + } + } +} + +class LengthMeasurer { + constructor() { + this.segments = 3 + } + + measureCubic(c) { + return this.closestProgressTo(c, Number.POSITIVE_INFINITY).y + } + + findCubicCutPoint(c, m) { + return this.closestProgressTo(c, m).x + } + + closestProgressTo(cubic, threshold) { + let total = 0 + let remainder = threshold + let prev = new Point.Point(cubic.anchor0X, cubic.anchor0Y) + + for (let i = 1; i < this.segments; i++) { + const progress = i / this.segments + const point = cubic.pointOnCurve(progress) + const segment = point.minus(prev).getDistance() + + if (segment >= remainder) { + return new Point.Point(progress - (1.0 - remainder / segment) / this.segments, threshold) + } + + remainder -= segment + total += segment + prev = point + } + + return new Point.Point(1.0, total) + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/rounded-corner.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/rounded-corner.js new file mode 100644 index 0000000..f2d7b3c --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/rounded-corner.js @@ -0,0 +1,229 @@ +.pragma library +.import "point.js" as PointModule +.import "corner-rounding.js" as RoundingModule +.import "utils.js" as UtilsModule +.import "cubic.js" as CubicModule + +var Point = PointModule.Point; +var CornerRounding = RoundingModule.CornerRounding; +var DistanceEpsilon = UtilsModule.DistanceEpsilon; +var directionVector = UtilsModule.directionVector; +var Cubic = CubicModule.Cubic; + +class RoundedCorner { + /** + * @param {Point} p0 + * @param {Point} p1 + * @param {Point} p2 + * @param {CornerRounding} [rounding=null] + */ + constructor(p0, p1, p2, rounding = null) { + this.p0 = p0; + this.p1 = p1; + this.p2 = p2; + this.rounding = rounding; + this.center = new Point(0, 0); + + const v01 = p0.minus(p1); + const v21 = p2.minus(p1); + const d01 = v01.getDistance(); + const d21 = v21.getDistance(); + + if (d01 > 0 && d21 > 0) { + this.d1 = v01.div(d01); + this.d2 = v21.div(d21); + this.cornerRadius = rounding?.radius ?? 0; + this.smoothing = rounding?.smoothing ?? 0; + + // cosine of angle at p1 is dot product of unit vectors to the other two vertices + this.cosAngle = this.d1.dotProduct(this.d2); + + // identity: sin^2 + cos^2 = 1 + // sinAngle gives us the intersection + this.sinAngle = Math.sqrt(1 - Math.pow(this.cosAngle, 2)); + + // How much we need to cut, as measured on a side, to get the required radius + // calculating where the rounding circle hits the edge + // This uses the identity of tan(A/2) = sinA/(1 + cosA), where tan(A/2) = radius/cut + this.expectedRoundCut = this.sinAngle > 1e-3 ? this.cornerRadius * (this.cosAngle + 1) / this.sinAngle : 0; + } else { + // One (or both) of the sides is empty, not much we can do. + this.d1 = new Point(0, 0); + this.d2 = new Point(0, 0); + this.cornerRadius = 0; + this.smoothing = 0; + this.cosAngle = 0; + this.sinAngle = 0; + this.expectedRoundCut = 0; + } + } + + get expectedCut() { + return ((1 + this.smoothing) * this.expectedRoundCut); + } + + /** + * @param {float} allowedCut0 + * @param {float} [allowedCut1] + * @returns {Array} + */ + getCubics(allowedCut0, allowedCut1 = allowedCut0) { + // We use the minimum of both cuts to determine the radius, but if there is more space + // in one side we can use it for smoothing. + const allowedCut = Math.min(allowedCut0, allowedCut1); + + // Nothing to do, just use lines, or a point + if ( + this.expectedRoundCut < DistanceEpsilon || + allowedCut < DistanceEpsilon || + this.cornerRadius < DistanceEpsilon + ) { + this.center = this.p1; + return [Cubic.straightLine(this.p1.x, this.p1.y, this.p1.x, this.p1.y)]; + } + + // How much of the cut is required for the rounding part. + const actualRoundCut = Math.min(allowedCut, this.expectedRoundCut); + + // We have two smoothing values, one for each side of the vertex + // Space is used for rounding values first. If there is space left over, then we + // apply smoothing, if it was requested + const actualSmoothing0 = this.calculateActualSmoothingValue(allowedCut0); + const actualSmoothing1 = this.calculateActualSmoothingValue(allowedCut1); + + // Scale the radius if needed + const actualR = this.cornerRadius * actualRoundCut / this.expectedRoundCut; + + // Distance from the corner (p1) to the center + const centerDistance = Math.sqrt(Math.pow(actualR, 2) + Math.pow(actualRoundCut, 2)); + + // Center of the arc we will use for rounding + this.center = this.p1.plus(this.d1.plus(this.d2).div(2).getDirection().times(centerDistance)); + + const circleIntersection0 = this.p1.plus(this.d1.times(actualRoundCut)); + const circleIntersection2 = this.p1.plus(this.d2.times(actualRoundCut)); + + const flanking0 = this.computeFlankingCurve( + actualRoundCut, + actualSmoothing0, + this.p1, + this.p0, + circleIntersection0, + circleIntersection2, + this.center, + actualR + ); + + const flanking2 = this.computeFlankingCurve( + actualRoundCut, + actualSmoothing1, + this.p1, + this.p2, + circleIntersection2, + circleIntersection0, + this.center, + actualR + ).reverse(); + + return [ + flanking0, + Cubic.circularArc( + this.center.x, + this.center.y, + flanking0.anchor1X, + flanking0.anchor1Y, + flanking2.anchor0X, + flanking2.anchor0Y + ), + flanking2 + ]; + } + + /** + * @private + * @param {float} allowedCut + * @returns {float} + */ + calculateActualSmoothingValue(allowedCut) { + if (allowedCut > this.expectedCut) { + return this.smoothing; + } else if (allowedCut > this.expectedRoundCut) { + return this.smoothing * (allowedCut - this.expectedRoundCut) / (this.expectedCut - this.expectedRoundCut); + } else { + return 0; + } + } + + /** + * @private + * @param {float} actualRoundCut + * @param {float} actualSmoothingValues + * @param {Point} corner + * @param {Point} sideStart + * @param {Point} circleSegmentIntersection + * @param {Point} otherCircleSegmentIntersection + * @param {Point} circleCenter + * @param {float} actualR + * @returns {Cubic} + */ + computeFlankingCurve( + actualRoundCut, + actualSmoothingValues, + corner, + sideStart, + circleSegmentIntersection, + otherCircleSegmentIntersection, + circleCenter, + actualR + ) { + // sideStart is the anchor, 'anchor' is actual control point + const sideDirection = (sideStart.minus(corner)).getDirection(); + const curveStart = corner.plus(sideDirection.times(actualRoundCut * (1 + actualSmoothingValues))); + + // We use an approximation to cut a part of the circle section proportional to 1 - smooth, + // When smooth = 0, we take the full section, when smooth = 1, we take nothing. + const p = Point.interpolate( + circleSegmentIntersection, + (circleSegmentIntersection.plus(otherCircleSegmentIntersection)).div(2), + actualSmoothingValues + ); + + // The flanking curve ends on the circle + const curveEnd = circleCenter.plus( + directionVector(p.x - circleCenter.x, p.y - circleCenter.y).times(actualR) + ); + + // The anchor on the circle segment side is in the intersection between the tangent to the + // circle in the circle/flanking curve boundary and the linear segment. + const circleTangent = (curveEnd.minus(circleCenter)).rotate90(); + const anchorEnd = this.lineIntersection(sideStart, sideDirection, curveEnd, circleTangent) ?? circleSegmentIntersection; + + // From what remains, we pick a point for the start anchor. + // 2/3 seems to come from design tools? + const anchorStart = (curveStart.plus(anchorEnd.times(2))).div(3); + + return Cubic.create(curveStart, anchorStart, anchorEnd, curveEnd); + } + + /** + * @private + * @param {Point} p0 + * @param {Point} d0 + * @param {Point} p1 + * @param {Point} d1 + * @returns {Point|null} + */ + lineIntersection(p0, d0, p1, d1) { + const rotatedD1 = d1.rotate90(); + const den = d0.dotProduct(rotatedD1); + if (Math.abs(den) < DistanceEpsilon) return null; + + const num = (p1.minus(p0)).dotProduct(rotatedD1); + // Also check the relative value. This is equivalent to abs(den/num) < DistanceEpsilon, + // but avoid doing a division + if (Math.abs(den) < DistanceEpsilon * Math.abs(num)) return null; + + const k = num / den; + return p0.plus(d0.times(k)); + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/rounded-polygon.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/rounded-polygon.js new file mode 100644 index 0000000..9815875 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/rounded-polygon.js @@ -0,0 +1,343 @@ +.pragma library + +.import "feature.js" as Feature +.import "point.js" as Point +.import "cubic.js" as Cubic +.import "utils.js" as Utils +.import "corner-rounding.js" as CornerRounding +.import "rounded-corner.js" as RoundedCorner + +class RoundedPolygon { + constructor(features, center) { + this.features = features + this.center = center + this.cubics = this.buildCubicList() + } + + get centerX() { + return this.center.x + } + + get centerY() { + return this.center.y + } + + transformed(f) { + const center = this.center.transformed(f) + return new RoundedPolygon(this.features.map(x => x.transformed(f)), center) + } + + normalized() { + const bounds = this.calculateBounds() + const width = bounds[2] - bounds[0] + const height = bounds[3] - bounds[1] + const side = Math.max(width, height) + // Center the shape if bounds are not a square + const offsetX = (side - width) / 2 - bounds[0] /* left */ + const offsetY = (side - height) / 2 - bounds[1] /* top */ + return this.transformed((x, y) => { + return new Point.Point((x + offsetX) / side, (y + offsetY) / side) + }) + } + + calculateMaxBounds(bounds = []) { + let maxDistSquared = 0 + for (let i = 0; i < this.cubics.length; i++) { + const cubic = this.cubics[i] + const anchorDistance = Utils.distanceSquared(cubic.anchor0X - this.centerX, cubic.anchor0Y - this.centerY) + const middlePoint = cubic.pointOnCurve(.5) + const middleDistance = Utils.distanceSquared(middlePoint.x - this.centerX, middlePoint.y - this.centerY) + maxDistSquared = Math.max(maxDistSquared, Math.max(anchorDistance, middleDistance)) + } + const distance = Math.sqrt(maxDistSquared) + bounds[0] = this.centerX - distance + bounds[1] = this.centerY - distance + bounds[2] = this.centerX + distance + bounds[3] = this.centerY + distance + return bounds + } + + calculateBounds(bounds = [], approximate = true) { + let minX = Number.MAX_SAFE_INTEGER + let minY = Number.MAX_SAFE_INTEGER + let maxX = Number.MIN_SAFE_INTEGER + let maxY = Number.MIN_SAFE_INTEGER + for (let i = 0; i < this.cubics.length; i++) { + const cubic = this.cubics[i] + cubic.calculateBounds(bounds, approximate) + minX = Math.min(minX, bounds[0]) + minY = Math.min(minY, bounds[1]) + maxX = Math.max(maxX, bounds[2]) + maxY = Math.max(maxY, bounds[3]) + } + bounds[0] = minX + bounds[1] = minY + bounds[2] = maxX + bounds[3] = maxY + return bounds + } + + buildCubicList() { + const result = [] + + // The first/last mechanism here ensures that the final anchor point in the shape + // exactly matches the first anchor point. There can be rendering artifacts introduced + // by those points being slightly off, even by much less than a pixel + let firstCubic = null + let lastCubic = null + let firstFeatureSplitStart = null + let firstFeatureSplitEnd = null + + if (this.features.length > 0 && this.features[0].cubics.length == 3) { + const centerCubic = this.features[0].cubics[1] + const { a: start, b: end } = centerCubic.split(.5) + firstFeatureSplitStart = [this.features[0].cubics[0], start] + firstFeatureSplitEnd = [end, this.features[0].cubics[2]] + } + + // iterating one past the features list size allows us to insert the initial split + // cubic if it exists + for (let i = 0; i <= this.features.length; i++) { + let featureCubics + if (i == 0 && firstFeatureSplitEnd != null) { + featureCubics = firstFeatureSplitEnd + } else if (i == this.features.length) { + if (firstFeatureSplitStart != null) { + featureCubics = firstFeatureSplitStart + } else { + break + } + } else { + featureCubics = this.features[i].cubics + } + + for (let j = 0; j < featureCubics.length; j++) { + // Skip zero-length curves; they add nothing and can trigger rendering artifacts + const cubic = featureCubics[j] + if (!cubic.zeroLength()) { + if (lastCubic != null) + result.push(lastCubic) + lastCubic = cubic + if (firstCubic == null) + firstCubic = cubic + } else { + if (lastCubic != null) { + // Dropping several zero-ish length curves in a row can lead to + // enough discontinuity to throw an exception later, even though the + // distances are quite small. Account for that by making the last + // cubic use the latest anchor point, always. + lastCubic = new Cubic.Cubic([...lastCubic.points]) // Make a copy before mutating + lastCubic.points[6] = cubic.anchor1X + lastCubic.points[7] = cubic.anchor1Y + } + } + } + } + if (lastCubic != null && firstCubic != null) { + result.push( + new Cubic.Cubic([ + lastCubic.anchor0X, + lastCubic.anchor0Y, + lastCubic.control0X, + lastCubic.control0Y, + lastCubic.control1X, + lastCubic.control1Y, + firstCubic.anchor0X, + firstCubic.anchor0Y, + ]) + ) + } else { + // Empty / 0-sized polygon. + result.push(new Cubic.Cubic([this.centerX, this.centerY, this.centerX, this.centerY, this.centerX, this.centerY, this.centerX, this.centerY])) + } + + return result + } + + static calculateCenter(vertices) { + let cumulativeX = 0 + let cumulativeY = 0 + let index = 0 + while (index < vertices.length) { + cumulativeX += vertices[index++] + cumulativeY += vertices[index++] + } + return new Point.Point(cumulativeX / (vertices.length / 2), cumulativeY / (vertices.length / 2)) + } + + static verticesFromNumVerts(numVertices, radius, centerX, centerY) { + const result = [] + let arrayIndex = 0 + for (let i = 0; i < numVertices; i++) { + const vertex = Utils.radialToCartesian(radius, (Math.PI / numVertices * 2 * i)).plus(new Point.Point(centerX, centerY)) + result[arrayIndex++] = vertex.x + result[arrayIndex++] = vertex.y + } + return result + } + + static fromNumVertices(numVertices, radius = 1, centerX = 0, centerY = 0, rounding = CornerRounding.Unrounded, perVertexRounding = null) { + return RoundedPolygon.fromVertices(this.verticesFromNumVerts(numVertices, radius, centerX, centerY), rounding, perVertexRounding, centerX, centerY) + } + + static fromVertices(vertices, rounding = CornerRounding.Unrounded, perVertexRounding = null, centerX = Number.MIN_SAFE_INTEGER, centerY = Number.MAX_SAFE_INTEGER) { + const corners = [] + const n = vertices.length / 2 + const roundedCorners = [] + for (let i = 0; i < n; i++) { + const vtxRounding = perVertexRounding?.[i] ?? rounding + const prevIndex = ((i + n - 1) % n) * 2 + const nextIndex = ((i + 1) % n) * 2 + roundedCorners.push( + new RoundedCorner.RoundedCorner( + new Point.Point(vertices[prevIndex], vertices[prevIndex + 1]), + new Point.Point(vertices[i * 2], vertices[i * 2 + 1]), + new Point.Point(vertices[nextIndex], vertices[nextIndex + 1]), + vtxRounding + ) + ) + } + + // For each side, check if we have enough space to do the cuts needed, and if not split + // the available space, first for round cuts, then for smoothing if there is space left. + // Each element in this list is a pair, that represent how much we can do of the cut for + // the given side (side i goes from corner i to corner i+1), the elements of the pair are: + // first is how much we can use of expectedRoundCut, second how much of expectedCut + const cutAdjusts = Array.from({ length: n }).map((_, ix) => { + const expectedRoundCut = roundedCorners[ix].expectedRoundCut + roundedCorners[(ix + 1) % n].expectedRoundCut + const expectedCut = roundedCorners[ix].expectedCut + roundedCorners[(ix + 1) % n].expectedCut + const vtxX = vertices[ix * 2] + const vtxY = vertices[ix * 2 + 1] + const nextVtxX = vertices[((ix + 1) % n) * 2] + const nextVtxY = vertices[((ix + 1) % n) * 2 + 1] + const sideSize = Utils.distance(vtxX - nextVtxX, vtxY - nextVtxY) + + // Check expectedRoundCut first, and ensure we fulfill rounding needs first for + // both corners before using space for smoothing + if (expectedRoundCut > sideSize) { + // Not enough room for fully rounding, see how much we can actually do. + return { a: sideSize / expectedRoundCut, b: 0 } + } else if (expectedCut > sideSize) { + // We can do full rounding, but not full smoothing. + return { a: 1, b: (sideSize - expectedRoundCut) / (expectedCut - expectedRoundCut) } + } else { + // There is enough room for rounding & smoothing. + return { a: 1, b: 1 } + } + }) + + // Create and store list of beziers for each [potentially] rounded corner + for (let i = 0; i < n; i++) { + // allowedCuts[0] is for the side from the previous corner to this one, + // allowedCuts[1] is for the side from this corner to the next one. + const allowedCuts = [] + for(const delta of [0, 1]) { + const { a: roundCutRatio, b: cutRatio } = cutAdjusts[(i + n - 1 + delta) % n] + allowedCuts.push( + roundedCorners[i].expectedRoundCut * roundCutRatio + + (roundedCorners[i].expectedCut - roundedCorners[i].expectedRoundCut) * cutRatio + ) + } + corners.push( + roundedCorners[i].getCubics(allowedCuts[0], allowedCuts[1]) + ) + } + + const tempFeatures = [] + for (let i = 0; i < n; i++) { + // Note that these indices are for pairs of values (points), they need to be + // doubled to access the xy values in the vertices float array + const prevVtxIndex = (i + n - 1) % n + const nextVtxIndex = (i + 1) % n + const currVertex = new Point.Point(vertices[i * 2], vertices[i * 2 + 1]) + const prevVertex = new Point.Point(vertices[prevVtxIndex * 2], vertices[prevVtxIndex * 2 + 1]) + const nextVertex = new Point.Point(vertices[nextVtxIndex * 2], vertices[nextVtxIndex * 2 + 1]) + const cnvx = Utils.convex(prevVertex, currVertex, nextVertex) + tempFeatures.push(new Feature.Corner(corners[i], cnvx)) + tempFeatures.push( + new Feature.Edge([Cubic.Cubic.straightLine( + corners[i][corners[i].length - 1].anchor1X, + corners[i][corners[i].length - 1].anchor1Y, + corners[(i + 1) % n][0].anchor0X, + corners[(i + 1) % n][0].anchor0Y, + )]) + ) + } + + let center + if (centerX == Number.MIN_SAFE_INTEGER || centerY == Number.MIN_SAFE_INTEGER) { + center = RoundedPolygon.calculateCenter(vertices) + } else { + center = new Point.Point(centerX, centerY) + } + + return RoundedPolygon.fromFeatures(tempFeatures, center.x, center.y) + } + + static fromFeatures(features, centerX, centerY) { + const vertices = [] + for (const feature of features) { + for (const cubic of feature.cubics) { + vertices.push(cubic.anchor0X) + vertices.push(cubic.anchor0Y) + } + } + + if (Number.isNaN(centerX)) { + centerX = this.calculateCenter(vertices).x + } + if (Number.isNaN(centerY)) { + centerY = this.calculateCenter(vertices).y + } + + return new RoundedPolygon(features, new Point.Point(centerX, centerY)) + } + + static circle(numVertices = 8, radius = 1, centerX = 0, centerY = 0) { + // Half of the angle between two adjacent vertices on the polygon + const theta = Math.PI / numVertices + // Radius of the underlying RoundedPolygon object given the desired radius of the circle + const polygonRadius = radius / Math.cos(theta) + return RoundedPolygon.fromNumVertices( + numVertices, + polygonRadius, + centerX, + centerY, + new CornerRounding.CornerRounding(radius) + ) + } + + static rectangle(width, height, rounding = CornerRounding.Unrounded, perVertexRounding = null, centerX = 0, centerY = 0) { + const left = centerX - width / 2 + const top = centerY - height / 2 + const right = centerX + width / 2 + const bottom = centerY + height / 2 + + return RoundedPolygon.fromVertices([right, bottom, left, bottom, left, top, right, top], rounding, perVertexRounding, centerX, centerY) + } + + static star(numVerticesPerRadius, radius = 1, innerRadius = .5, rounding = CornerRounding.Unrounded, innerRounding = null, perVertexRounding = null, centerX = 0, centerY = 0) { + let pvRounding = perVertexRounding + // If no per-vertex rounding supplied and caller asked for inner rounding, + // create per-vertex rounding list based on supplied outer/inner rounding parameters + if (pvRounding == null && innerRounding != null) { + pvRounding = Array.from({ length: numVerticesPerRadius * 2 }).flatMap(() => [rounding, innerRounding]) + } + + return RoundedPolygon.fromVertices(RoundedPolygon.starVerticesFromNumVerts(numVerticesPerRadius, radius, innerRadius, centerX, centerY), rounding, perVertexRounding, centerX, centerY) + } + + static starVerticesFromNumVerts(numVerticesPerRadius, radius, innerRadius, centerX, centerY) { + const result = [] + let arrayIndex = 0 + for (let i = 0; i < numVerticesPerRadius; i++) { + let vertex = Utils.radialToCartesian(radius, (Math.PI / numVerticesPerRadius * 2 * i)) + result[arrayIndex++] = vertex.x + centerX + result[arrayIndex++] = vertex.y + centerY + vertex = Utils.radialToCartesian(innerRadius, (Math.PI / numVerticesPerRadius * (2 * i + 1))) + result[arrayIndex++] = vertex.x + centerX + result[arrayIndex++] = vertex.y + centerY + } + return result + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/utils.js b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/utils.js new file mode 100644 index 0000000..17b56f6 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/components/morphedPolygons/shapes/utils.js @@ -0,0 +1,94 @@ +.pragma library +.import "point.js" as PointModule + +var Point = PointModule.Point; +var DistanceEpsilon = 1e-4; +var AngleEpsilon = 1e-6; + +/** + * @param {Point} previous + * @param {Point} current + * @param {Point} next + * @returns {boolean} + */ +function convex(previous, current, next) { + return (current.minus(previous)).clockwise(next.minus(current)); +} + +/** + * @param {float} start + * @param {float} stop + * @param {float} fraction + * @returns {float} + */ +function interpolate(start, stop, fraction) { + return (1 - fraction) * start + fraction * stop; +} + +/** + * @param {float} x + * @param {float} y + * @returns {Point} + */ +function directionVector(x, y) { + const d = distance(x, y); + return new Point(x / d, y / d); +} + +/** + * @param {float} x + * @param {float} y + * @returns {float} + */ +function distance(x, y) { + return Math.sqrt(x * x + y * y); +} + +/** + * @param {float} x + * @param {float} y + * @returns {float} + */ +function distanceSquared(x, y) { + return x * x + y * y; +} + +/** + * @param {float} radius + * @param {float} angleRadians + * @param {Point} [center] + * @returns {Point} + */ +function radialToCartesian(radius, angleRadians, center = new Point(0, 0)) { + return new Point(Math.cos(angleRadians), Math.sin(angleRadians)) + .times(radius) + .plus(center); +} + +/** + * @param {float} value + * @param {float|object} min + * @param {float} [max] + * @returns {float} + */ +function coerceIn(value, min, max) { + if (max === undefined) { + if (typeof min === 'object' && 'start' in min && 'endInclusive' in min) { + return Math.max(min.start, Math.min(min.endInclusive, value)); + } + throw new Error("Invalid arguments for coerceIn"); + } + + const [actualMin, actualMax] = min <= max ? [min, max] : [max, min]; + return Math.max(actualMin, Math.min(actualMax, value)); +} + +/** + * @param {float} value + * @param {float} mod + * @returns {float} + */ +function positiveModulo(value, mod) { + return ((value % mod) + mod) % mod; +} + diff --git a/.config/quickshell/nucleus-shell/modules/functions/ColorUtils.qml b/.config/quickshell/nucleus-shell/modules/functions/ColorUtils.qml new file mode 100644 index 0000000..b036627 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/functions/ColorUtils.qml @@ -0,0 +1,70 @@ +pragma Singleton +import Quickshell + +// From github.com/end-4/dots-hyprland with modifications + +Singleton { + id: root + + function colorWithHueOf(color1, color2) { + var c1 = Qt.color(color1); + var c2 = Qt.color(color2); + var hue = c2.hsvHue; + var sat = c1.hsvSaturation; + var val = c1.hsvValue; + var alpha = c1.a; + return Qt.hsva(hue, sat, val, alpha); + } + + function colorWithSaturationOf(color1, color2) { + var c1 = Qt.color(color1); + var c2 = Qt.color(color2); + var hue = c1.hsvHue; + var sat = c2.hsvSaturation; + var val = c1.hsvValue; + var alpha = c1.a; + return Qt.hsva(hue, sat, val, alpha); + } + + function colorWithLightness(color, lightness) { + var c = Qt.color(color); + return Qt.hsla(c.hslHue, c.hslSaturation, lightness, c.a); + } + + function colorWithLightnessOf(color1, color2) { + var c2 = Qt.color(color2); + return colorWithLightness(color1, c2.hslLightness); + } + + function adaptToAccent(color1, color2) { + var c1 = Qt.color(color1); + var c2 = Qt.color(color2); + var hue = c2.hslHue; + var sat = c2.hslSaturation; + var light = c1.hslLightness; + var alpha = c1.a; + return Qt.hsla(hue, sat, light, alpha); + } + + function mix(color1, color2, percentage = 0.5) { + var c1 = Qt.color(color1); + var c2 = Qt.color(color2); + return Qt.rgba( + percentage * c1.r + (1 - percentage) * c2.r, + percentage * c1.g + (1 - percentage) * c2.g, + percentage * c1.b + (1 - percentage) * c2.b, + percentage * c1.a + (1 - percentage) * c2.a + ); + } + + function transparentize(color, percentage = 1) { + var c = Qt.color(color); + return Qt.rgba(c.r, c.g, c.b, c.a * (1 - percentage)); + } + + function applyAlpha(color, alpha) { + var c = Qt.color(color); + var a = Math.max(0, Math.min(1, alpha)); + return Qt.rgba(c.r, c.g, c.b, a); + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/functions/DisplayMetrics.qml b/.config/quickshell/nucleus-shell/modules/functions/DisplayMetrics.qml new file mode 100644 index 0000000..5730ae0 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/functions/DisplayMetrics.qml @@ -0,0 +1,15 @@ +pragma Singleton +import Quickshell +import QtQuick +import qs.services + +Singleton { + // Prefer Compositor scales because niri and hyprland have diffrent scaling factors + function scaledWidth(ratio) { + return Compositor.screenW * ratio / Compositor.screenScale + } + + function scaledHeight(ratio) { + return Compositor.screenH * ratio / Compositor.screenScale + } +} diff --git a/.config/quickshell/nucleus-shell/modules/functions/FileUtils.qml b/.config/quickshell/nucleus-shell/modules/functions/FileUtils.qml new file mode 100644 index 0000000..df487ac --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/functions/FileUtils.qml @@ -0,0 +1,106 @@ +import Quickshell +import Quickshell.Io +pragma Singleton + +Singleton { + id: root + + function resolveIcon(className) { + if (!className || className.length === 0) + return ""; + + const original = className; + const normalized = className.toLowerCase(); + // 1. Exact icon name + if (Quickshell.iconPath(original, true).length > 0) + return original; + + // 2. Normalized guess + if (Quickshell.iconPath(normalized, true).length > 0) + return normalized; + + // 3. Dashed guess + const dashed = normalized.replace(/\s+/g, "-"); + if (Quickshell.iconPath(dashed, true).length > 0) + return dashed; + + // 4. Extension guess + const ext = original.split(".").pop().toLowerCase(); + if (Quickshell.iconPath(ext, true).length > 0) + return ext; + + return ""; + } + + function trimFileProtocol(str) { + let s = str; + if (typeof s !== "string") + s = str.toString(); + + // Convert to string if it's an url or whatever + return s.startsWith("file://") ? s.slice(7) : s; + } + + function isVideo(path) { + if (!path) + return false; + + // Convert QUrl → string if needed + let p = path.toString ? path.toString() : path; + // Strip file:// + if (p.startsWith("file://")) + p = p.replace("file://", ""); + + const ext = p.split(".").pop().toLowerCase(); + return ["mp4", "mkv", "webm", "mov", "avi", "m4v"].includes(ext); + } + + function createFile(filePath, callback) { + if (!filePath) + return ; + + let p = Qt.createQmlObject('import QtQuick; import Quickshell.Io; Process {}', root); + p.command = ["touch", filePath]; + p.onExited.connect(function() { + console.debug("Created file:", filePath, "exit code:", p.exitCode); + p.destroy(); + if (callback) + callback(true); + + }); + p.running = true; + } + + function removeFile(filePath, callback) { + if (!filePath) + return ; + + let p = Qt.createQmlObject('import QtQuick; import Quickshell.Io; Process {}', root); + p.command = ["rm", "-f", filePath]; + p.onExited.connect(function() { + console.debug("Removed file:", filePath, "exit code:", p.exitCode); + p.destroy(); + if (callback) + callback(true); + + }); + p.running = true; + } + + function renameFile(oldPath, newPath, callback) { + if (!oldPath || !newPath || oldPath === newPath) + return ; + + let p = Qt.createQmlObject('import QtQuick; import Quickshell.Io; Process {}', root); + p.command = ["mv", oldPath, newPath]; + p.onExited.connect(function() { + console.debug("Renamed file:", oldPath, "→", newPath, "exit code:", p.exitCode); + p.destroy(); + if (callback) + callback(true); + + }); + p.running = true; + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/functions/StringUtils.qml b/.config/quickshell/nucleus-shell/modules/functions/StringUtils.qml new file mode 100644 index 0000000..6ea1fb9 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/functions/StringUtils.qml @@ -0,0 +1,42 @@ +pragma Singleton +import Quickshell + +Singleton { + id: root + + function shortText(str, len = 25) { + if (!str) + return "" + return str.length > len ? str.slice(0, len) + "..." : str + } + + function verticalize(text) { + return text.split("").join("\n") + } + + function markdownToHtml(md) { + if (!md) return ""; + + let html = md + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/\*\*(.*?)\*\*/g, "$1") // bold + .replace(/\*(.*?)\*/g, "$1") // italic + .replace(/`([^`]+)`/g, "$1") // inline code + .replace(/^### (.*)$/gm, "

$1

") // headers + .replace(/```([\s\S]+?)```/g, '
$1
') // code blocks + .replace(/^## (.*)$/gm, "

$1

") + .replace(/^# (.*)$/gm, "

$1

") + .replace(/^- (.*)$/gm, "
  • $1
  • "); // simple lists + + // Wrap list items in
      without `s` flag + html = html.replace(/(
    • [\s\S]*?<\/li>)/g, "
        $1
      "); + + // Replace newlines with
      for normal text + html = html.replace(/\n/g, "
      "); + + return html; + } + +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/functions/fuzzy/fuzzysort.js b/.config/quickshell/nucleus-shell/modules/functions/fuzzy/fuzzysort.js new file mode 100644 index 0000000..f308fc6 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/functions/fuzzy/fuzzysort.js @@ -0,0 +1,679 @@ +.pragma library + +var single = (search, target) => { + if(!search || !target) return NULL + + var preparedSearch = getPreparedSearch(search) + if(!isPrepared(target)) target = getPrepared(target) + + var searchBitflags = preparedSearch.bitflags + if((searchBitflags & target._bitflags) !== searchBitflags) return NULL + + return algorithm(preparedSearch, target) +} + +var go = (search, targets, options) => { + if(!search) return options?.all ? all(targets, options) : noResults + + var preparedSearch = getPreparedSearch(search) + var searchBitflags = preparedSearch.bitflags + var containsSpace = preparedSearch.containsSpace + + var threshold = denormalizeScore( options?.threshold || 0 ) + var limit = options?.limit || INFINITY + + var resultsLen = 0; var limitedCount = 0 + var targetsLen = targets.length + + function push_result(result) { + if(resultsLen < limit) { q.add(result); ++resultsLen } + else { + ++limitedCount + if(result._score > q.peek()._score) q.replaceTop(result) + } + } + + // This code is copy/pasted 3 times for performance reasons [options.key, options.keys, no keys] + + // options.key + if(options?.key) { + var key = options.key + for(var i = 0; i < targetsLen; ++i) { var obj = targets[i] + var target = getValue(obj, key) + if(!target) continue + if(!isPrepared(target)) target = getPrepared(target) + + if((searchBitflags & target._bitflags) !== searchBitflags) continue + var result = algorithm(preparedSearch, target) + if(result === NULL) continue + if(result._score < threshold) continue + + result.obj = obj + push_result(result) + } + + // options.keys + } else if(options?.keys) { + var keys = options.keys + var keysLen = keys.length + + outer: for(var i = 0; i < targetsLen; ++i) { var obj = targets[i] + + { // early out based on bitflags + var keysBitflags = 0 + for (var keyI = 0; keyI < keysLen; ++keyI) { + var key = keys[keyI] + var target = getValue(obj, key) + if(!target) { tmpTargets[keyI] = noTarget; continue } + if(!isPrepared(target)) target = getPrepared(target) + tmpTargets[keyI] = target + + keysBitflags |= target._bitflags + } + + if((searchBitflags & keysBitflags) !== searchBitflags) continue + } + + if(containsSpace) for(let i=0; i -1000) { + if(keysSpacesBestScores[i] > NEGATIVE_INFINITY) { + var tmp = (keysSpacesBestScores[i] + allowPartialMatchScores[i]) / 4/*bonus score for having multiple matches*/ + if(tmp > keysSpacesBestScores[i]) keysSpacesBestScores[i] = tmp + } + } + if(allowPartialMatchScores[i] > keysSpacesBestScores[i]) keysSpacesBestScores[i] = allowPartialMatchScores[i] + } + } + + if(containsSpace) { + for(let i=0; i -1000) { + if(score > NEGATIVE_INFINITY) { + var tmp = (score + result._score) / 4/*bonus score for having multiple matches*/ + if(tmp > score) score = tmp + } + } + if(result._score > score) score = result._score + } + } + + objResults.obj = obj + objResults._score = score + if(options?.scoreFn) { + score = options.scoreFn(objResults) + if(!score) continue + score = denormalizeScore(score) + objResults._score = score + } + + if(score < threshold) continue + push_result(objResults) + } + + // no keys + } else { + for(var i = 0; i < targetsLen; ++i) { var target = targets[i] + if(!target) continue + if(!isPrepared(target)) target = getPrepared(target) + + if((searchBitflags & target._bitflags) !== searchBitflags) continue + var result = algorithm(preparedSearch, target) + if(result === NULL) continue + if(result._score < threshold) continue + + push_result(result) + } + } + + if(resultsLen === 0) return noResults + var results = new Array(resultsLen) + for(var i = resultsLen - 1; i >= 0; --i) results[i] = q.poll() + results.total = resultsLen + limitedCount + return results +} + + +// this is written as 1 function instead of 2 for minification. perf seems fine ... +// except when minified. the perf is very slow +var highlight = (result, open='', close='') => { + var callback = typeof open === 'function' ? open : undefined + + var target = result.target + var targetLen = target.length + var indexes = result.indexes + var highlighted = '' + var matchI = 0 + var indexesI = 0 + var opened = false + var parts = [] + + for(var i = 0; i < targetLen; ++i) { var char = target[i] + if(indexes[indexesI] === i) { + ++indexesI + if(!opened) { opened = true + if(callback) { + parts.push(highlighted); highlighted = '' + } else { + highlighted += open + } + } + + if(indexesI === indexes.length) { + if(callback) { + highlighted += char + parts.push(callback(highlighted, matchI++)); highlighted = '' + parts.push(target.substr(i+1)) + } else { + highlighted += char + close + target.substr(i+1) + } + break + } + } else { + if(opened) { opened = false + if(callback) { + parts.push(callback(highlighted, matchI++)); highlighted = '' + } else { + highlighted += close + } + } + } + highlighted += char + } + + return callback ? parts : highlighted +} + + +var prepare = (target) => { + if(typeof target === 'number') target = ''+target + else if(typeof target !== 'string') target = '' + var info = prepareLowerInfo(target) + return new_result(target, {_targetLower:info._lower, _targetLowerCodes:info.lowerCodes, _bitflags:info.bitflags}) +} + +var cleanup = () => { preparedCache.clear(); preparedSearchCache.clear() } + + +// Below this point is only internal code +// Below this point is only internal code +// Below this point is only internal code +// Below this point is only internal code + + +class Result { + get ['indexes']() { return this._indexes.slice(0, this._indexes.len).sort((a,b)=>a-b) } + set ['indexes'](indexes) { return this._indexes = indexes } + ['highlight'](open, close) { return highlight(this, open, close) } + get ['score']() { return normalizeScore(this._score) } + set ['score'](score) { this._score = denormalizeScore(score) } +} + +class KeysResult extends Array { + get ['score']() { return normalizeScore(this._score) } + set ['score'](score) { this._score = denormalizeScore(score) } +} + +var new_result = (target, options) => { + const result = new Result() + result['target'] = target + result['obj'] = options.obj ?? NULL + result._score = options._score ?? NEGATIVE_INFINITY + result._indexes = options._indexes ?? [] + result._targetLower = options._targetLower ?? '' + result._targetLowerCodes = options._targetLowerCodes ?? NULL + result._nextBeginningIndexes = options._nextBeginningIndexes ?? NULL + result._bitflags = options._bitflags ?? 0 + return result +} + + +var normalizeScore = score => { + if(score === NEGATIVE_INFINITY) return 0 + if(score > 1) return score + return Math.E ** ( ((-score + 1)**.04307 - 1) * -2) +} +var denormalizeScore = normalizedScore => { + if(normalizedScore === 0) return NEGATIVE_INFINITY + if(normalizedScore > 1) return normalizedScore + return 1 - Math.pow((Math.log(normalizedScore) / -2 + 1), 1 / 0.04307) +} + + +var prepareSearch = (search) => { + if(typeof search === 'number') search = ''+search + else if(typeof search !== 'string') search = '' + search = search.trim() + var info = prepareLowerInfo(search) + + var spaceSearches = [] + if(info.containsSpace) { + var searches = search.split(/\s+/) + searches = [...new Set(searches)] // distinct + for(var i=0; i { + if(target.length > 999) return prepare(target) // don't cache huge targets + var targetPrepared = preparedCache.get(target) + if(targetPrepared !== undefined) return targetPrepared + targetPrepared = prepare(target) + preparedCache.set(target, targetPrepared) + return targetPrepared +} +var getPreparedSearch = (search) => { + if(search.length > 999) return prepareSearch(search) // don't cache huge searches + var searchPrepared = preparedSearchCache.get(search) + if(searchPrepared !== undefined) return searchPrepared + searchPrepared = prepareSearch(search) + preparedSearchCache.set(search, searchPrepared) + return searchPrepared +} + + +var all = (targets, options) => { + var results = []; results.total = targets.length // this total can be wrong if some targets are skipped + + var limit = options?.limit || INFINITY + + if(options?.key) { + for(var i=0;i= limit) return results + } + } else if(options?.keys) { + for(var i=0;i= 0; --keyI) { + var target = getValue(obj, options.keys[keyI]) + if(!target) { objResults[keyI] = noTarget; continue } + if(!isPrepared(target)) target = getPrepared(target) + target._score = NEGATIVE_INFINITY + target._indexes.len = 0 + objResults[keyI] = target + } + objResults.obj = obj + objResults._score = NEGATIVE_INFINITY + results.push(objResults); if(results.length >= limit) return results + } + } else { + for(var i=0;i= limit) return results + } + } + + return results +} + + +var algorithm = (preparedSearch, prepared, allowSpaces=false, allowPartialMatch=false) => { + if(allowSpaces===false && preparedSearch.containsSpace) return algorithmSpaces(preparedSearch, prepared, allowPartialMatch) + + var searchLower = preparedSearch._lower + var searchLowerCodes = preparedSearch.lowerCodes + var searchLowerCode = searchLowerCodes[0] + var targetLowerCodes = prepared._targetLowerCodes + var searchLen = searchLowerCodes.length + var targetLen = targetLowerCodes.length + var searchI = 0 // where we at + var targetI = 0 // where you at + var matchesSimpleLen = 0 + + // very basic fuzzy match; to remove non-matching targets ASAP! + // walk through target. find sequential matches. + // if all chars aren't found then exit + for(;;) { + var isMatch = searchLowerCode === targetLowerCodes[targetI] + if(isMatch) { + matchesSimple[matchesSimpleLen++] = targetI + ++searchI; if(searchI === searchLen) break + searchLowerCode = searchLowerCodes[searchI] + } + ++targetI; if(targetI >= targetLen) return NULL // Failed to find searchI + } + + var searchI = 0 + var successStrict = false + var matchesStrictLen = 0 + + var nextBeginningIndexes = prepared._nextBeginningIndexes + if(nextBeginningIndexes === NULL) nextBeginningIndexes = prepared._nextBeginningIndexes = prepareNextBeginningIndexes(prepared.target) + targetI = matchesSimple[0]===0 ? 0 : nextBeginningIndexes[matchesSimple[0]-1] + + // Our target string successfully matched all characters in sequence! + // Let's try a more advanced and strict test to improve the score + // only count it as a match if it's consecutive or a beginning character! + var backtrackCount = 0 + if(targetI !== targetLen) for(;;) { + if(targetI >= targetLen) { + // We failed to find a good spot for this search char, go back to the previous search char and force it forward + if(searchI <= 0) break // We failed to push chars forward for a better match + + ++backtrackCount; if(backtrackCount > 200) break // exponential backtracking is taking too long, just give up and return a bad match + + --searchI + var lastMatch = matchesStrict[--matchesStrictLen] + targetI = nextBeginningIndexes[lastMatch] + + } else { + var isMatch = searchLowerCodes[searchI] === targetLowerCodes[targetI] + if(isMatch) { + matchesStrict[matchesStrictLen++] = targetI + ++searchI; if(searchI === searchLen) { successStrict = true; break } + ++targetI + } else { + targetI = nextBeginningIndexes[targetI] + } + } + } + + // check if it's a substring match + var substringIndex = searchLen <= 1 ? -1 : prepared._targetLower.indexOf(searchLower, matchesSimple[0]) // perf: this is slow + var isSubstring = !!~substringIndex + var isSubstringBeginning = !isSubstring ? false : substringIndex===0 || prepared._nextBeginningIndexes[substringIndex-1] === substringIndex + + // if it's a substring match but not at a beginning index, let's try to find a substring starting at a beginning index for a better score + if(isSubstring && !isSubstringBeginning) { + for(var i=0; i { + var score = 0 + + var extraMatchGroupCount = 0 + for(var i = 1; i < searchLen; ++i) { + if(matches[i] - matches[i-1] !== 1) {score -= matches[i]; ++extraMatchGroupCount} + } + var unmatchedDistance = matches[searchLen-1] - matches[0] - (searchLen-1) + + score -= (12+unmatchedDistance) * extraMatchGroupCount // penality for more groups + + if(matches[0] !== 0) score -= matches[0]*matches[0]*.2 // penality for not starting near the beginning + + if(!successStrict) { + score *= 1000 + } else { + // successStrict on a target with too many beginning indexes loses points for being a bad target + var uniqueBeginningIndexes = 1 + for(var i = nextBeginningIndexes[0]; i < targetLen; i=nextBeginningIndexes[i]) ++uniqueBeginningIndexes + + if(uniqueBeginningIndexes > 24) score *= (uniqueBeginningIndexes-24)*10 // quite arbitrary numbers here ... + } + + score -= (targetLen - searchLen)/2 // penality for longer targets + + if(isSubstring) score /= 1+searchLen*searchLen*1 // bonus for being a full substring + if(isSubstringBeginning) score /= 1+searchLen*searchLen*1 // bonus for substring starting on a beginningIndex + + score -= (targetLen - searchLen)/2 // penality for longer targets + + return score + } + + if(!successStrict) { + if(isSubstring) for(var i=0; i { + var seen_indexes = new Set() + var score = 0 + var result = NULL + + var first_seen_index_last_search = 0 + var searches = preparedSearch.spaceSearches + var searchesLen = searches.length + var changeslen = 0 + + // Return _nextBeginningIndexes back to its normal state + var resetNextBeginningIndexes = () => { + for(let i=changeslen-1; i>=0; i--) target._nextBeginningIndexes[nextBeginningIndexesChanges[i*2 + 0]] = nextBeginningIndexesChanges[i*2 + 1] + } + + var hasAtLeast1Match = false + for(var i=0; i=0; i--) { + if(toReplace !== target._nextBeginningIndexes[i]) break + target._nextBeginningIndexes[i] = newBeginningIndex + nextBeginningIndexesChanges[changeslen*2 + 0] = i + nextBeginningIndexesChanges[changeslen*2 + 1] = toReplace + changeslen++ + } + } + } + + score += result._score / searchesLen + allowPartialMatchScores[i] = result._score / searchesLen + + // dock points based on order otherwise "c man" returns Manifest.cpp instead of CheatManager.h + if(result._indexes[0] < first_seen_index_last_search) { + score -= (first_seen_index_last_search - result._indexes[0]) * 2 + } + first_seen_index_last_search = result._indexes[0] + + for(var j=0; j score) { + if(allowPartialMatch) { + for(var i=0; i str.replace(/\p{Script=Latin}+/gu, match => match.normalize('NFD')).replace(/[\u0300-\u036f]/g, '') + +var prepareLowerInfo = (str) => { + str = remove_accents(str) + var strLen = str.length + var lower = str.toLowerCase() + var lowerCodes = [] // new Array(strLen) sparse array is too slow + var bitflags = 0 + var containsSpace = false // space isn't stored in bitflags because of how searching with a space works + + for(var i = 0; i < strLen; ++i) { + var lowerCode = lowerCodes[i] = lower.charCodeAt(i) + + if(lowerCode === 32) { + containsSpace = true + continue // it's important that we don't set any bitflags for space + } + + var bit = lowerCode>=97&&lowerCode<=122 ? lowerCode-97 // alphabet + : lowerCode>=48&&lowerCode<=57 ? 26 // numbers + // 3 bits available + : lowerCode<=127 ? 30 // other ascii + : 31 // other utf8 + bitflags |= 1< { + var targetLen = target.length + var beginningIndexes = []; var beginningIndexesLen = 0 + var wasUpper = false + var wasAlphanum = false + for(var i = 0; i < targetLen; ++i) { + var targetCode = target.charCodeAt(i) + var isUpper = targetCode>=65&&targetCode<=90 + var isAlphanum = isUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57 + var isBeginning = isUpper && !wasUpper || !wasAlphanum || !isAlphanum + wasUpper = isUpper + wasAlphanum = isAlphanum + if(isBeginning) beginningIndexes[beginningIndexesLen++] = i + } + return beginningIndexes +} +var prepareNextBeginningIndexes = (target) => { + target = remove_accents(target) + var targetLen = target.length + var beginningIndexes = prepareBeginningIndexes(target) + var nextBeginningIndexes = [] // new Array(targetLen) sparse array is too slow + var lastIsBeginning = beginningIndexes[0] + var lastIsBeginningI = 0 + for(var i = 0; i < targetLen; ++i) { + if(lastIsBeginning > i) { + nextBeginningIndexes[i] = lastIsBeginning + } else { + lastIsBeginning = beginningIndexes[++lastIsBeginningI] + nextBeginningIndexes[i] = lastIsBeginning===undefined ? targetLen : lastIsBeginning + } + } + return nextBeginningIndexes +} + +var preparedCache = new Map() +var preparedSearchCache = new Map() + +// the theory behind these being globals is to reduce garbage collection by not making new arrays +var matchesSimple = []; var matchesStrict = [] +var nextBeginningIndexesChanges = [] // allows straw berry to match strawberry well, by modifying the end of a substring to be considered a beginning index for the rest of the search +var keysSpacesBestScores = []; var allowPartialMatchScores = [] +var tmpTargets = []; var tmpResults = [] + +// prop = 'key' 2.5ms optimized for this case, seems to be about as fast as direct obj[prop] +// prop = 'key1.key2' 10ms +// prop = ['key1', 'key2'] 27ms +// prop = obj => obj.tags.join() ??ms +var getValue = (obj, prop) => { + var tmp = obj[prop]; if(tmp !== undefined) return tmp + if(typeof prop === 'function') return prop(obj) // this should run first. but that makes string props slower + var segs = prop + if(!Array.isArray(prop)) segs = prop.split('.') + var len = segs.length + var i = -1 + while (obj && (++i < len)) obj = obj[segs[i]] + return obj +} + +var isPrepared = (x) => { return typeof x === 'object' && typeof x._bitflags === 'number' } +var INFINITY = Infinity; var NEGATIVE_INFINITY = -INFINITY +var noResults = []; noResults.total = 0 +var NULL = null + +var noTarget = prepare('') + +// Hacked version of https://github.com/lemire/FastPriorityQueue.js +var fastpriorityqueue=r=>{var e=[],o=0,a={},v=r=>{for(var a=0,v=e[a],c=1;c>1]=e[a],c=1+(a<<1)}for(var f=a-1>>1;a>0&&v._score>1)e[a]=e[f];e[a]=v};return a.add=(r=>{var a=o;e[o++]=r;for(var v=a-1>>1;a>0&&r._score>1)e[a]=e[v];e[a]=r}),a.poll=(r=>{if(0!==o){var a=e[0];return e[0]=e[--o],v(),a}}),a.peek=(r=>{if(0!==o)return e[0]}),a.replaceTop=(r=>{e[0]=r,v()}),a} +var q = fastpriorityqueue() // reuse this + diff --git a/.config/quickshell/nucleus-shell/modules/interface/background/Background.qml b/.config/quickshell/nucleus-shell/modules/interface/background/Background.qml new file mode 100644 index 0000000..8471556 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/background/Background.qml @@ -0,0 +1,267 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Hyprland +import qs.config +import qs.modules.functions +import qs.modules.components +import qs.services + +Scope { + id: root + + Variants { + model: Quickshell.screens + + PanelWindow { + id: backgroundContainer + + required property var modelData + property string displayName: modelData.name + + property url wallpaperPath: { + const displays = Config.runtime.monitors + const fallback = Config.runtime.appearance.background.defaultPath + + if (!displays) + return fallback + + const monitor = displays?.[displayName] + return monitor?.wallpaper ?? fallback + } + + // parallax config + property bool parallaxEnabled: Config.runtime.appearance.background.parallax.enabled + property real parallaxZoom: Config.runtime.appearance.background.parallax.zoom + property int workspaceRange: Config.runtime.bar.modules.workspaces.workspaceIndicators + + // hyprland + property int activeWorkspaceId: Hyprland.focusedWorkspace?.id ?? 1 + + // wallpaper geometry + property real wallpaperWidth: bgImg.implicitWidth + property real wallpaperHeight: bgImg.implicitHeight + + property real wallpaperToScreenRatio: { + if (wallpaperWidth <= 0 || wallpaperHeight <= 0) + return 1 + return Math.min( + wallpaperWidth / width, + wallpaperHeight / height + ) + } + + property real effectiveScale: parallaxEnabled ? parallaxZoom : 1 + + property real movableXSpace: Math.max( + 0, + ((wallpaperWidth / wallpaperToScreenRatio * effectiveScale) - width) / 2 + ) + + // workspace mapping + property int lowerWorkspace: Math.floor((activeWorkspaceId - 1) / workspaceRange) * workspaceRange + 1 + property int upperWorkspace: lowerWorkspace + workspaceRange + property int workspaceSpan: Math.max(1, upperWorkspace - lowerWorkspace) + + property real valueX: { + if (!parallaxEnabled) + return 0.5 + return (activeWorkspaceId - lowerWorkspace) / workspaceSpan + } + + // sidebar globals + property bool sidebarLeftOpen: Globals.visiblility.sidebarLeft + && Config.runtime.appearance.background.parallax.enableSidebarLeft + + property bool sidebarRightOpen: Globals.visiblility.sidebarRight + && Config.runtime.appearance.background.parallax.enableSidebarRight + + property real sidebarOffset: { + if (sidebarLeftOpen && !sidebarRightOpen) + if (Config.runtime.bar.position === "right") + return 0.15 + else return -0.15 + if (sidebarRightOpen && !sidebarLeftOpen) + if (Config.runtime.bar.position === "left") + return -0.15 + else return 0.15 + return 0 + } + + property real effectiveValueX: Math.max( + 0, + Math.min( + 1, + valueX + sidebarOffset + ) + ) + + // window + color: (bgImg.status === Image.Error) ? Appearance.colors.colLayer2 : "transparent" + WlrLayershell.namespace: "nucleus:background" + exclusionMode: ExclusionMode.Ignore + WlrLayershell.layer: WlrLayer.Background + screen: modelData + visible: Config.initialized && Config.runtime.appearance.background.enabled + + anchors { + top: true + left: true + right: true + bottom: true + } + + // wallpaper picker + Process { + id: wallpaperProc + + command: ["bash", "-c", Directories.scriptsPath + "/interface/changebg.sh"] + + stdout: StdioCollector { + onStreamFinished: { + const out = text.trim() + + if (out !== "null" && out.length > 0) { + const parts = out.split("|") + + if (parts.length === 2) { + const monitor = parts[0] + const wallpaper = parts[1] + + Config.updateKey( + "monitors." + monitor + ".wallpaper", + wallpaper + ) + } + } + + Quickshell.execDetached([ + "nucleus", "ipc", "call", "clock", "changePosition" + ]) + if (Config.runtime.appearance.colors.autogenerated) { + Quickshell.execDetached([ + "nucleus", "ipc", "call", "global", "regenColors" + ]); + } + } + } + } + + // wallpaper + Item { + anchors.fill: parent + clip: true + + StyledImage { + id: bgImg + + visible: status === Image.Ready + smooth: false + cache: false + fillMode: Image.PreserveAspectCrop + source: wallpaperPath + "?t=" + Date.now() + + width: wallpaperWidth / wallpaperToScreenRatio * effectiveScale + height: wallpaperHeight / wallpaperToScreenRatio * effectiveScale + + x: -movableXSpace - (effectiveValueX - 0.5) * 2 * movableXSpace + y: 0 + + Behavior on x { + NumberAnimation { + duration: Metrics.chronoDuration(600) + easing.type: Easing.OutCubic + } + } + + onStatusChanged: { + if (status === Image.Ready) { + backgroundContainer.wallpaperWidth = implicitWidth + backgroundContainer.wallpaperHeight = implicitHeight + } + } + } + + MouseArea { + id: widgetCanvas + anchors.fill: parent + } + + // error ui + Item { + anchors.centerIn: parent + visible: bgImg.status === Image.Error + + Rectangle { + width: 550 + height: 400 + radius: Appearance.rounding.windowRounding + color: "transparent" + anchors.centerIn: parent + + ColumnLayout { + anchors.centerIn: parent + anchors.margins: Metrics.margin("normal") + spacing: Metrics.margin("small") + + MaterialSymbol { + text: "wallpaper" + font.pixelSize: Metrics.fontSize("wildass") + color: Appearance.colors.colOnLayer2 + Layout.alignment: Qt.AlignHCenter + } + + StyledText { + text: "Wallpaper Missing" + font.pixelSize: Metrics.fontSize("hugeass") + font.bold: true + color: Appearance.colors.colOnLayer2 + horizontalAlignment: Text.AlignHCenter + Layout.alignment: Qt.AlignHCenter + } + + StyledText { + text: "Seems like you haven't set a wallpaper yet." + font.pixelSize: Metrics.fontSize("small") + color: Appearance.colors.colSubtext + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + Layout.alignment: Qt.AlignHCenter + } + + Item { Layout.fillHeight: true } + + StyledButton { + text: "Set wallpaper" + icon: "wallpaper" + secondary: true + radius: Metrics.radius("large") + Layout.alignment: Qt.AlignHCenter + onClicked: wallpaperProc.running = true + } + } + } + } + } + + IpcHandler { + target: "background" + + function change() { + wallpaperProc.running = true + } + + function next() { + WallpaperSlideshow.nextWallpaper() + } + } + } + } + + Clock { + id: clock + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/background/Clock.qml b/.config/quickshell/nucleus-shell/modules/interface/background/Clock.qml new file mode 100644 index 0000000..7c9f80f --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/background/Clock.qml @@ -0,0 +1,287 @@ +import "../../components/morphedPolygons/geometry/offset.js" as Offset +import "../../components/morphedPolygons/material-shapes.js" as MaterialShapes // For polygons +import "../../components/morphedPolygons/shapes/corner-rounding.js" as CornerRounding +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import qs.config +import qs.modules.components +import qs.modules.components.morphedPolygons +import qs.services + +Scope { + id: root + + property bool imageFailed: false + + Variants { + model: Quickshell.screens + + PanelWindow { + id: clock + + required property var modelData + property int padding: Config.runtime.appearance.background.clock.edgeSpacing + property int clockHeight: Config.runtime.appearance.background.clock.isAnalog ? 250 : 160 + property int clockWidth: Config.runtime.appearance.background.clock.isAnalog ? 250 : 360 + + function setRandomPosition() { + const x = Math.floor(Math.random() * (width - clockWidth)); + const y = Math.floor(Math.random() * (height - clockHeight)); + animX.to = x; + animY.to = y; + moveAnim.start(); + Config.updateKey("appearance.background.clock.xPos", x); + Config.updateKey("appearance.background.clock.yPos", y); + } + + color: "transparent" + visible: (Config.runtime.appearance.background.clock.enabled && Config.initialized && !imageFailed) + exclusiveZone: 0 + WlrLayershell.layer: WlrLayer.Bottom + screen: modelData + + ParallelAnimation { + id: moveAnim + + NumberAnimation { + id: animX + + target: rootContentContainer + property: "x" + duration: Metrics.chronoDuration(400) + easing.type: Easing.InOutCubic + } + + NumberAnimation { + id: animY + + target: rootContentContainer + property: "y" + duration: Metrics.chronoDuration(400) + easing.type: Easing.InOutCubic + } + + } + + anchors { + top: true + bottom: true + left: true + right: true + } + + margins { + top: padding + bottom: padding + left: padding + right: padding + } + + Item { + id: rootContentContainer + + property real releasedX: 0 + property real releasedY: 0 + + height: clockHeight + width: clockWidth + Component.onCompleted: { + Qt.callLater(() => { + x = Config.runtime.appearance.background.clock.xPos; + y = Config.runtime.appearance.background.clock.yPos; + }); + } + + MouseArea { + id: ma + + anchors.fill: parent + drag.target: rootContentContainer + drag.axis: Drag.XAndYAxis + acceptedButtons: Qt.RightButton + onReleased: { + if (ma.button === Qt.RightButton) + return + Config.updateKey("appearance.background.clock.xPos", rootContentContainer.x); + Config.updateKey("appearance.background.clock.yPos", rootContentContainer.y); + } + } + + Item { + id: digitalClockContainer + + visible: !Config.runtime.appearance.background.clock.isAnalog + + Column { + spacing: Metrics.spacing(-40) + + StyledText { + animate: false + text: Time.format("hh:mm") + font.pixelSize: Metrics.fontSize(Appearance.font.size.wildass * 3) + font.family: Metrics.fontFamily("main") + font.bold: true + } + + StyledText { + anchors.left: parent.left + anchors.leftMargin: Metrics.margin(8) + animate: false + text: Time.format("dddd, dd/MM") + font.pixelSize: Metrics.fontSize(32) + font.family: Metrics.fontFamily("main") + font.bold: true + } + + } + + } + + Item { + id: analogClockContainer + + property int hours: parseInt(Time.format("hh")) + property int minutes: parseInt(Time.format("mm")) + property int seconds: parseInt(Time.format("ss")) + readonly property real cx: width / 2 + readonly property real cy: height / 2 + property var shapes: [MaterialShapes.getCookie7Sided, MaterialShapes.getCookie9Sided, MaterialShapes.getCookie12Sided, MaterialShapes.getPixelCircle, MaterialShapes.getCircle, MaterialShapes.getGhostish] + + anchors.fill: parent + visible: Config.runtime.appearance.background.clock.isAnalog + width: clock.width / 1.1 + height: clock.height / 1.1 + + // Polygon + MorphedPolygon { + id: shapeCanvas + + anchors.fill: parent + color: Appearance.m3colors.m3secondaryContainer + roundedPolygon: analogClockContainer.shapes[Config.runtime.appearance.background.clock.shape]() + + transform: Rotation { + origin.x: shapeCanvas.width / 2 + origin.y: shapeCanvas.height / 2 + angle: shapeCanvas.rotation + } + + NumberAnimation on rotation { + from: 0 + to: 360 + running: Config.runtime.appearance.animations.enabled && Config.runtime.appearance.background.clock.rotatePolygonBg + duration: Config.runtime.appearance.background.clock.rotationDuration * 1000 + loops: Animation.Infinite + } + } + + ClockDial { + id: dial + anchors.fill: parent + anchors.margins: parent.width * 0.12 + color: Appearance.colors.colOnSecondaryContainer + z: 0 + } + + // Hour hand + StyledRect { + z: 2 + width: 10 + height: parent.height * 0.3 + radius: Metrics.radius("full") + color: Qt.darker(Appearance.m3colors.m3secondary, 0.8) + x: analogClockContainer.cx - width / 2 + y: analogClockContainer.cy - height + transformOrigin: Item.Bottom + rotation: (analogClockContainer.hours % 12 + analogClockContainer.minutes / 60) * 30 + } + + StyledRect { + anchors.centerIn: parent + width: 16 + height: 16 + radius: width / 2 + color: Appearance.m3colors.m3secondary + z: 99 // Ensures its on top of everthing + + // Inner dot + StyledRect { + width: parent.width / 2 + height: parent.height / 2 + radius: width / 2 + anchors.centerIn: parent + z: 100 + color: Appearance.m3colors.m3primaryContainer + } + + } + + // Minute hand + StyledRect { + width: 18 + height: parent.height * 0.35 + radius: Metrics.radius("full") + color: Appearance.m3colors.m3secondary + x: analogClockContainer.cx - width / 2 + y: analogClockContainer.cy - height + transformOrigin: Item.Bottom + rotation: analogClockContainer.minutes * 6 + z: 10 // On top of all hands + } + + // Second hand + StyledRect { + visible: true + width: 4 + height: parent.height * 0.28 + radius: Metrics.radius("full") + color: Appearance.m3colors.m3error + x: analogClockContainer.cx - width / 2 + y: analogClockContainer.cy - height + transformOrigin: Item.Bottom + rotation: analogClockContainer.seconds * 6 + z: 2 + } + + StyledText { + text: Time.format("hh") + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Metrics.margin(30) + font.pixelSize: Metrics.fontSize(80) + font.bold: true + opacity: 0.3 + animate: false + } + + StyledText { + text: Time.format("mm") + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Metrics.margin(110) + font.pixelSize: Metrics.fontSize(80) + font.bold: true + opacity: 0.3 + animate: false + } + + IpcHandler { + function changePosition() { + clock.setRandomPosition(); + } + + target: "clock" + } + + } + + } + + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/background/ClockDial.qml b/.config/quickshell/nucleus-shell/modules/interface/background/ClockDial.qml new file mode 100644 index 0000000..b0f4bbe --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/background/ClockDial.qml @@ -0,0 +1,56 @@ +import QtQuick +import qs.modules.components + +Item { + id: root + + property color color: "white" + readonly property real cx: width / 2 + readonly property real cy: height / 2 + readonly property real radius: Math.min(width, height) / 2 + opacity: 0.4 + + // Hour marks (12 ticks) + Repeater { + model: 12 + + Item { + width: root.width + height: root.height + anchors.centerIn: parent + rotation: index * 30 + transformOrigin: Item.Center + + Rectangle { + width: 3 // thickness of tick + height: 15 // length of tick + color: root.color + anchors.horizontalCenter: parent.horizontalCenter + y: -root.radius * 0.15 / 2 + radius: width / 2 + } + } + } + + // Minute marks (60 ticks) + Repeater { + model: 60 + + Item { + width: root.width + height: root.height + anchors.centerIn: parent + rotation: index * 6 + transformOrigin: Item.Center + + Rectangle { + width: index % 5 === 0 ? 3 : 2 // thicker for 5-minute marks + height: index % 5 === 0 ? 15 : 8 // longer for 5-minute marks + color: root.color + anchors.horizontalCenter: parent.horizontalCenter + y: -root.radius * 0.15 / 2 + radius: width / 2 + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/Bar.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/Bar.qml new file mode 100644 index 0000000..a9c600c --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/Bar.qml @@ -0,0 +1,163 @@ +import QtQuick +import Quickshell +import Quickshell.Wayland +import qs.config +import qs.services +import qs.modules.components + +Scope { + id: root + + GothCorners { + opacity: ConfigResolver.bar(bar.displayName).gothCorners && !ConfigResolver.bar(bar.displayName).floating && ConfigResolver.bar(bar.displayName).enabled && !ConfigResolver.bar(bar.displayName).merged ? 1 : 0 + } + + Variants { + model: Quickshell.screens + + PanelWindow { + // some exclusiveSpacing so it won't look like its sticking into the window when floating + + id: bar + + required property var modelData + property string displayName: modelData.name + property int rd: ConfigResolver.bar(displayName).radius * Config.runtime.appearance.rounding.factor // So it won't be modified when factor is 0 + property int margin: ConfigResolver.bar(displayName).margins + property bool floating: ConfigResolver.bar(displayName).floating + property bool merged: ConfigResolver.bar(displayName).merged + property string pos: ConfigResolver.bar(displayName).position + property bool vertical: pos === "left" || pos === "right" + // Simple position properties + property bool attachedTop: pos === "top" + property bool attachedBottom: pos === "bottom" + property bool attachedLeft: pos === "left" + property bool attachedRight: pos === "right" + + screen: modelData // Show bar on all screens + visible: ConfigResolver.bar(displayName).enabled && Config.initialized + WlrLayershell.namespace: "nucleus:bar" + exclusiveZone: ConfigResolver.bar(displayName).floating ? ConfigResolver.bar(displayName).density + Metrics.margin("tiny") : ConfigResolver.bar(displayName).density + implicitHeight: ConfigResolver.bar(displayName).density // density === height. (horizontal orientation) + implicitWidth: ConfigResolver.bar(displayName).density // density === width. (vertical orientation) + color: "transparent" // Keep panel window's color transparent, so that it can be modified by background rect + + // This is probably a little weird way to set anchors but I think it's the best way. (and it works) + anchors { + top: ConfigResolver.bar(displayName).position === "top" || ConfigResolver.bar(displayName).position === "left" || ConfigResolver.bar(displayName).position === "right" + bottom: ConfigResolver.bar(displayName).position === "bottom" || ConfigResolver.bar(displayName).position === "left" || ConfigResolver.bar(displayName).position === "right" + left: ConfigResolver.bar(displayName).position === "left" || ConfigResolver.bar(displayName).position === "top" || ConfigResolver.bar(displayName).position === "bottom" + right: ConfigResolver.bar(displayName).position === "right" || ConfigResolver.bar(displayName).position === "top" || ConfigResolver.bar(displayName).position === "bottom" + } + + margins { + top: { + if (floating) + return margin; + + if (merged && vertical) + return margin; + + return 0; + } + bottom: { + if (floating) + return margin; + + if (merged && vertical) + return margin; + + return 0; + } + left: { + if (floating) + return margin; + + if (merged && !vertical) + return margin; + + return 0; + } + right: { + if (floating) + return margin; + + if (merged && !vertical) + return margin; + + return 0; + } + } + + StyledRect { + id: background + color: Appearance.m3colors.m3background + anchors.fill: parent + topLeftRadius: { + if (floating) + return rd; + + if (!merged) + return 0; + + return attachedBottom || attachedRight ? rd : 0; + } + topRightRadius: { + if (floating) + return rd; + + if (!merged) + return 0; + + return attachedBottom || attachedLeft ? rd : 0; + } + bottomLeftRadius: { + if (floating) + return rd; + + if (!merged) + return 0; + + return attachedTop || attachedRight ? rd : 0; + } + bottomRightRadius: { + if (floating) + return rd; + + if (!merged) + return 0; + + return attachedTop || attachedLeft ? rd : 0; + } + + BarContent { + anchors.fill: parent + } + + Behavior on bottomLeftRadius { + enabled: Config.runtime.appearance.animations.enabled + animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + } + + Behavior on topLeftRadius { + enabled: Config.runtime.appearance.animations.enabled + animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + } + + Behavior on bottomRightRadius { + enabled: Config.runtime.appearance.animations.enabled + animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + } + + Behavior on topRightRadius { + enabled: Config.runtime.appearance.animations.enabled + animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + } + + } + + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/BarContent.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/BarContent.qml new file mode 100644 index 0000000..e5c35aa --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/BarContent.qml @@ -0,0 +1,178 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import "content/" +import qs.config +import qs.services +import qs.modules.components + +Item { + property string displayName: screen?.name ?? "" + property bool isHorizontal: (ConfigResolver.bar(displayName).position === "top" || ConfigResolver.bar(displayName).position === "bottom") + + Row { + id: hCenterRow + visible: isHorizontal + anchors.centerIn: parent + spacing: Metrics.spacing(4) + + SystemUsageModule {} + MediaPlayerModule {} + ActiveWindowModule {} + ClockModule {} + BatteryIndicatorModule {} + } + + RowLayout { + id: hLeftRow + + visible: isHorizontal + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + spacing: Metrics.spacing(4) + anchors.leftMargin: ConfigResolver.bar(displayName).density * 0.3 + + ToggleModule { + icon: "menu" + iconSize: Metrics.iconSize(22) + iconColor: Appearance.m3colors.m3error + toggle: Globals.visiblility.sidebarLeft + + onToggled: function(value) { + Globals.visiblility.sidebarLeft = value + } + } + + WorkspaceModule {} + } + + RowLayout { + id: hRightRow + + visible: isHorizontal + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + spacing: Metrics.spacing(4) + anchors.rightMargin: ConfigResolver.bar(displayName).density * 0.3 + + SystemTray { + id: sysTray + } + + StyledText { + id: seperator + visible: (sysTray.items.count > 0) && ConfigResolver.bar(displayName).modules.statusIcons.enabled + Layout.alignment: Qt.AlignLeft + font.pixelSize: Metrics.fontSize("hugeass") + text: "·" + } + + StatusIconsModule {} + + StyledText { + id: seperator2 + Layout.alignment: Qt.AlignLeft + font.pixelSize: Metrics.fontSize("hugeass") + text: "·" + } + + ToggleModule { + icon: "power_settings_new" + iconSize: Metrics.iconSize(22) + iconColor: Appearance.m3colors.m3error + toggle: Globals.visiblility.powermenu + + onToggled: function(value) { + Globals.visiblility.powermenu = value + } + } + } + + // Vertical Layout + Item { + visible: !isHorizontal + anchors.top: parent.top + anchors.topMargin: ConfigResolver.bar(displayName).density * 0.1 + anchors.horizontalCenter: parent.horizontalCenter + implicitWidth: vRow.implicitHeight + implicitHeight: vRow.implicitWidth + + Row { + id: vRow + anchors.centerIn: parent + spacing: Metrics.spacing(8) + rotation: 90 + + ToggleModule { + icon: "menu" + iconSize: Metrics.iconSize(22) + iconColor: Appearance.m3colors.m3error + toggle: Globals.visiblility.sidebarLeft + rotation: 270 + + onToggled: function(value) { + Globals.visiblility.sidebarLeft = value + } + } + + SystemUsageModule {} + MediaPlayerModule {} + + SystemTray { + rotation: 0 + } + } + } + + Item { + visible: !isHorizontal + anchors.centerIn: parent + anchors.verticalCenterOffset: 35 + implicitWidth: centerRow.implicitHeight + implicitHeight: centerRow.implicitWidth + + Row { + id: centerRow + anchors.centerIn: parent + + WorkspaceModule { + rotation: 90 + } + } + } + + Item { + visible: !isHorizontal + anchors.bottom: parent.bottom + anchors.bottomMargin: ConfigResolver.bar(displayName).density * 0.1 + anchors.horizontalCenter: parent.horizontalCenter + implicitWidth: row.implicitHeight + implicitHeight: row.implicitWidth + + Row { + id: row + anchors.centerIn: parent + spacing: Metrics.spacing(6) + rotation: 90 + + ClockModule { + rotation: 270 + } + + StatusIconsModule {} + BatteryIndicatorModule {} + + ToggleModule { + icon: "power_settings_new" + iconSize: Metrics.iconSize(22) + iconColor: Appearance.m3colors.m3error + toggle: Globals.visiblility.powermenu + rotation: 270 + + onToggled: function(value) { + Globals.visiblility.powermenu = value + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/GothCorners.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/GothCorners.qml new file mode 100644 index 0000000..ca6fa37 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/GothCorners.qml @@ -0,0 +1,82 @@ +import QtQuick +import QtQuick.Effects +import Quickshell +import Quickshell.Hyprland +import Quickshell.Io +import Quickshell.Wayland +import qs.config +import qs.modules.components + +PanelWindow { + id: root + + property int opacity: 0 + + color: "transparent" + visible: Config.initialized + WlrLayershell.layer: WlrLayer.Top + + anchors { + top: true + left: true + bottom: true + right: true + } + + Item { + id: container + + anchors.fill: parent + + StyledRect { + anchors.fill: parent + color: Appearance.m3colors.m3background + layer.enabled: true + opacity: root.opacity + + layer.effect: MultiEffect { + maskSource: mask + maskEnabled: true + maskInverted: true + maskThresholdMin: 0.5 + maskSpreadAtMin: 1 + } + + Behavior on opacity { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration("large") + easing.type: Easing.InOutExpo + easing.bezierCurve: Appearance.animation.elementMove.bezierCurve + } + + } + + } + + Item { + id: mask + + anchors.fill: parent + layer.enabled: true + visible: false + + StyledRect { + anchors.fill: parent + anchors.topMargin: Config.runtime.bar.position === "bottom" ? -15 : 0 + anchors.bottomMargin: Config.runtime.bar.position === "top" ? -15 : 0 + anchors.leftMargin: Config.runtime.bar.position === "right" ? -15 : 0 + anchors.rightMargin: Config.runtime.bar.position === "left" ? -15 : 0 + radius: Metrics.radius("normal") + } + + } + + } + + mask: Region { + item: container + intersection: Intersection.Xor + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/content/ActiveWindowModule.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/content/ActiveWindowModule.qml new file mode 100644 index 0000000..d8612be --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/content/ActiveWindowModule.qml @@ -0,0 +1,136 @@ +import qs.config +import qs.modules.components +import qs.modules.functions +import qs.services +import QtQuick +import Quickshell +import Quickshell.Wayland +import QtQuick.Layouts + +Item { + id: container + property string displayName: screen?.name ?? "" + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + + property Toplevel activeToplevel: Compositor.isWorkspaceOccupied(Compositor.focusedWorkspaceId) + ? Compositor.activeToplevel + : null + + implicitWidth: row.implicitWidth + 30 + implicitHeight: ConfigResolver.bar(displayName).modules.height + + function simplifyTitle(title) { + if (!title) + return "" + + title = title.replace(/[●⬤○◉◌◎]/g, "") // Symbols to remove + + // Normalize separators + title = title + .replace(/\s*[|—]\s*/g, " - ") + .replace(/\s+/g, " ") + .trim() + + const parts = title.split(" - ").map(p => p.trim()).filter(Boolean) + + if (parts.length === 1) + return parts[0] + + // Known app names (extend freely my fellow contributors) + const apps = [ + "Firefox", "Mozilla Firefox", + "Chromium", "Google Chrome", + "Neovim", "VS Code", "Code", + "Kitty", "Alacritty", "Terminal", + "Discord", "Spotify", "Steam", + "Settings - Nucleus", "Settings" + ] + + let app = "" + for (let i = parts.length - 1; i >= 0; i--) { // loop over + for (let a of apps) { + if (parts[i].includes(a)) { + app = a + break + } + } + if (app) break + } + + if (!app) + app = parts[parts.length - 1] + + const context = parts.find(p => p !== app) + + return context ? `${app} · ${context}` : app + } + + + function formatAppId(appId) { // Random ass function to make it look good + if (!appId || appId.length === 0) + return ""; + + // split on dashes/underscores + const parts = appId.split(/[-_]/); + // capitalize each segment + for (let i = 0; i < parts.length; i++) { + const p = parts[i]; + parts[i] = p.charAt(0).toUpperCase() + p.slice(1); + } + return parts.join("-"); + } + + /* Column { + id: col + anchors.centerIn: parent + + StyledText { + id: workspaceText + font.pixelSize: Metrics.fontSize("smallie") + text: { + if (!activeToplevel) + return "Desktop" + + const id = activeToplevel.appId || "" + + return id // Just for aesthetics + } + horizontalAlignment: Text.AlignHCenter + } + + StyledText { + id: titleText + text: StringUtils.shortText(simplifyTitle(activeToplevel?.title, 24) || `Workspace ${Hyprland.focusedWorkspaceId}`) + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Metrics.fontSize("smalle") + } + } */ + + Rectangle { + visible: (ConfigResolver.bar(displayName).position === "top" || ConfigResolver.bar(displayName).position === "bottom") + color: Appearance.m3colors.m3paddingContainer + anchors.fill: parent + height: 34 + width: row.height + 30 + radius: ConfigResolver.bar(displayName).modules.radius + } + + + RowLayout { + id: row + spacing: 12 + anchors.centerIn: parent + + MaterialSymbol { + icon: "desktop_windows" + rotation: (ConfigResolver.bar(displayName).position === "left" || ConfigResolver.bar(displayName).position === "right") ? 270 : 0 + } + + StyledText { + text: StringUtils.shortText(simplifyTitle(activeToplevel?.title), 24) || `Workspace ${Hyprland.focusedWorkspaceId}` + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Appearance.font.size.small + } + } + +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/content/BatteryIndicatorModule.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/content/BatteryIndicatorModule.qml new file mode 100644 index 0000000..854c600 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/content/BatteryIndicatorModule.qml @@ -0,0 +1,57 @@ +import QtQuick +import QtQuick.Layouts +import qs.config +import qs.modules.components +import qs.services + +Item { + id: batteryIndicatorModuleContainer + + visible: UPower.batteryPresent + Layout.alignment: Qt.AlignVCenter + + // Determine if bar is isVertical + property bool isVertical: ConfigResolver.bar(screen?.name ?? "").position === "left" || ConfigResolver.bar(screen?.name ?? "").position === "right" + + implicitWidth: bgRect.implicitWidth + implicitHeight: bgRect.implicitHeight + + Rectangle { + id: bgRect + color: isVertical ? Appearance.m3colors.m3primary : Appearance.m3colors.m3paddingContainer + radius: ConfigResolver.bar(screen?.name ?? "").modules.radius * Config.runtime.appearance.rounding.factor // No need to use metrics here... + + implicitWidth: child.implicitWidth + Appearance.margin.large - (isVertical ? 10 : 0) + implicitHeight: ConfigResolver.bar(screen?.name ?? "").modules.height + } + + RowLayout { + id: child + anchors.centerIn: parent + spacing: isVertical ? 0 : Metrics.spacing(8) + + // Icon for isVertical bars + MaterialSymbol { + visible: isVertical + icon: UPower.battIcon + iconSize: Metrics.iconSize(20) + } + + // Battery percentage text + StyledText { + animate: false + font.pixelSize: Metrics.fontSize(16) + rotation: isVertical ? 270 : 0 + text: (isVertical ? UPower.percentage : UPower.percentage + "%") + } + + // Circular progress for horizontal bars + CircularProgressBar { + visible: !isVertical + value: UPower.percentage / 100 + icon: UPower.battIcon + iconSize: Metrics.iconSize(18) + Layout.bottomMargin: Metrics.margin(2) + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/content/BongoCat.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/content/BongoCat.qml new file mode 100644 index 0000000..73eb544 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/content/BongoCat.qml @@ -0,0 +1,27 @@ +import QtQuick +import QtQuick.Layouts +import qs.services +import qs.config +import qs.modules.components + +Item { + id: clockContainer + + property string format: isVertical ? "hh\nmm\nAP" : "hh:mm • dd/MM" + property bool isVertical: (ConfigResolver.bar(screen?.name ?? "").position === "left" || ConfigResolver.bar(screen?.name ?? "").position === "right") + + Layout.alignment: Qt.AlignVCenter + implicitWidth: 37 + implicitHeight: 30 + + AnimatedImage { + id: art + anchors.fill: parent + source: Directories.assetsPath + "/gifs/bongo-cat.gif" + cache: false // this is important + smooth: true // smooooooth + rotation: isVertical ? 270 : 0 + } + + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/content/ClockModule.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/content/ClockModule.qml new file mode 100644 index 0000000..85020aa --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/content/ClockModule.qml @@ -0,0 +1,36 @@ +import QtQuick +import QtQuick.Layouts +import qs.services +import qs.config +import qs.modules.components + +Item { + id: clockContainer + + property string format: isVertical ? "hh\nmm\nAP" : "hh:mm • dd/MM" + property bool isVertical: (ConfigResolver.bar(screen?.name ?? "").position === "left" || ConfigResolver.bar(screen?.name ?? "").position === "right") + + Layout.alignment: Qt.AlignVCenter + implicitWidth: bgRect.implicitWidth + implicitHeight: bgRect.implicitHeight + + // Let the layout compute size automatically + + Rectangle { + id: bgRect + + color: isVertical ? "transparent" : Appearance.m3colors.m3paddingContainer + radius: ConfigResolver.bar(screen?.name ?? "").modules.radius * Config.runtime.appearance.rounding.factor + // Padding around the text + implicitWidth: isVertical ? textItem.implicitWidth + 40 : textItem.implicitWidth + Metrics.margin("large") + implicitHeight: ConfigResolver.bar(screen?.name ?? "").modules.height + } + + StyledText { + id: textItem + anchors.centerIn: parent + animate: false + text: Time.format(clockContainer.format) + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/content/MediaPlayerModule.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/content/MediaPlayerModule.qml new file mode 100644 index 0000000..2c73743 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/content/MediaPlayerModule.qml @@ -0,0 +1,127 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets +import Quickshell.Io + +import qs.config +import qs.modules.functions +import qs.modules.components +import qs.services + +Item { + id: mediaPlayer + + property bool isVertical: ( + ConfigResolver.bar(screen?.name ?? "").position === "left" || + ConfigResolver.bar(screen?.name ?? "").position === "right" + ) + + Layout.alignment: Qt.AlignCenter | Qt.AlignVCenter + + implicitWidth: bgRect.implicitWidth + implicitHeight: bgRect.implicitHeight + + + Rectangle { + id: bgRect + + color: Appearance.m3colors.m3paddingContainer + radius: ConfigResolver.bar(screen?.name ?? "").modules.radius * + Config.runtime.appearance.rounding.factor + + implicitWidth: isVertical + ? row.implicitWidth + Metrics.margin("large") - 10 + : row.implicitWidth + Metrics.margin("large") + + implicitHeight: ConfigResolver.bar(screen?.name ?? "").modules.height + } + + + Row { + id: row + + anchors.centerIn: parent + spacing: Metrics.margin("small") + + + ClippingRectangle { + id: iconButton + + width: 24 + height: 24 + radius: ConfigResolver.bar(screen?.name ?? "").modules.radius / 1.2 + + color: Appearance.colors.colLayer1Hover + opacity: 0.9 + + clip: true + layer.enabled: true + + + Item { + anchors.fill: parent + + + Image { + id: art + + anchors.fill: parent + visible: Mpris.artUrl !== "" + + source: Mpris.artUrl + fillMode: Image.PreserveAspectCrop + smooth: true + mipmap: true + } + + + MaterialSymbol { + anchors.centerIn: parent + + visible: Mpris.artUrl === "" + icon: "music_note" + + iconSize: 18 + color: Config.runtime.appearance.theme === "dark" + ? "#b1a4a4" + : "grey" + } + } + + + MouseArea { + anchors.fill: parent + hoverEnabled: true + + onClicked: Mpris.playPause() + + onEntered: iconButton.opacity = 1 + onExited: iconButton.opacity = 0.9 + } + + + RotationAnimation on rotation { + from: 0 + to: 360 + + duration: Metrics.chronoDuration(4000) + loops: Animation.Infinite + + running: Mpris.isPlaying && + Config.runtime.appearance.animations.enabled + } + } + + + StyledText { + id: textItem + + anchors.verticalCenter: parent.verticalCenter + + text: StringUtils.shortText(Mpris.title, 16) + + visible: !mediaPlayer.isVertical + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/content/StatusIconsModule.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/content/StatusIconsModule.qml new file mode 100644 index 0000000..531c3bc --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/content/StatusIconsModule.qml @@ -0,0 +1,65 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs.config +import qs.modules.components +import qs.services + +Item { + id: statusIconsContainer + + property bool isVertical: (ConfigResolver.bar(screen?.name ?? "").position === "left" || ConfigResolver.bar(screen?.name ?? "").position === "right") + + Layout.alignment: Qt.AlignVCenter + visible: ConfigResolver.bar(screen?.name ?? "").modules.statusIcons.enabled + implicitWidth: bgRect.implicitWidth + implicitHeight: bgRect.implicitHeight + + StyledRect { + id: bgRect + + color: Globals.visiblility.sidebarRight ? Appearance.m3colors.m3paddingContainer : "transparent" + radius: ConfigResolver.bar(screen?.name ?? "").modules.radius * Config.runtime.appearance.rounding.factor + implicitWidth: isVertical ? contentRow.implicitWidth + Metrics.margin("large") - 8 : contentRow.implicitWidth + Metrics.margin("large") + implicitHeight: ConfigResolver.bar(screen?.name ?? "").modules.height + + RowLayout { + id: contentRow + + anchors.centerIn: parent + spacing: isVertical ? Metrics.spacing(8) : Metrics.spacing(16) + + + MaterialSymbol { + id: wifi + animate: false + visible: ConfigResolver.bar(screen?.name ?? "").modules.statusIcons.networkStatusEnabled + rotation: isVertical ? 270 : 0 + icon: Network.icon + iconSize: Metrics.fontSize("huge") + } + + MaterialSymbol { + id: btIcon + animate: false + visible: ConfigResolver.bar(screen?.name ?? "").modules.statusIcons.bluetoothStatusEnabled + rotation: isVertical ? 270 : 0 + icon: Bluetooth.icon + iconSize: Metrics.fontSize("huge") + } + + + } + + MouseArea { + anchors.fill: parent + onClicked: { + if (Globals.visiblility.sidebarLeft) + return + Globals.visiblility.sidebarRight = !Globals.visiblility.sidebarRight + } + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/content/SystemTray.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/content/SystemTray.qml new file mode 100644 index 0000000..c252f73 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/content/SystemTray.qml @@ -0,0 +1,165 @@ +import qs.modules.components +import qs.config +import qs.services +import Quickshell.Services.SystemTray +import QtQuick +import Quickshell +import Quickshell.Widgets +import QtQuick.Layouts + +Item { + id: root + readonly property Repeater items: items + property bool horizontalMode: (ConfigResolver.bar(screen?.name ?? "").position === "top" || ConfigResolver.bar(screen?.name ?? "").position === "bottom") + clip: true + implicitWidth: layout.implicitWidth + Metrics.margin("verylarge") + implicitHeight: 34 + + Rectangle { + visible: (items.count > 0) ? 1 : 0 + id: padding + implicitHeight: padding.height + anchors.fill: parent + radius: ConfigResolver.bar(screen?.name ?? "").modules.radius + color: "transparent" + } + + GridLayout { + id: layout + anchors.centerIn: parent + rows: 1 + columns: items.count + rowSpacing: Metrics.spacing(10) + columnSpacing: Metrics.spacing(10) + + Repeater { + id: items + model: SystemTray.items + + delegate: Item { + id: trayItemRoot + required property SystemTrayItem modelData + implicitWidth: 20 + implicitHeight: 20 + + IconImage { + visible: trayItemRoot.modelData.icon !== "" + source: trayItemRoot.modelData.icon + asynchronous: true + anchors.fill: parent + rotation: root.horizontalMode ? 0 : 270 + } + + HoverHandler { + id: hover + } + + QsMenuOpener { + id: menuOpener + menu: trayItemRoot.modelData.menu + } + + StyledPopout { + id: popout + hoverTarget: hover + interactable: true + hCenterOnItem: true + requiresHover: false + + Component { + Item { + width: childColumn.implicitWidth + height: childColumn.height + + ColumnLayout { + id: childColumn + spacing: Metrics.spacing(5) + + Repeater { + model: menuOpener.children + delegate: TrayMenuItem { + parentColumn: childColumn + Layout.preferredWidth: childColumn.width > 0 ? childColumn.width : implicitWidth + } + } + } + } + } + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + hoverEnabled: true + + onClicked: { + if (popout.isVisible) + popout.hide(); + else + popout.show(); + } + } + } + } + } + + component TrayMenuItem: Item { + id: itemRoot + required property QsMenuEntry modelData + required property ColumnLayout parentColumn + + Layout.fillWidth: true + implicitWidth: rowLayout.implicitWidth + 10 + implicitHeight: !itemRoot.modelData.isSeparator ? rowLayout.implicitHeight + 10 : 1 + + MouseArea { + id: hover + hoverEnabled: itemRoot.modelData.enabled + anchors.fill: parent + onClicked: { + if (!itemRoot.modelData.hasChildren) + itemRoot.modelData.triggered(); + } + } + + Rectangle { + id: itemBg + anchors.fill: parent + opacity: itemRoot.modelData.isSeparator ? 0.5 : 1 + color: itemRoot.modelData.isSeparator ? Appearance.m3colors.m3outline : hover.containsMouse ? Appearance.m3colors.m3surfaceContainer : Appearance.m3colors.m3surface + } + + RowLayout { + id: rowLayout + visible: !itemRoot.modelData.isSeparator + opacity: itemRoot.modelData.isSeparator ? 0.5 : 1 + spacing: Metrics.spacing(5) + anchors { + left: itemBg.left + leftMargin: Metrics.margin(5) + top: itemBg.top + topMargin:Metrics.margin(5) + } + + IconImage { + visible: itemRoot.modelData.icon !== "" + source: itemRoot.modelData.icon + width: 15 + height: 15 + } + + StyledText { + text: itemRoot.modelData.text + font.pixelSize: Metrics.fontSize(14) + color: Appearance.m3colors.m3onSurface + } + + MaterialSymbol { + visible: itemRoot.modelData.hasChildren + icon: "chevron_right" + iconSize: Metrics.iconSize(16) + color: Appearance.m3colors.m3onSurface + } + } + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/content/SystemUsageModule.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/content/SystemUsageModule.qml new file mode 100644 index 0000000..3d0e267 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/content/SystemUsageModule.qml @@ -0,0 +1,99 @@ +import QtQuick +import QtQuick.Layouts +import qs.config +import qs.modules.components +import qs.services + +Item { + id: systemUsageContainer + property string displayName: screen?.name ?? "" + property bool isHorizontal: (ConfigResolver.bar(displayName).position === "top" || ConfigResolver.bar(displayName).position === "bottom") + + visible: ConfigResolver.bar(displayName).modules.systemUsage.enabled && haveWidth + Layout.alignment: Qt.AlignVCenter + + implicitWidth: bgRect.implicitWidth + implicitHeight: bgRect.implicitHeight + + property bool haveWidth: + ConfigResolver.bar(displayName).modules.systemUsage.tempStatsEnabled || + ConfigResolver.bar(displayName).modules.systemUsage.cpuStatsEnabled || + ConfigResolver.bar(displayName).modules.systemUsage.memoryStatsEnabled + + + // Normalize values so UI always receives correct ranges + function normalize(v) { + if (v > 1) return v / 100 + return v + } + + function percent(v) { + if (v <= 1) return Math.round(v * 100) + return Math.round(v) + } + + Rectangle { + id: bgRect + color: Appearance.m3colors.m3paddingContainer + radius: ConfigResolver.bar(displayName).modules.radius * Config.runtime.appearance.rounding.factor + + implicitWidth: child.implicitWidth + Metrics.margin("large") + implicitHeight: ConfigResolver.bar(displayName).modules.height + } + + RowLayout { + id: child + anchors.centerIn: parent + spacing: Metrics.spacing(4) + + // CPU + CircularProgressBar { + rotation: !isHorizontal ? 270 : 0 + icon: "developer_board" + visible: ConfigResolver.bar(displayName).modules.systemUsage.cpuStatsEnabled + iconSize: Metrics.iconSize(14) + value: normalize(SystemDetails.cpuPercent) + Layout.bottomMargin: Metrics.margin(2) + } + + StyledText { + visible: ConfigResolver.bar(displayName).modules.systemUsage.cpuStatsEnabled && isHorizontal + animate: false + text: percent(SystemDetails.cpuPercent) + "%" + } + + // RAM + CircularProgressBar { + rotation: !isHorizontal ? 270 : 0 + Layout.leftMargin: Metrics.margin(4) + icon: "memory_alt" + visible: ConfigResolver.bar(displayName).modules.systemUsage.memoryStatsEnabled + iconSize: Metrics.iconSize(14) + value: normalize(SystemDetails.ramPercent) + Layout.bottomMargin: Metrics.margin(2) + } + + StyledText { + visible: ConfigResolver.bar(displayName).modules.systemUsage.memoryStatsEnabled && isHorizontal + animate: false + text: percent(SystemDetails.ramPercent) + "%" + } + + // Temperature + CircularProgressBar { + rotation: !isHorizontal ? 270 : 0 + visible: ConfigResolver.bar(displayName).modules.systemUsage.tempStatsEnabled + Layout.leftMargin: Metrics.margin(4) + icon: "device_thermostat" + iconSize: Metrics.iconSize(14) + value: normalize(SystemDetails.cpuTempPercent) + Layout.bottomMargin: Metrics.margin(2) + } + + StyledText { + visible: ConfigResolver.bar(displayName).modules.systemUsage.tempStatsEnabled && isHorizontal + animate: false + text: percent(SystemDetails.cpuTempPercent) + "%" + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/content/ToggleModule.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/content/ToggleModule.qml new file mode 100644 index 0000000..239ff38 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/content/ToggleModule.qml @@ -0,0 +1,43 @@ +import qs.config +import qs.modules.components +import QtQuick +import Quickshell +import QtQuick.Layouts + +StyledRect { + id: bg + + property string icon + property color iconColor: Appearance.syntaxHighlightingTheme + property int iconSize + property bool toggle + property bool transparentBg: false + + signal toggled(bool value) + + color: (ma.containsMouse && !transparentBg) + ? Appearance.m3colors.m3paddingContainer + : "transparent" + + radius: Metrics.radius("childish") + + implicitWidth: textItem.implicitWidth + 12 + implicitHeight: textItem.implicitHeight + 6 + + MaterialSymbol { + id: textItem + anchors.centerIn: parent + anchors.verticalCenterOffset: 0.4 + anchors.horizontalCenterOffset: 0.499 + iconSize: bg.iconSize + icon: bg.icon + color: bg.iconColor + } + + MouseArea { + id: ma + anchors.fill: parent + hoverEnabled: true + onClicked: bg.toggled(!bg.toggle) + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/bar/content/WorkspaceModule.qml b/.config/quickshell/nucleus-shell/modules/interface/bar/content/WorkspaceModule.qml new file mode 100644 index 0000000..910ca86 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/bar/content/WorkspaceModule.qml @@ -0,0 +1,254 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Effects +import Quickshell +import Quickshell.Widgets +import qs.config +import qs.modules.components +import qs.modules.functions +import qs.services + +Item { + id: workspaceContainer + property string displayName: screen?.name ?? "" + property int numWorkspaces: ConfigResolver.bar(displayName).modules.workspaces.workspaceIndicators + property var workspaceOccupied: [] + property var occupiedRanges: [] + + function japaneseNumber(num) { + var kanjiMap = { + "0": "零", + "1": "一", + "2": "二", + "3": "三", + "4": "四", + "5": "五", + "6": "六", + "7": "七", + "8": "八", + "9": "九", + "10": "十" + }; + return kanjiMap[num] !== undefined ? kanjiMap[num] : "Number out of range"; + } + + function updateWorkspaceOccupied() { + const offset = 1; + workspaceOccupied = Array.from({ + "length": numWorkspaces + }, (_, i) => { + return Compositor.isWorkspaceOccupied(i + 1); + }); + const ranges = []; + let start = -1; + for (let i = 0; i < workspaceOccupied.length; i++) { + if (workspaceOccupied[i]) { + if (start === -1) + start = i; + + } else if (start !== -1) { + ranges.push({ + "start": start, + "end": i - 1 + }); + start = -1; + } + } + if (start !== -1) + ranges.push({ + "start": start, + "end": workspaceOccupied.length - 1 + }); + + occupiedRanges = ranges; + } + + visible: ConfigResolver.bar(displayName).modules.workspaces.enabled + implicitWidth: bg.implicitWidth + implicitHeight: ConfigResolver.bar(displayName).modules.height + Component.onCompleted: updateWorkspaceOccupied() + + Connections { + function onStateChanged() { + updateWorkspaceOccupied(); + } + + target: Compositor + } + + Rectangle { + id: bg + + color: Appearance.m3colors.m3paddingContainer + radius: ConfigResolver.bar(displayName).modules.radius * Config.runtime.appearance.rounding.factor + implicitWidth: workspaceRow.implicitWidth + Metrics.margin("large") - 8 + implicitHeight: ConfigResolver.bar(displayName).modules.height + + // occupied background highlight + Item { + id: occupiedStretchLayer + + anchors.centerIn: workspaceRow + width: workspaceRow.width + height: 26 + z: 0 + visible: Compositor.require("hyprland") // Hyprland only + + Repeater { + model: occupiedRanges + + Rectangle { + height: 26 + radius: ConfigResolver.bar(displayName).modules.radius * Config.runtime.appearance.rounding.factor + color: ColorUtils.mix(Appearance.m3colors.m3tertiary, Appearance.m3colors.m3surfaceContainerLowest) + opacity: 0.8 + x: modelData.start * (26 + workspaceRow.spacing) + width: (modelData.end - modelData.start + 1) * 26 + (modelData.end - modelData.start) * workspaceRow.spacing + } + + } + + } + + // workspace highlight + Rectangle { + id: highlight + + property int offset: Compositor.require("hyprland") ? 1 : 0 + property int index: Math.max(0, Compositor.focusedWorkspaceId - 1 - offset) + property real itemWidth: 26 + property real spacing: workspaceRow.spacing + property int highlightIndex: { + if (!Compositor.focusedWorkspaceId) + return 0; + + if (Compositor.require("hyprland")) + return Compositor.focusedWorkspaceId - 1; + // Hyprland starts at 2 internally + return Compositor.focusedWorkspaceId - 2; // Niri or default + } + property real targetX: Math.min(highlightIndex, numWorkspaces - 1) * (itemWidth + spacing) + 7.3 + property real animatedX1: targetX + property real animatedX2: targetX + + x: Math.min(animatedX1, animatedX2) + anchors.verticalCenter: parent.verticalCenter + width: Math.abs(animatedX2 - animatedX1) + itemWidth - 1 + height: 24 + radius: ConfigResolver.bar(displayName).modules.radius * Config.runtime.appearance.rounding.factor + color: Appearance.m3colors.m3tertiary + onTargetXChanged: { + animatedX1 = targetX; + animatedX2 = targetX; + } + + Behavior on animatedX1 { + enabled: Config.runtime.appearance.animations.enabled + + NumberAnimation { + duration: Metrics.chronoDuration(400) + easing.type: Easing.OutSine + } + + } + + Behavior on animatedX2 { + enabled: Config.runtime.appearance.animations.enabled + + NumberAnimation { + duration: Metrics.chronoDuration(133) + easing.type: Easing.OutSine + } + + } + + } + + RowLayout { + id: workspaceRow + + anchors.centerIn: parent + spacing: Metrics.spacing(10) + + Repeater { + model: numWorkspaces + + Item { + property int wsIndex: index + 1 + property bool occupied: Compositor.isWorkspaceOccupied(wsIndex) + property bool focused: wsIndex === Compositor.focusedWorkspaceId + + width: 26 + height: 26 + + // Icon container — only used on Hyprland + ClippingRectangle { + id: iconContainer + + anchors.centerIn: parent + width: 20 + height: 20 + color: "transparent" + radius: Appearance.rounding.small + clip: true + + IconImage { + id: appIcon + + anchors.fill: parent + visible: Compositor.require("hyprland") && ConfigResolver.bar(displayName).modules.workspaces.showAppIcons && occupied + rotation: (ConfigResolver.bar(displayName).position === "left" || ConfigResolver.bar(displayName).position === "right") ? 270 : 0 + source: { + const win = Compositor.focusedWindowForWorkspace(wsIndex); + return win ? AppRegistry.iconForClass(win.class) : ""; + } + layer.enabled: true + layer.effect: MultiEffect { + saturation: (Config.runtime.appearance.tintIcons || (Config.runtime.appearance.colors.matugenScheme === "scheme-monochrome" && Config.runtime.appearance.colors.autogenerated) || Config.runtime.appearance.colors.scheme.toLowerCase() === "monochrome") ? -1.0 : 1.0 + } + } + + } + + // Kanji mode — only if not Hyprland + StyledText { + anchors.centerIn: parent + visible: ConfigResolver.bar(displayName).modules.workspaces.showJapaneseNumbers && !ConfigResolver.bar(displayName).modules.workspaces.showAppIcons + text: japaneseNumber(index + 1) + rotation: (ConfigResolver.bar(displayName).position === "left" || ConfigResolver.bar(displayName).position === "right") ? 270 : 0 + } + + // Numbers mode — only if not Hyprland + StyledText { + anchors.centerIn: parent + visible: !ConfigResolver.bar(displayName).modules.workspaces.showJapaneseNumbers && !ConfigResolver.bar(displayName).modules.workspaces.showAppIcons + text: index + 1 + rotation: (ConfigResolver.bar(displayName).position === "left" || ConfigResolver.bar(displayName).position === "right") ? 270 : 0 + } + + // Symbols for unoccupied workspaces — only for Hyprland icons + MaterialSymbol { + property string displayText: Config.runtime.appearance.rounding.factor === 0 ? "crop_square" : "fiber_manual_record" + + anchors.centerIn: parent + visible: Compositor.require("hyprland") && ConfigResolver.bar(displayName).modules.workspaces.showAppIcons && !occupied + text: displayText + rotation: (ConfigResolver.bar(displayName).position === "left" || ConfigResolver.bar(displayName).position === "right") ? 270 : 0 + font.pixelSize: Metrics.iconSize(10) + fill: 1 + } + + MouseArea { + anchors.fill: parent + onClicked: Compositor.changeWorkspace(wsIndex) + } + + } + + } + + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/intelligence/Intelligence.qml b/.config/quickshell/nucleus-shell/modules/interface/intelligence/Intelligence.qml new file mode 100644 index 0000000..406f6a6 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/intelligence/Intelligence.qml @@ -0,0 +1,576 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Window +import Quickshell +import Quickshell.Io +import qs.config +import qs.modules.functions +import qs.modules.components +import qs.services + +FloatingWindow { + id: appWin + color: Appearance.m3colors.m3background + property bool initialChatSelected: false + property bool chatsInitialized: false + + function appendMessage(sender, message) { + messageModel.append({ + "sender": sender, + "message": message + }); + scrollToBottom(); + } + + function updateChatsList(files) { + let existing = { + }; + for (let i = 0; i < chatListModel.count; i++) existing[chatListModel.get(i).name] = true + for (let file of files) { + let name = file.trim(); + if (!name.length) + continue; + + if (name.endsWith(".txt")) + name = name.slice(0, -4); + + if (!existing[name]) + chatListModel.append({ + "name": name + }); + + delete existing[name]; + } + // remove chats that no longer exist + for (let name in existing) { + for (let i = 0; i < chatListModel.count; i++) { + if (chatListModel.get(i).name === name) { + chatListModel.remove(i); + break; + } + } + } + // ensure default exists + let hasDefault = false; + for (let i = 0; i < chatListModel.count; i++) if (chatListModel.get(i).name === "default") { + hasDefault = true; + } + if (!hasDefault) { + chatListModel.insert(0, { + "name": "default" + }); + FileUtils.createFile(FileUtils.trimFileProtocol(Directories.config) + "/zenith/chats/default.txt"); + } + } + + function scrollToBottom() { + // Always scroll to end after appending + chatView.forceLayout(); + chatView.positionViewAtEnd(); + } + + function sendMessage() { + if (userInput.text === "" || Zenith.loading) + return ; + + Zenith.pendingInput = userInput.text; + appendMessage("You", userInput.text); + userInput.text = ""; + Zenith.loading = true; + Zenith.send(); + } + + function loadChatHistory(chatName) { + messageModel.clear(); + Zenith.loadChat(chatName); + } + + function selectDefaultChat() { + let defaultIndex = -1; + for (let i = 0; i < chatListModel.count; i++) { + if (chatListModel.get(i).name === "default") { + defaultIndex = i; + break; + } + } + if (defaultIndex !== -1) { + chatSelector.currentIndex = defaultIndex; + Zenith.currentChat = "default"; + loadChatHistory("default"); + } else if (chatListModel.count > 0) { + chatSelector.currentIndex = 0; + Zenith.currentChat = chatListModel.get(0).name; + loadChatHistory(Zenith.currentChat); + } + } + + visible: Globals.states.intelligenceWindowOpen + + onVisibleChanged: { + if (!visible) + return ; + + chatsInitialized = false; + messageModel.clear(); + } + + IpcHandler { + function openWindow() { + Globals.states.intelligenceWindowOpen = true; + } + + function closeWindow() { + Globals.states.intelligenceWindowOpen = false; + } + + target: "intelligence" + } + + ListModel { + // { sender: "You" | "AI", message: string } + + id: messageModel + } + + ListModel { + id: chatListModel + } + + ColumnLayout { + spacing: Metrics.spacing(8) + anchors.centerIn: parent + + StyledText { + visible: !Config.runtime.misc.intelligence.enabled + text: "Intelligence is disabled!" + Layout.leftMargin: Metrics.margin(24) + font.pixelSize: Metrics.fontSize("huge") + } + + StyledText { + visible: !Config.runtime.misc.intelligence.enabled + text: "Go to the settings to enable intelligence" + } + + } + + StyledRect { + anchors.fill: parent + color: "transparent" + visible: Config.runtime.misc.intelligence.enabled + + ColumnLayout { + anchors.fill: parent + anchors.margins: Metrics.margin(16) + spacing: Metrics.spacing(10) + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(10) + + StyledDropDown { + id: chatSelector + + Layout.fillWidth: true + model: chatListModel + textRole: "name" + Layout.preferredHeight: 40 + onCurrentIndexChanged: { + if (currentIndex < 0) + return ; + + let name = chatListModel.get(currentIndex).name; + if (name === Zenith.currentChat) + return ; + + Zenith.currentChat = name; + loadChatHistory(name); + } + } + + StyledButton { + icon: "add" + Layout.preferredWidth: 40 + onClicked: { + let name = "new-chat-" + chatListModel.count; + let path = FileUtils.trimFileProtocol(Directories.config) + "/zenith/chats/" + name + ".txt"; + FileUtils.createFile(path, function(success) { + if (success) { + chatListModel.append({ + "name": name + }); + chatSelector.currentIndex = chatListModel.count - 1; + Zenith.currentChat = name; + messageModel.clear(); + } + }); + } + } + + StyledButton { + icon: "edit" + Layout.preferredWidth: 40 + enabled: chatSelector.currentIndex >= 0 + onClicked: renameDialog.open() + } + + StyledButton { + icon: "delete" + Layout.preferredWidth: 40 + enabled: chatSelector.currentIndex >= 0 && chatSelector.currentText !== "default" + onClicked: { + let name = chatSelector.currentText; + let path = FileUtils.trimFileProtocol(Directories.config) + "/zenith/chats/" + name + ".txt"; + FileUtils.removeFile(path, function(success) { + if (success) { + chatListModel.remove(chatSelector.currentIndex); + selectDefaultChat(); + } + }); + } + } + + } + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(10) + + StyledDropDown { + id: modelSelector + + Layout.fillWidth: true + model: ["openai/gpt-4o","openai/gpt-4","openai/gpt-3.5-turbo","openai/gpt-4o-mini","anthropic/claude-3.5-sonnet","anthropic/claude-3-haiku","meta-llama/llama-3.3-70b-instruct:free","deepseek/deepseek-r1-0528:free","qwen/qwen3-coder:free"] + currentIndex: 0 + Layout.preferredHeight: 40 + onCurrentTextChanged: Zenith.currentModel = currentText + } + + StyledButton { + icon: "close_fullscreen" + Layout.preferredWidth: 40 + onClicked: { + Quickshell.execDetached(["nucleus", "ipc", "call", "intelligence", "closeWindow"]); + Globals.visiblility.sidebarLeft = false; + } + } + + } + + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true + radius: Metrics.radius("normal") + color: Appearance.m3colors.m3surfaceContainerLow + + ScrollView { + anchors.fill: parent + clip: true + + ListView { + id: chatView + + model: messageModel + spacing: Metrics.spacing(8) + anchors.fill: parent + anchors.margins: Metrics.margin(12) + clip: true + + delegate: Item { + property bool isCodeBlock: message.split("\n").length > 2 && message.includes("import ") // simple heuristic + + width: chatView.width + height: bubble.implicitHeight + 6 + Component.onCompleted: { + chatView.forceLayout(); + } + + Row { + width: parent.width + spacing: Metrics.spacing(8) + + Item { + width: sender === "AI" ? 0 : parent.width * 0.2 + } + + StyledRect { + id: bubble + + radius: Metrics.radius("normal") + color: sender === "You" ? Appearance.m3colors.m3primaryContainer : Appearance.m3colors.m3surfaceContainerHigh + implicitWidth: Math.min(textItem.implicitWidth + 20, chatView.width * 0.8) + implicitHeight: textItem.implicitHeight + anchors.right: sender === "You" ? parent.right : undefined + anchors.left: sender === "AI" ? parent.left : undefined + anchors.topMargin: Metrics.margin(2) + + TextEdit { + id: textItem + + text: StringUtils.markdownToHtml(message) + wrapMode: TextEdit.Wrap + textFormat: TextEdit.RichText + readOnly: true // make it selectable but not editable + font.pixelSize: Metrics.fontSize(16) + color: Appearance.syntaxHighlightingTheme + padding: Metrics.padding(8) + anchors.fill: parent + } + + MouseArea { + id: ma + + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + let p = Qt.createQmlObject('import Quickshell; import Quickshell.Io; Process { command: ["wl-copy", "' + message + '"] }', parent); + p.running = true; + } + } + + } + + Item { + width: sender === "You" ? 0 : parent.width * 0.2 + } + + } + + } + + } + + } + + } + + StyledRect { + Layout.fillWidth: true + height: 50 + radius: Metrics.radius("normal") + color: Appearance.m3colors.m3surfaceContainer + + RowLayout { + anchors.fill: parent + anchors.margins: Metrics.margin(6) + spacing: Metrics.spacing(10) + + StyledTextField { + // Shift+Enter → insert newline + // Enter → send message + + id: userInput + + Layout.fillWidth: true + placeholderText: "Type your message..." + font.pixelSize: Metrics.iconSize(14) + padding: Metrics.spacing(8) + Keys.onPressed: { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { + if (event.modifiers & Qt.ShiftModifier) + insert("\n"); + else + sendMessage(); + event.accepted = true; + } + } + } + + StyledButton { + text: "Send" + enabled: userInput.text.trim().length > 0 && !Zenith.loading + opacity: enabled ? 1 : 0.5 + onClicked: sendMessage() + } + + } + + } + + } + + Dialog { + id: renameDialog + + title: "Rename Chat" + modal: true + visible: false + standardButtons: Dialog.NoButton + x: (appWin.width - 360) / 2 // center horizontally + y: (appWin.height - 160) / 2 // center vertically + width: 360 + height: 200 + + ColumnLayout { + anchors.fill: parent + anchors.margins: Metrics.margin(16) + spacing: Metrics.spacing(12) + + StyledText { + text: "Enter a new name for the chat" + font.pixelSize: Metrics.fontSize(18) + horizontalAlignment: Text.AlignHCenter + Layout.fillWidth: true + } + + StyledTextField { + id: renameInput + + Layout.fillWidth: true + placeholderText: "New name" + filled: false + highlight: false + text: chatSelector.currentText + font.pixelSize: Metrics.fontSize(16) + Layout.preferredHeight: 45 + padding: Metrics.padding(8) + } + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(12) + Layout.alignment: Qt.AlignRight + + StyledButton { + text: "Cancel" + Layout.preferredWidth: 80 + onClicked: renameDialog.close() + } + + StyledButton { + text: "Rename" + Layout.preferredWidth: 100 + enabled: renameInput.text.trim().length > 0 && renameInput.text !== chatSelector.currentText + onClicked: { + let oldName = chatSelector.currentText; + let newName = renameInput.text.trim(); + let oldPath = FileUtils.trimFileProtocol(Directories.config) + "/zenith/chats/" + oldName + ".txt"; + let newPath = FileUtils.trimFileProtocol(Directories.config) + "/zenith/chats/" + newName + ".txt"; + FileUtils.renameFile(oldPath, newPath, function(success) { + if (success) { + chatListModel.set(chatSelector.currentIndex, { + "name": newName + }); + Zenith.currentChat = newName; + renameDialog.close(); + } + }); + } + } + + } + + } + + background: StyledRect { + color: Appearance.m3colors.m3surfaceContainer + radius: Metrics.radius("normal") + border.color: Appearance.colors.colOutline + border.width: 1 + } + + header: StyledRect { + color: Appearance.m3colors.m3surfaceContainer + radius: Metrics.radius("normal") + border.color: Appearance.colors.colOutline + border.width: 1 + } + + } + + StyledText { + text: "Thinking…" + visible: Zenith.loading + color: Appearance.colors.colSubtext + font.pixelSize: Metrics.fontSize(14) + + anchors { + left: parent.left + bottom: parent.bottom + leftMargin: Metrics.margin(22) + bottomMargin: Metrics.margin(76) + } + + } + + } + + Connections { + // only auto-select once + function onChatsListed(text) { + let lines = text.split(/\r?\n/); + let previousChat = Zenith.currentChat; + updateChatsList(lines); + // select & load once + if (!chatsInitialized) { + chatsInitialized = true; + let index = -1; + for (let i = 0; i < chatListModel.count; i++) { + if (chatListModel.get(i).name === previousChat) { + index = i; + break; + } + } + if (index === -1 && chatListModel.count > 0) + index = 0; + + if (index !== -1) { + chatSelector.currentIndex = index; + Zenith.currentChat = chatListModel.get(index).name; + loadChatHistory(Zenith.currentChat); + } + return ; + } + // AFTER init: only react if current chat vanished + let stillExists = false; + for (let i = 0; i < chatListModel.count; i++) { + if (chatListModel.get(i).name === Zenith.currentChat) { + stillExists = true; + break; + } + } + if (!stillExists && chatListModel.count > 0) { + chatSelector.currentIndex = 0; + Zenith.currentChat = chatListModel.get(0).name; + loadChatHistory(Zenith.currentChat); + } + } + + function onAiReply(text) { + appendMessage("AI", text.slice(5)); + Zenith.loading = false; + } + + function onChatLoaded(text) { + let lines = text.split(/\r?\n/); + let batch = []; + for (let l of lines) { + let line = l.trim(); + if (!line.length) + continue; + + let u = line.match(/^\[\d{4}-.*\] User: (.*)$/); + let a = line.match(/^\[\d{4}-.*\] AI: (.*)$/); + if (u) + batch.push({ + "sender": "You", + "message": u[1] + }); + else if (a) + batch.push({ + "sender": "AI", + "message": a[1] + }); + else if (batch.length) + batch[batch.length - 1].message += "\n" + line; + } + messageModel.clear(); + for (let m of batch) messageModel.append(m) + scrollToBottom(); + } + + target: Zenith + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/launcher/AppItem.qml b/.config/quickshell/nucleus-shell/modules/interface/launcher/AppItem.qml new file mode 100644 index 0000000..3700654 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/launcher/AppItem.qml @@ -0,0 +1,122 @@ +import Quickshell +import Quickshell.Io +import Quickshell.Widgets + +import QtQuick +import QtQuick.Layouts +import QtQuick.Effects +import QtQuick.Controls + +import qs.config +import qs.modules.components +import qs.modules.functions + +StyledRect { + id: root + property bool hovered: false + property bool selected: false + + required property int parentWidth + + width: parentWidth + height: 50 + color: { + if (selected || hovered) + return Appearance.m3colors.m3surfaceContainerHigh + else + return Appearance.m3colors.m3surface + } + radius: Metrics.radius(15) + + Behavior on color { + PropertyAnimation { + duration: Metrics.chronoDuration(200) + easing.type: Easing.InSine + } + } + + ClippingWrapperRectangle { + id: entryIcon + anchors.left: parent.left + anchors.leftMargin: Metrics.margin(10) + + anchors.top: parent.top + anchors.topMargin: (parent.height / 2) - (size / 2) + + property int size: 25 + height: size + width: size + radius: Metrics.radius(1000) + + color: "transparent" + + child: Image { + source: Quickshell.iconPath(modelData.icon, "application-x-executable") + layer.enabled: true + layer.effect: MultiEffect { // Tint if needed, ngl this looks fucking cool when you use monochrome + saturation: (Config.runtime.appearance.tintIcons || (Config.runtime.appearance.colors.matugenScheme === "scheme-monochrome" && Config.runtime.appearance.colors.autogenerated) || Config.runtime.appearance.colors.scheme.toLowerCase() === "monochrome") ? -1.0 : 1.0 + } + } + } + + ColumnLayout { + anchors.left: entryIcon.right + anchors.leftMargin: Metrics.margin(10) + anchors.top: parent.top + anchors.topMargin: (parent.height / 2) - (height / 2) + + height: 40 + spacing: Metrics.spacing(-5) + + StyledText { + font.weight: 400 + text: modelData.name + font.pixelSize: Metrics.fontSize(14) + color: { + if (root.hovered || root.selected) + return Appearance.m3colors.m3onSurface + else + return Appearance.colors.colOutline + } + + Behavior on color { + PropertyAnimation { + duration: Metrics.chronoDuration(200) + easing.type: Easing.InSine + } + } + } + + StyledText { + font.weight: 400 + text: StringUtils.shortText(modelData.comment, 65) // Limit maximum chars to 65 + font.pixelSize: Metrics.fontSize(12) + color: { + if (root.hovered || root.selected) + return Qt.alpha(Appearance.m3colors.m3onSurface, 0.7) + else + return Qt.alpha(Appearance.colors.colOutline, 0.7) + } + + Behavior on color { + PropertyAnimation { + duration: Metrics.chronoDuration(200) + easing.type: Easing.InSine + } + } + } + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + + onEntered: root.hovered = true + onExited: root.hovered = false + onClicked: { + modelData.execute() + IPCLoader.toggleLauncher() + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/launcher/Launcher.qml b/.config/quickshell/nucleus-shell/modules/interface/launcher/Launcher.qml new file mode 100644 index 0000000..f692af0 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/launcher/Launcher.qml @@ -0,0 +1,170 @@ +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import Quickshell.Wayland + +import QtQuick +import QtQuick.Layouts +import QtQuick.Effects +import QtQuick.Controls + +import qs.modules.components +import qs.modules.functions +import qs.config +import qs.services + +PanelWindow { + id: launcherWindow + + readonly property bool launcherOpen: Globals.visiblility.launcher + + visible: launcherOpen + focusable: true + aboveWindows: true // btw I never knew this was a property (read docs) + color: "transparent" + + anchors { + top: true + bottom: true + left: true + right: true + } + + exclusionMode: ExclusionMode.Ignore // why this? idk but it works atleast + WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive + + ScrollView { + id: maskId + + implicitHeight: DisplayMetrics.scaledHeight(0.623) + implicitWidth: DisplayMetrics.scaledWidth(0.3) + + anchors.top: parent.top + anchors.left: parent.left + anchors.leftMargin: (parent.width / 2) - (implicitWidth / 2) + anchors.topMargin: (parent.height / 2) - (implicitHeight / 2) + + clip: true + focus: true + + Rectangle { + id: launcher + property string currentSearch: "" + property int entryIndex: 0 + property list appList: Apps.list + + Connections { + target: launcherWindow + function onLauncherOpenChanged() { + if (!launcherWindow.launcherOpen) { + launcher.currentSearch = "" + launcher.entryIndex = 0 + launcher.appList = Apps.list + } + } + } + + anchors.fill: parent + color: Appearance.m3colors.m3surface + radius: Metrics.radius(21) + + StyledRect { + id: searchBox + anchors.top: parent.top + anchors.topMargin: Metrics.margin(10) + + color: Appearance.m3colors.m3surfaceContainerLow + width: parent.width - 20 + anchors.left: parent.left + anchors.leftMargin: (parent.width / 2) - (width / 2) + height: 45 + radius: Metrics.radius(15) + z: 2 + + focus: true + + Keys.onDownPressed: launcher.entryIndex += 1 + Keys.onUpPressed: { + if (launcher.entryIndex != 0) + launcher.entryIndex -= 1 + } + Keys.onEscapePressed: Globals.visiblility.launcher = false + + Keys.onPressed: event => { + if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { + launcher.appList[launcher.entryIndex].execute() + Globals.visiblility.launcher = false + } else if (event.key === Qt.Key_Backspace) { + launcher.currentSearch = launcher.currentSearch.slice(0, -1) + } else if (" abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?".includes(event.text.toLowerCase())) { + launcher.currentSearch += event.text + } + + launcher.appList = Apps.fuzzyQuery(launcher.currentSearch) + launcher.entryIndex = 0 + } + + MaterialSymbol { + id: iconText + anchors.left: parent.left + anchors.leftMargin: Metrics.margin(10) + icon: "search" + font.pixelSize: Metrics.fontSize(14) + font.weight: 600 + anchors.top: parent.top + anchors.topMargin: (parent.height / 2) - ((font.pixelSize + 5) / 2) + opacity: 0.8 + } + + StyledText { + id: placeHolderText + anchors.left: iconText.right + anchors.leftMargin: Metrics.margin(10) + color: (launcher.currentSearch != "") ? Appearance.m3colors.m3onSurface : Appearance.colors.colOutline + text: (launcher.currentSearch != "") ? launcher.currentSearch : "Start typing to search ..." + font.pixelSize: Metrics.fontSize(13) + anchors.top: parent.top + anchors.topMargin: (parent.height / 2) - ((font.pixelSize + 5) / 2) + animate: false + opacity: 0.8 + } + } + + ScrollView { + anchors.top: searchBox.bottom + anchors.topMargin: Metrics.margin(10) + + anchors.left: parent.left + anchors.leftMargin: (parent.width / 2) - (width / 2) + width: parent.width - 20 + height: parent.height - searchBox.height - 20 + + ListView { + id: appList + anchors.fill: parent + spacing: Metrics.spacing(10) + anchors.bottomMargin: Metrics.margin(4) + + model: launcher.appList + currentIndex: launcher.entryIndex + + delegate: AppItem { + required property int index + required property DesktopEntry modelData + selected: index === launcher.entryIndex + parentWidth: appList.width + } + } + } + } + } + + IpcHandler { + function toggle() { + Globals.visiblility.launcher = !Globals.visiblility.launcher; + } + + target: "launcher" + } + +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/interface/launcher/LauncherContent.qml b/.config/quickshell/nucleus-shell/modules/interface/launcher/LauncherContent.qml new file mode 100644 index 0000000..e85d42b --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/launcher/LauncherContent.qml @@ -0,0 +1,313 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import qs.config +import qs.modules.functions +import qs.modules.components +import qs.services + +/* + +This LauncherContent has been depricated. +And yet not used. (4/3/26) + +*/ + +Item { + id: content + + property int selectedIndex: -1 + property string searchQuery: "" + property var calcVars: ({}) + + property alias listView: listView + property alias filteredModel: filteredModel + + function launchCurrent() { + launchApp(listView.currentIndex) + } + + function webSearchUrl(query) { + const engine = (Config.runtime.launcher.webSearchEngine || "").toLowerCase() + if (engine.startsWith("http")) + return engine.replace("%s", encodeURIComponent(query)) + + const engines = { + "google": "https://www.google.com/search?q=%s", + "duckduckgo": "https://duckduckgo.com/?q=%s", + "brave": "https://search.brave.com/search?q=%s", + "bing": "https://www.bing.com/search?q=%s", + "startpage": "https://www.startpage.com/search?q=%s" + } + const template = engines[engine] || engines["duckduckgo"] + return template.replace("%s", encodeURIComponent(query)) + } + + function moveSelection(delta) { + if (filteredModel.count === 0) return + + selectedIndex = Math.max(0, Math.min(selectedIndex + delta, filteredModel.count - 1)) + listView.currentIndex = selectedIndex + listView.positionViewAtIndex(selectedIndex, ListView.Contain) + } + + function fuzzyMatch(text, pattern) { + text = text.toLowerCase() + pattern = pattern.toLowerCase() + let ti = 0, pi = 0 + while (ti < text.length && pi < pattern.length) { + if (text[ti] === pattern[pi]) pi++ + ti++ + } + return pi === pattern.length + } + + function evalExpression(expr) { + try { + const fn = new Function("vars", ` + with (vars) { with (Math) { return (${expr}); } } + `) + const res = fn(calcVars) + if (res === undefined || Number.isNaN(res)) return null + return res + } catch (e) { + return null + } + } + + function updateFilter() { + filteredModel.clear() + const query = searchQuery.toLowerCase().trim() + + const calcVal = evalExpression(query) + if (calcVal !== null && query !== "") { + filteredModel.append({ + name: String(calcVal), + displayName: String(calcVal), + comment: "Calculation", + icon: "", + exec: "", + isCalc: true, + isWeb: false + }) + } + + const sourceApps = AppRegistry.apps + + if (query === "") { + for (let app of sourceApps) { + filteredModel.append({ + name: app.name, + displayName: app.name, + comment: app.comment, + icon: AppRegistry.iconForDesktopIcon(app.icon), + exec: app.exec, + isCalc: false, + isWeb: false + }) + } + selectedIndex = filteredModel.count > 0 ? 0 : -1 + listView.currentIndex = selectedIndex + return + } + + let exactMatches = [] + let startsWithMatches = [] + let containsMatches = [] + let fuzzyMatches = [] + + for (let app of sourceApps) { + const name = app.name ? app.name.toLowerCase() : "" + const comment = app.comment ? app.comment.toLowerCase() : "" + + if (name === query) exactMatches.push(app) + else if (name.startsWith(query)) startsWithMatches.push(app) + else if (name.includes(query) || comment.includes(query)) containsMatches.push(app) + else if (Config.runtime.launcher.fuzzySearchEnabled && fuzzyMatch(name, query)) fuzzyMatches.push(app) + } + + const sortedResults = [ + ...exactMatches, + ...startsWithMatches, + ...containsMatches, + ...fuzzyMatches + ] + + for (let app of sortedResults) { + filteredModel.append({ + name: app.name, + displayName: app.name, + comment: app.comment, + icon: AppRegistry.iconForDesktopIcon(app.icon), + exec: app.exec, + isCalc: false, + isWeb: false + }) + } + + if (filteredModel.count === 0 && query !== "") { + filteredModel.append({ + name: query, + displayName: "Search the web for \"" + query + "\"", + comment: "Web search", + icon: "public", + exec: webSearchUrl(query), + isCalc: false, + isWeb: true + }) + } + + selectedIndex = filteredModel.count > 0 ? 0 : -1 + listView.currentIndex = selectedIndex + listView.positionViewAtBeginning() + } + + function launchApp(idx) { + if (idx < 0 || idx >= filteredModel.count) return + + const app = filteredModel.get(idx) + if (app.isCalc) return + if (app.isWeb) + Quickshell.execDetached(["xdg-open", app.exec]) + else + Quickshell.execDetached(["bash", "-c", app.exec + " &"]) + + closeLauncher() + } + + function closeLauncher() { + Globals.visiblility.launcher = false + } + + function resetSearch() { + searchQuery = "" + updateFilter() + selectedIndex = -1 + listView.currentIndex = -1 + } + + Connections { + target: AppRegistry + function onReady() { + updateFilter() + } + } + + anchors.fill: parent + opacity: Globals.visiblility.launcher ? 1 : 0 + anchors.margins: Metrics.margin(10) + + ListModel { id: filteredModel } + + ColumnLayout { + anchors.fill: parent + anchors.margins: Metrics.margin(16) + spacing: Metrics.spacing(12) + + ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + + ListView { + id: listView + model: filteredModel + spacing: Metrics.spacing(8) + clip: true + boundsBehavior: Flickable.StopAtBounds + highlightRangeMode: ListView.StrictlyEnforceRange + preferredHighlightBegin: 0 + preferredHighlightEnd: height + highlightMoveDuration: 120 + currentIndex: selectedIndex + + delegate: Rectangle { + property bool isSelected: listView.currentIndex === index + + width: listView.width + height: 60 + radius: Appearance.rounding.normal + color: isSelected ? Appearance.m3colors.m3surfaceContainerHighest : "transparent" + + Row { + anchors.fill: parent + anchors.margins: Metrics.margin(10) + spacing: Metrics.spacing(12) + + Item { + width: 32 + height: 32 + + Image { + anchors.fill: parent + visible: !model.isCalc && !model.isWeb + smooth: true + mipmap: true + antialiasing: true + fillMode: Image.PreserveAspectFit + sourceSize.width: 128 + sourceSize.height: 128 + source: model.icon + } + + MaterialSymbol { + anchors.centerIn: parent + visible: model.isCalc + icon: "calculate" + iconSize: Metrics.iconSize(28) + color: Appearance.m3colors.m3onSurfaceVariant + } + + MaterialSymbol { + anchors.centerIn: parent + visible: model.isWeb + icon: "public" + iconSize: Metrics.iconSize(28) + color: Appearance.m3colors.m3onSurfaceVariant + } + } + + Column { + anchors.verticalCenter: parent.verticalCenter + width: listView.width - 120 + spacing: Metrics.spacing(4) + + Text { + text: model.displayName + font.pixelSize: Metrics.fontSize(14) + font.bold: true + elide: Text.ElideRight + color: Appearance.m3colors.m3onSurface + } + + Text { + text: model.comment + font.pixelSize: Metrics.fontSize(11) + elide: Text.ElideRight + color: Appearance.m3colors.m3onSurfaceVariant + } + } + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: launchApp(index) + onEntered: listView.currentIndex = index + } + } + } + } + } + + Behavior on opacity { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration(400) + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.curves.standard + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/lockscreen/LockContext.qml b/.config/quickshell/nucleus-shell/modules/interface/lockscreen/LockContext.qml new file mode 100644 index 0000000..802f3fe --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/lockscreen/LockContext.qml @@ -0,0 +1,56 @@ +import QtQuick +import Quickshell +import Quickshell.Services.Pam + +// I just copied the default example and modified it. lol + +Scope { + id: root + signal unlocked() + signal failed() + + // These properties are in the context and not individual lock surfaces + // so all surfaces can share the same state. + property string currentText: "" + property bool unlockInProgress: false + property bool showFailure: false + + // Clear the failure text once the user starts typing. + onCurrentTextChanged: showFailure = false; + + function tryUnlock() { + if (currentText === "") return; + + root.unlockInProgress = true; + pam.start(); + } + + PamContext { + id: pam + + // Its best to have a custom pam config for quickshell, as the system one + // might not be what your interface expects, and break in some way. + // This particular example only supports passwords. + configDirectory: "pam" + config: "password.conf" + + // pam_unix will ask for a response for the password prompt + onPamMessage: { + if (this.responseRequired) { + this.respond(root.currentText); + } + } + + // pam_unix won't send any important messages so all we need is the completion status. + onCompleted: result => { + if (result == PamResult.Success) { + root.unlocked(); + } else { + root.currentText = ""; + root.showFailure = true; + } + + root.unlockInProgress = false; + } + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/interface/lockscreen/LockScreen.qml b/.config/quickshell/nucleus-shell/modules/interface/lockscreen/LockScreen.qml new file mode 100644 index 0000000..f48340d --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/lockscreen/LockScreen.qml @@ -0,0 +1,41 @@ +import Quickshell +import Quickshell.Io +import Quickshell.Wayland + +Scope { + // This stores all the information shared between the lock surfaces on each screen. + LockContext { + id: lockContext + + onUnlocked: { + // Unlock the screen before exiting, or the compositor will display a + // fallback lock you can't interact with. + lock.locked = false; + + } + } + + WlSessionLock { + id: lock + + // Lock the session immediately when quickshell starts. + locked: false + + WlSessionLockSurface { + LockSurface { + anchors.fill: parent + context: lockContext + } + } + } + + IpcHandler { + target: "lockscreen" + function lock() { + lock.locked = true; + } + function unlock() { + lock.locked = false; + } + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/interface/lockscreen/LockSurface.qml b/.config/quickshell/nucleus-shell/modules/interface/lockscreen/LockSurface.qml new file mode 100644 index 0000000..8c28aa5 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/lockscreen/LockSurface.qml @@ -0,0 +1,267 @@ +import "../../components/morphedPolygons/geometry/offset.js" as Offset +import "../../components/morphedPolygons/material-shapes.js" as MaterialShapes // For polygons +import "../../components/morphedPolygons/shapes/corner-rounding.js" as CornerRounding +import QtQuick +import QtQuick.Controls.Fusion +import QtQuick.Layouts +import Quickshell.Wayland +import qs.config +import qs.modules.functions +import qs.modules.interface.background +import qs.modules.components +import qs.modules.components.morphedPolygons +import qs.services + +Rectangle { + id: root + + required property LockContext context + + color: "transparent" + + Image { + anchors.fill: parent + z: -1 + source: Config.runtime.appearance.background.path + } + + RowLayout { + spacing: Metrics.spacing(20) + + anchors { + top: parent.top + right: parent.right + topMargin: Metrics.spacing(20) + rightMargin: Metrics.spacing(30) + } + + MaterialSymbol { + id: themeIcon + + fill: 1 + icon: Config.runtime.appearance.theme === "light" ? "light_mode" : "dark_mode" + iconSize: Metrics.fontSize("hugeass") + } + + MaterialSymbol { + id: wifi + + icon: Network.icon + iconSize: Metrics.fontSize("hugeass") + } + + MaterialSymbol { + id: btIcon + + icon: Bluetooth.icon + iconSize: Metrics.fontSize("hugeass") + } + + StyledText { + id: keyboardLayoutIcon + + text: SystemDetails.keyboardLayout + font.pixelSize: Metrics.fontSize(Appearance.font.size.huge - 4) + } + + } + + ColumnLayout { + + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + topMargin: Metrics.margin(150) + } + + StyledText { + id: clock + + visible: !Config.runtime.appearance.background.clock.isAnalog + Layout.alignment: Qt.AlignBottom + animate: false + renderType: Text.NativeRendering + font.pixelSize: Metrics.fontSize(180) + text: Time.format("hh:mm") + } + + StyledText { + id: date + + visible: !Config.runtime.appearance.background.clock.isAnalog + Layout.alignment: Qt.AlignCenter + animate: false + renderType: Text.NativeRendering + font.pixelSize: Metrics.fontSize(50) + text: Time.format("dddd, dd/MM") + } + + Item { + id: analogClockContainer + + property int hours: parseInt(Time.format("hh")) + property int minutes: parseInt(Time.format("mm")) + property int seconds: parseInt(Time.format("ss")) + readonly property real cx: width / 2 + readonly property real cy: height / 2 + property var shapes: [MaterialShapes.getCookie7Sided, MaterialShapes.getCookie9Sided, MaterialShapes.getCookie12Sided, MaterialShapes.getPixelCircle, MaterialShapes.getCircle, MaterialShapes.getGhostish] + + visible: Config.runtime.appearance.background.clock.isAnalog + width: 350 + height: 350 + + // Polygon + MorphedPolygon { + id: shapeCanvas + + anchors.fill: parent + color: Appearance.m3colors.m3secondaryContainer + roundedPolygon: analogClockContainer.shapes[Config.runtime.appearance.background.clock.shape]() + } + + ClockDial { + anchors.fill: parent + anchors.margins: parent.width * 0.12 + color: Appearance.colors.colOnSecondaryContainer + z: 0 + } + + // Hour hand + StyledRect { + z: 2 + width: 10 + height: parent.height * 0.3 + radius: Metrics.radius("full") + color: Qt.darker(Appearance.m3colors.m3secondary, 0.8) + x: analogClockContainer.cx - width / 2 + y: analogClockContainer.cy - height + transformOrigin: Item.Bottom + rotation: (analogClockContainer.hours % 12 + analogClockContainer.minutes / 60) * 30 + } + + StyledRect { + anchors.centerIn: parent + width: 16 + height: 16 + radius: width / 2 + color: Appearance.m3colors.m3secondary + z: 99 // Ensures its on top of everthing + + // Inner dot + StyledRect { + width: parent.width / 2 + height: parent.height / 2 + radius: width / 2 + anchors.centerIn: parent + z: 100 + color: Appearance.m3colors.m3primaryContainer + } + + } + + // Minute hand + StyledRect { + width: 14 + height: parent.height * 0.35 + radius: Metrics.radius("full") + color: Appearance.m3colors.m3secondary + x: analogClockContainer.cx - width / 2 + y: analogClockContainer.cy - height + transformOrigin: Item.Bottom + rotation: analogClockContainer.minutes * 6 + z: 10 // On top of all hands + } + + // Second hand + StyledRect { + visible: true + width: 4 + height: parent.height * 0.28 + radius: Metrics.radius("full") + color: Appearance.m3colors.m3error + x: analogClockContainer.cx - width / 2 + y: analogClockContainer.cy - height + transformOrigin: Item.Bottom + rotation: analogClockContainer.seconds * 6 + z: 2 + } + + StyledText { + text: Time.format("hh") + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Metrics.margin(60) + font.pixelSize: Metrics.fontSize(100) + font.bold: true + opacity: 0.3 + animate: false + } + + StyledText { + text: Time.format("mm") + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: Metrics.margin(150) + font.pixelSize: Metrics.fontSize(100) + font.bold: true + opacity: 0.3 + animate: false + } + + } + + } + + ColumnLayout { + // Commenting this will make the password entry visible on all monitors. + visible: Window.active + + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + bottomMargin: Metrics.margin(20) + } + + RowLayout { + StyledTextField { + id: passwordBox + + implicitWidth: 300 + padding: Metrics.padding(10) + placeholder: root.context.showFailure ? "Incorrect Password" : "Enter Password" + focus: true + enabled: !root.context.unlockInProgress + echoMode: TextInput.Password + inputMethodHints: Qt.ImhSensitiveData + // Update the text in the context when the text in the box changes. + onTextChanged: root.context.currentText = this.text + // Try to unlock when enter is pressed. + onAccepted: root.context.tryUnlock() + + // Update the text in the box to match the text in the context. + // This makes sure multiple monitors have the same text. + Connections { + function onCurrentTextChanged() { + passwordBox.text = root.context.currentText; + } + + target: root.context + } + + } + + StyledButton { + icon: "chevron_right" + padding: Metrics.padding(10) + radius: Metrics.radius("unsharpenmore") + // don't steal focus from the text box + focusPolicy: Qt.NoFocus + enabled: !root.context.unlockInProgress && root.context.currentText !== "" + onClicked: root.context.tryUnlock() + } + + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/lockscreen/pam/password.conf b/.config/quickshell/nucleus-shell/modules/interface/lockscreen/pam/password.conf new file mode 100644 index 0000000..7b313c8 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/lockscreen/pam/password.conf @@ -0,0 +1 @@ +auth required pam_unix.so \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/interface/notifications/NotificationChild.qml b/.config/quickshell/nucleus-shell/modules/interface/notifications/NotificationChild.qml new file mode 100644 index 0000000..f64603a --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/notifications/NotificationChild.qml @@ -0,0 +1,144 @@ +import qs.config +import qs.modules.components +import qs.services +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets +import Quickshell.Wayland + +Rectangle { + id: root + + property bool startAnim: false + property string title: "No Title" + property string body: "No content" + property var rawNotif: null + property bool tracked: false + property string image: "" + property var buttons: [ + { label: "Okay!", onClick: () => console.log("Okay") } + ] + + opacity: tracked ? 1 : (startAnim ? 1 : 0) + Behavior on opacity { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Easing.InOutExpo + } + } + + Layout.fillWidth: true + radius: Metrics.radius("large") + + property bool hovered: mouseHandler.containsMouse + property bool clicked: mouseHandler.containsPress + color: hovered ? (clicked ? Appearance.m3colors.m3surfaceContainerHigh : Appearance.m3colors.m3surfaceContainerLow) : Appearance.m3colors.m3surface + Behavior on color { + enabled: Config.runtime.appearance.animations.enabled + ColorAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Easing.InOutExpo + } + } + implicitHeight: Math.max(content.implicitHeight + 30, 80) + + RowLayout { + id: content + anchors.fill: parent + anchors.margins: Metrics.margin(10) + spacing: Metrics.spacing(10) + + ClippingRectangle { + width: 50 + height: 50 + radius: Metrics.radius("large") + clip: true + color: root.image === "" ? Appearance.m3colors.m3surfaceContainer : "transparent" + Image { + anchors.fill: parent + source: root.image + fillMode: Image.PreserveAspectCrop + smooth: true + } + MaterialSymbol { + icon: "chat" + color: Appearance.m3colors.m3onSurfaceVariant + anchors.centerIn: parent + visible: root.image === "" + iconSize: Metrics.iconSize(22) + } + } + + ColumnLayout { + StyledText { + text: root.title + font.bold: true + font.pixelSize: Metrics.fontSize(18) + wrapMode: Text.Wrap + color: Appearance.m3colors.m3onSurface + Layout.fillWidth: true + } + + StyledText { + text: root.body.length > 123 ? root.body.substr(0, 120) + "..." : root.body + visible: root.body.length > 0 + font.pixelSize: Metrics.fontSize(12) + color: Appearance.m3colors.m3onSurfaceVariant + wrapMode: Text.Wrap + Layout.fillWidth: true + } + + RowLayout { + visible: root.buttons.length > 1 + Layout.preferredHeight: 40 + Layout.fillWidth: true + spacing: Metrics.spacing(10) + + Repeater { + model: buttons + + StyledButton { + Layout.fillWidth: true + implicitHeight: 30 + implicitWidth: 0 + text: modelData.label + base_bg: index !== 0 + ? Appearance.m3colors.m3secondaryContainer + : Appearance.m3colors.m3primary + + base_fg: index !== 0 + ? Appearance.m3colors.m3onSecondaryContainer + : Appearance.m3colors.m3onPrimary + onClicked: modelData.onClick() + } + } + } + } + } + MouseArea { + id: mouseHandler + anchors.fill: parent + hoverEnabled: true + visible: root.buttons.length === 0 || root.buttons.length === 1 + cursorShape: Qt.PointingHandCursor + onClicked: { + if (root.buttons.length === 1 && root.buttons[0].onClick) { + root.buttons[0].onClick() + root.rawNotif?.notification.dismiss() + } else if (root.buttons.length === 0) { + console.log("[Notification] Dismissed a notification with no action.") + root.rawNotif.notification.tracked = false + root.rawNotif.popup = false + root.rawNotif?.notification.dismiss() + } else { + console.log("[Notification] Dismissed a notification with multiple actions.") + root.rawNotif?.notification.dismiss() + } + } + } + Component.onCompleted: { + startAnim = true + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/interface/notifications/Notifications.qml b/.config/quickshell/nucleus-shell/modules/interface/notifications/Notifications.qml new file mode 100644 index 0000000..d39d3cb --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/notifications/Notifications.qml @@ -0,0 +1,154 @@ +import QtQuick +import QtQuick.Effects +import QtQuick.Layouts +import Quickshell +import Quickshell.Services.Notifications +import Quickshell.Wayland +import Quickshell.Widgets +import qs.services +import qs.config +import qs.modules.components + +Scope { + id: root + + property int innerSpacing: Metrics.spacing(10) + + PanelWindow { + id: window + + implicitWidth: 520 + visible: true + color: "transparent" + WlrLayershell.layer: WlrLayer.Overlay + WlrLayershell.exclusionMode: ExclusionMode.Normal + WlrLayershell.namespace: "nucleus:notification" + + anchors { + top: true + left: Config.runtime.notifications.position.endsWith("left") + bottom: true + right: Config.runtime.notifications.position.endsWith("right") + } + + Item { + id: notificationList + + anchors.leftMargin: 0 + anchors.topMargin: Metrics.margin(10) + anchors.rightMargin: 0 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + Rectangle { + id: bgRectangle + + layer.enabled: true + anchors.top: parent.top + anchors.left: parent.left + anchors.leftMargin: Metrics.margin(20) + anchors.rightMargin: Metrics.margin(20) + anchors.right: parent.right + height: window.mask.height > 0 ? window.mask.height + 40 : 0 + color: Appearance.m3colors.m3background + radius: Metrics.radius("large") + + layer.effect: MultiEffect { + shadowEnabled: true + shadowOpacity: 1 + shadowColor: Appearance.m3colors.m3shadow + shadowBlur: 1 + shadowScale: 1 + } + + Behavior on height { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Easing.InOutExpo + } + + } + + } + + Item { + id: notificationColumn + + anchors.left: parent.left + anchors.right: parent.right + + Repeater { + id: rep + + model: (!Config.runtime.notifications.doNotDisturb && Config.runtime.notifications.enabled) ? NotifServer.popups : [] + + NotificationChild { + id: child + + width: notificationColumn.width - 80 + anchors.horizontalCenter: notificationColumn.horizontalCenter + y: { + var pos = 0; + for (let i = 0; i < index; i++) { + var prev = rep.itemAt(i); + if (prev) + pos += prev.height + root.innerSpacing; + + } + return pos + 20; + } + Component.onCompleted: { + if (!modelData.shown) + modelData.shown = true; + + } + title: modelData.summary + body: modelData.body + image: modelData.image || modelData.appIcon + rawNotif: modelData + tracked: modelData.shown + buttons: modelData.actions.map((action) => { + return ({ + "label": action.text, + "onClick": () => { + return action.invoke(); + } + }); + }) + + Behavior on y { + enabled: Config.runtime.appearance.animations.enabled + NumberAnimation { + duration: Metrics.chronoDuration("normal") + easing.type: Easing.InOutExpo + } + + } + + } + + } + + } + + } + + mask: Region { + width: window.width + height: { + var total = 0; + for (let i = 0; i < rep.count; i++) { + var child = rep.itemAt(i); + if (child) + total += child.height + (i < rep.count - 1 ? root.innerSpacing : 0); + + } + return total; + } + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/overlays/BrightnessOverlay.qml b/.config/quickshell/nucleus-shell/modules/interface/overlays/BrightnessOverlay.qml new file mode 100644 index 0000000..21c2092 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/overlays/BrightnessOverlay.qml @@ -0,0 +1,99 @@ +import qs.config +import qs.modules.components +import qs.services +import QtQuick +import QtQuick.Layouts +import Quickshell.Wayland +import Quickshell +import Quickshell.Widgets + +Scope { + id: root + + Connections { + target: Brightness + + function onBrightnessChanged() { + root.shouldShowOsd = true; + hideTimer.restart(); + } + } + + property var monitor: Brightness.monitors.length > 0 ? Brightness.monitors[0] : null + + property bool shouldShowOsd: false + + Timer { + id: hideTimer + interval: 3000 + onTriggered: root.shouldShowOsd = false + } + + LazyLoader { + active: root.shouldShowOsd + + PanelWindow { + visible: Config.runtime.overlays.brightnessOverlayEnabled && Config.runtime.overlays.enabled + WlrLayershell.namespace: "nucleus:brightnessOsd" + exclusiveZone: 0 + anchors.top: Config.runtime.overlays.brightnessOverlayPosition.startsWith("top") + anchors.bottom: Config.runtime.overlays.brightnessOverlayPosition.startsWith("bottom") + anchors.right: Config.runtime.overlays.brightnessOverlayPosition.endsWith("right") + anchors.left: Config.runtime.overlays.brightnessOverlayPosition.endsWith("left") + margins { + top: Metrics.margin(10) + bottom: Metrics.margin(10) + left: Metrics.margin(10) + right: Metrics.margin(10) + } + + implicitWidth: 460 + implicitHeight: 105 + color: "transparent" + mask: Region {} + + Rectangle { + anchors.fill: parent + radius: Appearance.rounding.childish + color: Appearance.m3colors.m3background + + RowLayout { + spacing: Metrics.spacing(10) + anchors { + fill: parent + leftMargin: Metrics.margin(15) + rightMargin: Metrics.margin(25) + } + + MaterialSymbol { + property real brightnessLevel: Math.floor(Brightness.getMonitorForScreen(Hyprland.focusedMonitor)?.multipliedBrightness*100) + icon: { + if (brightnessLevel > 66) return "brightness_high" + else if (brightnessLevel > 33) return "brightness_medium" + else return "brightness_low" + } + iconSize: Metrics.iconSize(30) + } + + ColumnLayout { + implicitHeight: 40 + spacing: Metrics.spacing(5) + + StyledText { + animate: false + text: "Brightness - " + Math.round(monitor.brightness * 100) + '%' + font.pixelSize: Metrics.fontSize(18) + } + + StyledSlider { + implicitHeight: 35 + from: 0 + to: 100 + value: Math.round(monitor.brightness * 100) + } + } + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/overlays/Overlays.qml b/.config/quickshell/nucleus-shell/modules/interface/overlays/Overlays.qml new file mode 100644 index 0000000..df4aa43 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/overlays/Overlays.qml @@ -0,0 +1,8 @@ +import QtQuick +import Quickshell + +Scope { + id: root + VolumeOverlay{} + BrightnessOverlay{} +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/interface/overlays/VolumeOverlay.qml b/.config/quickshell/nucleus-shell/modules/interface/overlays/VolumeOverlay.qml new file mode 100644 index 0000000..32caef9 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/overlays/VolumeOverlay.qml @@ -0,0 +1,109 @@ +import qs.config +import qs.modules.components +import qs.services +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Wayland +import Quickshell.Services.Pipewire +import Quickshell.Widgets + +Scope { + id: root + + PwObjectTracker { + objects: [ Pipewire.defaultAudioSink ] + } + + Connections { + target: Pipewire.defaultAudioSink?.audio ?? null + + function onVolumeChanged() { + root.shouldShowOsd = true; + hideTimer.restart(); + } + + function onMutedChanged() { + root.shouldShowOsd = true; + hideTimer.restart(); + } + } + + + property bool shouldShowOsd: false + + Timer { + id: hideTimer + interval: 3000 + onTriggered: root.shouldShowOsd = false + } + + LazyLoader { + active: root.shouldShowOsd + + PanelWindow { + visible: Config.runtime.overlays.volumeOverlayEnabled && Config.runtime.overlays.enabled + WlrLayershell.namespace: "nucleus:brightnessOsd" + exclusiveZone: 0 + anchors.top: Config.runtime.overlays.volumeOverlayPosition.startsWith("top") + anchors.bottom: Config.runtime.overlays.volumeOverlayPosition.startsWith("bottom") + anchors.right: Config.runtime.overlays.volumeOverlayPosition.endsWith("right") + anchors.left: Config.runtime.overlays.volumeOverlayPosition.endsWith("left") + margins { + top: Metrics.margin(10) + bottom: Metrics.margin(10) + left: Metrics.margin(10) + right: Metrics.margin(10) + } + implicitWidth: 460 + implicitHeight: 105 + color: "transparent" + + mask: Region {} + + + Rectangle { + anchors.fill: parent + radius: Appearance.rounding.childish + color: Appearance.m3colors.m3background + + RowLayout { + spacing: Metrics.spacing(10) + anchors { + fill: parent + leftMargin: Metrics.margin(15) + rightMargin: Metrics.margin(25) + } + + MaterialSymbol { + property real volume: Pipewire.defaultAudioSink?.audio.muted ? 0 : Pipewire.defaultAudioSink?.audio.volume * 100 + icon: volume > 50 ? "volume_up" : volume > 0 ? "volume_down" : 'volume_off' + iconSize: Metrics.iconSize(34); + } + + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + spacing: Metrics.spacing(2) + + StyledText { + Layout.fillWidth: true + elide: Text.ElideRight + + animate: false + text: (Pipewire.defaultAudioSink?.description ?? "Unknown") + " - " + + (Pipewire.defaultAudioSink?.audio.muted ? 'Muted' : Math.floor(Pipewire.defaultAudioSink?.audio.volume * 100) + '%') + font.pixelSize: Metrics.fontSize(18) + } + + StyledSlider { + Layout.fillWidth: true + implicitHeight: 35 + value: (Pipewire.defaultAudioSink?.audio.muted ? 0 : Pipewire.defaultAudioSink?.audio.volume) * 100 + } + } + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/polkit/PolkitAgent.qml b/.config/quickshell/nucleus-shell/modules/interface/polkit/PolkitAgent.qml new file mode 100644 index 0000000..b9b8dd5 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/polkit/PolkitAgent.qml @@ -0,0 +1,207 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Effects + +import Quickshell +import Quickshell.Wayland + +import qs.config +import qs.services +import qs.modules.components + + +Scope { + id: root + property bool active: false + property var window: null + + Connections { + target: Polkit + function onIsActiveChanged() { + if (Polkit.isActive) { + root.active = true; + } else if (root.active && window) { + window.closeWithAnimation(); + } + } + } + + LazyLoader { + active: root.active + component: Prompt { + id: window + + Component.onCompleted: root.window = window + Component.onDestruction: root.window = null + + onFadeOutFinished: root.active = false + + Item { + id: promptContainer + property bool showPassword: false + property bool authenticating: false + + anchors.centerIn: parent + width: promptBg.width + height: promptBg.height + + Item { + Component.onCompleted: { + parent.layer.enabled = true; + parent.layer.effect = effectComponent; + } + + Component { + id: effectComponent + MultiEffect { + shadowEnabled: true + shadowOpacity: 1 + shadowColor: Appearance.colors.m3shadow + shadowBlur: 1 + shadowScale: 1 + } + } + } + + Rectangle { + id: promptBg + width: promptLayout.width + 40 + height: promptLayout.height + 40 + color: Appearance.m3colors.m3surface + radius: Metrics.radius(20) + + Behavior on height { + NumberAnimation { + duration: Metrics.chronoDuration("small") + easing.type: Appearance.animation.easing + } + } + } + + ColumnLayout { + id: promptLayout + spacing: Metrics.spacing(10) + anchors { + left: promptBg.left + leftMargin: Metrics.margin(20) + top: promptBg.top + topMargin: Metrics.margin(20) + } + + ColumnLayout { + spacing: Metrics.spacing(5) + MaterialSymbol { + icon: "security" + color: Appearance.m3colors.m3primary + font.pixelSize: Metrics.fontSize(22) + Layout.alignment: Qt.AlignHCenter + } + StyledText { + text: "Authentication required" + font.family: "Outfit SemiBold" + font.pixelSize: Metrics.fontSize(20) + Layout.alignment: Qt.AlignHCenter + } + StyledText { + text: Polkit.flow.message + Layout.alignment: Qt.AlignHCenter + } + } + + RowLayout { + spacing: Metrics.spacing(5) + StyledTextField { + id: textfield + Layout.fillWidth: true + leftPadding: undefined + padding: Metrics.padding(10) + filled: false + enabled: !promptContainer.authenticating + placeholder: Polkit.flow.inputPrompt.substring(0, Polkit.flow.inputPrompt.length - 2) + echoMode: promptContainer.showPassword ? TextInput.Normal : TextInput.Password + inputMethodHints: Qt.ImhSensitiveData + focus: true + Keys.onReturnPressed: okButton.clicked() + } + StyledButton { + Layout.fillHeight: true + width: height + radius: Metrics.radius(10) + topLeftRadius: Metrics.radius(5) + bottomLeftRadius: Metrics.radius(5) + enabled: !promptContainer.authenticating + checkable: true + checked: promptContainer.showPassword + icon: promptContainer.showPassword ? 'visibility' : 'visibility_off' + onToggled: promptContainer.showPassword = !promptContainer.showPassword + } + } + + + RowLayout { + RowLayout { + visible: Polkit.flow.failed && !Polkit.flow.isSuccessful && !promptContainer.authenticating + MaterialSymbol { + icon: "warning" + color: Appearance.m3colors.m3error + font.pixelSize: Metrics.fontSize(15) + } + StyledText { + text: "Failed to authenticate, incorrect password." + color: Appearance.m3colors.m3error + font.pixelSize: Metrics.fontSize(15) + } + } + LoadingIcon { + visible: promptContainer.authenticating + Layout.alignment: Qt.AlignLeft + } + Item { + Layout.fillWidth: true + } + StyledButton { + radius: Metrics.radius(10) + topRightRadius: Metrics.radius(5) + bottomRightRadius: Metrics.radius(5) + secondary: true + text: "Cancel" + // enabled: !promptContainer.authenticating (Allows to cancel if stuck in loop) + onClicked: Polkit.flow.cancelAuthenticationRequest() + } + StyledButton { + id: okButton + radius: Metrics.radius(10) + topLeftRadius: Metrics.radius(5) + bottomLeftRadius: Metrics.radius(5) + text: promptContainer.authenticating ? "Authenticating..." : "OK" + enabled: !promptContainer.authenticating + onClicked: { + promptContainer.authenticating = true; + Polkit.flow.submit(textfield.text); + } + } + } + } + + Connections { + target: Polkit.flow + function onIsCompletedChanged() { + if (Polkit.flow.isCompleted) { + promptContainer.authenticating = false; + } + } + function onFailedChanged() { + if (Polkit.flow.failed) { + promptContainer.authenticating = false; + } + } + function onIsCancelledChanged() { + if (Polkit.flow.isCancelled) { + promptContainer.authenticating = false; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/interface/polkit/Prompt.qml b/.config/quickshell/nucleus-shell/modules/interface/polkit/Prompt.qml new file mode 100644 index 0000000..da52a26 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/polkit/Prompt.qml @@ -0,0 +1,151 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Effects + +import Quickshell +import Quickshell.Wayland + +import qs.config +import qs.services +import qs.modules.components + +PanelWindow { + id: window + property bool isClosing: false + default property alias content: contentContainer.data + signal fadeOutFinished() + + anchors { + top: true + left: true + right: true + bottom: true + } + WlrLayershell.layer: WlrLayer.Overlay + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive + color: "transparent" + WlrLayershell.namespace: "nucleus:prompt" + + function closeWithAnimation() { + if (isClosing) return + isClosing = true + fadeOutAnim.start() + } + + Item { + anchors.fill: parent + + Keys.onPressed: { + if (event.key === Qt.Key_Escape) { + window.closeWithAnimation() + } + } + + ScreencopyView { + id: screencopy + visible: hasContent + captureSource: window.screen + anchors.fill: parent + opacity: 0 + scale: 1 + layer.enabled: true + layer.effect: MultiEffect { + blurEnabled: true + blur: 1 + blurMax: 32 + brightness: -0.05 + layer.enabled: true + layer.effect: MultiEffect { + autoPaddingEnabled: false + blurEnabled: true + blur: 1 + blurMax: 32 + } + } + } + + NumberAnimation { + id: fadeInAnim + target: screencopy + property: "opacity" + from: 0 + to: 1 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + running: screencopy.visible && !window.isClosing + } + + ParallelAnimation { + id: scaleInAnim + running: screencopy.visible && !window.isClosing + NumberAnimation { + target: contentContainer + property: "scale" + from: 0.9 + to: 1 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + ColorAnimation { + target: window + property: "color" + from: "transparent" + to: Appearance.m3colors.m3surface + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + NumberAnimation { + target: contentContainer + property: "opacity" + from: 0 + to: 1 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + } + + ParallelAnimation { + id: fadeOutAnim + NumberAnimation { + target: screencopy + property: "opacity" + to: 0 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + ColorAnimation { + target: window + property: "color" + to: "transparent" + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + NumberAnimation { + target: contentContainer + property: "opacity" + to: 0 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + NumberAnimation { + target: contentContainer + property: "scale" + to: 0.9 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + onFinished: { + window.visible = false + window.fadeOutFinished() + } + } + + Item { + id: contentContainer + anchors.fill: parent + opacity: 0 + scale: 0.9 + } + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/interface/powermenu/Powermenu.qml b/.config/quickshell/nucleus-shell/modules/interface/powermenu/Powermenu.qml new file mode 100644 index 0000000..bd6a4dc --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/powermenu/Powermenu.qml @@ -0,0 +1,153 @@ +import Qt5Compat.GraphicalEffects +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Hyprland +import Quickshell.Io +import Quickshell.Services.Pipewire +import Quickshell.Wayland +import qs.config +import qs.modules.functions +import qs.services +import qs.modules.interface.lockscreen +import qs.modules.components + +PanelWindow { + id: powermenu + + WlrLayershell.keyboardFocus: Compositor.require("hyprland") && Globals.visiblility.powermenu + + function togglepowermenu() { + Globals.visiblility.powermenu = !Globals.visiblility.powermenu; // Simple toggle logic kept in a function as it might have more things to it later on. + } + + WlrLayershell.namespace: "nucleus:powermenu" + WlrLayershell.layer: WlrLayer.Top + visible: Config.initialized && Globals.visiblility.powermenu + color: "transparent" + exclusiveZone: 0 + implicitWidth: DisplayMetrics.scaledWidth(0.25) + implicitHeight: DisplayMetrics.scaledWidth(0.168) + + HyprlandFocusGrab { + id: grab + + active: Compositor.require("hyprland") + windows: [powermenu] + } + + StyledRect { + id: container + + color: Appearance.m3colors.m3background + radius: Metrics.radius("verylarge") + implicitWidth: powermenu.implicitWidth + anchors.fill: parent + + FocusScope { + focus: true + anchors.fill: parent + Keys.onPressed: { + if (event.key === Qt.Key_Escape) + Globals.visiblility.powermenu = false; + + } + + Item { + id: content + + anchors.margins: Metrics.radius(12) + anchors.topMargin: Metrics.radius(16) + anchors.leftMargin: Metrics.radius(18) + anchors.fill: parent + + Grid { + columns: 3 + rows: 3 + rowSpacing: Metrics.spacing(10) + columnSpacing: Metrics.spacing(10) + anchors.fill: parent + + PowerMenuButton { + buttonIcon: "power_settings_new" + onClicked: { + Quickshell.execDetached(["poweroff"]); + Globals.visiblility.powermenu = false; + } + } + + PowerMenuButton { + buttonIcon: "logout" + onClicked: { + Quickshell.execDetached(["hyprctl", "dispatch", "exit"]); + Globals.visiblility.powermenu = false; + } + } + + PowerMenuButton { + buttonIcon: "sleep" + onClicked: { + Quickshell.execDetached(["systemctl", "suspend"]); + Globals.visiblility.powermenu = false; + } + } + + PowerMenuButton { + buttonIcon: "lock" + onClicked: { + Quickshell.execDetached(["nucleus", "ipc", "call", "lockscreen", "lock"]); + Globals.visiblility.powermenu = false; + } + } + + PowerMenuButton { + buttonIcon: "restart_alt" + onClicked: { + Quickshell.execDetached(["reboot"]); + Globals.visiblility.powermenu = false; + } + } + + PowerMenuButton { + buttonIcon: "light_off" + onClicked: { + Quickshell.execDetached(["systemctl", "hibernate"]); + Globals.visiblility.powermenu = false; + } + } + + } + + component Anim: NumberAnimation { + running: Config.runtime.appearance.animations.enabled + duration: Metrics.chronoDuration(400) + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.curves.standard + } + + } + + } + + } + + IpcHandler { + function toggle() { + togglepowermenu(); + } + + target: "powermenu" + } + + component PowerMenuButton: StyledButton { + property string buttonIcon + + icon: buttonIcon + iconSize: Metrics.iconSize(50) + width: powermenu.implicitWidth / 3.4 + height: powermenu.implicitHeight / 2.3 + radius: beingHovered ? Metrics.radius("verylarge") * 2 : Metrics.radius("large") + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/screencapture/ScreenCapture.qml b/.config/quickshell/nucleus-shell/modules/interface/screencapture/ScreenCapture.qml new file mode 100644 index 0000000..4402b81 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/screencapture/ScreenCapture.qml @@ -0,0 +1,606 @@ +pragma ComponentBehavior: Bound +import Quickshell +import Quickshell.Hyprland +import Quickshell.Io +import QtQuick +import QtQuick.Layouts +import QtQuick.Effects +import Quickshell.Wayland +import qs.config +import qs.modules.components + +Scope { + id: root + property bool active: false + property rect selectedRegion: Qt.rect(0, 0, 0, 0) + property string tempScreenshot: "" + + IpcHandler { + target: "screen" + function capture() { + if (root.active) { + console.info("screencap", "already active"); + return; + } + console.info("screencap", "starting capture"); + root.active = true; + } + } + + LazyLoader { + active: root.active + component: PanelWindow { + id: win + property bool closing: false + property bool ready: false + property bool processing: false + property bool windowMode: false + property string savedPath: "" + property bool savedSuccess: false + + color: Appearance.m3colors.m3surface + anchors { top: true; left: true; right: true; bottom: true } + WlrLayershell.layer: WlrLayer.Overlay + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.namespace: "nucleus:screencapture" + + Component.onCompleted: { + var ts = Qt.formatDateTime(new Date(), "yyyy-MM-dd_hh-mm-ss"); + root.tempScreenshot = "/tmp/screenshot_" + ts + ".png"; + } + + function close() { + if (closing) return; + closing = true; + closeAnim.start(); + } + + function saveFullscreen() { + console.info("screencap", "saveFullscreen started"); + win.processing = true; + screencopy.grabToImage(function(result) { + console.info("screencap", "fullscreen grabbed"); + var ts = Qt.formatDateTime(new Date(), "yyyy-MM-dd_hh-mm-ss"); + win.savedPath = Quickshell.env("HOME") + "/Pictures/Screenshots/screenshot_" + ts + ".png"; + + console.info("screencap", "saving to: " + win.savedPath); + if (result.saveToFile(win.savedPath)) { + console.info("screencap", "saved, copying"); + Quickshell.execDetached({ + command: ["sh", "-c", "cat '" + win.savedPath + "' | wl-copy --type image/png"] + }); + win.savedSuccess = true; + } else { + console.info("screencap", "save failed"); + win.savedSuccess = false; + } + win.processing = false; + console.info("screencap", "closing window"); + win.close(); + }); + } + + Component { + id: ffmpegProc + Process { + property string outputPath + property bool success: false + + onExited: (code) => { + console.info("screencap", "ffmpeg exited: " + code); + success = code === 0; + + if (success) { + console.info("screencap", "copying to clipboard"); + Quickshell.execDetached({ + command: ["sh", "-c", "cat '" + outputPath + "' | wl-copy --type image/png"] + }); + } + + Quickshell.execDetached({ command: ["rm", root.tempScreenshot] }); + + win.savedSuccess = success; + win.processing = false; + console.info("screencap", "done, closing"); + win.close(); + destroy(); + } + } + } + + function saveRegion(rect, suffix) { + console.info("screencap", "saveRegion started: " + rect.x + "," + rect.y + " " + rect.width + "x" + rect.height); + screencopy.grabToImage(function(result) { + console.info("screencap", "full screenshot grabbed for cropping"); + if (!result.saveToFile(root.tempScreenshot)) { + console.info("screencap", "ERROR: failed to save temp screenshot"); + win.savedSuccess = false; + win.processing = false; + win.close(); + return; + } + + console.info("screencap", "temp saved, cropping with ffmpeg"); + var ts = Qt.formatDateTime(new Date(), "yyyy-MM-dd_hh-mm-ss"); + win.savedPath = Quickshell.env("HOME") + "/Pictures/Screenshots/screenshot_" + ts + suffix + ".png"; + + ffmpegProc.createObject(win, { + command: ["ffmpeg", "-i", root.tempScreenshot, "-vf", "crop=" + Math.floor(rect.width) + ":" + Math.floor(rect.height) + ":" + Math.floor(rect.x) + ":" + Math.floor(rect.y), "-y", win.savedPath], + outputPath: win.savedPath, + running: true + }); + }); + } + + function captureFullscreen() { + win.processing = true; + saveFullscreen(); + } + + function captureWindow(rect) { + win.processing = true; + saveRegion(rect, "_window"); + } + + function captureRegion() { + if (!ready || !selection.hasSelection) return; + win.processing = true; + saveRegion(root.selectedRegion, "_region"); + } + + ScreencopyView { + id: screencopy + anchors.fill: parent + captureSource: win.screen + z: -999 + live: false + + onHasContentChanged: { + console.info("screencap", "hasContent: " + hasContent); + if (hasContent) { + console.info("screencap", "grabbing for preview"); + grabToImage(function(result) { + console.info("screencap", "preview grabbed: " + result.url); + frozen.source = result.url; + readyTimer.start(); + }); + } + } + } + + Timer { + id: readyTimer + interval: Metrics.chronoDuration("normal") + 50 + onTriggered: { + console.info("screencap", "UI ready"); + win.ready = true; + } + } + + Item { + anchors.fill: parent + focus: true + + Keys.onEscapePressed: win.close() + Keys.onPressed: event => { + if (event.key === Qt.Key_F) { + win.captureFullscreen(); + event.accepted = true; + } else if (event.key === Qt.Key_W) { + win.windowMode = !win.windowMode; + event.accepted = true; + } + } + + Image { + id: bg + anchors.fill: parent + source: Config.runtime.appearance.background.path + fillMode: Image.PreserveAspectCrop + opacity: 0 + scale: 1 + + layer.enabled: true + layer.effect: MultiEffect { + blurEnabled: true + blur: 1.0 + blurMax: 64 + brightness: -0.1 + } + + onStatusChanged: { + if (status === Image.Ready) fadeIn.start(); + } + + NumberAnimation on opacity { + id: fadeIn + to: 1 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + } + + Item { + id: container + anchors.centerIn: parent + width: win.width + height: win.height + + layer.enabled: true + layer.effect: MultiEffect { + shadowEnabled: true + shadowOpacity: 1 + shadowColor: Appearance.m3colors.m3shadow + } + + Image { + id: frozen + anchors.fill: parent + fillMode: Image.PreserveAspectFit + smooth: true + cache: false + } + + Item { + id: darkOverlay + anchors.fill: parent + visible: (selection.hasSelection || selection.selecting) && !win.windowMode + + Rectangle { + y: 0 + width: parent.width + height: selection.sy + color: "black" + opacity: 0.5 + } + Rectangle { + y: selection.sy + selection.h + width: parent.width + height: parent.height - (selection.sy + selection.h) + color: "black" + opacity: 0.5 + } + Rectangle { + x: 0 + y: selection.sy + width: selection.sx + height: selection.h + color: "black" + opacity: 0.5 + } + Rectangle { + x: selection.sx + selection.w + y: selection.sy + width: parent.width - (selection.sx + selection.w) + height: selection.h + color: "black" + opacity: 0.5 + } + + Rectangle { + x: selection.sx + y: selection.sy + width: selection.w + height: selection.h + color: "black" + opacity: win.processing ? 0.6 : 0 + + Behavior on opacity { + NumberAnimation { duration: 200 } + } + + LoadingIcon { + anchors.centerIn: parent + visible: win.processing + } + } + } + + Rectangle { + id: outline + x: selection.sx + y: selection.sy + width: selection.w + height: selection.h + color: "transparent" + border.color: Appearance.m3colors.m3primary + border.width: 2 + visible: (selection.selecting || selection.hasSelection) && !win.windowMode + } + + Rectangle { + visible: selection.selecting + anchors.top: outline.bottom + anchors.topMargin: Metrics.margin(10) + anchors.horizontalCenter: outline.horizontalCenter + width: coords.width + 10 + height: coords.height + 10 + color: Appearance.m3colors.m3surface + radius: Metrics.radius(20) + + StyledText { + id: coords + anchors.centerIn: parent + font.pixelSize: Metrics.fontSize(14) + animate: false + color: Appearance.m3colors.m3onSurface + property real scaleX: container.width / win.width + property real scaleY: container.height / win.height + text: Math.floor(selection.sx/scaleX) + "," + Math.floor(selection.sy/scaleY) + " " + Math.floor(selection.w/scaleX) + "x" + Math.floor(selection.h/scaleY) + } + } + + MouseArea { + id: selection + anchors.fill: parent + enabled: win.ready && !win.windowMode + + property real x1: 0 + property real y1: 0 + property real x2: 0 + property real y2: 0 + property bool selecting: false + property bool hasSelection: false + + property real xp: 0 + property real yp: 0 + property real wp: 0 + property real hp: 0 + + property real sx: xp * parent.width + property real sy: yp * parent.height + property real w: wp * parent.width + property real h: hp * parent.height + + onPressed: mouse => { + if (!win.ready) return; + x1 = Math.max(0, Math.min(mouse.x, width)); + y1 = Math.max(0, Math.min(mouse.y, height)); + x2 = x1; + y2 = y1; + selecting = true; + hasSelection = false; + } + + onPositionChanged: mouse => { + if (selecting) { + x2 = Math.max(0, Math.min(mouse.x, width)); + y2 = Math.max(0, Math.min(mouse.y, height)); + xp = Math.min(x1, x2) / width; + yp = Math.min(y1, y2) / height; + wp = Math.abs(x2 - x1) / width; + hp = Math.abs(y2 - y1) / height; + } + } + + onReleased: mouse => { + if (!selecting) return; + + x2 = Math.max(0, Math.min(mouse.x, width)); + y2 = Math.max(0, Math.min(mouse.y, height)); + selecting = false; + + hasSelection = Math.abs(x2 - x1) > 5 && Math.abs(y2 - y1) > 5; + + if (hasSelection) { + xp = Math.min(x1, x2) / width; + yp = Math.min(y1, y2) / height; + wp = Math.abs(x2 - x1) / width; + hp = Math.abs(y2 - y1) / height; + + root.selectedRegion = Qt.rect( + Math.min(x1, x2) * win.screen.width / width, + Math.min(y1, y2) * win.screen.height / height, + Math.abs(x2 - x1) * win.screen.width / width, + Math.abs(y2 - y1) * win.screen.height / height + ); + + win.captureRegion(); + } else { + win.close(); + } + } + } + + Repeater { + model: { + if (!win.windowMode || !win.ready) return []; + var ws = Hyprland.focusedMonitor?.activeWorkspace; + return ws?.toplevels ? ws.toplevels.values : []; + } + + delegate: Item { + required property var modelData + property var w: modelData?.lastIpcObject + visible: w?.at && w?.size + + property real barX: 0 + property real barY: 0 + property real sx: container.width / (win.screen.width - barX) + property real sy: container.height / (win.screen.height - barY) + + x: visible ? (w.at[0] - barX) * sx : 0 + y: visible ? (w.at[1] - barY) * sy : 0 + width: visible ? w.size[0] * sx : 0 + height: visible ? w.size[1] * sy : 0 + z: w?.floating ? (hover.containsMouse ? 1000 : 100) : (hover.containsMouse ? 50 : 0) + + Rectangle { + anchors.fill: parent + color: "transparent" + border.color: Appearance.m3colors.m3primary + border.width: hover.containsMouse ? 3 : 0 + radius: Metrics.radius(8) + Behavior on border.width { + NumberAnimation { duration: Metrics.chronoDuration(150) } + } + } + + Rectangle { + anchors.fill: parent + color: Appearance.m3colors.m3primary + opacity: hover.containsMouse ? 0.15 : 0 + radius: Metrics.radius(8) + Behavior on opacity { + NumberAnimation { duration: Metrics.chronoDuration(150) } + } + } + + MouseArea { + id: hover + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + win.captureWindow(Qt.rect(w.at[0], w.at[1], w.size[0], w.size[1])); + } + } + } + } + + ParallelAnimation { + running: win.visible && !win.closing && frozen.source != "" + + NumberAnimation { + target: bg + property: "scale" + to: bg.scale + 0.05 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + NumberAnimation { + target: container + property: "width" + to: win.width * 0.8 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + NumberAnimation { + target: container + property: "height" + to: win.height * 0.8 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + } + + ParallelAnimation { + id: closeAnim + + NumberAnimation { + target: bg + property: "scale" + to: bg.scale - 0.05 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + NumberAnimation { + target: container + property: "width" + to: win.width + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + NumberAnimation { + target: container + property: "height" + to: win.height + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + NumberAnimation { + target: darkOverlay + property: "opacity" + to: 0 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + NumberAnimation { + target: outline + property: "opacity" + to: 0 + duration: Metrics.chronoDuration("normal") + easing.type: Appearance.animation.easing + } + + onFinished: { + root.active = false; + if (win.savedSuccess) { + Quickshell.execDetached({ + command: ["notify-send", "Screenshot saved", win.savedPath.split("/").pop() + " (copied)"] + }); + } else if (win.savedPath !== "") { + Quickshell.execDetached({ + command: ["notify-send", "Screenshot failed", "Could not save"] + }); + } + } + } + } + + Item { + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: Metrics.margin(30) + width: row.width + 20 + height: row.height + 20 + visible: true + + Rectangle { + anchors.fill: parent + color: Appearance.m3colors.m3surface + radius: Metrics.radius("large") + } + + RowLayout { + id: row + anchors.centerIn: parent + + StyledButton { + icon: "fullscreen" + text: "Full screen" + tooltipText: "Capture the whole screen [F]" + onClicked: win.captureFullscreen() + } + Rectangle { + Layout.fillHeight: true + width: 2 + color: Appearance.m3colors.m3onSurfaceVariant + opacity: 0.2 + } + StyledButton { + icon: "window" + checkable: true + checked: win.windowMode + text: "Window" + tooltipText: "Hover and click a window [W]" + onClicked: win.windowMode = !win.windowMode + } + StyledButton { + secondary: true + icon: "close" + tooltipText: "Exit [Escape]" + onClicked: win.close() + } + } + } + } + + HyprlandFocusGrab { + id: grab + windows: [win] + } + + onVisibleChanged: { + if (visible) grab.active = true + } + + Connections { + target: grab + function onActiveChanged() { + if (!grab.active && !win.closing) win.close(); + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/About.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/About.qml new file mode 100644 index 0000000..9f10c18 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/About.qml @@ -0,0 +1,115 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets +import qs.config +import qs.modules.components +import qs.config +import qs.services + +Item { + id: root + + Layout.fillWidth: true + Layout.fillHeight: true + property int logoOffset: -30 + + Column { + anchors.centerIn: parent + width: 460 + spacing: Metrics.spacing(12) + Item { + width: parent.width + height: Metrics.fontSize(200) + + StyledText { + text: SystemDetails.osIcon + anchors.centerIn: parent + x: root.logoOffset + font.pixelSize: Metrics.fontSize(200) + } + } + + StyledText { + text: "Nucleus Shell" + width: parent.width + horizontalAlignment: Text.AlignHCenter + font.family: "Outfit ExtraBold" + font.pixelSize: Metrics.fontSize(26) + } + + StyledText { + text: "A shell built to get things done." + width: parent.width + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Metrics.fontSize(14) + } + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: Metrics.spacing(10) + + StyledButton { + text: "View on GitHub" + icon: "code" + secondary: true + onClicked: Qt.openUrlExternally("https://github.com/xZepyx/nucleus-shell") + } + + StyledButton { + text: "Report Issue" + icon: "bug_report" + secondary: true + onClicked: Qt.openUrlExternally("https://github.com/xZepyx/nucleus-shell/issues") + } + + } + + } + + StyledText { + text: "Nucleus-Shell v" + Config.runtime.shell.version + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: Metrics.margin(24) + font.pixelSize: Metrics.fontSize(12) + } + + StyledRect { + width: 52 + height: 52 + radius: Appearance.rounding.small + + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: Metrics.margin(24) + + StyledText { + text: "↻" + anchors.centerIn: parent + font.pixelSize: Metrics.fontSize(22) + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + + onClicked: { + Globals.states.settingsOpen = false + + Quickshell.execDetached(["notify-send", "Updating Nucleus Shell"]) + + Quickshell.execDetached([ + "kitty", + "--hold", + "bash", + "-c", + Directories.scriptsPath + "/system/update.sh" + ]) + } + } + + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/AppearanceConfig.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/AppearanceConfig.qml new file mode 100644 index 0000000..23a7e8e --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/AppearanceConfig.qml @@ -0,0 +1,364 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import qs.config +import qs.modules.components +import qs.services +import qs.plugins + +ContentMenu { + title: "Appearance" + description: "Adjust how the desktop looks like." + + ContentCard { + ColumnLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(16) + + ColumnLayout { + spacing: Metrics.spacing(4) + + StyledText { + text: "Select Theme" + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: "Choose between dark or light mode." + font.pixelSize: Metrics.fontSize(12) + color: "#888888" + } + } + + RowLayout { + Layout.leftMargin: Metrics.margin(15) + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + spacing: Metrics.spacing(16) + + StyledButton { + Layout.preferredHeight: 300 + Layout.preferredWidth: 460 + Layout.maximumHeight: 400 + Layout.maximumWidth: 500 + icon: "dark_mode" + iconSize: Metrics.iconSize(64) + checked: Config.runtime.appearance.theme === "dark" + hoverEnabled: true + + onClicked: { + if (!Config.runtime.appearance.colors.autogenerated) { + const scheme = Config.runtime.appearance.colors.scheme + const file = Theme.map[scheme]?.dark + if (!file) { + Theme.notifyMissingVariant(scheme, "dark") + return + } + + Config.updateKey("appearance.theme", "dark") + Quickshell.execDetached([ + "nucleus", "theme", "switch", file + ]) + } else { + Config.updateKey("appearance.theme", "dark") + Quickshell.execDetached([ + "nucleus", "ipc", "call", "global", "regenColors" + ]) + } + } + } + + StyledButton { + Layout.preferredHeight: 300 + Layout.preferredWidth: 460 + Layout.maximumHeight: 400 + Layout.maximumWidth: 500 + icon: "light_mode" + iconSize: Metrics.iconSize(64) + checked: Config.runtime.appearance.theme === "light" + hoverEnabled: true + + onClicked: { + if (!Config.runtime.appearance.colors.autogenerated) { + const scheme = Config.runtime.appearance.colors.scheme + const file = Theme.map[scheme]?.light + if (!file) { + Theme.notifyMissingVariant(scheme, "light") + return + } + + Config.updateKey("appearance.theme", "light") + Quickshell.execDetached([ + "nucleus", "theme", "switch", file + ]) + } else { + Config.updateKey("appearance.theme", "light") + Quickshell.execDetached([ + "nucleus", "ipc", "call", "global", "regenColors" + ]) + } + } + } + } + + Item { + width: Metrics.spacing(30) + } + } + } + + ContentCard { + RowLayout { + opacity: autogeneratedColorsSelector.enabled ? 1 : 0.8 + + ColumnLayout { + StyledText { + text: "Color Generation Schemes:" + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: "Choose the scheme for autogenerated color generation." + font.pixelSize: Metrics.fontSize(12) + } + } + + Item { Layout.fillWidth: true } + + StyledDropDown { + id: autogeneratedColorsSelector + label: "Color Scheme" + model: [ + "scheme-content", + "scheme-expressive", + "scheme-fidelity", + "scheme-fruit-salad", + "scheme-monochrome", + "scheme-neutral", + "scheme-rainbow", + "scheme-tonal-spot" + ] + + currentIndex: model.indexOf(Config.runtime.appearance.colors.matugenScheme) + + onSelectedIndexChanged: (index) => { + if (!Config.runtime.appearance.colors.autogenerated) + return + const selectedScheme = model[index] + Config.updateKey("appearance.colors.matugenScheme", selectedScheme) + Quickshell.execDetached([ + "nucleus", "ipc", "call", "global", "regenColors" + ]) + } + + enabled: Config.runtime.appearance.colors.autogenerated + } + } + + RowLayout { + opacity: predefinedThemeSelector.enabled ? 1 : 0.8 + + ColumnLayout { + StyledText { + font.pixelSize: Metrics.fontSize(16) + text: "Predefined/Custom Themes:" + } + + StyledText { + font.pixelSize: Metrics.fontSize(12) + text: "Choose a pre-defined theme for your interface." + } + } + + Item { Layout.fillWidth: true } + + StyledDropDown { + id: predefinedThemeSelector + label: "Theme" + model: Object.keys(Theme.map) + currentIndex: model.indexOf(Config.runtime.appearance.colors.scheme) + + onSelectedIndexChanged: (index) => { + if (Config.runtime.appearance.colors.autogenerated) + return + const selectedTheme = model[index] + const variant = Config.runtime.appearance.theme + const file = Theme.map[selectedTheme][variant] + if (!file) return + + Config.updateKey("appearance.colors.scheme", selectedTheme) + Quickshell.execDetached([ + "nucleus", "theme", "switch", file + ]) + } + + enabled: !Config.runtime.appearance.colors.autogenerated + } + } + } + + ContentCard { + StyledSwitchOption { + title: "Tint Icons" + description: "Either tint icons across the shell or keep them colorized." + prefField: "appearance.tintIcons" + } + + StyledSwitchOption { + title: "Use Autogenerated Themes" + description: "Use autogenerated themes." + prefField: "appearance.colors.autogenerated" + } + + StyledSwitchOption { + title: "Use User Defined Themes" + description: "Enabling this will also run the default `config.toml` in `~/.config/matugen` dir." + prefField: "appearance.colors.runMatugenUserWide" + } + } + + ContentCard { + StyledText { + text: "Clock" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + + StyledSwitchOption { + title: "Show Clock" + description: "Whether to show or disable the clock on the background." + prefField: "appearance.background.clock.enabled" + } + + StyledSwitchOption { + title: "Analog Variant" + description: "Whether to use analog clock or not." + prefField: "appearance.background.clock.isAnalog" + } + + StyledSwitchOption { + title: "Rotate Clock Polygon" + description: "Rotate the shape polygon of the analog clock." + prefField: "appearance.background.clock.rotatePolygonBg" + enabled: Config.runtime.appearance.background.clock.isAnalog + opacity: enabled ? 1 : 0.8 + } + + NumberStepper { + label: "Rotation Duration" + description: "Adjust the duration in which the clock rotates 360* (Seconds)." + prefField: "appearance.background.clock.rotationDuration" + minimum: 1 + maximum: 40 + step: 1 + } + + RowLayout { + id: shapeSelector + + ColumnLayout { + StyledText { + text: "Analog Clock Shape" + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: "Choose the analog clock's shape." + font.pixelSize: Metrics.fontSize(12) + } + } + + Item { Layout.fillWidth: true } + + StyledDropDown { + label: "Shape Type" + model: ["Cookie 7 Sided", "Cookie 9 Sided", "Cookie 12 Sided", "Pixelated Circle", "Circle"] + + currentIndex: Config.runtime.appearance.background.clock.shape + + onSelectedIndexChanged: (index) => { + Config.updateKey( + "appearance.background.clock.shape", + index + ) + } + } + } + } + + ContentCard { + StyledText { + text: "Rounding" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + NumberStepper { + label: "Factor" + description: "Adjust the rounding factor." + prefField: "appearance.rounding.factor" + minimum: 0 + maximum: 1 + step: 0.1 + } + } + + ContentCard { + StyledText { + text: "Font" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + NumberStepper { + label: "Scale" + description: "Adjust the font scale." + prefField: "appearance.font.scale" + minimum: 0.1 + maximum: 2 + step: 0.1 + } + } + + ContentCard { + StyledText { + text: "Transparency" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + StyledSwitchOption { + title: "Enabled" + description: "Whether to enable or disable transparency." + prefField: "appearance.transparency.enabled" + } + NumberStepper { + label: "Factor" + description: "Adjust the alpha value for transparency." + prefField: "appearance.transparency.alpha" + minimum: 0.1 + maximum: 1 + step: 0.1 + } + } + + ContentCard { + StyledText { + text: "Animations" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + StyledSwitchOption { + title: "Enabled" + description: "Whether to enable or disable animations (applies everywhere in the shell)." + prefField: "appearance.animations.enabled" + } + NumberStepper { + label: "Duration Scale" + description: "Adjust the duration scale of the animations." + prefField: "appearance.animations.durationScale" + minimum: 0.1 + maximum: 1 + step: 0.1 + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/AudioConfig.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/AudioConfig.qml new file mode 100644 index 0000000..0059f9b --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/AudioConfig.qml @@ -0,0 +1,355 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell.Io +import qs.modules.functions +import qs.config +import qs.modules.components +import qs.services + +ContentMenu { + title: "Sound" + description: "Volume and audio devices" + + ContentCard { + ColumnLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(20) + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(16) + + Rectangle { + Layout.preferredWidth: 40 + Layout.preferredHeight: 40 + radius: Metrics.radius("large") + color: Appearance.m3colors.m3primaryContainer + + MaterialSymbol { + anchors.centerIn: parent + icon: "volume_up" + color: Appearance.m3colors.m3onPrimaryContainer + iconSize: Metrics.iconSize(24) + } + } + + ColumnLayout { + Layout.fillWidth: true + + StyledText { + text: "Output" + font.pixelSize: Metrics.fontSize(16) + font.family: Metrics.fontFamily("Outfit Medium") + color: Appearance.m3colors.m3onSurface + } + + StyledText { + text: Volume.defaultSink.description + font.pixelSize: Metrics.fontSize(13) + color: Appearance.m3colors.m3onSurfaceVariant + } + } + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 1 + color: Appearance.m3colors.m3outlineVariant + opacity: 0.4 + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(12) + + RowLayout { + Layout.fillWidth: true + + StyledText { + text: "Volume" + font.pixelSize: Metrics.fontSize(14) + font.family: Metrics.fontFamily("Outfit Medium") + color: Appearance.m3colors.m3onSurface + } + + Item { Layout.fillWidth: true } + + StyledText { + animate: false + text: Math.round(Volume.defaultSink.audio.volume * 100) + "%" + font.pixelSize: Metrics.fontSize(14) + font.family: Metrics.fontFamily("Outfit SemiBold") + color: Appearance.m3colors.m3primary + } + } + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(16) + + MaterialSymbol { + icon: Volume.defaultSink.audio.muted ? "volume_off" + : Volume.defaultSink.audio.volume < 0.33 ? "volume_mute" + : Volume.defaultSink.audio.volume < 0.66 ? "volume_down" + : "volume_up" + color: Appearance.m3colors.m3onSurfaceVariant + iconSize: Metrics.iconSize(24) + } + + StyledSlider { + id: outputVolumeSlider + Layout.fillWidth: true + value: Volume.defaultSink.audio.volume * 100 + onValueChanged: Volume.setVolume(value / 100) + } + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(8) + + StyledText { + text: "Device" + font.pixelSize: Metrics.fontSize(14) + font.family: Metrics.fontFamily("Outfit Medium") + color: Appearance.m3colors.m3onSurface + } + + StyledDropDown { + Layout.fillWidth: true + label: "Output device" + model: Volume.sinks.map(d => d.description) + currentIndex: { + for (let i = 0; i < Volume.sinks.length; i++) + if (Volume.sinks[i].name === Volume.defaultSink.name) return i + return -1 + } + onSelectedIndexChanged: index => { + if (index >= 0 && index < Volume.sinks.length) + Volume.setDefaultSink(Volume.sinks[index]) + } + } + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 56 + radius: Metrics.radius("small") + color: Appearance.m3colors.m3surfaceContainerHigh + + RowLayout { + anchors.fill: parent + anchors.leftMargin: Metrics.margin(16) + anchors.rightMargin: Metrics.margin(16) + spacing: Metrics.spacing(12) + + MaterialSymbol { + icon: Volume.defaultSink.audio.muted ? "volume_off" : "volume_up" + color: Volume.defaultSink.audio.muted ? Appearance.m3colors.m3error : Appearance.m3colors.m3onSurfaceVariant + iconSize: Metrics.iconSize(24) + } + + StyledText { + Layout.fillWidth: true + text: "Mute output" + font.pixelSize: Metrics.fontSize(14) + color: Appearance.m3colors.m3onSurface + } + + StyledSwitch { + checked: Volume.defaultSink.audio.muted + onToggled: Volume.toggleMuted(Volume.defaultSink) + } + } + } + } + } + + ContentCard { + ColumnLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(20) + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(16) + + Rectangle { + Layout.preferredWidth: 40 + Layout.preferredHeight: 40 + radius: Metrics.radius("large") + color: Appearance.m3colors.m3secondaryContainer + + MaterialSymbol { + anchors.centerIn: parent + icon: "mic" + color: Appearance.m3colors.m3onSecondaryContainer + iconSize: Metrics.iconSize(24) + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(2) + + StyledText { + text: "Input" + font.pixelSize: Metrics.fontSize(16) + font.family: Metrics.fontFamily("Outfit Medium") + color: Appearance.m3colors.m3onSurface + } + + StyledText { + visible: Volume.sources.length > 0 + text: Volume.defaultSource.description + font.pixelSize: Metrics.fontSize(13) + color: Appearance.m3colors.m3onSurfaceVariant + } + } + } + + Rectangle { + visible: Volume.sources.length === 0 + Layout.fillWidth: true + Layout.preferredHeight: 120 + radius: Metrics.radius("small") + color: Appearance.m3colors.m3surfaceContainerHigh + + ColumnLayout { + anchors.centerIn: parent + spacing: Metrics.spacing(8) + + MaterialSymbol { + icon: "mic_off" + iconSize: Metrics.iconSize(48) + color: ColorUtils.transparentize(Appearance.m3colors.m3onSurface, 0.3) + Layout.alignment: Qt.AlignHCenter + } + + StyledText { + text: "No input devices" + font.pixelSize: Metrics.fontSize(14) + font.family: Metrics.fontFamily("Outfit Medium") + color: Appearance.m3colors.m3onSurfaceVariant + Layout.alignment: Qt.AlignHCenter + } + } + } + + Rectangle { + visible: Volume.sources.length > 0 + Layout.fillWidth: true + Layout.preferredHeight: 1 + color: Appearance.m3colors.m3outlineVariant + opacity: 0.4 + } + + ColumnLayout { + visible: Volume.sources.length > 0 + Layout.fillWidth: true + spacing: Metrics.spacing(12) + + RowLayout { + Layout.fillWidth: true + + StyledText { + text: "Volume" + font.pixelSize: Metrics.fontSize(14) + font.family: Metrics.fontFamily("Outfit Medium") + color: Appearance.m3colors.m3onSurface + } + + Item { Layout.fillWidth: true } + + StyledText { + animate: false + text: Math.round(Volume.defaultSource.audio.volume * 100) + "%" + font.pixelSize: Metrics.fontSize(14) + font.family: Metrics.fontFamily("Outfit SemiBold") + color: Appearance.m3colors.m3primary + } + } + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(16) + + MaterialSymbol { + icon: Volume.defaultSource.audio.muted ? "mic_off" : "mic" + color: Appearance.m3colors.m3onSurfaceVariant + iconSize: Metrics.iconSize(24) + } + + StyledSlider { + id: inputVolumeSlider + Layout.fillWidth: true + value: Volume.defaultSource.audio.volume * 100 + onValueChanged: Volume.setSourceVolume(value / 100) + } + } + } + + ColumnLayout { + visible: Volume.sources.length > 0 + Layout.fillWidth: true + spacing: Metrics.spacing(8) + + StyledText { + text: "Device" + font.pixelSize: Metrics.fontSize(14) + font.family: Metrics.fontFamily("Outfit Medium") + color: Appearance.m3colors.m3onSurface + } + + StyledDropDown { + Layout.fillWidth: true + label: "Input device" + model: Volume.sources.map(d => d.description) + currentIndex: { + for (let i = 0; i < Volume.sources.length; i++) + if (Volume.sources[i].name === Volume.defaultSource.name) return i + return -1 + } + onSelectedIndexChanged: index => { + if (index >= 0 && index < Volume.sources.length) + Volume.setDefaultSource(Volume.sources[index]) + } + } + } + + Rectangle { + visible: Volume.sources.length > 0 + Layout.fillWidth: true + Layout.preferredHeight: 56 + radius: Metrics.radius("small") + color: Appearance.m3colors.m3surfaceContainerHigh + + RowLayout { + anchors.fill: parent + anchors.leftMargin: Metrics.margin(16) + anchors.rightMargin: Metrics.margin(16) + spacing: Metrics.spacing(12) + + MaterialSymbol { + icon: Volume.defaultSource.audio.muted ? "mic_off" : "mic" + color: Volume.defaultSource.audio.muted ? Appearance.m3colors.m3error : Appearance.m3colors.m3onSurfaceVariant + iconSize: Metrics.iconSize(24) + } + + StyledText { + Layout.fillWidth: true + text: "Mute input" + font.pixelSize: Metrics.fontSize(14) + color: Appearance.m3colors.m3onSurface + } + + StyledSwitch { + checked: Volume.defaultSource.audio.muted + onToggled: Volume.toggleMuted(Volume.defaultSource) + } + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/BarConfig.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/BarConfig.qml new file mode 100644 index 0000000..f6b75e4 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/BarConfig.qml @@ -0,0 +1,300 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import QtQuick.Controls +import Quickshell.Widgets +import qs.config +import qs.modules.components +import qs.services + +ContentMenu { + property string barKey: "bar" + title: "Bar" + description: "Adjust the bar's look." + + ContentCard { + id: monitorSelectorCard + + StyledText { + text: "Monitor Bar Configuration" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + + StyledText { + text: (Config.runtime.monitors?.[monitorSelector.model[monitorSelector.currentIndex]]?.bar) + ? "This monitor has its own bar configuration." + : "This monitor currently uses the global bar." + wrapMode: Text.WordWrap + } + + RowLayout { + spacing: Metrics.spacing("normal") + + StyledDropDown { + id: monitorSelector + Layout.preferredWidth: 220 + model: Xrandr.monitors.map(m => m.name) + currentIndex: 0 + onCurrentIndexChanged: monitorSelectorCard.updateMonitorProperties() + } + + Item { Layout.fillWidth: true } + + StyledButton { + id: createButton + icon: "add" + text: "Override Bar: (" + monitorSelector.model[monitorSelector.currentIndex] + ")" + Layout.preferredWidth: 280 + onClicked: { + const monitorName = monitorSelector.model[monitorSelector.currentIndex] + if (!monitorName) return + if (!Config.runtime.monitors) Config.runtime.monitors = {} + if (!Config.runtime.monitors[monitorName]) + Config.runtime.monitors[monitorName] = {} + + const defaultBar = { + density: 50, + enabled: true, + floating: false, + gothCorners: true, + margins: 16, + merged: false, + modules: { + height: 34, + paddingColor: "#1f1f1f", + radius: 17, + statusIcons: { + bluetoothStatusEnabled: true, + enabled: true, + networkStatusEnabled: true + }, + systemUsage: { + cpuStatsEnabled: true, + enabled: true, + memoryStatsEnabled: true, + tempStatsEnabled: true + }, + workspaces: { + enabled: true, + showAppIcons: true, + showJapaneseNumbers: false, + workspaceIndicators: 8 + } + }, + position: "top", + radius: 23 + } + + Config.updateKey("monitors." + monitorName + ".bar", defaultBar) + monitorSelectorCard.updateMonitorProperties() + } + } + + StyledButton { + id: deleteButton + icon: "delete" + text: "Use Global Bar: (" + monitorSelector.model[monitorSelector.currentIndex] + ")" + secondary: true + Layout.preferredWidth: 280 + onClicked: { + const monitorName = monitorSelector.model[monitorSelector.currentIndex] + if (!monitorName) return + Config.updateKey("monitors." + monitorName + ".bar", undefined) + monitorSelectorCard.updateMonitorProperties() + } + } + } + + function updateMonitorProperties() { + const monitorName = monitorSelector.model[monitorSelector.currentIndex] + const monitorBar = Config.runtime.monitors?.[monitorName]?.bar + barKey = monitorBar ? "monitors." + monitorName + ".bar" : "bar" + + createButton.enabled = !monitorBar + deleteButton.enabled = !!monitorBar + + monitorSelector.model = Xrandr.monitors.map(m => m.name) + monitorSelector.currentIndex = Xrandr.monitors.findIndex(m => m.name === monitorName) + } + } + + ContentCard { + StyledText { + text: "Bar" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + + ColumnLayout { + StyledText { + text: "Position" + font.pixelSize: Metrics.fontSize(16) + } + + RowLayout { + spacing: Metrics.spacing(8) + Repeater { + model: ["Top", "Bottom", "Left", "Right"] + delegate: StyledButton { + property string pos: modelData.toLowerCase() + text: modelData + Layout.fillWidth: true + checked: ConfigResolver.bar(monitorSelector.model[monitorSelector.currentIndex]).position === pos + topLeftRadius: Metrics.radius("normal") + topRightRadius: Metrics.radius("normal") + bottomLeftRadius: Metrics.radius("normal") + bottomRightRadius: Metrics.radius("normal") + onClicked: Config.updateKey(barKey + ".position", pos) + } + } + } + } + + StyledSwitchOption { + title: "Enabled" + description: "Toggle the bar visibility on/off" + prefField: barKey + ".enabled" + } + StyledSwitchOption { + title: "Floating Bar" + description: "Make the bar float above other windows instead of being part of the desktop" + prefField: barKey + ".floating" + } + StyledSwitchOption { + title: "Goth Corners" + description: "Apply gothic-style corner cutouts to the bar" + prefField: barKey + ".gothCorners" + } + StyledSwitchOption { + title: "Merged Layout" + description: "Merge all modules into a single continuous layout" + prefField: barKey + ".merged" + } + } + + ContentCard { + StyledText { + text: "Bar Rounding & Size" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + + NumberStepper { + label: "Bar Density" + prefField: barKey + ".density" + description: "Modify the bar's density" + minimum: 40 + maximum: 128 + } + NumberStepper { + label: "Bar Radius" + prefField: barKey + ".radius" + description: "Modify the bar's radius" + minimum: 10 + maximum: 128 + } + NumberStepper { + label: "Module Container Radius" + prefField: barKey + ".modules.radius" + description: "Modify the bar's module.radius" + minimum: 10 + maximum: 128 + } + NumberStepper { + label: "Module Height" + prefField: barKey + ".modules.height" + description: "Modify the bar's module.height" + minimum: 10 + maximum: 128 + } + NumberStepper { + label: "Workspace Indicators" + prefField: barKey + ".modules.workspaces.workspaceIndicators" + description: "Adjust how many workspace indicators to show." + minimum: 1 + maximum: 10 + } + } + + ContentCard { + StyledText { + text: "Bar Modules" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + + StyledText { + text: "Workspaces" + font.pixelSize: Metrics.fontSize(18) + font.bold: true + } + StyledSwitchOption { + title: "Enabled" + description: "Show workspace indicator module" + prefField: barKey + ".modules.workspaces.enabled" + } + StyledSwitchOption { + title: "Show App Icons" + description: "Display application icons in workspace indicators" + prefField: barKey + ".modules.workspaces.showAppIcons" + enabled: !barKey.modules.workspaces.showJapaneseNumbers && Compositor.require("hyprland") + opacity: !barKey.modules.workspaces.showJapaneseNumbers && Compositor.require("hyprland") ? 1 : 0.8 + } + StyledSwitchOption { + title: "Show Japanese Numbers" + description: "Use Japanese-style numbers instead of standard numerals" + prefField: barKey + ".modules.workspaces.showJapaneseNumbers" + enabled: !barKey.modules.workspaces.showAppIcons + opacity: !barKey.modules.workspaces.showAppIcons ? 1 : 0.8 + } + + StyledText { + text: "Status Icons" + font.pixelSize: Metrics.fontSize(18) + font.bold: true + } + StyledSwitchOption { + title: "Enabled" + description: "Show status icons module (wifi, bluetooth)" + prefField: barKey + ".modules.statusIcons.enabled" + } + StyledSwitchOption { + title: "Show Wifi Status" + description: "Display wifi connection status and signal strength" + prefField: barKey + ".modules.statusIcons.networkStatusEnabled" + } + StyledSwitchOption { + title: "Show Bluetooth Status" + description: "Display bluetooth connection status" + prefField: barKey + ".modules.statusIcons.bluetoothStatusEnabled" + } + + StyledText { + text: "System Stats" + font.pixelSize: Metrics.fontSize(18) + font.bold: true + } + StyledSwitchOption { + title: "Enabled" + description: "Show system resource monitoring module" + prefField: barKey + ".modules.systemUsage.enabled" + } + StyledSwitchOption { + title: "Show Cpu Usage Stats" + description: "Display CPU usage percentage and load" + prefField: barKey + ".modules.systemUsage.cpuStatsEnabled" + } + StyledSwitchOption { + title: "Show Memory Usage Stats" + description: "Display RAM usage and available memory" + prefField: barKey + ".modules.systemUsage.memoryStatsEnabled" + } + StyledSwitchOption { + title: "Show Cpu Temperature Stats" + description: "Display CPU temperature readings" + prefField: barKey + ".modules.systemUsage.tempStatsEnabled" + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/BluetoothConfig.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/BluetoothConfig.qml new file mode 100644 index 0000000..85a109c --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/BluetoothConfig.qml @@ -0,0 +1,187 @@ +import QtQuick +import QtQuick.Layouts +import qs.config +import qs.modules.components +import qs.modules.functions +import qs.services +import Quickshell.Bluetooth as QsBluetooth + +ContentMenu { + title: "Bluetooth" + description: "Manage Bluetooth devices and connections." + + ContentCard { + ContentRowCard { + cardSpacing: Metrics.spacing(0) + verticalPadding: Bluetooth.defaultAdapter.enabled ? Metrics.padding(10) : Metrics.padding(0) + cardMargin: Metrics.margin(0) + + StyledText { + text: powerSwitch.checked ? "Power: On" : "Power: Off" + font.pixelSize: Metrics.fontSize(16) + font.bold: true + } + + Item { Layout.fillWidth: true } + + StyledSwitch { + id: powerSwitch + checked: Bluetooth.defaultAdapter?.enabled + onToggled: Bluetooth.defaultAdapter.enabled = checked + } + } + + ContentRowCard { + visible: Bluetooth.defaultAdapter.enabled + cardSpacing: Metrics.spacing(0) + verticalPadding: Metrics.padding(10) + cardMargin: Metrics.margin(0) + + ColumnLayout { + spacing: Metrics.spacing(2) + + StyledText { + text: "Discoverable" + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: "Allow other devices to find this computer." + font.pixelSize: Metrics.fontSize(12) + color: ColorUtils.transparentize(Appearance.m3colors.m3onSurface, 0.6) + } + } + + Item { Layout.fillWidth: true } + + StyledSwitch { + checked: Bluetooth.defaultAdapter?.discoverable + onToggled: Bluetooth.defaultAdapter.discoverable = checked + } + } + + ContentRowCard { + visible: Bluetooth.defaultAdapter.enabled + cardSpacing: Metrics.spacing(0) + verticalPadding: Metrics.padding(0) + cardMargin: Metrics.margin(0) + + ColumnLayout { + spacing: Metrics.spacing(2) + + StyledText { + text: "Scanning" + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: "Search for nearby Bluetooth devices." + font.pixelSize: Metrics.fontSize(12) + color: ColorUtils.transparentize(Appearance.m3colors.m3onSurface, 0.6) + } + } + + Item { Layout.fillWidth: true } + + StyledSwitch { + checked: Bluetooth.defaultAdapter?.discovering + onToggled: Bluetooth.defaultAdapter.discovering = checked + } + } + } + + ContentCard { + visible: connectedDevices.count > 0 + + StyledText { + text: "Connected Devices" + font.pixelSize: Metrics.fontSize(18) + font.bold: true + } + + Repeater { + id: connectedDevices + model: Bluetooth.devices.filter(d => d.connected) + + delegate: BluetoothDeviceCard { + device: modelData + statusText: modelData.batteryAvailable + ? "Connected, " + Math.floor(modelData.battery * 100) + "% left" + : "Connected" + showDisconnect: true + showRemove: true + usePrimary: true + } + } + } + + ContentCard { + visible: Bluetooth.defaultAdapter?.enabled + + StyledText { + text: "Paired Devices" + font.pixelSize: Metrics.fontSize(18) + font.bold: true + } + + Item { + visible: pairedDevices.count === 0 + width: parent.width + height: Metrics.spacing(40) + + StyledText { + anchors.left: parent.left + text: "No paired devices" + font.pixelSize: Metrics.fontSize(14) + color: ColorUtils.transparentize(Appearance.m3colors.m3onSurface, 0.6) + } + } + + Repeater { + id: pairedDevices + model: Bluetooth.devices.filter(d => !d.connected && d.paired) + + delegate: BluetoothDeviceCard { + device: modelData + statusText: "Not connected" + showConnect: true + showRemove: true + } + } + } + + ContentCard { + visible: Bluetooth.defaultAdapter?.enabled + + StyledText { + text: "Available Devices" + font.pixelSize: Metrics.fontSize(18) + font.bold: true + } + + Item { + visible: discoveredDevices.count === 0 && !Bluetooth.defaultAdapter.discovering + width: parent.width + height: Metrics.spacing(40) + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: "No new devices found" + font.pixelSize: Metrics.fontSize(14) + color: ColorUtils.transparentize(Appearance.m3colors.m3onSurface, 0.6) + } + } + + Repeater { + id: discoveredDevices + model: Bluetooth.devices.filter(d => !d.paired && !d.connected) + + delegate: BluetoothDeviceCard { + device: modelData + statusText: "Discovered" + showConnect: true + showPair: true + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/BluetoothDeviceCard.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/BluetoothDeviceCard.qml new file mode 100644 index 0000000..cca4ac1 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/BluetoothDeviceCard.qml @@ -0,0 +1,90 @@ +import QtQuick +import QtQuick.Layouts +import qs.modules.components +import qs.config +import qs.modules.functions +import Quickshell.Bluetooth as QsBluetooth + +ContentRowCard { + id: deviceRow + property var device + property string statusText: "" + property bool usePrimary: false + property bool showConnect: false + property bool showDisconnect: false + property bool showPair: false + property bool showRemove: false + + cardMargin: Metrics.margin(0) + cardSpacing: Metrics.spacing(10) + verticalPadding: Metrics.padding(0) + opacity: device.state === QsBluetooth.BluetoothDeviceState.Connecting || + device.state === QsBluetooth.BluetoothDeviceState.Disconnecting ? 0.6 : 1 + + function mapBluetoothIcon(dbusIcon, name) { + console.log(dbusIcon, " / ", name) + const iconMap = { + "audio-headset": "headset", + "audio-headphones": "headphones", + "input-keyboard": "keyboard", + "input-mouse": "mouse", + "input-gaming": "sports_esports", + "phone": "phone_android", + "computer": "computer", + "printer": "print", + "camera": "photo_camera", + "unknown": "bluetooth" + } + return iconMap[dbusIcon] || "bluetooth" + } + + MaterialSymbol { + icon: mapBluetoothIcon(device.icon, device.name) + font.pixelSize: Metrics.fontSize(32) + } + + ColumnLayout { + Layout.alignment: Qt.AlignVCenter + spacing: Metrics.spacing(0) + + StyledText { + text: device.name || device.address + font.pixelSize: Metrics.fontSize(16) + font.bold: true + } + + StyledText { + text: statusText + font.pixelSize: Metrics.fontSize(12) + color: usePrimary + ? Appearance.m3colors.m3primary + : ColorUtils.transparentize(Appearance.m3colors.m3onSurface, 0.6) + } + } + + Item { Layout.fillWidth: true } + + StyledButton { + visible: showConnect + icon: "link" + onClicked: device.connect() + } + + StyledButton { + visible: showDisconnect + icon: "link_off" + onClicked: device.disconnect() + } + + StyledButton { + visible: showPair + icon: "add" + onClicked: device.pair() + } + + StyledButton { + visible: showRemove + icon: "delete" + onClicked: Bluetooth.removeDevice(device) + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/LauncherConfig.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/LauncherConfig.qml new file mode 100644 index 0000000..43f7e92 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/LauncherConfig.qml @@ -0,0 +1,79 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import qs.config +import qs.modules.components +import qs.services + +ContentMenu { + title: "Launcher" + description: "Adjust launcher's settings." + + ContentCard { + StyledText { + text: "Filters & Search" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + + StyledSwitchOption { + title: "Fuzzy Search" + description: "Enable or disable fuzzy search." + prefField: "launcher.fuzzySearchEnabled" + } + + RowLayout { + id: webEngineSelector + + property string title: "Web Search Engine" + property string description: "Choose the web search engine for web searches." + property string prefField: '' + + ColumnLayout { + StyledText { + text: webEngineSelector.title + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: webEngineSelector.description + font.pixelSize: Metrics.fontSize(12) + } + + } + + Item { + Layout.fillWidth: true + } + + StyledDropDown { + label: "Engine" + model: ["Google", "Brave", "DuckDuckGo", "Bing"] + // Set the initial index based on the lowercase value in Config + currentIndex: { + switch (Config.runtime.launcher.webSearchEngine.toLowerCase()) { + case "google": + return 0; + case "brave": + return 1; + case "duckduckgo": + return 2; + case "bing": + return 3; + default: + return 0; + } + } + onSelectedIndexChanged: (index) => { + // Update Config with lowercase version of selected model + Config.updateKey("launcher.webSearchEngine", model[index].toLowerCase()); + } + } + + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/MiscConfig.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/MiscConfig.qml new file mode 100644 index 0000000..0df8d69 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/MiscConfig.qml @@ -0,0 +1,109 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import qs.config +import qs.modules.components +import qs.services + +ContentMenu { + title: "Miscellaneous" + description: "Configure misc settings." + + ContentCard { + StyledText { + text: "Versions" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + + RowLayout { + id: releaseChannelSelector + + property string title: "Release Channel" + property string description: "Choose the release channel for updates." + property string prefField: '' + + ColumnLayout { + StyledText { + text: releaseChannelSelector.title + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: releaseChannelSelector.description + font.pixelSize: Metrics.fontSize(12) + } + + } + + Item { + Layout.fillWidth: true + } + + StyledDropDown { + label: "Type" + model: ["Stable", "Edge (indev)"] + currentIndex: Config.runtime.shell.releaseChannel === "edge" ? 1 : 0 + onSelectedIndexChanged: (index) => { + Config.updateKey("shell.releaseChannel", index === 1 ? "edge" : "stable"); + UpdateNotifier.notified = false; + } + } + + } + + } + + ContentCard { + StyledText { + text: "Intelligence" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + + StyledSwitchOption { + title: "Enabled" + description: "Enable or disable intelligence." + prefField: "misc.intelligence.enabled" + } + + } + + ContentCard { + StyledText { + text: "Intelligence Bearer/API" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + + StyledTextField { + id: apiKeyTextField + + clip: true + horizontalAlignment: Text.AlignLeft + placeholderText: Config.runtime.misc.intelligence.apiKey !== "" ? Config.runtime.misc.intelligence.apiKey : "Bearer Key" + Layout.fillWidth: true + Keys.onPressed: (event) => { + if (event.key === Qt.Key_S && (event.modifiers & Qt.ControlModifier)) { + event.accepted = true; + Config.updateKey("misc.intelligence.apiKey", apiKeyTextField.text); + Quickshell.execDetached(["notify-send", "Saved Bearer/API Key"]) + } + } + font.pixelSize: Metrics.fontSize(16) + } + + Item { + width: 20 + } + + InfoCard { + title: "How to save the api key" + description: "In order to save the api key press Ctrl+S and it will save the api key to the config." + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/NetworkCard.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/NetworkCard.qml new file mode 100644 index 0000000..a7ef194 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/NetworkCard.qml @@ -0,0 +1,136 @@ +import QtQuick +import QtQuick.Layouts +import qs.config +import qs.modules.components +import qs.services +import qs.modules.functions + +Item { + id: networkRow + property var connection + property bool isActive: false + property bool showConnect: false + property bool showDisconnect: false + property bool showPasswordField: false + property string password: "" + + width: parent.width + implicitHeight: mainLayout.implicitHeight + + function signalIcon(strength, secure) { + if (!connection) return "network_wifi"; + if (connection.type === "ethernet") return "settings_ethernet"; + if (strength >= 75) return "network_wifi"; + if (strength >= 50) return "network_wifi_3_bar"; + if (strength >= 25) return "network_wifi_2_bar"; + if (strength > 0) return "network_wifi_1_bar"; + return "network_wifi_1_bar"; + } + + ColumnLayout { + id: mainLayout + anchors.fill: parent + spacing: Metrics.spacing(10) + + RowLayout { + spacing: Metrics.spacing(10) + + // Signal icon with lock overlay + Item { + width: Metrics.spacing(32) + height: Metrics.spacing(32) + + MaterialSymbol { + anchors.fill: parent + icon: connection ? signalIcon(connection.strength, connection.isSecure) : "network_wifi" + font.pixelSize: Metrics.fontSize(32) + } + + // Lock overlay (anchors are safe because Item is not layout-managed) + MaterialSymbol { + icon: "lock" + visible: connection && connection.type === "wifi" && connection.isSecure + font.pixelSize: Metrics.fontSize(12) + anchors.right: parent.right + anchors.bottom: parent.bottom + } + } + + ColumnLayout { + Layout.alignment: Qt.AlignVCenter + spacing: Metrics.spacing(0) + + StyledText { + text: connection ? connection.name : "" + font.pixelSize: Metrics.fontSize(16) + font.bold: true + } + + StyledText { + text: connection ? ( + isActive ? "Connected" : + connection.type === "ethernet" ? connection.device || "Ethernet" : + connection.isSecure ? "Secured" : "Open" + ) : "" + font.pixelSize: Metrics.fontSize(12) + color: isActive + ? Appearance.m3colors.m3primary + : ColorUtils.transparentize(Appearance.m3colors.m3onSurface, 0.4) + } + } + + Item { Layout.fillWidth: true } + + StyledButton { + visible: showConnect && !showPasswordField + icon: "link" + onClicked: { + if (!connection) return; + if (connection.type === "ethernet") Network.connect(connection, "") + else if (connection.isSecure) showPasswordField = true + else Network.connect(connection, "") + } + } + + StyledButton { + visible: showDisconnect && !showPasswordField + icon: "link_off" + onClicked: Network.disconnect() + } + } + + // Password row + RowLayout { + visible: showPasswordField && connection && connection.type === "wifi" + spacing: Metrics.spacing(10) + + StyledTextField { + padding: Metrics.padding(10) + Layout.fillWidth: true + placeholderText: "Enter password" + echoMode: parent.showPassword ? TextInput.Normal : TextInput.Password + onTextChanged: networkRow.password = text + onAccepted: { + if (!connection) return; + Network.connect(connection, networkRow.password) + showPasswordField = false + } + } + + StyledButton { + property bool showPassword: false + icon: parent.showPassword ? "visibility" : "visibility_off" + onClicked: parent.showPassword = !parent.showPassword + } + + StyledButton { + icon: "link" + onClicked: { + if (!connection) return; + Network.connect(connection, networkRow.password) + showPasswordField = false + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/NetworkConfig.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/NetworkConfig.qml new file mode 100644 index 0000000..86c57c9 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/NetworkConfig.qml @@ -0,0 +1,172 @@ +import QtQuick +import QtQuick.Layouts +import qs.modules.functions +import qs.config +import qs.modules.components +import qs.services + +ContentMenu { + title: "Network" + description: "Manage network connections." + + ContentCard { + ContentRowCard { + cardSpacing: Metrics.spacing(0) + verticalPadding: Network.wifiEnabled ? Metrics.padding(10) : Metrics.padding(0) + cardMargin: Metrics.margin(0) + + StyledText { + text: powerSwitch.checked ? "Wi-Fi: On" : "Wi-Fi: Off" + font.pixelSize: Metrics.fontSize(16) + font.bold: true + } + + Item { Layout.fillWidth: true } + + StyledSwitch { + id: powerSwitch + checked: Network.wifiEnabled + onToggled: Network.enableWifi(checked) + } + } + + ContentRowCard { + visible: Network.wifiEnabled + cardSpacing: Metrics.spacing(0) + verticalPadding: Metrics.padding(10) + cardMargin: Metrics.margin(0) + + ColumnLayout { + spacing: Metrics.spacing(2) + + StyledText { + text: "Scanning" + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: "Search for nearby Wi-Fi networks." + font.pixelSize: Metrics.fontSize(12) + color: ColorUtils.transparentize( + Appearance.m3colors.m3onSurface, 0.4 + ) + } + } + + Item { Layout.fillWidth: true } + + StyledSwitch { + checked: Network.scanning + onToggled: { + if (checked) + Network.rescan() + } + } + } + } + + InfoCard { + visible: Network.message !== "" && Network.message !== "ok" + icon: "error" + backgroundColor: Appearance.m3colors.m3error + contentColor: Appearance.m3colors.m3onError + title: "Failed to connect to " + Network.lastNetworkAttempt + description: Network.message + } + + ContentCard { + visible: Network.active !== null + + StyledText { + text: "Active Connection" + font.pixelSize: Metrics.fontSize(18) + font.bold: true + } + + NetworkCard { + connection: Network.active + isActive: true + showDisconnect: Network.active?.type === "wifi" + } + } + + ContentCard { + visible: Network.connections.filter(c => c.type === "ethernet").length > 0 + + StyledText { + text: "Ethernet" + font.pixelSize: Metrics.fontSize(18) + font.bold: true + } + + Repeater { + model: Network.connections.filter(c => c.type === "ethernet" && !c.active) + delegate: NetworkCard { + connection: modelData + showConnect: true + } + } + } + + ContentCard { + visible: Network.wifiEnabled + + StyledText { + text: "Available Wi-Fi Networks" + font.pixelSize: Metrics.fontSize(18) + font.bold: true + } + + Item { + visible: Network.connections.filter(c => c.type === "wifi").length === 0 && !Network.scanning + width: parent.width + height: Metrics.spacing(40) + + StyledText { + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + text: "No networks found" + font.pixelSize: Metrics.fontSize(14) + color: ColorUtils.transparentize(Appearance.m3colors.m3onSurface, 0.4) + } + + } + + Repeater { + model: Network.connections.filter(c => c.type === "wifi" && !c.active) + delegate: NetworkCard { + connection: modelData + showConnect: true + } + } + } + + ContentCard { + visible: Network.savedNetworks.length > 0 + StyledText { + text: "Remembered Networks" + font.pixelSize: Metrics.fontSize(18) + font.bold: true + } + + Item { + visible: Network.savedNetworks.length === 0 + width: parent.width + height: Metrics.spacing(40) + StyledText { + anchors.left: parent.left + text: "No remembered networks" + font.pixelSize: Metrics.fontSize(14) + color: Appearance.colors.colSubtext + } + } + + Repeater { + model: Network.connections.filter(c => c.type === "wifi" && c.saved && !c.active) + delegate: NetworkCard { + connection: modelData + showConnect: false + showDisconnect: false + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/NotificationConfig.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/NotificationConfig.qml new file mode 100644 index 0000000..edd501f --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/NotificationConfig.qml @@ -0,0 +1,215 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import qs.config +import qs.modules.components +import qs.services +import qs.modules.functions + +ContentMenu { + title: "Notifications & Overlays" + description: "Adjust notification and overlay settings." + + function indexFromPosition(pos, model) { + pos = pos.toLowerCase() + for (let i = 0; i < model.length; i++) { + if (model[i].toLowerCase().replace(" ", "-") === pos) + return i + } + return 0 + } + + ContentCard { + + StyledText { + text: "Notifications" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + + StyledSwitchOption { + title: "Enabled" + description: "Enable or disable built-in notification daemon." + prefField: "notifications.enabled" + } + + StyledSwitchOption { + title: "Do not disturb enabled" + description: "Enable or disable dnd." + prefField: "notifications.doNotDisturb" + } + + RowLayout { + + ColumnLayout { + StyledText { + text: "Notification Position" + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: "Select where notification will be shown." + font.pixelSize: Metrics.fontSize(12) + } + } + + Item { Layout.fillWidth: true } + + StyledDropDown { + id: notificationDropdown + label: "Position" + + property var positions: ["Top Left", "Top Right", "Top"] + + model: positions + + currentIndex: + indexFromPosition( + Config.runtime.notifications.position, + positions + ) + + onSelectedIndexChanged: function(index) { + Config.updateKey( + "notifications.position", + positions[index].toLowerCase().replace(" ", "-") + ) + } + } + } + + RowLayout { + + ColumnLayout { + StyledText { + text: "Test Notifications" + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: "Run a test notification." + font.pixelSize: Metrics.fontSize(12) + } + } + + Item { Layout.fillWidth: true } + + StyledButton { + text: "Test" + icon: "chat" + + onClicked: + Quickshell.execDetached([ + "notify-send", + "Quickshell", + "This is a test notification" + ]) + } + } + } + + ContentCard { + + StyledText { + text: "Overlays / OSDs" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + } + + StyledSwitchOption { + title: "Enabled" + description: "Enable or disable built-in osd daemon." + prefField: "overlays.enabled" + } + + StyledSwitchOption { + title: "Volume OSD enabled" + description: "Enable or disable volume osd." + prefField: "overlays.volumeOverlayEnabled" + } + + StyledSwitchOption { + title: "Brightness OSD enabled" + description: "Enable or disable brightness osd." + prefField: "overlays.brightnessOverlayEnabled" + } + + RowLayout { + + ColumnLayout { + StyledText { + text: "Brightness OSD Position" + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: "Choose where brightness OSD is shown." + font.pixelSize: Metrics.fontSize(12) + } + } + + Item { Layout.fillWidth: true } + + StyledDropDown { + + property var positions: + ["Top Left","Top Right","Bottom Left","Bottom Right","Top","Bottom"] + + model: positions + + currentIndex: + indexFromPosition( + Config.runtime.overlays.brightnessOverlayPosition, + positions + ) + + onSelectedIndexChanged: function(index) { + Config.updateKey( + "overlays.brightnessOverlayPosition", + positions[index].toLowerCase().replace(" ", "-") + ) + } + } + } + + RowLayout { + + ColumnLayout { + StyledText { + text: "Volume OSD Position" + font.pixelSize: Metrics.fontSize(16) + } + + StyledText { + text: "Choose where volume OSD is shown." + font.pixelSize: Metrics.fontSize(12) + } + } + + Item { Layout.fillWidth: true } + + StyledDropDown { + + property var positions: + ["Top Left","Top Right","Bottom Left","Bottom Right","Top","Bottom"] + + model: positions + + currentIndex: + indexFromPosition( + Config.runtime.overlays.volumeOverlayPosition, + positions + ) + + onSelectedIndexChanged: function(index) { + Config.updateKey( + "overlays.volumeOverlayPosition", + positions[index].toLowerCase().replace(" ", "-") + ) + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/Plugins.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/Plugins.qml new file mode 100644 index 0000000..0ce7420 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/Plugins.qml @@ -0,0 +1,51 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import qs.config +import qs.modules.components +import qs.plugins + +ContentMenu { + title: "Plugins" + description: "Modify and Customize Installed Plugins." + + ContentCard { + Layout.fillWidth: true + Layout.preferredHeight: implicitHeight + color: "transparent" + + GridLayout { + id: grid + columns: 1 + Layout.fillWidth: true + columnSpacing: Metrics.spacing(16) + rowSpacing: Metrics.spacing(16) + + StyledText { + text: "Plugins not found!" + font.pixelSize: Metrics.fontSize(20) + font.bold: true + visible: PluginLoader.plugins.length === 0 + Layout.alignment: Qt.AlignHCenter + } + + Repeater { + model: PluginLoader.plugins + + delegate: ContentCard { + Layout.fillWidth: true + + Loader { + Layout.fillWidth: true + asynchronous: true + source: Qt.resolvedUrl( + Directories.shellConfig + "/plugins/" + modelData + "/Settings.qml" + ) + } + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/Settings.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/Settings.qml new file mode 100644 index 0000000..eefe720 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/Settings.qml @@ -0,0 +1,201 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Window +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import qs.config +import qs.modules.functions +import qs.modules.components +import qs.services + +Scope { + property var settingsWindow: null + + IpcHandler { + function open(menu: string) { + Globals.states.settingsOpen = true; + + if (menu !== "" && settingsWindow !== null) { + for (var i = 0; i < settingsWindow.menuModel.length; i++) { + var item = settingsWindow.menuModel[i]; + if (!item.header && item.label.toLowerCase() === menu.toLowerCase()) { + settingsWindow.selectedIndex = item.page; + break; + } + } + } + } + target: "settings" + } + + LazyLoader { + active: Globals.states.settingsOpen + + Window { + id: root + width: 1280 + height: 720 + visible: true + title: "Nucleus - Settings" + color: Appearance.m3colors.m3background + onClosing: Globals.states.settingsOpen = false + Component.onCompleted: settingsWindow = root + + property int selectedIndex: 0 + property bool sidebarCollapsed: false + + property var menuModel: [ + { "header": true, "label": "System" }, + { "icon": "bluetooth", "label": "Bluetooth", "page": 0 }, + { "icon": "network_wifi", "label": "Network", "page": 1 }, + { "icon": "volume_up", "label": "Audio", "page": 2 }, + { "icon": "instant_mix", "label": "Appearance", "page": 3 }, + + { "header": true, "label": "Customization" }, + { "icon": "toolbar", "label": "Bar", "page": 4 }, + { "icon": "wallpaper", "label": "Wallpapers", "page": 5 }, + { "icon": "apps", "label": "Launcher", "page": 6 }, + { "icon": "chat", "label": "Notifications", "page": 7 }, + { "icon": "extension", "label": "Plugins", "page": 8 }, + { "icon": "apps", "label": "Store", "page": 9 }, + { "icon": "build", "label": "Miscellaneous", "page": 10 }, + + { "header": true, "label": "About" }, + { "icon": "info", "label": "About", "page": 11 } + ] + + Item { + anchors.fill: parent + Rectangle { + id: sidebarBG + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom + width: root.sidebarCollapsed ? 80 : 350 + color: Appearance.m3colors.m3surfaceContainerLow + + ColumnLayout { + anchors.fill: parent + anchors.margins: Metrics.margin(40) + spacing: Metrics.spacing(5) + + RowLayout { + Layout.fillWidth: true + + StyledText { + Layout.fillWidth: true + text: "Settings" + font.family: "Outfit ExtraBold" + font.pixelSize: Metrics.fontSize(28) + visible: !root.sidebarCollapsed + } + + StyledButton { + Layout.preferredHeight: 40 + icon: root.sidebarCollapsed ? "chevron_right" : "chevron_left" + secondary: true + onClicked: root.sidebarCollapsed = !root.sidebarCollapsed + } + } + + ListView { + id: sidebarList + Layout.fillWidth: true + Layout.fillHeight: true + model: root.menuModel + spacing: Metrics.spacing(5) + clip: true + + delegate: Item { + width: sidebarList.width + height: modelData.header ? (root.sidebarCollapsed ? 0 : 30) : 42 + visible: !modelData.header || !root.sidebarCollapsed + + // header + Item { + width: parent.width + height: parent.height + + StyledText { + y: (parent.height - height) * 0.5 + x: 10 + text: modelData.label + font.pixelSize: Metrics.fontSize(14) + font.bold: true + opacity: modelData.header ? 1 : 0 + } + + } + + Rectangle { + anchors.fill: parent + visible: !modelData.header + radius: Appearance.rounding.large + color: root.selectedIndex === modelData.page + ? Appearance.m3colors.m3primary + : "transparent" + + RowLayout { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + spacing: 10 + + MaterialSymbol { + visible: !modelData.header + icon: modelData.icon ? modelData.icon : "" + iconSize: Metrics.iconSize(24) + } + + StyledText { + text: modelData.label + visible: !root.sidebarCollapsed + } + } + } + + MouseArea { + anchors.fill: parent + enabled: modelData.page !== undefined + onClicked: { + root.selectedIndex = modelData.page + settingsStack.currentIndex = modelData.page + } + } + } + } + } + + Behavior on width { + NumberAnimation { duration: 180; easing.type: Easing.InOutCubic } + } + } + + + StackLayout { + id: settingsStack + anchors.left: sidebarBG.right + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + currentIndex: root.selectedIndex + + BluetoothConfig { Layout.fillWidth: true; Layout.fillHeight: true } + NetworkConfig { Layout.fillWidth: true; Layout.fillHeight: true } + AudioConfig { Layout.fillWidth: true; Layout.fillHeight: true } + AppearanceConfig { Layout.fillWidth: true; Layout.fillHeight: true } + BarConfig { Layout.fillWidth: true; Layout.fillHeight: true } + WallpaperConfig { Layout.fillWidth: true; Layout.fillHeight: true } + LauncherConfig { Layout.fillWidth: true; Layout.fillHeight: true } + NotificationConfig { Layout.fillWidth: true; Layout.fillHeight: true } + Plugins { Layout.fillWidth: true; Layout.fillHeight: true } + Store { Layout.fillWidth: true; Layout.fillHeight: true } + MiscConfig { Layout.fillWidth: true; Layout.fillHeight: true } + About { Layout.fillWidth: true; Layout.fillHeight: true } + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/Store.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/Store.qml new file mode 100644 index 0000000..843f422 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/Store.qml @@ -0,0 +1,104 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import qs.config +import qs.modules.components +import qs.plugins + +ContentMenu { + title: "Store" + description: "Manage plugins and other stuff for the shell." + + ContentCard { + Layout.fillWidth: true + + GridLayout { + columns: 1 + Layout.fillWidth: true + columnSpacing: Metrics.spacing(16) + rowSpacing: Metrics.spacing(16) + + Repeater { + model: PluginParser.model + + delegate: StyledRect { + Layout.preferredHeight: 90 + Layout.fillWidth: true + radius: Metrics.radius("small") + color: Appearance.m3colors.m3surfaceContainer + + RowLayout { + anchors.fill: parent + anchors.margins: Metrics.margin("normal") + spacing: Metrics.spacing(12) + + Column { + Layout.fillWidth: true + spacing: Metrics.spacing(2) + + StyledText { + font.pixelSize: Metrics.fontSize("large") + text: name + } + + RowLayout { + spacing: Metrics.spacing(6) + + StyledText { + font.pixelSize: Metrics.fontSize("small") + text: author + color: Appearance.colors.colSubtext + } + + StyledText { + font.pixelSize: Metrics.fontSize("small") + text: "| Requires Nucleus " + requires_nucleus + color: Appearance.colors.colSubtext + } + } + + StyledText { + font.pixelSize: Metrics.fontSize("normal") + text: description + color: Appearance.colors.colSubtext + } + } + + RowLayout { + spacing: Metrics.spacing(8) + + StyledButton { + icon: "download" + text: "Install" + visible: !installed + secondary: true + Layout.preferredWidth: 140 + onClicked: PluginParser.install(id) + } + + StyledButton { + icon: "update" + text: "Update" + visible: installed + secondary: true + Layout.preferredWidth: 140 + onClicked: PluginParser.update(id) + } + + StyledButton { + icon: "delete" + text: "Remove" + visible: installed + secondary: true + Layout.preferredWidth: 140 + onClicked: PluginParser.uninstall(id) + } + } + } + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/settings/WallpaperConfig.qml b/.config/quickshell/nucleus-shell/modules/interface/settings/WallpaperConfig.qml new file mode 100644 index 0000000..68e7480 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/settings/WallpaperConfig.qml @@ -0,0 +1,294 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Widgets +import qs.config +import qs.modules.components +import qs.services + +ContentMenu { + property string displayName: root.screen?.name ?? "" + property var intervalOptions: [{ + "value": 5, + "label": "5 minutes" + }, { + "value": 15, + "label": "15 minutes" + }, { + "value": 30, + "label": "30 minutes" + }, { + "value": 60, + "label": "1 hour" + }, { + "value": 120, + "label": "2 hours" + }, { + "value": 360, + "label": "6 hours" + }] + + function getIntervalIndex(minutes) { + for (let i = 0; i < intervalOptions.length; i++) { + if (intervalOptions[i].value === minutes) + return i; + } + return 0; + } + + title: "Wallpaper" + description: "Manage your wallpapers" + + ContentCard { + ClippingRectangle { + id: wpContainer + + Layout.alignment: Qt.AlignHCenter + width: root.screen.width / 2 + height: width * root.screen.height / root.screen.width + radius: Metrics.radius("unsharpenmore") + color: Appearance.m3colors.m3surfaceContainer + + StyledText { + text: "Current Wallpaper:" + font.pixelSize: Metrics.fontSize("big") + font.bold: true + } + + ClippingRectangle { + id: wpPreview + + Layout.alignment: Qt.AlignHCenter | Qt.AlignCenter + anchors.fill: parent + radius: Metrics.radius("unsharpenmore") + color: Appearance.m3colors.m3paddingContainer + layer.enabled: true + + StyledText { + opacity: !Config.runtime.appearance.background.enabled ? 1 : 0 + font.pixelSize: Metrics.fontSize("title") + text: "Wallpaper Manager Disabled" + anchors.centerIn: parent + + Behavior on opacity { + enabled: Config.runtime.appearance.animations.enabled + Anim { } + } + } + + Image { + opacity: Config.runtime.appearance.background.enabled ? 1 : 0 + anchors.fill: parent + source: previewImg + "?t=" + Date.now() + property string previewImg: { + const displays = Config.runtime.monitors + const fallback = Config.runtime.appearance.background.defaultPath + + if (!displays) + return fallback + + const monitor = displays?.[displayName] + return monitor?.wallpaper ?? fallback + } + fillMode: Image.PreserveAspectCrop + cache: true + + Behavior on opacity { + enabled: Config.runtime.appearance.animations.enabled + Anim { } + } + } + } + } + + StyledButton { + icon: "wallpaper" + text: "Change Wallpaper" + Layout.fillWidth: true + onClicked: { + Quickshell.execDetached(["nucleus", "ipc", "call", "background", "change"]); + } + } + + StyledSwitchOption { + title: "Enabled" + description: "Enabled or disable built-in wallpaper daemon." + prefField: "appearance.background.enabled" + } + } + + ContentCard { + StyledText { + text: "Parallax Effect" + font.pixelSize: Metrics.fontSize("big") + font.bold: true + } + + StyledSwitchOption { + title: "Enabled" + description: "Enabled or disable wallpaper parallax effect." + prefField: "appearance.background.parallax.enabled" + } + + StyledSwitchOption { + title: "Enabled for Sidebar Left" + description: "Show parralax effect when sidebarLeft is opened." + prefField: "appearance.background.parallax.enableSidebarLeft" + } + + StyledSwitchOption { + title: "Enabled for Sidebar Right" + description: "Show parralax effect when sidebarRight is opened." + prefField: "appearance.background.parallax.enableSidebarRight" + } + + NumberStepper { + label: "Zoom Amount" + description: "Adjust the zoom of the parallax effect." + prefField: "appearance.background.parallax.zoom" + step: 0.1 + minimum: 1.10 + maximum: 2 + } + } + + ContentCard { + StyledText { + text: "Wallpaper Slideshow" + font.pixelSize: Metrics.fontSize("big") + font.bold: true + } + + StyledSwitchOption { + title: "Enable Slideshow" + description: "Automatically rotate wallpapers from a folder." + prefField: "appearance.background.slideshow.enabled" + } + + StyledSwitchOption { + title: "Include Subfolders" + description: "Also search for wallpapers in subfolders." + prefField: "appearance.background.slideshow.includeSubfolders" + } + + ColumnLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(8) + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(12) + + ColumnLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(4) + + StyledText { + text: "Wallpaper Folder" + font.pixelSize: Metrics.fontSize("normal") + } + + StyledText { + text: Config.runtime.appearance.background.slideshow.folder || "No folder selected" + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurfaceVariant + elide: Text.ElideMiddle + Layout.fillWidth: true + } + } + + StyledButton { + icon: "folder_open" + text: "Browse" + onClicked: folderPickerProc.running = true + } + } + } + + RowLayout { + id: skipWallpaper + + property string title: "Skip To Next Wallpaper" + property string description: "Skip to the next wallpaper in the wallpaper directory." + property string prefField: '' + + ColumnLayout { + StyledText { + text: skipWallpaper.title + font.pixelSize: Metrics.fontSize("normal") + } + + StyledText { + text: skipWallpaper.description + font.pixelSize: Metrics.fontSize("small") + } + } + + Item { Layout.fillWidth: true } + + StyledButton { + icon: "skip_next" + text: "Skip Next" + enabled: WallpaperSlideshow.wallpapers.length > 0 + onClicked: { + Quickshell.execDetached(["nucleus", "ipc", "call", "background", "next"]); + } + } + } + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(12) + + ColumnLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(4) + + StyledText { + text: "Change Interval" + font.pixelSize: Metrics.fontSize("normal") + } + + StyledText { + text: "How often to change the wallpaper." + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurfaceVariant + } + } + + Item { Layout.fillWidth: true } + + StyledDropDown { + label: "Interval" + model: intervalOptions.map((opt) => { + return opt.label; + }) + currentIndex: getIntervalIndex(Config.runtime.appearance.background.slideshow.interval) + onSelectedIndexChanged: (index) => { + Config.updateKey("appearance.background.slideshow.interval", intervalOptions[index].value); + } + } + } + } + + Process { + id: folderPickerProc + + command: ["bash", Directories.scriptsPath + "/interface/selectfolder.sh", Config.runtime.appearance.background.slideshow.folder || Directories.pictures] + + stdout: StdioCollector { + onStreamFinished: { + const out = text.trim(); + if (out !== "null" && out.length > 0) + Config.updateKey("appearance.background.slideshow.folder", out); + } + } + } + + component Anim: NumberAnimation { + duration: Metrics.chronoDuration(400) + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.curves.standard + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/IntelligencePanel.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/IntelligencePanel.qml new file mode 100644 index 0000000..f4a80d8 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/IntelligencePanel.qml @@ -0,0 +1,525 @@ +import Qt5Compat.GraphicalEffects +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import qs.config +import qs.modules.functions +import qs.modules.components +import qs.services + +Item { + id: root + + property bool initialChatSelected: false + + function appendMessage(sender, message) { + messageModel.append({ + "sender": sender, + "message": message + }); + scrollToBottom(); + } + + function updateChatsList(files) { + let existing = { + }; + for (let i = 0; i < chatListModel.count; i++) existing[chatListModel.get(i).name] = true + for (let file of files) { + let name = file.trim(); + if (!name.length) + continue; + + if (name.endsWith(".txt")) + name = name.slice(0, -4); + + if (!existing[name]) + chatListModel.append({ + "name": name + }); + + delete existing[name]; + } + // remove chats that no longer exist + for (let name in existing) { + for (let i = 0; i < chatListModel.count; i++) { + if (chatListModel.get(i).name === name) { + chatListModel.remove(i); + break; + } + } + } + // ensure default exists + let hasDefault = false; + for (let i = 0; i < chatListModel.count; i++) if (chatListModel.get(i).name === "default") { + hasDefault = true; + } + if (!hasDefault) { + chatListModel.insert(0, { + "name": "default" + }); + FileUtils.createFile(FileUtils.trimFileProtocol(Directories.config) + "/zenith/chats/default.txt"); + } + } + + function scrollToBottom() { + chatView.positionViewAtEnd(); + } + + function sendMessage() { + if (userInput.text === "" || Zenith.loading) + return ; + + Zenith.pendingInput = userInput.text; + appendMessage("You", userInput.text); + userInput.text = ""; + Zenith.loading = true; + Zenith.send(); + } + + function loadChatHistory(chatName) { + messageModel.clear(); + Zenith.loadChat(chatName); + } + + function selectDefaultChat() { + let defaultIndex = -1; + for (let i = 0; i < chatListModel.count; i++) { + if (chatListModel.get(i).name === "default") { + defaultIndex = i; + break; + } + } + if (defaultIndex !== -1) { + chatSelector.currentIndex = defaultIndex; + Zenith.currentChat = "default"; + loadChatHistory("default"); + } else if (chatListModel.count > 0) { + chatSelector.currentIndex = 0; + Zenith.currentChat = chatListModel.get(0).name; + loadChatHistory(Zenith.currentChat); + } + } + + ListModel { + // { sender: "You" | "AI", message: string } + + id: messageModel + } + + ListModel { + id: chatListModel + } + + ColumnLayout { + spacing: Metrics.spacing(8) + anchors.centerIn: parent + + StyledText { + visible: !Config.runtime.misc.intelligence.enabled + text: "Intelligence is disabled!" + Layout.leftMargin: Metrics.margin(24) + font.pixelSize: Appearance.font.size.huge + } + + StyledText { + visible: !Config.runtime.misc.intelligence.enabled + text: "Go to the settings to enable intelligence" + } + + } + + StyledRect { + anchors.topMargin: Metrics.margin(74) + radius: Metrics.radius("normal") + anchors.fill: parent + color: "transparent" + visible: Config.runtime.misc.intelligence.enabled + + ColumnLayout { + anchors.fill: parent + anchors.margins: Metrics.margin(16) + spacing: Metrics.spacing(10) + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(10) + + StyledDropDown { + id: chatSelector + + Layout.fillWidth: true + model: chatListModel + textRole: "name" + Layout.preferredHeight: 40 + onCurrentIndexChanged: { + if (!initialChatSelected) + return ; + + if (currentIndex < 0 || currentIndex >= chatListModel.count) + return ; + + let chatName = chatListModel.get(currentIndex).name; + Zenith.currentChat = chatName; + loadChatHistory(chatName); + } + } + + StyledButton { + icon: "add" + Layout.preferredWidth: 40 + onClicked: { + let name = "new-chat-" + chatListModel.count; + let path = FileUtils.trimFileProtocol(Directories.config) + "/zenith/chats/" + name + ".txt"; + FileUtils.createFile(path, function(success) { + if (success) { + chatListModel.append({ + "name": name + }); + chatSelector.currentIndex = chatListModel.count - 1; + Zenith.currentChat = name; + messageModel.clear(); + } + }); + } + } + + StyledButton { + icon: "edit" + Layout.preferredWidth: 40 + enabled: chatSelector.currentIndex >= 0 + onClicked: renameDialog.open() + } + + StyledButton { + icon: "delete" + Layout.preferredWidth: 40 + enabled: chatSelector.currentIndex >= 0 && chatSelector.currentText !== "default" + onClicked: { + let name = chatSelector.currentText; + let path = FileUtils.trimFileProtocol(Directories.config) + "/zenith/chats/" + name + ".txt"; + FileUtils.removeFile(path, function(success) { + if (success) { + chatListModel.remove(chatSelector.currentIndex); + selectDefaultChat(); + } + }); + } + } + + } + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(10) + + StyledDropDown { + id: modelSelector + + Layout.fillWidth: true + model: ["openai/gpt-4o","openai/gpt-4","openai/gpt-3.5-turbo","openai/gpt-4o-mini","anthropic/claude-3.5-sonnet","anthropic/claude-3-haiku","meta-llama/llama-3.3-70b-instruct:free","deepseek/deepseek-r1-0528:free","qwen/qwen3-coder:free"] + currentIndex: 0 + Layout.preferredHeight: 40 + onCurrentTextChanged: Zenith.currentModel = currentText + } + + StyledButton { + icon: "fullscreen" + Layout.preferredWidth: 40 + onClicked: { + Quickshell.execDetached(["nucleus", "ipc", "call", "intelligence", "openWindow"]); + Globals.visiblility.sidebarLeft = false; + } + } + + } + + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true + radius: Metrics.radius("normal") + color: Appearance.m3colors.m3surfaceContainerLow + + ScrollView { + anchors.fill: parent + clip: true + + ListView { + id: chatView + + model: messageModel + spacing: Metrics.spacing(8) + anchors.fill: parent + anchors.margins: Metrics.margin(12) + clip: true + + delegate: Item { + property bool isCodeBlock: message.split("\n").length > 2 && message.includes("import ") // simple heuristic + + width: chatView.width + height: bubble.implicitHeight + 6 + Component.onCompleted: { + chatView.forceLayout(); + } + + Row { + width: parent.width + spacing: Metrics.spacing(8) + + Item { + width: sender === "AI" ? 0 : parent.width * 0.2 + } + + StyledRect { + id: bubble + + radius: Metrics.radius("normal") + color: sender === "You" ? Appearance.m3colors.m3primaryContainer : Appearance.m3colors.m3surfaceContainerHigh + implicitWidth: Math.min(textItem.implicitWidth + 20, chatView.width * 0.8) + implicitHeight: textItem.implicitHeight + anchors.right: sender === "You" ? parent.right : undefined + anchors.left: sender === "AI" ? parent.left : undefined + anchors.topMargin: Metrics.margin(2) + + TextEdit { + id: textItem + + text: StringUtils.markdownToHtml(message) + wrapMode: TextEdit.Wrap + textFormat: TextEdit.RichText + readOnly: true // make it selectable but not editable + font.pixelSize: Metrics.fontSize(16) + anchors.leftMargin: Metrics.margin(12) + color: Appearance.syntaxHighlightingTheme + padding: Metrics.padding(8) + anchors.fill: parent + } + + MouseArea { + id: ma + + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + let p = Qt.createQmlObject('import Quickshell; import Quickshell.Io; Process { command: ["wl-copy", "' + message + '"] }', parent); + p.running = true; + } + } + + } + + Item { + width: sender === "You" ? 0 : parent.width * 0.2 + } + + } + + } + + } + + } + + } + + StyledRect { + Layout.fillWidth: true + height: 50 + radius: Metrics.radius("normal") + color: Appearance.m3colors.m3surfaceContainer + + RowLayout { + anchors.fill: parent + anchors.margins: 6 + spacing: 10 + + StyledTextField { + // Shift+Enter → insert newline + // Enter → send message + + id: userInput + + Layout.fillWidth: true + placeholderText: "Type your message..." + font.pixelSize: Metrics.fontSize(14) + padding: Metrics.padding(8) + Keys.onPressed: { + if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { + if (event.modifiers & Qt.ShiftModifier) + insert("\n"); + else + sendMessage(); + event.accepted = true; + } + } + } + + StyledButton { + text: "Send" + enabled: userInput.text.trim().length > 0 && !Zenith.loading + opacity: enabled ? 1 : 0.5 + onClicked: sendMessage() + } + + } + + } + + } + + Dialog { + id: renameDialog + + title: "Rename Chat" + modal: true + visible: false + standardButtons: Dialog.NoButton + x: (root.width - 360) / 2 // center horizontally + y: (root.height - 160) / 2 // center vertically + width: 360 + height: 200 + + ColumnLayout { + anchors.fill: parent + anchors.margins: Metrics.margin(16) + spacing: Metrics.spacing(12) + + StyledText { + text: "Enter a new name for the chat" + font.pixelSize: Metrics.fontSize(18) + horizontalAlignment: Text.AlignHCenter + Layout.fillWidth: true + } + + StyledTextField { + id: renameInput + + Layout.fillWidth: true + placeholderText: "New name" + filled: false + highlight: false + text: chatSelector.currentText + font.pixelSize: Metrics.iconSize(16) + Layout.preferredHeight: 45 + padding: Metrics.padding(8) + } + + RowLayout { + Layout.fillWidth: true + spacing: Metrics.spacing(12) + Layout.alignment: Qt.AlignRight + + StyledButton { + text: "Cancel" + Layout.preferredWidth: 80 + onClicked: renameDialog.close() + } + + StyledButton { + text: "Rename" + Layout.preferredWidth: 100 + enabled: renameInput.text.trim().length > 0 && renameInput.text !== chatSelector.currentText + onClicked: { + let oldName = chatSelector.currentText; + let newName = renameInput.text.trim(); + let oldPath = FileUtils.trimFileProtocol(Directories.config) + "/zenith/chats/" + oldName + ".txt"; + let newPath = FileUtils.trimFileProtocol(Directories.config) + "/zenith/chats/" + newName + ".txt"; + FileUtils.renameFile(oldPath, newPath, function(success) { + if (success) { + chatListModel.set(chatSelector.currentIndex, { + "name": newName + }); + Zenith.currentChat = newName; + renameDialog.close(); + } + }); + } + } + + } + + } + + background: StyledRect { + color: Appearance.m3colors.m3surfaceContainer + radius: Metrics.radius("normal") + border.color: Appearance.colors.colOutline + border.width: 1 + } + + header: StyledRect { + color: Appearance.m3colors.m3surfaceContainer + radius: Metrics.radius("normal") + border.color: Appearance.colors.colOutline + border.width: 1 + } + + } + + StyledText { + text: "Thinking…" + visible: Zenith.loading + color: Appearance.colors.colSubtext + font.pixelSize: Metrics.fontSize(14) + + anchors { + left: parent.left + bottom: parent.bottom + leftMargin: Metrics.margin(22) + bottomMargin: Metrics.margin(76) + } + + } + + } + + Connections { + function onChatsListed(text) { + let lines = text.split(/\r?\n/); + updateChatsList(lines); + // only auto-select once + if (!initialChatSelected) { + selectDefaultChat(); + initialChatSelected = true; + } + } + + function onAiReply(text) { + appendMessage("AI", text.slice(5)); + Zenith.loading = false; + } + + function onChatLoaded(text) { + let lines = text.split(/\r?\n/); + let batch = []; + for (let l of lines) { + let line = l.trim(); + if (!line.length) + continue; + + let u = line.match(/^\[\d{4}-.*\] User: (.*)$/); + let a = line.match(/^\[\d{4}-.*\] AI: (.*)$/); + if (u) + batch.push({ + "sender": "You", + "message": u[1] + }); + else if (a) + batch.push({ + "sender": "AI", + "message": a[1] + }); + else if (batch.length) + batch[batch.length - 1].message += "\n" + line; + } + messageModel.clear(); + for (let m of batch) messageModel.append(m) + scrollToBottom(); + } + + target: Zenith + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SidebarLeft.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SidebarLeft.qml new file mode 100644 index 0000000..d498aa6 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SidebarLeft.qml @@ -0,0 +1,90 @@ +import qs.config +import qs.modules.components +import qs.modules.functions +import qs.services +import QtQuick +import Quickshell +import QtQuick.Layouts +import Quickshell.Wayland +import Quickshell.Io +import Quickshell.Hyprland +import QtQuick.Controls +import Qt5Compat.GraphicalEffects + +PanelWindow { + id: sidebarLeft + WlrLayershell.namespace: "nucleus:sidebarLeft" + WlrLayershell.layer: WlrLayer.Top + visible: Config.initialized && Globals.visiblility.sidebarLeft && !Globals.visiblility.sidebarRight + color: "transparent" + exclusiveZone: 0 + WlrLayershell.keyboardFocus: Compositor.require("hyprland") && Globals.visiblility.sidebarLeft + + property real sidebarLeftWidth: 500 + + implicitWidth: Compositor.screenW + + HyprlandFocusGrab { + id: grab + active: Compositor.require("hyprland") + windows: [sidebarLeft] + } + + anchors { + top: true + left: (Config.runtime.bar.position === "top" || Config.runtime.bar.position === "bottom" || Config.runtime.bar.position === "left") + bottom: true + right: (Config.runtime.bar.position === "right") + } + + margins { + top: Config.runtime.bar.margins + bottom: Config.runtime.bar.margins + left: Metrics.margin("small") + right: Metrics.margin("small") + } + + MouseArea { + anchors.fill: parent + z: 0 + onPressed: Globals.visiblility.sidebarLeft = false + } + + StyledRect { + id: container + z: 1 + color: Appearance.m3colors.m3background + radius: Metrics.radius("large") + width: sidebarLeft.sidebarLeftWidth + + anchors { + top: parent.top + bottom: parent.bottom + left: parent.left + } + + FocusScope { + focus: true + anchors.fill: parent + + Keys.onPressed: { + if (event.key === Qt.Key_Escape) { + Globals.visiblility.sidebarLeft = false; + } + } + + SidebarLeftContent {} + } + } + + function togglesidebarLeft() { + Globals.visiblility.sidebarLeft = !Globals.visiblility.sidebarLeft; + } + + IpcHandler { + target: "sidebarLeft" + function toggle() { + togglesidebarLeft(); + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SidebarLeftContent.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SidebarLeftContent.qml new file mode 100644 index 0000000..9726f98 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SidebarLeftContent.qml @@ -0,0 +1,142 @@ +import Qt5Compat.GraphicalEffects +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import qs.config +import qs.modules.functions +import qs.modules.components +import qs.services + +Item { + anchors.fill: parent + + SwipeView { + id: view + + anchors.fill: parent + + // IntelligencePanel {} + SystemOverview {} + // WallpapersPage {} + + } + + Rectangle { + height: 2 + width: parent.width - Metrics.margin("verylarge") + color: Appearance.m3colors.m3outlineVariant + opacity: 0.6 + + anchors { + top: view.top + topMargin: segmentedIndicator.height + Metrics.margin("verysmall") + horizontalCenter: view.horizontalCenter + } + + } + + Rectangle { + id: activeTabIndicator + + height: 2 + width: 96 + radius: Metrics.radius(1) + color: Appearance.m3colors.m3primary + x: (segmentedIndicator.width / view.count) * view.currentIndex + (segmentedIndicator.width / view.count - width) / 2 + + anchors { + top: segmentedIndicator.bottom + topMargin: Metrics.margin(8) + } + + Behavior on x { + NumberAnimation { + duration: Metrics.chronoDuration(220) + easing.type: Easing.OutCubic + } + + } + + } + + Item { + id: segmentedIndicator + + height: 56 + width: parent.width + + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + } + + Row { + anchors.fill: parent + spacing: 0 + + Repeater { + model: [ + // { + // "icon": "neurology", + // "text": "Intelligence" + // }, + { + "icon": "overview", + "text": "Overview" + }, + // { + // "icon": "wallpaper", + // "text": "Wallpapers" + // } + ] + + Item { + width: segmentedIndicator.width / view.count + height: parent.height + + MouseArea { + anchors.fill: parent + onClicked: view.currentIndex = index + } + + // Icon (true center) + MaterialSymbol { + icon: modelData.icon + iconSize: Metrics.iconSize("huge") + color: view.currentIndex === index ? Appearance.m3colors.m3primary : Appearance.m3colors.m3onSurfaceVariant + + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + topMargin: Metrics.margin(12) + } + + } + + // Label (independent centering) + StyledText { + text: modelData.text + font.pixelSize: Metrics.fontSize("large") + font.weight: Font.Medium + color: view.currentIndex === index ? Appearance.m3colors.m3primary : Appearance.m3colors.m3onSurfaceVariant + + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + bottomMargin: 0 + } + + } + + } + + } + + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SystemOverview.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SystemOverview.qml new file mode 100644 index 0000000..f2ecf9d --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/SystemOverview.qml @@ -0,0 +1,486 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import qs.modules.functions +import qs.services +import qs.config +import qs.modules.components + +Item { + id: root + + implicitWidth: 300 + implicitHeight: parent ? parent.height : 500 + + ColumnLayout { + anchors.topMargin: Metrics.margin(90) + anchors.fill: parent + anchors.margins: Metrics.margin("normal") + spacing: Metrics.margin("small") + + // Header + RowLayout { + Layout.fillWidth: true + + RowLayout { + spacing: Metrics.margin("normal") + + StyledText { + text: SystemDetails.osIcon + font.family: Metrics.fontFamily("nerdIcons") + font.pixelSize: Metrics.fontSize(48) + color: Appearance.colors.colPrimary + } + + ColumnLayout { + spacing: Metrics.spacing(2) + + StyledText { + text: SystemDetails.osName + font.pixelSize: Metrics.fontSize("large") + color: Appearance.m3colors.m3onSurface + } + + StyledText { + text: `${SystemDetails.username}@${SystemDetails.hostname}` + font.pixelSize: Metrics.fontSize("small") + color: Appearance.colors.colSubtext + } + + } + + } + + Item { + Layout.fillWidth: true + } + + ColumnLayout { + spacing: Metrics.spacing(2) + Layout.alignment: Qt.AlignRight + + StyledText { + text: `qs ${SystemDetails.qsVersion}` + font.pixelSize: Metrics.fontSize("small") + color: Appearance.colors.colSubtext + } + + StyledText { + text: `nucleus-shell v${Config.runtime.shell.version}` + font.pixelSize: Metrics.fontSize("smaller") + color: Appearance.colors.colSubtext + } + + } + + } + + Rectangle { + Layout.fillWidth: true + implicitHeight: 56 + radius: Metrics.radius("normal") + color: Appearance.colors.colLayer2 + + RowLayout { + anchors.fill: parent + anchors.margins: Metrics.margin("small") + + StyledText { + text: "Uptime" + font.pixelSize: Metrics.fontSize("normal") + color: Appearance.colors.colPrimary + } + + Item { + Layout.fillWidth: true + } + + StyledText { + text: SystemDetails.uptime + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurface + } + + } + + } + + Rectangle { + Layout.fillWidth: true + implicitHeight: 56 + radius: Metrics.radius("normal") + color: Appearance.colors.colLayer2 + + RowLayout { + anchors.fill: parent + anchors.margins: Metrics.margin("small") + + StyledText { + text: "Operating System" + font.pixelSize: Metrics.fontSize("normal") + color: Appearance.colors.colPrimary + } + + Item { + Layout.fillWidth: true + } + + StyledText { + text: SystemDetails.osName + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurface + elide: Text.ElideRight + } + + } + + } + + Rectangle { + Layout.fillWidth: true + implicitHeight: 320 + radius: Metrics.radius("large") + color: Appearance.colors.colLayer2 + + ColumnLayout { + anchors.fill: parent + anchors.margins: Metrics.margin("large") + spacing: Metrics.margin("normal") + + ColumnLayout { + spacing: Metrics.spacing(6) + + RowLayout { + StyledText { + text: "CPU Usage" + color: Appearance.colors.colSubtext + } + + Item { + Layout.fillWidth: true + } + + StyledText { + animate: false + text: SystemDetails.cpuLoad + color: Appearance.colors.colSubtext + } + + } + + Rectangle { + Layout.fillWidth: true + height: 10 + radius: Metrics.radius(5) + color: Appearance.colors.colLayer1 + + Rectangle { + width: parent.width * SystemDetails.cpuPercent + height: parent.height + radius: Metrics.radius(5) + color: Appearance.colors.colPrimary + } + + } + + } + + ColumnLayout { + spacing: Metrics.spacing(6) + + RowLayout { + StyledText { + text: "Ram Usage" + color: Appearance.colors.colSubtext + } + + Item { + Layout.fillWidth: true + } + + StyledText { + animate: false + text: SystemDetails.ramUsage + color: Appearance.colors.colSubtext + } + + } + + Rectangle { + Layout.fillWidth: true + height: 10 + radius: Metrics.radius(5) + color: Appearance.colors.colLayer1 + + Rectangle { + width: parent.width * SystemDetails.ramPercent + height: parent.height + radius: Metrics.radius(5) + color: Appearance.colors.colPrimary + } + + } + + } + + ColumnLayout { + spacing: Metrics.spacing(6) + + RowLayout { + StyledText { + text: "Disk Usage" + color: Appearance.colors.colSubtext + } + + Item { + Layout.fillWidth: true + } + + StyledText { + animate: false + text: SystemDetails.diskUsage + color: Appearance.colors.colSubtext + } + + } + + Rectangle { + Layout.fillWidth: true + height: 10 + radius: Metrics.radius(5) + color: Appearance.colors.colLayer1 + + Rectangle { + width: parent.width * SystemDetails.diskPercent + height: parent.height + radius: Metrics.radius(5) + color: Appearance.colors.colPrimary + } + + } + + } + + ColumnLayout { + spacing: Metrics.spacing(6) + + RowLayout { + StyledText { + text: "Swap Usage" + color: Appearance.colors.colSubtext + } + + Item { + Layout.fillWidth: true + } + + StyledText { + text: SystemDetails.swapUsage + color: Appearance.colors.colSubtext + } + + } + + Rectangle { + Layout.fillWidth: true + height: 10 + radius: Metrics.radius(5) + color: Appearance.colors.colLayer1 + + Rectangle { + width: parent.width * SystemDetails.swapPercent + height: parent.height + radius: Metrics.radius(5) + color: Appearance.colors.colPrimary + } + + } + + } + + } + + } + + Rectangle { + Layout.fillWidth: true + implicitHeight: 72 + radius: Metrics.radius("normal") + color: Appearance.colors.colLayer2 + + RowLayout { + anchors.fill: parent + anchors.margins: Metrics.margin("small") + spacing: Metrics.margin("large") + + ColumnLayout { + spacing: Metrics.spacing(2) + + StyledText { + text: "Kernel" + font.pixelSize: Metrics.fontSize("small") + color: Appearance.colors.colSubtext + } + + StyledText { + text: SystemDetails.kernelVersion + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurface + } + + } + + Item { + Layout.fillWidth: true + } + + ColumnLayout { + spacing: Metrics.spacing(2) + Layout.alignment: Qt.AlignRight + + StyledText { + text: "Architecture" + font.pixelSize: Metrics.fontSize("small") + color: Appearance.colors.colSubtext + horizontalAlignment: Text.AlignRight + } + + StyledText { + text: SystemDetails.architecture + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurface + horizontalAlignment: Text.AlignRight + } + + } + + } + + } + + Rectangle { + Layout.fillWidth: true + implicitHeight: 72 + radius: Metrics.radius("normal") + color: Appearance.colors.colLayer2 + visible: UPower.batteryPresent + + RowLayout { + anchors.fill: parent + anchors.margins: Metrics.margin("small") + spacing: Metrics.margin("large") + + ColumnLayout { + spacing: Metrics.spacing(2) + + StyledText { + text: "Battery" + font.pixelSize: Metrics.fontSize("small") + color: Appearance.colors.colSubtext + } + + StyledText { + text: `${Math.round(UPower.percentage)}%` + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurface + } + + } + + Item { + Layout.fillWidth: true + } + + ColumnLayout { + spacing: Metrics.spacing(2) + Layout.alignment: Qt.AlignRight + + StyledText { + text: "AC" + font.pixelSize: Metrics.fontSize("small") + color: Appearance.colors.colSubtext + horizontalAlignment: Text.AlignRight + } + + StyledText { + text: UPower.acOnline ? "online" : "battery" + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurface + horizontalAlignment: Text.AlignRight + } + + } + + } + + } + + Rectangle { + Layout.fillWidth: true + implicitHeight: 56 + radius: Metrics.radius("normal") + color: Appearance.colors.colLayer2 + + RowLayout { + anchors.fill: parent + anchors.margins: Metrics.margin("small") + + StyledText { + text: "Running Processes" + font.pixelSize: Metrics.fontSize("normal") + color: Appearance.colors.colPrimary + } + + Item { + Layout.fillWidth: true + } + + StyledText { + text: SystemDetails.runningProcesses + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurface + } + + } + + } + + Rectangle { + Layout.fillWidth: true + implicitHeight: 56 + radius: Metrics.radius("normal") + color: Appearance.colors.colLayer2 + + RowLayout { + anchors.fill: parent + anchors.margins: Metrics.margin("small") + + StyledText { + text: "Logged-in Users" + font.pixelSize: Metrics.fontSize("normal") + color: Appearance.colors.colPrimary + } + + Item { + Layout.fillWidth: true + } + + StyledText { + text: SystemDetails.loggedInUsers + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurface + } + + } + + } + + Item { + Layout.fillHeight: true + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/WallpapersPage.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/WallpapersPage.qml new file mode 100644 index 0000000..ebab61c --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarLeft/WallpapersPage.qml @@ -0,0 +1,114 @@ +import Qt.labs.folderlistmodel +import Qt5Compat.GraphicalEffects +import QtCore +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import qs.modules.functions +import qs.services +import qs.config +import qs.modules.components + +Item { + id: wallpapersPage + property string displayName: screen?.name ?? "" + + FolderListModel { + id: wallpaperModel + + folder: StandardPaths.writableLocation(StandardPaths.PicturesLocation) + "/Wallpapers" + nameFilters: ["*.png", "*.jpg", "*.jpeg", "*.webp", "mp4", "mkv", "webm", "avi", "mov", "flv", "wmv", "m4v"] + showDirs: false + showDotAndDotDot: false + } + + // EMPTY STATE + StyledText { + visible: wallpaperModel.count === 0 + text: "Put some wallpapers in\n~/Pictures/Wallpapers" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: Appearance.m3colors.m3onSurfaceVariant + font.pixelSize: Appearance.font.size.large + anchors.centerIn: parent + } + + // WALLPAPER LIST + ListView { + anchors.topMargin: 90 + visible: wallpaperModel.count > 0 + anchors.fill: parent + model: wallpaperModel + spacing: Appearance.margin.normal + clip: true + + delegate: Item { + width: ListView.view.width + height: 240 + + StyledRect { + id: imgContainer + property bool activeWallpaper: + Config.runtime.monitors?.[wallpapersPage.displayName]?.wallpaper === fileUrl + + anchors.fill: parent + anchors.leftMargin: 20 + anchors.rightMargin: 20 + radius: Appearance.rounding.normal + color: activeWallpaper + ? Appearance.m3colors.m3secondaryContainer + : Appearance.m3colors.m3surfaceContainerLow + layer.enabled: true + + Image { + id: wallImg + + anchors.fill: parent + source: fileUrl + fillMode: Image.PreserveAspectCrop + asynchronous: true + cache: true + clip: true + } + + StyledText { + anchors.centerIn: parent + text: "Unsupported / Corrupted Image" + visible: wallImg.status === Image.Error + } + + MouseArea { + anchors.fill: parent + onClicked: { + Config.updateKey( + "monitors." + wallpapersPage.displayName + ".wallpaper", + fileUrl + ); + if (Config.runtime.appearance.colors.autogenerated) { + Quickshell.execDetached([ + "nucleus", "ipc", "call", "global", "regenColors" + ]); + } + } + cursorShape: Qt.PointingHandCursor + } + + layer.effect: OpacityMask { + + maskSource: Rectangle { + width: imgContainer.width + height: imgContainer.height + radius: imgContainer.radius + } + + } + + } + + } + + } + +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/SidebarRight.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/SidebarRight.qml new file mode 100644 index 0000000..e813ba8 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/SidebarRight.qml @@ -0,0 +1,97 @@ +import qs.config +import qs.modules.components +import qs.modules.functions +import qs.services +import QtQuick +import Quickshell +import QtQuick.Layouts +import Quickshell.Wayland +import Quickshell.Io +import Quickshell.Hyprland +import QtQuick.Controls +import Quickshell.Services.Pipewire +import Qt5Compat.GraphicalEffects + +PanelWindow { + id: sidebarRight + WlrLayershell.namespace: "nucleus:sidebarRight" + WlrLayershell.layer: WlrLayer.Top + visible: Config.initialized && Globals.visiblility.sidebarRight && !Globals.visiblility.sidebarLeft + color: "transparent" + exclusiveZone: 0 + WlrLayershell.keyboardFocus: Compositor.require("hyprland") && Globals.visiblility.sidebarRight + + property real sidebarRightWidth: 500 + + implicitWidth: Compositor.screenW + + HyprlandFocusGrab { + id: grab + active: Compositor.require("hyprland") + windows: [sidebarRight] + } + + anchors { + top: true + right: (Config.runtime.bar.position === "top" || Config.runtime.bar.position === "bottom" || Config.runtime.bar.position === "right") + bottom: true + left: (Config.runtime.bar.position === "left") + } + + margins { + top: Config.runtime.bar.margins + bottom: Config.runtime.bar.margins + left: Metrics.margin("small") + right: Metrics.margin("small") + } + + PwObjectTracker { + objects: [Pipewire.defaultAudioSink] + } + + property var sink: Pipewire.defaultAudioSink?.audio + + MouseArea { + anchors.fill: parent + z: 0 + onPressed: Globals.visiblility.sidebarRight = false + } + + StyledRect { + id: container + z: 1 + color: Appearance.m3colors.m3background + radius: Metrics.radius("large") + width: sidebarRight.sidebarRightWidth + + anchors { + top: parent.top + bottom: parent.bottom + right: parent.right + } + + FocusScope { + focus: true + anchors.fill: parent + + Keys.onPressed: { + if (event.key === Qt.Key_Escape) { + Globals.visiblility.sidebarRight = false; + } + } + + SidebarRightContent {} + } + } + + function togglesidebarRight() { + Globals.visiblility.sidebarRight = !Globals.visiblility.sidebarRight; + } + + IpcHandler { + target: "sidebarRight" + function toggle() { + togglesidebarRight(); + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/SidebarRightContent.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/SidebarRightContent.qml new file mode 100644 index 0000000..8780c94 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/SidebarRightContent.qml @@ -0,0 +1,247 @@ +import qs.config +import qs.modules.components +import qs.services +import qs.modules.functions +import QtQuick +import Quickshell +import QtQuick.Layouts +import Quickshell.Wayland +import Quickshell.Io +import QtQuick.Controls +import Quickshell.Services.Pipewire +import Qt5Compat.GraphicalEffects +import "content/" + +Item { + anchors.fill: parent + anchors.leftMargin: Metrics.margin("normal") + anchors.rightMargin: Metrics.margin("normal") + anchors.topMargin: Metrics.margin("large") + anchors.bottomMargin: Metrics.margin("large") + + ColumnLayout { + id: mainLayout + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: Metrics.margin("tiny") + anchors.rightMargin: Metrics.margin("tiny") + anchors.margins: Metrics.margin("large") + spacing: Metrics.margin("large") + + RowLayout { + id: topSection + Layout.fillWidth: true + + ColumnLayout { + Layout.fillWidth: true + Layout.leftMargin: Metrics.margin(10) + Layout.alignment: Qt.AlignVCenter + spacing: Metrics.spacing(2) + + RowLayout { + spacing: Metrics.spacing(8) + + StyledText { + text: SystemDetails.osIcon + font.pixelSize: Metrics.fontSize("hugeass") + 6 + } + + StyledText { + text: SystemDetails.uptime + font.pixelSize: Metrics.fontSize("large") + Layout.alignment: Qt.AlignBottom + Layout.bottomMargin: Metrics.margin(5) + } + } + } + + Item { Layout.fillWidth: true } + + Row { + spacing: Metrics.spacing(6) + Layout.leftMargin: Metrics.margin(25) + Layout.alignment: Qt.AlignVCenter + + StyledRect { + id: screenshotbtncontainer + color: "transparent" + radius: Metrics.radius("large") + implicitHeight: screenshotButton.height + Metrics.margin("tiny") + implicitWidth: screenshotButton.width + Metrics.margin("small") + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.topMargin: Metrics.margin(10) + Layout.leftMargin: Metrics.margin(15) + + MaterialSymbolButton { + id: screenshotButton + icon: "edit" + anchors.centerIn: parent + iconSize: Metrics.iconSize("hugeass") + 2 + tooltipText: "Take a screenshot" + + onButtonClicked: { + Quickshell.execDetached(["nucleus", "ipc", "call", "screen", "capture"]) + Globals.visiblility.sidebarRight = false; + } + } + } + + StyledRect { + id: reloadbtncontainer + color: "transparent" + radius: Metrics.radius("large") + implicitHeight: reloadButton.height + Metrics.margin("tiny") + implicitWidth: reloadButton.width + Metrics.margin("small") + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.topMargin: Metrics.margin(10) + Layout.leftMargin: Metrics.margin(15) + + MaterialSymbolButton { + id: reloadButton + icon: "refresh" + anchors.centerIn: parent + iconSize: Metrics.iconSize("hugeass") + 4 + tooltipText: "Reload Nucleus Shell" + + onButtonClicked: { + Quickshell.execDetached(["nucleus", "run", "--reload"]) + } + } + } + + StyledRect { + id: settingsbtncontainer + color: "transparent" + radius: Metrics.radius("large") + implicitHeight: settingsButton.height + Metrics.margin("tiny") + implicitWidth: settingsButton.width + Metrics.margin("small") + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.topMargin: Metrics.margin(10) + Layout.leftMargin: Metrics.margin(15) + + MaterialSymbolButton { + id: settingsButton + icon: "settings" + anchors.centerIn: parent + iconSize: Metrics.iconSize("hugeass") + 2 + tooltipText: "Open Settings" + onButtonClicked: { + Globals.visiblility.sidebarRight = false + Globals.states.settingsOpen = true + } + } + } + + StyledRect { + id: powerbtncontainer + color: "transparent" + radius: Metrics.radius("large") + implicitHeight: settingsButton.height + Metrics.margin("tiny") + implicitWidth: settingsButton.width + Metrics.margin("small") + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.topMargin: Metrics.margin(10) + Layout.leftMargin: Metrics.margin(15) + + MaterialSymbolButton { + id: powerButton + icon: "power_settings_new" + anchors.centerIn: parent + iconSize: Metrics.iconSize("hugeass") + 2 + tooltipText: "Open PowerMenu" + + onButtonClicked: { + Globals.visiblility.sidebarRight = false + Globals.visiblility.powermenu = true + } + } + } + } + } + + Rectangle { + Layout.fillWidth: true + height: 1 + color: Appearance.m3colors.m3outlineVariant + radius: Metrics.radius(1) + } + + ColumnLayout { + id: sliderColumn + Layout.fillWidth: true + + VolumeSlider { + Layout.fillWidth: true + Layout.preferredHeight: 50 + icon: "volume_up" + iconSize: Metrics.iconSize("large") + 3 + } + + BrightnessSlider { + Layout.fillWidth: true + Layout.preferredHeight: 50 + icon: "brightness_high" + } + } + + Rectangle { + Layout.fillWidth: true + height: 1 + color: Appearance.m3colors.m3outlineVariant + radius: Metrics.radius(1) + } + + GridLayout { + id: middleGrid + Layout.fillWidth: true + columns: 1 + columnSpacing: Metrics.spacing(8) + rowSpacing: Metrics.spacing(8) + Layout.preferredWidth: parent.width + + RowLayout { + NetworkToggle { + Layout.fillWidth: true + Layout.preferredHeight: 80 + } + FlightModeToggle { + Layout.fillWidth: true + Layout.preferredHeight: 80 + } + } + + RowLayout { + BluetoothToggle { + Layout.preferredWidth: 220 + Layout.preferredHeight: 80 + } + ThemeToggle { + Layout.preferredHeight: 80 + Layout.fillWidth: true + } + NightModeToggle { + Layout.preferredHeight: 80 + Layout.fillWidth: true + } + } + } + + ColumnLayout { + spacing: Metrics.margin("small") + Layout.fillWidth: true + + Rectangle { + Layout.fillWidth: true + height: 1 + color: Appearance.m3colors.m3outlineVariant + radius: Metrics.radius(1) + Layout.topMargin: Metrics.margin(5) + Layout.bottomMargin: Metrics.margin(5) + } + + NotifModal { + Layout.preferredHeight: (Config.runtime.bar.position === "left" || Config.runtime.bar.position === "right") ? 480 : 470 + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/BluetoothToggle.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/BluetoothToggle.qml new file mode 100644 index 0000000..4f3ce1f --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/BluetoothToggle.qml @@ -0,0 +1,91 @@ +import qs.config +import qs.modules.components +import qs.services +import QtQuick +import Quickshell +import QtQuick.Layouts + +StyledRect { + id: root + width: 200 + height: 80 + radius: Metrics.radius("verylarge") + color: Appearance.m3colors.m3surfaceContainerHigh + + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + + readonly property bool adapterPresent: Bluetooth.defaultAdapter !== null + readonly property bool enabled: Bluetooth.defaultAdapter?.enabled ?? false + readonly property var activeDevice: Bluetooth.activeDevice + + readonly property string iconName: Bluetooth.icon + + readonly property string statusText: { + if (!adapterPresent) + return "No adapter"; + if (!enabled) + return "Disabled"; + if (activeDevice) + return activeDevice.name; + return Bluetooth.defaultAdapter.discovering + ? "Scanning…" + : "Enabled"; + } + + StyledRect { + id: iconBg + width: 50 + height: 50 + radius: Metrics.radius("verylarge") + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Metrics.margin("small") + + color: { + if (!enabled) + return Appearance.m3colors.m3surfaceContainerHigh; + if (activeDevice) + return Appearance.m3colors.m3primaryContainer; + return Appearance.m3colors.m3secondaryContainer; + } + + MaterialSymbol { + anchors.centerIn: parent + iconSize: Metrics.iconSize(35) + icon: iconName + } + } + + Column { + anchors.verticalCenter: parent.verticalCenter + anchors.left: iconBg.right + anchors.leftMargin: Metrics.margin("small") + spacing: Metrics.spacing(2) + + StyledText { + text: "Bluetooth" + font.pixelSize: Metrics.fontSize("large") + elide: Text.ElideRight + width: root.width - iconBg.width - 30 + } + + StyledText { + text: statusText + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurfaceVariant + elide: Text.ElideRight + width: root.width - iconBg.width - 30 + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + if (!adapterPresent) + return; + + Bluetooth.defaultAdapter.enabled = + !Bluetooth.defaultAdapter.enabled; + } + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/BrightnessSlider.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/BrightnessSlider.qml new file mode 100644 index 0000000..f790b12 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/BrightnessSlider.qml @@ -0,0 +1,28 @@ +import qs.config +import qs.modules.components +import qs.services +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Services.Pipewire +import Quickshell.Widgets +import QtQuick.Controls + + +StyledSlider { + id: brightnessSlider + Layout.fillWidth: true + from: 0 + to: 1 + stepSize: 0.01 + property var monitor: Brightness.monitors.length > 0 ? Brightness.monitors[0] : null + value: monitor ? monitor.brightness : 0.5 + + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + + property real level: brightnessSlider.value * 100 + + onMoved: if (monitor) { + monitor.setBrightness(value); + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/FlightModeToggle.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/FlightModeToggle.qml new file mode 100644 index 0000000..956cea3 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/FlightModeToggle.qml @@ -0,0 +1,73 @@ +import qs.config +import qs.modules.components +import qs.modules.functions +import qs.services +import QtQuick +import Quickshell +import Quickshell.Io +import QtQuick.Layouts + +StyledRect { + id: root + width: 150 + height: 50 + radius: Metrics.radius("verylarge") + color: Appearance.m3colors.m3surfaceContainerHigh + + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + + property bool flightMode + property string flightModeText: flightMode ? "Enabled" : "Disabled" + + Process { + id: toggleflightModeProc + running: false + command: [] + + function toggle() { + flightMode = !flightMode; + const cmd = flightMode ? "off" : "on"; + toggleflightModeProc.command = ["bash", "-c", `nmcli radio all ${cmd}`]; + toggleflightModeProc.running = true; + } + } + + StyledRect { + id: iconBg + width: 50 + height: 50 + radius: Metrics.radius("large") + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Metrics.margin(10) + color: !flightMode ? Appearance.m3colors.m3surfaceContainerHigh : Appearance.m3colors.m3primaryContainer + + MaterialSymbol { + anchors.centerIn: parent + iconSize: Metrics.iconSize(35) + icon: "flight" + } + } + + Column { + anchors.verticalCenter: parent.verticalCenter + anchors.left: iconBg.right + anchors.leftMargin: Metrics.margin(10) + + StyledText { + text: "Flight Mode" + font.pixelSize: Metrics.fontSize(20) + } + + StyledText { + text: flightModeText + font.pixelSize: Metrics.fontSize("small") + } + } + + MouseArea { + anchors.fill: parent + propagateComposedEvents: true + onClicked: toggleflightModeProc.toggle() + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/Media.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/Media.qml new file mode 100644 index 0000000..fbce4a5 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/Media.qml @@ -0,0 +1,196 @@ +import Qt5Compat.GraphicalEffects +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets +import Quickshell.Io +import qs.config +import qs.modules.functions +import qs.modules.interface.notifications +import qs.modules.components +import qs.services + +StyledRect { + id: root + + Layout.fillWidth: true + radius: Metrics.radius("normal") + color: Appearance.m3colors.m3surfaceContainer + + ClippingRectangle { + color: Appearance.colors.colLayer1 + radius: Metrics.radius("normal") + implicitHeight: 90 + anchors.fill: parent + + RowLayout { + anchors.fill: parent + spacing: Metrics.margin("small") + + ClippingRectangle { + implicitWidth: 140 + implicitHeight: 140 + Layout.leftMargin: Metrics.margin("large") + radius: Metrics.radius("normal") + clip: true + color: Appearance.colors.colLayer2 + + Image { + anchors.fill: parent + source: Mpris.artUrl + fillMode: Image.PreserveAspectCrop + cache: true + } + + } + + ColumnLayout { + Layout.fillWidth: true + Layout.rightMargin: Metrics.margin("small") + spacing: Metrics.spacing(2) + + Text { + text: Mpris.albumTitle + elide: Text.ElideRight + Layout.maximumWidth: 190 + font.family: Metrics.fontFamily("title") + font.pixelSize: Metrics.fontSize("hugeass") + font.bold: true + color: Appearance.colors.colOnLayer2 + } + + Text { + text: Mpris.albumArtist + elide: Text.ElideRight + Layout.maximumWidth: 160 + font.family: Metrics.fontFamily("main") + font.pixelSize: Metrics.fontSize("normal") + color: Appearance.colors.colSubtext + } + + RowLayout { + + Layout.fillWidth: true + spacing: Metrics.spacing(12) + + Process { + id: control + } + + Button { + Layout.preferredWidth: 36 + Layout.preferredHeight: 36 + onClicked: Quickshell.execDetached(["playerctl", "previous"]) + + background: Rectangle { + radius: Metrics.radius("large") + color: Appearance.colors.colLayer2 + } + + contentItem: MaterialSymbol { + anchors.centerIn: parent + icon: "skip_previous" + font.pixelSize: Metrics.fontSize(24) + color: Appearance.colors.colOnLayer2 + fill: 1 + } + + } + + Button { + Layout.preferredWidth: 42 + Layout.preferredHeight: 42 + onClicked: Quickshell.execDetached(["playerctl", "play-pause"]) + + background: Rectangle { + radius: Metrics.radius("full") + color: Appearance.colors.colPrimary + } + + contentItem: MaterialSymbol { + anchors.bottom: parent.bottom + anchors.top: parent.top + icon: "play_arrow" + font.pixelSize: Metrics.fontSize(36) + color: Appearance.colors.colOnPrimary + fill: 1 + + } + + } + + Button { + Layout.preferredWidth: 36 + Layout.preferredHeight: 36 + onClicked: Quickshell.execDetached(["playerctl", "next"]) + + background: Rectangle { + radius: Metrics.radius("large") + color: Appearance.colors.colLayer2 + } + + contentItem: MaterialSymbol { + anchors.centerIn: parent + icon: "skip_next" + font.pixelSize: Metrics.fontSize(24) + color: Appearance.colors.colOnLayer2 + fill: 1 + + } + + } + + } + + RowLayout { + Layout.topMargin: Metrics.margin(15) + Layout.fillWidth: true + spacing: Metrics.spacing(12) + + Text { + text: Mpris.formatTime(Mpris.positionSec) + font.pixelSize: Metrics.fontSize("smallest") + color: Appearance.colors.colSubtext + } + + Item { + Layout.fillWidth: true + implicitHeight: 20 + + Rectangle { + anchors.fill: parent + radius: Metrics.radius("full") + color: Appearance.colors.colLayer2 + } + + Rectangle { + width: parent.width * (Mpris.lengthSec > 0 ? Mpris.positionSec / Mpris.lengthSec : 0) + radius: Metrics.radius("full") + color: Appearance.colors.colPrimary + + anchors { + left: parent.left + top: parent.top + bottom: parent.bottom + } + + } + + } + + Text { + text: Mpris.formatTime(Mpris.lengthSec) + font.pixelSize: Metrics.fontSize("smallest") + color: Appearance.colors.colSubtext + } + + } + + } + + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NetworkToggle.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NetworkToggle.qml new file mode 100644 index 0000000..428edb1 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NetworkToggle.qml @@ -0,0 +1,78 @@ +import qs.config +import qs.modules.components +import qs.modules.functions +import qs.services +import QtQuick +import Quickshell +import QtQuick.Layouts + +StyledRect { + id: root + width: 150 + height: 50 + radius: Metrics.radius("verylarge") + color: Appearance.m3colors.m3surfaceContainerHigh + + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + + // Service bindings + readonly property bool wifiEnabled: Network.wifiEnabled + readonly property bool hasActive: Network.active !== null + readonly property string iconName: Network.icon + readonly property string titleText: Network.label + readonly property string statusText: Network.status + + // Icon background + StyledRect { + id: iconBg + width: 50 + height: 50 + radius: Metrics.radius("large") + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Metrics.margin(10) + + color: { + if (!wifiEnabled) + return Appearance.m3colors.m3surfaceContainerHigh; + if (hasActive) + return Appearance.m3colors.m3primaryContainer; + return Appearance.m3colors.m3secondaryContainer; + } + + MaterialSymbol { + anchors.centerIn: parent + icon: iconName + iconSize: Metrics.iconSize(35) + } + } + + // Labels + Column { + anchors.verticalCenter: parent.verticalCenter + anchors.left: iconBg.right + anchors.leftMargin: Metrics.margin(10) + spacing: Metrics.spacing(2) + + StyledText { + text: titleText + font.pixelSize: Metrics.fontSize(20) + elide: Text.ElideRight + width: root.width - iconBg.width - 30 + } + + StyledText { + text: statusText + font.pixelSize: Metrics.fontSize("small") + color: Appearance.m3colors.m3onSurfaceVariant + elide: Text.ElideRight + width: root.width - iconBg.width - 30 + } + } + + // Interaction + MouseArea { + anchors.fill: parent + onClicked: Network.toggleWifi() + } +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NightModeToggle.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NightModeToggle.qml new file mode 100644 index 0000000..9c6b08b --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NightModeToggle.qml @@ -0,0 +1,33 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs.services +import qs.config +import qs.modules.components + +Rectangle { + id: root + + property bool nightTime + width: 200 + height: 80 + radius: Metrics.radius("childish") + color: !nightTime ? Appearance.m3colors.m3surfaceContainer : Appearance.m3colors.m3paddingContainer + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + Layout.margins: 0 + + MaterialSymbol { + anchors.centerIn: parent + iconSize: Metrics.iconSize(35) + icon: "coffee" + } + + MouseArea { + anchors.fill: parent + onClicked: { + nightTime = !nightTime; + nightTime ? Quickshell.execDetached(["gammastep", "-O", "4000"]) : Quickshell.execDetached(["killall", "gammastep"]); + } + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NotifModal.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NotifModal.qml new file mode 100644 index 0000000..7ea455a --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/NotifModal.qml @@ -0,0 +1,110 @@ +import Qt5Compat.GraphicalEffects +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import qs.modules.functions +import qs.modules.interface.notifications +import qs.services +import qs.config +import qs.modules.components + +StyledRect { + id: root + + Layout.fillWidth: true + radius: Metrics.radius("normal") + color: Appearance.colors.colLayer1 + property bool dndActive: Config.runtime.notifications.doNotDisturb + + function toggleDnd() { + Config.updateKey("notifications.doNotDisturb", !dndActive); + } + + StyledButton { + id: clearButton + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.bottomMargin: Metrics.margin(10) + anchors.rightMargin: Metrics.margin(10) + icon: "clear_all" + text: "Clear" + implicitHeight: 40 + implicitWidth: 100 + secondary: true + + onClicked: { + for (let i = 0; i < NotifServer.history.length; i++) { + let n = NotifServer.history[i]; + if (n?.notification) n.notification.dismiss(); + } + } + } + + StyledButton { + id: silentButton + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.bottomMargin: Metrics.margin(10) + anchors.rightMargin: clearButton.implicitWidth + Metrics.margin(15) + text: "Silent" + icon: "do_not_disturb_on" + implicitHeight: 40 + implicitWidth: 100 + secondary: true + checkable: true + checked: Config.runtime.notifications.doNotDisturb + + onClicked: { + toggleDnd() + } + } + + StyledText { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.bottomMargin: Metrics.margin(15) + anchors.leftMargin: Metrics.margin(15) + text: NotifServer.history.length + " Notifications" + + } + + StyledText { + anchors.centerIn: parent + text: "No notifications" + visible: NotifServer.history.length < 1 + font.pixelSize: Metrics.fontSize("huge") + } + + ListView { + id: notifList + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: clearButton.top + anchors.margins: Metrics.margin(10) + + clip: true + spacing: Metrics.spacing(8) + boundsBehavior: Flickable.StopAtBounds + ScrollBar.vertical: ScrollBar { } + + model: Config.runtime.notifications.enabled + ? NotifServer.history + : [] + + delegate: NotificationChild { + width: notifList.width + title: model.summary + body: model.body + image: model.image || model.appIcon + rawNotif: model + buttons: model.actions.map((action) => ({ + "label": action.text, + "onClick": () => action.invoke() + })) + } + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/ThemeToggle.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/ThemeToggle.qml new file mode 100644 index 0000000..dfc08b1 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/ThemeToggle.qml @@ -0,0 +1,34 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs.services +import qs.config +import qs.modules.components + +Rectangle { + id: root + + readonly property bool isDark: Config.runtime.appearance.theme === "dark" + property string themestatusicon: isDark ? "dark_mode" : "light_mode" + + width: 200 + height: 80 + radius: Metrics.radius("childish") + color: Appearance.m3colors.m3paddingContainer + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + Layout.margins: 0 + + MaterialSymbol { + anchors.centerIn: parent + iconSize: Metrics.iconSize(35) + icon: themestatusicon + } + + MouseArea { + anchors.fill: parent + onClicked: { + Quickshell.execDetached(["nucleus", "ipc", "call", "global", "toggleTheme"]); + } + } + +} diff --git a/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/VolumeSlider.qml b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/VolumeSlider.qml new file mode 100644 index 0000000..8631b43 --- /dev/null +++ b/.config/quickshell/nucleus-shell/modules/interface/sidebarRight/content/VolumeSlider.qml @@ -0,0 +1,34 @@ +import qs.config +import qs.modules.components +import qs.services +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Services.Pipewire +import Quickshell.Widgets +import QtQuick.Controls + + +StyledSlider { + id: volSlider + Layout.fillWidth: true + from: 0 + to: 1 + stepSize: 0.01 + value: sink ? sink.volume : 0 + + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + + property real level: volSlider.value * 100 + + PwObjectTracker { + objects: [Pipewire.defaultAudioSink] + } + + property var sink: Pipewire.defaultAudioSink?.audio + + + onMoved: { + if (sink) sink.volume = value + } +} diff --git a/.config/quickshell/nucleus-shell/plugins/PluginHost.qml b/.config/quickshell/nucleus-shell/plugins/PluginHost.qml new file mode 100644 index 0000000..cb297de --- /dev/null +++ b/.config/quickshell/nucleus-shell/plugins/PluginHost.qml @@ -0,0 +1,27 @@ +import QtQuick +import Quickshell +import qs.config + +Item { + Repeater { + model: PluginLoader.plugins + + delegate: Item { + width: 0 + height: 0 + + LazyLoader { + id: pluginLoader + active: Config.initialized + && Config.runtime + && Config.runtime.plugins + && Config.runtime.plugins[modelData] + && Config.runtime.plugins[modelData].enabled === true // Long ass binding to guard object existence + source: Qt.resolvedUrl( + Directories.shellConfig + "/plugins/" + modelData + "/Main.qml" + ) + loading: true // optional, keeps plugin loaded + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/plugins/PluginLoader.qml b/.config/quickshell/nucleus-shell/plugins/PluginLoader.qml new file mode 100644 index 0000000..33361dd --- /dev/null +++ b/.config/quickshell/nucleus-shell/plugins/PluginLoader.qml @@ -0,0 +1,32 @@ +pragma Singleton +import QtQuick +import Quickshell +import Quickshell.Io +import qs.config + +Item { + id: root + + property var plugins: [] + + function reload() { + listPluginsProc.running = true + } + + Component.onCompleted: reload() + + Process { + id: listPluginsProc + // List directories under ~/.config/nucleus-shell/plugins + command: ["sh", "-c", "ls -1 ~/.config/nucleus-shell/plugins"] + running: true + + stdout: StdioCollector { + onStreamFinished: { + const names = text.split("\n").filter(s => s.trim() !== "") + root.plugins = names + } + } + + } +} diff --git a/.config/quickshell/nucleus-shell/plugins/PluginParser.qml b/.config/quickshell/nucleus-shell/plugins/PluginParser.qml new file mode 100644 index 0000000..bed085c --- /dev/null +++ b/.config/quickshell/nucleus-shell/plugins/PluginParser.qml @@ -0,0 +1,137 @@ +import QtQuick +import Quickshell +import Quickshell.Io +import qs.config +pragma Singleton + +Item { + id: root + + property alias model: pluginModel + property string pendingPid: "" + property bool waitingForState: false + + Timer { + id: statePoller + interval: 100 + repeat: true + running: false + onTriggered: { + if (!waitingForState) + return + + const idx = indexOf(pendingPid) + if (idx === -1) + return + + const realInstalled = isInstalled(pendingPid) + if (pluginModel.get(idx).installed !== realInstalled) { + pluginModel.setProperty(idx, "installed", realInstalled) + pluginModel.setProperty(idx, "busy", false) + waitingForState = false + pendingPid = "" + statePoller.stop() + } + } + } + + function isInstalled(pid) { + return PluginLoader.plugins.indexOf(pid) !== -1 + } + + function indexOf(pid) { + for (let i = 0; i < pluginModel.count; ++i) { + if (pluginModel.get(i).id === pid) + return i + } + return -1 + } + + function refresh() { + pluginModel.clear() + fetchProc.running = true + } + + function install(pid) { + runAction("install", pid) + } + + function uninstall(pid) { + runAction("uninstall", pid) + } + + function update(pid) { + runAction("update", pid) + } + + function runAction(action, pid) { + const idx = indexOf(pid) + if (idx === -1) + return + + pendingPid = pid + waitingForState = true + + pluginModel.setProperty(idx, "busy", true) + + actionProc.command = [ + "bash", + "-c", + Directories.scriptsPath + "/plugins/plugins.sh " + action + " " + pid + ] + actionProc.running = true + } + + ListModel { + id: pluginModel + } + + Process { + id: fetchProc + running: true + command: [ + "bash", + "-c", + Directories.scriptsPath + "/plugins/plugins.sh fetch all-machine" + ] + + stdout: SplitParser { + onRead: (data) => { + const lines = data.split("\n") + for (let i = 0; i < lines.length; ++i) { + const line = lines[i].trim() + if (!line) + continue + + const parts = line.split("\t") + if (parts.length < 7) + continue + + const pid = parts[0] + pluginModel.append({ + id: pid, + name: parts[1], + version: parts[2], + author: parts[3], + description: parts[4], + requires_nucleus: parts[5], + repo: parts[6], + installed: isInstalled(pid), + busy: false + }) + } + } + } + } + + Process { + id: actionProc + + stdout: StdioCollector { + onStreamFinished: { + PluginLoader.reload() + statePoller.start() + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/plugins/PluginSettingsLoader.qml b/.config/quickshell/nucleus-shell/plugins/PluginSettingsLoader.qml new file mode 100644 index 0000000..3c4c959 --- /dev/null +++ b/.config/quickshell/nucleus-shell/plugins/PluginSettingsLoader.qml @@ -0,0 +1,34 @@ +import QtQuick +import QtQuick.Layouts +import qs.config +import qs.plugins + +ColumnLayout { + id: pluginColumn + Layout.fillWidth: true + spacing: 8 + implicitHeight: childrenRect.height + + Repeater { + model: PluginLoader.plugins + + delegate: ContentCard { + Layout.fillWidth: true + + Loader { + Layout.fillWidth: true + asynchronous: true + source: Qt.resolvedUrl( + Directories.shellConfig + "/plugins/" + modelData + "/Settings.qml" + ) + + onStatusChanged: { + if (status === Loader.Ready) { + // recompute height when loader finishes loading + pluginColumn.implicitHeight = pluginColumn.childrenRect.height + } + } + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/scripts/finders/find-apps.sh b/.config/quickshell/nucleus-shell/scripts/finders/find-apps.sh new file mode 100755 index 0000000..c0862a3 --- /dev/null +++ b/.config/quickshell/nucleus-shell/scripts/finders/find-apps.sh @@ -0,0 +1,118 @@ +#!/bin/bash +# List desktop applications for the launcher +# from github.com/bgibson72/yahr-quickshell with modifications +# Blacklist - apps to hide (add desktop file basenames here) +BLACKLIST=( + "xfce4-about.desktop" + "avahi-discover.desktop" + "bssh.desktop" + "bvnc.desktop" + "qv4l2.desktop" + "qvidcap.desktop" + "lstopo.desktop" + "uuctl.desktop" + "codium.desktop" # Hide regular VSCodium (keep Wayland version) + "xgps.desktop" # Hide Xgps + "xgpsspeed.desktop" # Hide Xgpsspeed +) + +# Whitelist - always include these desktop files +WHITELIST=( + "wallpaper.desktop" + "theme.desktop" + "powermenu.desktop" +) + +# Search paths for .desktop files (local first so overrides work) +SEARCH_PATHS=( + "$HOME/.local/share/applications" + "$HOME/.local/share/flatpak/exports/share/applications" + "/var/lib/flatpak/exports/share/applications" + "/usr/local/share/applications" + "/usr/share/applications" +) + +# Function to find icon path +find_icon() { + local icon_name="$1" + local theme="Papirus" + icon_name="${icon_name#theme://}" + [[ "$icon_name" == /* ]] && { echo "$icon_name"; return; } + + local exts=(png svg xpm) + local sizes=(16 22 24 32 48 64 128 256 512 scalable) + local icon_bases=( + "$HOME/.local/share/icons/$theme" + "/usr/share/icons/$theme" + "/usr/share/icons/hicolor" + "/usr/share/pixmaps" + ) + + for base in "${icon_bases[@]}"; do + for size in "${sizes[@]}"; do + for ext in "${exts[@]}"; do + for subdir in apps actions status devices places panel mimetypes; do + local candidate="$base/${size}x${size}/$subdir/$icon_name.$ext" + [[ -f "$candidate" ]] && { echo "$candidate"; return; } + done + local scalable="$base/scalable/apps/$icon_name.$ext" + [[ -f "$scalable" ]] && { echo "$scalable"; return; } + done + done + done + + for ext in "${exts[@]}"; do + [[ -f "/usr/share/pixmaps/$icon_name.$ext" ]] && { echo "/usr/share/pixmaps/$icon_name.$ext"; return; } + done + + echo "$icon_name" +} + +# Collect all desktop files and process +declare -A seen_apps + +for dir in "${SEARCH_PATHS[@]}"; do + [ ! -d "$dir" ] && continue + + while IFS= read -r desktop_file; do + basename_file=$(basename "$desktop_file") + + # Skip duplicates (local overrides system) + [[ -n "${seen_apps[$basename_file]}" ]] && continue + seen_apps[$basename_file]=1 + + # Skip blacklisted unless whitelisted + skip=0 + for blacklisted in "${BLACKLIST[@]}"; do + [[ "$basename_file" == "$blacklisted" ]] && skip=1 && break + done + # Check whitelist override + for whitelisted in "${WHITELIST[@]}"; do + [[ "$basename_file" == "$whitelisted" ]] && skip=0 && break + done + [[ $skip -eq 1 ]] && continue + + # Skip if NoDisplay=true + grep -q "^NoDisplay=true" "$desktop_file" 2>/dev/null && continue + + # Extract fields + name=$(grep "^Name=" "$desktop_file" | head -1 | cut -d= -f2-) + comment=$(grep "^Comment=" "$desktop_file" | head -1 | cut -d= -f2-) + icon=$(grep "^Icon=" "$desktop_file" | head -1 | cut -d= -f2-) + exec=$(grep "^Exec=" "$desktop_file" | head -1 | cut -d= -f2- | sed 's/%[uUfF]//g' | sed 's/%[cdnNvmki]//g') + + # Skip if no name or exec + [ -z "$name" ] && continue + [ -z "$exec" ] && continue + + # Default comment + [ -z "$comment" ] && comment="Application" + + # Find icon + icon_path=$(find_icon "$icon") + + # Output + echo "$name|$comment|$icon_path|$exec" + + done < <(find -L "$dir" -name "*.desktop" -type f 2>/dev/null) +done | sort -u diff --git a/.config/quickshell/nucleus-shell/scripts/interface/changebg.sh b/.config/quickshell/nucleus-shell/scripts/interface/changebg.sh new file mode 100755 index 0000000..ef9adae --- /dev/null +++ b/.config/quickshell/nucleus-shell/scripts/interface/changebg.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +START_DIR="$HOME/Pictures/Wallpapers" + +# Get monitor list (Wayland/Hyprland/Qtile etc. usually expose via xrandr or hyprctl) +MONITORS=$(xrandr --query | grep " connected" | cut -d" " -f1) + +# Convert monitors into Zenity list arguments +LIST_ARGS=() +for m in $MONITORS; do + LIST_ARGS+=("$m") +done + +DISPLAY=$(zenity --list \ + --title="Select Display" \ + --column="Monitor" \ + "${LIST_ARGS[@]}" \ + --height=300 \ + --width=300 2>/dev/null) + +# User cancelled +[ -z "$DISPLAY" ] && echo "null" && exit + +FILE=$(zenity --file-selection \ + --title="Select Wallpaper for $DISPLAY" \ + --filename="$START_DIR/" \ + --file-filter="Images/Videos | *.png *.jpg *.jpeg *.webp *.bmp *.svg *.mp4 *.mkv *.webm *.mov *.avi *.m4v" \ + 2>/dev/null) + +[ -z "$FILE" ] && echo "null" && exit + +# Output format: monitor|wallpaper +echo "$DISPLAY|file://$FILE" \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/scripts/interface/gencolors.sh b/.config/quickshell/nucleus-shell/scripts/interface/gencolors.sh new file mode 100755 index 0000000..68294a9 --- /dev/null +++ b/.config/quickshell/nucleus-shell/scripts/interface/gencolors.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# ~/config/quickshell/scripts/background/gencolors.sh +# Generate Matugen color scheme for a given wallpaper + +USER_WIDE=false + +# Parse flags +while [[ "$1" == --* ]]; do + case "$1" in + --user-wide) + USER_WIDE=true + shift + ;; + *) + echo "Unknown flag: $1" >&2 + exit 1 + ;; + esac +done + +WALLPAPER_PATH="$1" +SCHEME_TYPE="$2" +SCHEME_MODE="$3" +CONFIG_PATH="$4" + +# Validate required arguments +if [[ -z "$WALLPAPER_PATH" || "$WALLPAPER_PATH" == "null" ]]; then + echo "Error: no wallpaper provided" >&2 + exit 1 +fi + +: "${SCHEME_TYPE:?Error: scheme type not provided}" +: "${SCHEME_MODE:?Error: scheme mode not provided}" + +# Strip file:// prefix if present +if [[ "$WALLPAPER_PATH" == file://* ]]; then + WALLPAPER_PATH="${WALLPAPER_PATH#file://}" +fi + +if ! $USER_WIDE; then + if [[ -z "$CONFIG_PATH" || ! -f "$CONFIG_PATH" ]]; then + echo "Error: config file not found: $CONFIG_PATH" >&2 + exit 1 + fi +fi + + +run_with_config() { + matugen --config "$CONFIG_PATH" \ + image "$WALLPAPER_PATH" \ + --type "$SCHEME_TYPE" \ + --mode "$SCHEME_MODE" +} + +run_without_config() { + matugen image "$WALLPAPER_PATH" \ + --type "$SCHEME_TYPE" \ + --mode "$SCHEME_MODE" +} + +if $USER_WIDE; then + run_with_config + run_without_config +else + run_with_config +fi diff --git a/.config/quickshell/nucleus-shell/scripts/interface/selectfolder.sh b/.config/quickshell/nucleus-shell/scripts/interface/selectfolder.sh new file mode 100755 index 0000000..c363f51 --- /dev/null +++ b/.config/quickshell/nucleus-shell/scripts/interface/selectfolder.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Folder selector for wallpaper slideshow + +START_DIR="${1:-$HOME/Pictures/Wallpapers}" + +# Ensure start dir exists, fallback to Pictures or Home +if [ ! -d "$START_DIR" ]; then + START_DIR="$HOME/Pictures" +fi +if [ ! -d "$START_DIR" ]; then + START_DIR="$HOME" +fi + +FOLDER=$(zenity --file-selection \ + --directory \ + --title="Select Wallpaper Folder" \ + --filename="$START_DIR/" 2>/dev/null) + +if [ $? -eq 0 ] && [ -n "$FOLDER" ]; then + echo "$FOLDER" +else + echo "null" +fi diff --git a/.config/quickshell/nucleus-shell/scripts/interface/switchTheme.sh b/.config/quickshell/nucleus-shell/scripts/interface/switchTheme.sh new file mode 100755 index 0000000..8a1d4ba --- /dev/null +++ b/.config/quickshell/nucleus-shell/scripts/interface/switchTheme.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +THEME_NAME="${1:-}" + +THEME_DIR="$HOME/.config/nucleus-shell/colorschemes" +TARGET="$HOME/.config/nucleus-shell/config/colors.json" + +if [[ -z "$THEME_NAME" ]]; then + echo "Usage: switch-theme.sh " + exit 1 +fi + +# === AUTOGENERATED THEME === +if [[ "$THEME_NAME" == "auto" || "$THEME_NAME" == "autogen" ]]; then + echo "Generating theme via Quickshell IPC…" + + qs -c nucleus-shell ipc call global regenColors + + echo "Autogenerated theme applied" + exit 0 +fi + +# === STATIC THEME === +SOURCE="$THEME_DIR/$THEME_NAME.json" + +if [[ ! -f "$SOURCE" ]]; then + echo "Theme not found: $THEME_NAME" + exit 1 +fi + +# Atomic write +tmp="$(mktemp)" +cat "$SOURCE" > "$tmp" +mv "$tmp" "$TARGET" + +echo "Theme switched to: $THEME_NAME" diff --git a/.config/quickshell/nucleus-shell/scripts/plugins/plugins.sh b/.config/quickshell/nucleus-shell/scripts/plugins/plugins.sh new file mode 100755 index 0000000..d38fe95 --- /dev/null +++ b/.config/quickshell/nucleus-shell/scripts/plugins/plugins.sh @@ -0,0 +1,242 @@ +#!/usr/bin/env bash +set -euo pipefail + +# This script the now depreciated as it is succeeded by the nucleus-cli (https://github.com/unf6/nucleus-cli) + +# Config + +INSTALL_DIR="$HOME/.config/nucleus-shell/plugins" +CACHE_BASE="/tmp/nucleus-plugins" + +declare -A PLUGIN_REPOS=( + [official]="https://github.com/xZepyx/nucleus-plugins.git" +) + +# Dependencies + +require() { + command -v "$1" >/dev/null 2>&1 || { + echo "Missing dependency: $1" + exit 1 + } +} + +require git +require jq + +mkdir -p "$INSTALL_DIR" "$CACHE_BASE" + +# Repo handling + +update_repo() { + local name="$1" + local url="$2" + local dir="$CACHE_BASE/$name" + + if [[ -d "$dir/.git" ]]; then + git -C "$dir" pull --quiet + else + rm -rf "$dir" + git clone --quiet "$url" "$dir" + fi +} + +update_all_repos() { + for name in "${!PLUGIN_REPOS[@]}"; do + update_repo "$name" "${PLUGIN_REPOS[$name]}" + done +} + +# Plugin Lookup + +find_plugin() { + local plugin="$1" + + for repo in "${!PLUGIN_REPOS[@]}"; do + local path="$CACHE_BASE/$repo/$plugin" + if [[ -d "$path" && -f "$path/manifest.json" ]]; then + echo "$repo:$path" + return 0 + fi + done + + return 1 +} + +# Fetch + +fetch_all() { + update_all_repos + + for repo in "${!PLUGIN_REPOS[@]}"; do + local base="$CACHE_BASE/$repo" + + for dir in "$base"/*/; do + [[ -f "$dir/manifest.json" ]] || continue + + jq -r ' + "id: \(.id) +name: \(.name) +version: \(.version) +author: \(.author) +description: \(.description) +requires_nucleus: \(.requires_nucleus // "none") +repo: '"$repo"' +---" + ' "$dir/manifest.json" + done + done +} + +fetch_one() { + local plugin="$1" + update_all_repos + + local result + result=$(find_plugin "$plugin") || { + echo "Plugin '$plugin' not found in any repo" + exit 1 + } + + local repo="${result%%:*}" + local path="${result#*:}" + + jq -r ' + "id: \(.id) +name: \(.name) +version: \(.version) +author: \(.author) +description: \(.description) +requires_nucleus: \(.requires_nucleus // "none") +repo: '"$repo"' +---" + ' "$path/manifest.json" +} + +# Install / Update / Uninstall + +install_plugin() { + local plugin="$1" + update_all_repos + + local dst="$INSTALL_DIR/$plugin" + [[ -d "$dst" ]] && { + echo "Plugin '$plugin' already installed" + exit 0 + } + + local result + result=$(find_plugin "$plugin") || { + echo "Plugin '$plugin' not found" + exit 1 + } + + local path="${result#*:}" + cp -r "$path" "$dst" + + echo "Installed plugin '$plugin'" +} + +uninstall_plugin() { + local plugin="$1" + local dst="$INSTALL_DIR/$plugin" + + [[ -d "$dst" ]] || { + echo "Plugin '$plugin' is not installed" + exit 0 + } + + rm -rf "$dst" + echo "Uninstalled plugin '$plugin'" +} + +fetch_all_machine() { # For quickshell + update_all_repos + + for repo in "${!PLUGIN_REPOS[@]}"; do + local base="$CACHE_BASE/$repo" + + for dir in "$base"/*/; do + [[ -f "$dir/manifest.json" ]] || continue + + jq -r ' + [ + .id, + .name, + .version, + .author, + .description, + (.requires_nucleus // "none"), + "'"$repo"'" + ] | @tsv + ' "$dir/manifest.json" + done + done +} + + +update_plugin() { + local plugin="$1" + update_all_repos + + local dst="$INSTALL_DIR/$plugin" + [[ -d "$dst" ]] || { + echo "Plugin '$plugin' not installed" + exit 1 + } + + local result + result=$(find_plugin "$plugin") || { + echo "Plugin '$plugin' not found in repos" + exit 1 + } + + local src="${result#*:}" + + local local_version repo_version + local_version=$(jq -r '.version' "$dst/manifest.json") + repo_version=$(jq -r '.version' "$src/manifest.json") + + if [[ "$local_version" == "$repo_version" ]]; then + echo "Plugin '$plugin' already up to date ($local_version)" + exit 0 + fi + + rm -rf "$dst" + cp -r "$src" "$dst" + + echo "Updated '$plugin' $local_version → $repo_version" +} + +# CLI + +usage() { + cat < + plugins install + plugins uninstall + plugins update +EOF +} + +case "${1:-}" in + fetch) + [[ "${2:-}" == "all-machine" ]] && fetch_all_machine \ + || [[ "${2:-}" == "all" ]] && fetch_all \ + || fetch_one "${2:-}" + ;; + install) + install_plugin "${2:-}" + ;; + uninstall) + uninstall_plugin "${2:-}" + ;; + update) + update_plugin "${2:-}" + ;; + *) + usage + ;; +esac diff --git a/.config/quickshell/nucleus-shell/scripts/system/reload.sh b/.config/quickshell/nucleus-shell/scripts/system/reload.sh new file mode 100755 index 0000000..c049a7f --- /dev/null +++ b/.config/quickshell/nucleus-shell/scripts/system/reload.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +killall quickshell +nucleus run \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/scripts/system/update.sh b/.config/quickshell/nucleus-shell/scripts/system/update.sh new file mode 100755 index 0000000..8903d59 --- /dev/null +++ b/.config/quickshell/nucleus-shell/scripts/system/update.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# Paths / repo +CONFIG="$HOME/.config/nucleus-shell/config/configuration.json" +QS_DIR="$HOME/.config/quickshell/nucleus-shell" +REPO="xZepyx/nucleus-shell" +API="https://api.github.com/repos/$REPO/releases" + +# Spinner +spinner() { + local pid=$1 + local spin='|/-\' + local i=0 + + while kill -0 "$pid" 2>/dev/null; do + printf "\r[*] %s %c" "$SPINNER_MSG" "${spin:i++%4:1}" + sleep 0.1 + done +} + +run() { + SPINNER_MSG="$1" + shift + "$@" &>/dev/null & + spinner $! + wait $! || fail "$SPINNER_MSG failed" + printf "\r[✓] %s\n" "$SPINNER_MSG" +} + +fail() { + printf "[✗] %s\n" "$1" >&2 + exit 1 +} + +info() { + printf "[*] %s\n" "$1" +} + +# Selection +echo "Select the version to install:" +echo "1. Latest" +echo "2. Edge" +echo "3. Git" + +read -rp "[?] Choice: " choice + +case "$choice" in + 1) mode="stable" ;; + 2) mode="indev" ;; + 3) + read -rp "[?] Enter git tag or version: " input + [[ -z "$input" ]] && fail "No version provided" + latest="${input#v}" + latest_tag="v$latest" + ;; + *) fail "Invalid choice" ;; +esac + +# Validate config +[[ -f "$CONFIG" ]] || fail "configuration.json not found" + +current="$(jq -r '.shell.version // empty' "$CONFIG")" +[[ -n "$current" ]] || fail "Current version not set" + +# Resolve release +if [[ "${mode:-}" ]]; then + info "Resolving release" + latest_tag="$( + curl -fsSL "$API" | + jq -r " + map(select(.draft == false)) | + $( [[ "$mode" == "stable" ]] && echo 'map(select(.prerelease == false)) |' ) + sort_by(.published_at) | + last | + .tag_name + " + )" + [[ -n "$latest_tag" && "$latest_tag" != "null" ]] || fail "Release resolution failed" + latest="${latest_tag#v}" +fi + +# No-op +if [[ "$current" == "$latest" ]]; then + info "Already up to date ($current)" + exit 0 +fi + +# Temp workspace +tmp="$(mktemp -d)" +zip="$tmp/source.zip" +root_dir="$tmp/nucleus-shell-$latest" +SRC_DIR="$root_dir/quickshell/nucleus-shell" + +# Download +run "Downloading nucleus-shell $latest" \ + curl -fsSL \ + "https://github.com/$REPO/archive/refs/tags/$latest_tag.zip" \ + -o "$zip" + +# Extract +run "Extracting archive" unzip -q "$zip" -d "$tmp" + +[[ -d "$SRC_DIR" ]] || fail "nucleus-shell directory missing in archive" + +# Install +run "Installing files" bash -c " + rm -rf '$QS_DIR' && + mkdir -p '$QS_DIR' && + cp -r '$SRC_DIR/'* '$QS_DIR/' +" + +# Update config +run "Updating configuration" bash -c " + tmp_cfg=\$(mktemp) && + jq --arg v '$latest' '.shell.version = \$v' '$CONFIG' > \"\$tmp_cfg\" && + mv \"\$tmp_cfg\" '$CONFIG' +" + +# Reload shell +run "Reloading shell" bash -c " + killall qs &>/dev/null || true + nohup qs -c nucleus-shell &>/dev/null & disown +" + +printf "[✓] Updated nucleus-shell: %s -> %s\n" "$current" "$latest" diff --git a/.config/quickshell/nucleus-shell/services/AppRegistry.qml b/.config/quickshell/nucleus-shell/services/AppRegistry.qml new file mode 100644 index 0000000..bc052af --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/AppRegistry.qml @@ -0,0 +1,168 @@ +pragma Singleton +import QtQuick +import Quickshell +import qs.modules.functions +import qs.config + +/* + This registry is only used to get app details for wm classes. +*/ + +Singleton { + id: registry + + property var apps: [] + property var classToIcon: ({}) + property var desktopIdToIcon: ({}) + property var nameToIcon: ({}) + + signal ready() + + function iconForDesktopIcon(icon) { + if (!icon) return "" + + // If it's already a URL, keep it + if (icon.startsWith("file://") || icon.startsWith("qrc:/")) + return icon + + // Absolute filesystem path → convert to file URL + if (icon.startsWith("/")) + return "file://" + icon + + // Otherwise treat as theme icon name + return Quickshell.iconPath(icon) + } + + // Try very aggressive matching so the running app always gets the same icon as launcher + function iconForClass(id) { + if (!id) return "" + + const lower = id.toLowerCase() + + // direct hits first + if (classToIcon[lower]) + return iconForDesktopIcon(classToIcon[lower]) + + if (desktopIdToIcon[lower]) + return iconForDesktopIcon(desktopIdToIcon[lower]) + + if (nameToIcon[lower]) + return iconForDesktopIcon(nameToIcon[lower]) + + // fuzzy contains match against wmClass map + for (let key in classToIcon) { + if (lower.includes(key) || key.includes(lower)) + return iconForDesktopIcon(classToIcon[key]) + } + + // fuzzy against desktop ids + for (let key in desktopIdToIcon) { + if (lower.includes(key) || key.includes(lower)) + return iconForDesktopIcon(desktopIdToIcon[key]) + } + + // fuzzy against names + for (let key in nameToIcon) { + if (lower.includes(key) || key.includes(lower)) + return iconForDesktopIcon(nameToIcon[key]) + } + + // final fallback to theme resolution + const resolved = FileUtils.resolveIcon(id) + return iconForDesktopIcon(resolved) + } + + // Extra helper: resolve icon using any metadata we might have (Hyprland, Niri, etc.) + function iconForAppMeta(meta) { + if (!meta) return Quickshell.iconPath("application-x-executable") + + const candidates = [ + meta.appId, + meta.class, + meta.initialClass, + meta.desktopId, + meta.title, + meta.name + ] + + for (let c of candidates) { + const icon = iconForClass(c) + if (icon !== "") + return icon + } + + // fallback: try compositor provided icon name + if (meta.icon) + return iconForDesktopIcon(meta.icon) + + // hard fallback icons (guaranteed to exist in most themes) + const fallbacks = [ + "application-x-executable", + "application-default-icon", + "window" + ] + + for (let f of fallbacks) { + const resolved = Quickshell.iconPath(f) + if (resolved) + return resolved + } + + return "" + } + + function registerApp(displayName, comment, icon, exec, wmClass, desktopId) { + const entry = { + name: displayName, + comment: comment, + icon: icon, + exec: exec, + wmClass: wmClass, + desktopId: desktopId + } + + apps.push(entry) + + if (wmClass) + classToIcon[wmClass.toLowerCase()] = icon + + if (desktopId) + desktopIdToIcon[desktopId.toLowerCase()] = icon + + if (displayName) + nameToIcon[displayName.toLowerCase()] = icon + + // Hard aliases for apps with messy WM_CLASS values + if (displayName.toLowerCase().includes("visual studio code") || + icon.toLowerCase().includes("code")) { + + classToIcon["code"] = icon + classToIcon["code-oss"] = icon + classToIcon["code-url-handler"] = icon + desktopIdToIcon["code.desktop"] = icon + desktopIdToIcon["code-oss.desktop"] = icon + } + } + + function buildRegistry() { + const entries = DesktopEntries.applications.values + + for (let entry of entries) { + if (entry.noDisplay) + continue + + registry.registerApp( + entry.name || "", + entry.comment || "", + entry.icon || "", + entry.execString || "", + entry.startupWMClass || "", + entry.id || "" + ) + } + + registry.ready() + } + + Component.onCompleted: buildRegistry() +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/services/Apps.qml b/.config/quickshell/nucleus-shell/services/Apps.qml new file mode 100644 index 0000000..410ba49 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Apps.qml @@ -0,0 +1,30 @@ +pragma Singleton + +import "../modules/functions/fuzzy/fuzzysort.js" as Fuzzy +import Quickshell + +Singleton { + id: root + + readonly property list list: DesktopEntries.applications.values.filter(a => !a.noDisplay).sort((a, b) => a.name.localeCompare(b.name)) + readonly property list preppedApps: list.map(a => ({ + name: Fuzzy.prepare(a.name), + comment: Fuzzy.prepare(a.comment), + entry: a + })) + + function fuzzyQuery(search: string): var { // idk why list doesn't work + return Fuzzy.go(search, preppedApps, { + all: true, + keys: ["name", "comment"], + scoreFn: r => r[0].score > 0 ? r[0].score * 0.9 + r[1].score * 0.1 : 0 + }).map(r => r.obj.entry); + } + + function launch(entry: DesktopEntry): void { + if (entry.execString.startsWith("sh -c")) + Quickshell.execDetached(["sh", "-c", `app2unit -- ${entry.execString}`]); + else + Quickshell.execDetached(["sh", "-c", `app2unit -- '${entry.id}.desktop' || app2unit -- ${entry.execString}`]); + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/services/Bluetooth.qml b/.config/quickshell/nucleus-shell/services/Bluetooth.qml new file mode 100644 index 0000000..c906a57 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Bluetooth.qml @@ -0,0 +1,24 @@ +pragma Singleton +import QtQuick +import Quickshell +import Quickshell.Bluetooth + + +Singleton { + id: root + readonly property BluetoothAdapter defaultAdapter: Bluetooth.defaultAdapter + readonly property list devices: defaultAdapter?.devices?.values ?? [] + readonly property BluetoothDevice activeDevice: devices.find(d => d.connected) ?? null + readonly property string icon: { + if (!defaultAdapter?.enabled) + return "bluetooth_disabled" + + if (activeDevice) + return "bluetooth_connected" + + return defaultAdapter.discovering + ? "bluetooth_searching" + : "bluetooth" + } + +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/services/Brightness.qml b/.config/quickshell/nucleus-shell/services/Brightness.qml new file mode 100755 index 0000000..2b6f9e8 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Brightness.qml @@ -0,0 +1,142 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Io +import Quickshell.Hyprland +import QtQuick + +// from github.com/end-4/dots-hyprland + +Singleton { + id: root + signal brightnessChanged() + + property var ddcMonitors: [] + readonly property list monitors: Quickshell.screens.map(screen => monitorComp.createObject(root, { screen })) + + function getMonitorForScreen(screen: ShellScreen): var { + return monitors.find(m => m.screen === screen) + } + + function increaseBrightness(): void { + const focusedName = Hyprland.focusedMonitor.name + const monitor = monitors.find(m => focusedName === m.screen.name) + if (monitor) + monitor.setBrightness(monitor.brightness + 0.05) + } + + function decreaseBrightness(): void { + const focusedName = Hyprland.focusedMonitor.name + const monitor = monitors.find(m => focusedName === m.screen.name) + if (monitor) + monitor.setBrightness(monitor.brightness - 0.05) + } + + reloadableId: "brightness" + + onMonitorsChanged: { + ddcMonitors = [] + ddcProc.running = true + } + + Process { + id: ddcProc + command: ["ddcutil", "detect", "--brief"] + stdout: SplitParser { + splitMarker: "\n\n" + onRead: data => { + if (data.startsWith("Display ")) { + const lines = data.split("\n").map(l => l.trim()) + root.ddcMonitors.push({ + model: lines.find(l => l.startsWith("Monitor:")).split(":")[2], + busNum: lines.find(l => l.startsWith("I2C bus:")).split("/dev/i2c-")[1] + }) + } + } + } + onExited: root.ddcMonitorsChanged() + } + + Process { id: setProc } + + component BrightnessMonitor: QtObject { + id: monitor + + required property ShellScreen screen + + readonly property bool isDdc: { + const match = root.ddcMonitors.find(m => m.model === screen.model && + !root.monitors.slice(0, root.monitors.indexOf(this)) + .some(mon => mon.busNum === m.busNum)) + return !!match + } + + readonly property string busNum: { + const match = root.ddcMonitors.find(m => m.model === screen.model && + !root.monitors.slice(0, root.monitors.indexOf(this)) + .some(mon => mon.busNum === m.busNum)) + return match?.busNum ?? "" + } + + property int rawMaxBrightness: 100 + property real brightness + property real brightnessMultiplier: 1.0 + property real multipliedBrightness: Math.max(0, Math.min(1, brightness * brightnessMultiplier)) + property bool ready: false + property bool animateChanges: !monitor.isDdc + + onBrightnessChanged: { + if (!monitor.ready) return + root.brightnessChanged() + if (monitor.animateChanges) + syncBrightness() + else + setTimer.restart() + } + + property var setTimer: Timer { + id: setTimer + interval: monitor.isDdc ? 300 : 0 + onTriggered: syncBrightness() + } + + function initialize() { + monitor.ready = false + initProc.command = isDdc + ? ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"] + : ["sh", "-c", `echo "a b c $(brightnessctl g) $(brightnessctl m)"`] + initProc.running = true + } + + readonly property Process initProc: Process { + stdout: SplitParser { + onRead: data => { + const [, , , current, max] = data.split(" ") + monitor.rawMaxBrightness = parseInt(max) + monitor.brightness = parseInt(current) / monitor.rawMaxBrightness + monitor.ready = true + } + } + } + + function syncBrightness() { + const brightnessValue = Math.max(Math.min(monitor.multipliedBrightness, 1), 0) + const rawValueRounded = Math.max(Math.floor(brightnessValue * monitor.rawMaxBrightness), 1) + setProc.command = isDdc + ? ["ddcutil", "-b", busNum, "setvcp", "10", rawValueRounded] + : ["brightnessctl", "set", rawValueRounded.toString()] + setProc.startDetached() + } + + function setBrightness(value: real): void { + value = Math.max(0, Math.min(1, value)) + monitor.brightness = value + } + + Component.onCompleted: initialize() + onBusNumChanged: initialize() + } + + Component { id: monitorComp; BrightnessMonitor {} } +} diff --git a/.config/quickshell/nucleus-shell/services/Compositor.qml b/.config/quickshell/nucleus-shell/services/Compositor.qml new file mode 100644 index 0000000..578b810 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Compositor.qml @@ -0,0 +1,89 @@ +pragma Singleton + +import QtQuick +import Quickshell +import Quickshell.Wayland +import Quickshell.Io + +Singleton { + id: root + + // compositor stuff + property string detectedCompositor: "" + + readonly property var backend: { + if (detectedCompositor === "niri") + return Niri + if (detectedCompositor === "hyprland") + return Hyprland + return null + } + + function require(compositors) { // This function can be effectively used to detect check requirements for a feature (also supports multiple compositors) + if (Array.isArray(compositors)) { + return compositors.includes(detectedCompositor); + } + return compositors === detectedCompositor; + } + + // Unified api + property string title: backend?.title ?? "" + property bool isFullscreen: backend?.isFullscreen ?? false + property string layout: backend?.layout ?? "Tiled" + property int focusedWorkspaceId: backend?.focusedWorkspaceId ?? 1 + property var workspaces: backend?.workspaces ?? [] + property var windowList: backend?.windowList ?? [] + property bool initialized: backend?.initialized ?? true + property int workspaceCount: backend?.workspaceCount ?? 0 + property real screenW: backend?.screenW ?? 0 + property real screenH: backend?.screenH ?? 0 + property real screenScale: backend?.screenScale ?? 1 + readonly property Toplevel activeToplevel: ToplevelManager.activeToplevel + + function changeWorkspace(id) { + backend?.changeWorkspace?.(id) + } + + function changeWorkspaceRelative(delta) { + backend?.changeWorkspaceRelative?.(delta) + } + + function isWorkspaceOccupied(id) { + return backend?.isWorkspaceOccupied?.(id) ?? false + } + + function focusedWindowForWorkspace(id) { + return backend?.focusedWindowForWorkspace?.(id) ?? null + } + + // process to detect compositor + Process { + command: ["sh", "-c", "echo \"$XDG_CURRENT_DESKTOP $XDG_SESSION_DESKTOP\""] + running: true + + stdout: SplitParser { + onRead: data => { + if (!data) + return + + const val = data.trim().toLowerCase() + + if (val.includes("hyprland")) { + root.detectedCompositor = "hyprland" + } else if (val.includes("niri")) { + root.detectedCompositor = "niri" + } + } + } + } + + signal stateChanged() + + Connections { + target: backend + function onStateChanged() { + root.stateChanged() + } + } + +} diff --git a/.config/quickshell/nucleus-shell/services/ConfigResolver.qml b/.config/quickshell/nucleus-shell/services/ConfigResolver.qml new file mode 100644 index 0000000..75383c9 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/ConfigResolver.qml @@ -0,0 +1,34 @@ +import QtQuick +import Quickshell +import qs.config +pragma Singleton + + +/* + + This service primarily resolves configs for widgets that are customizable per monitor. + +*/ + + +Singleton { + + function bar(displayName) { + const displays = Config.runtime.monitors; + const fallback = Config.runtime.bar; + if (!displays || !displays[displayName] || !displays[displayName].bar || displayName === "") + return fallback; + + return displays[displayName].bar; + } + + function getBarConfigurableHandle(displayName) { // returns prefField string + const displays = Config.runtime.monitors; + + if (!displays || !displays[displayName] || !displays[displayName].bar || displayName === "") + return "bar"; + + return "monitors." + displayName + ".bar"; + } + +} diff --git a/.config/quickshell/nucleus-shell/services/Contracts.qml b/.config/quickshell/nucleus-shell/services/Contracts.qml new file mode 100644 index 0000000..c4f9a6e --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Contracts.qml @@ -0,0 +1,69 @@ +pragma Singleton +import QtQuick +import Quickshell.Io +import qs.config + +QtObject { + // Power menu + property url powerMenu: Qt.resolvedUrl("../modules/interface/powermenu/Powermenu.qml") + property bool overriddenPowerMenu: false + function overridePowerMenu() { + overriddenPowerMenu = true + } + + // Bar + property url bar: Qt.resolvedUrl("../modules/interface/bar/Bar.qml") + property bool overriddenBar: false + function overrideBar() { + overriddenBar = true + } + + // App launcher + property url launcher: Qt.resolvedUrl("../modules/interface/launcher/Launcher.qml") + property bool overriddenLauncher: false + function overrideLauncher() { + overriddenLauncher = true + } + + // Lock screen + property url lockScreen: Qt.resolvedUrl("../modules/interface/lockscreen/LockScreen.qml") + property bool overriddenLockScreen: false + function overrideLockScreen() { + overriddenLockScreen = true + } + + // Desktop background / wallpaper handler + property url background: Qt.resolvedUrl("../modules/interface/background/Background.qml") + property bool overriddenBackground: false + function overrideBackground() { + overriddenBackground = true + } + + // Notifications UI + property url notifications: Qt.resolvedUrl("../modules/interface/notifications/Notifications.qml") + property bool overriddenNotifications: false + function overrideNotifications() { + overriddenNotifications = true + } + + // Global overlays (OSD, volume, brightness, etc.) + property url overlays: Qt.resolvedUrl("../modules/interface/overlays/Overlays.qml") + property bool overriddenOverlays: false + function overrideOverlays() { + overriddenOverlays = true + } + + // Right sidebar + property url sidebarRight: !overriddenSidebarRight ? Qt.resolvedUrl("../modules/interface/sidebarRight/SidebarRight.qml") : "" // Force override + property bool overriddenSidebarRight: false + function overrideSidebarRight() { + overriddenSidebarRight = true + } + + // Left sidebar + property url sidebarLeft: !overriddenSidebarLeft ? Qt.resolvedUrl("../modules/interface/sidebarLeft/SidebarLeft.qml") : "" // Force override + property bool overriddenSidebarLeft: false + function overrideSidebarLeft() { + overriddenSidebarLeft = true + } +} diff --git a/.config/quickshell/nucleus-shell/services/Hyprland.qml b/.config/quickshell/nucleus-shell/services/Hyprland.qml new file mode 100755 index 0000000..ba17fa0 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Hyprland.qml @@ -0,0 +1,216 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell +import Quickshell.Io +import Quickshell.Hyprland +import Quickshell.Wayland + +Singleton { + id: root + + // true if Hyprland is running, false otherwise + readonly property bool isHyprland: Compositor.require("hyprland") + + // reactive Hyprland data, only valid if Hyprland is running + signal stateChanged() + readonly property var toplevels: isHyprland ? Hyprland.toplevels : [] + readonly property var workspaces: isHyprland ? Hyprland.workspaces : [] + readonly property var monitors: isHyprland ? Hyprland.monitors : [] + readonly property Toplevel activeToplevel: isHyprland ? ToplevelManager.activeToplevel : null + readonly property HyprlandWorkspace focusedWorkspace: isHyprland ? Hyprland.focusedWorkspace : null + readonly property HyprlandMonitor focusedMonitor: isHyprland ? Hyprland.focusedMonitor : null + readonly property int focusedWorkspaceId: focusedWorkspace?.id ?? 1 + property real screenW: focusedMonitor ? focusedMonitor.width : 0 + property real screenH: focusedMonitor ? focusedMonitor.height : 0 + property real screenScale: focusedMonitor ? focusedMonitor.scale : 1 + + // parsed hyprctl data, defaults are empty + property var windowList: [] + property var windowByAddress: ({}) + property var addresses: [] + property var layers: ({}) + property var monitorsInfo: [] + property var workspacesInfo: [] + property var workspaceById: ({}) + property var workspaceIds: [] + property var activeWorkspaceInfo: null + property string keyboardLayout: "?" + + // dispatch a command to Hyprland, no-op if not running + function dispatch(request: string): void { + if (!isHyprland) return + Hyprland.dispatch(request) + } + + // switch workspace safely + function changeWorkspace(targetWorkspaceId) { + if (!isHyprland || !targetWorkspaceId) return + root.dispatch("workspace " + targetWorkspaceId) + } + + // find most recently focused window in a workspace + function focusedWindowForWorkspace(workspaceId) { + if (!isHyprland) return null + const wsWindows = root.windowList.filter(w => w.workspace.id === workspaceId) + if (wsWindows.length === 0) return null + return wsWindows.reduce((best, win) => { + const bestFocus = best?.focusHistoryID ?? Infinity + const winFocus = win?.focusHistoryID ?? Infinity + return winFocus < bestFocus ? win : best + }, null) + } + + // check if a workspace has any windows + function isWorkspaceOccupied(id: int): bool { + if (!isHyprland) return false + return Hyprland.workspaces.values.find(w => w?.id === id)?.lastIpcObject.windows > 0 || false + } + + // update all hyprctl processes + function updateAll() { + if (!isHyprland) return + getClients.running = true + getLayers.running = true + getMonitors.running = true + getWorkspaces.running = true + getActiveWorkspace.running = true + } + + // largest window in a workspace + function biggestWindowForWorkspace(workspaceId) { + if (!isHyprland) return null + const windowsInThisWorkspace = root.windowList.filter(w => w.workspace.id === workspaceId) + return windowsInThisWorkspace.reduce((maxWin, win) => { + const maxArea = (maxWin?.size?.[0] ?? 0) * (maxWin?.size?.[1] ?? 0) + const winArea = (win?.size?.[0] ?? 0) * (win?.size?.[1] ?? 0) + return winArea > maxArea ? win : maxWin + }, null) + } + + // refresh keyboard layout + function refreshKeyboardLayout() { + if (!isHyprland) return + hyprctlDevices.running = true + } + + // only create hyprctl processes if Hyprland is running + Component.onCompleted: { + if (isHyprland) { + updateAll() + refreshKeyboardLayout() + } + } + + // process to get keyboard layout + Process { + id: hyprctlDevices + running: false + command: ["hyprctl", "devices", "-j"] + stdout: StdioCollector { + onStreamFinished: { + try { + const devices = JSON.parse(this.text) + const keyboard = devices.keyboards.find(k => k.main) || devices.keyboards[0] + root.keyboardLayout = keyboard?.active_keymap?.toUpperCase()?.slice(0, 2) ?? "?" + } catch (err) { + console.error("Failed to parse keyboard layout:", err) + root.keyboardLayout = "?" + } + } + } + } + + Process { + id: getClients + running: false + command: ["hyprctl", "clients", "-j"] + stdout: StdioCollector { + onStreamFinished: { + try { + root.windowList = JSON.parse(this.text) + let tempWinByAddress = {} + for (let win of root.windowList) tempWinByAddress[win.address] = win + root.windowByAddress = tempWinByAddress + root.addresses = root.windowList.map(w => w.address) + } catch (e) { + console.error("Failed to parse clients:", e) + } + } + } + } + + Process { + id: getMonitors + running: false + command: ["hyprctl", "monitors", "-j"] + stdout: StdioCollector { + onStreamFinished: { + try { root.monitorsInfo = JSON.parse(this.text) } + catch (e) { console.error("Failed to parse monitors:", e) } + } + } + } + + Process { + id: getLayers + running: false + command: ["hyprctl", "layers", "-j"] + stdout: StdioCollector { + onStreamFinished: { + try { root.layers = JSON.parse(this.text) } + catch (e) { console.error("Failed to parse layers:", e) } + } + } + } + + Process { + id: getWorkspaces + running: false + command: ["hyprctl", "workspaces", "-j"] + stdout: StdioCollector { + onStreamFinished: { + try { + root.workspacesInfo = JSON.parse(this.text) + let map = {} + for (let ws of root.workspacesInfo) map[ws.id] = ws + root.workspaceById = map + root.workspaceIds = root.workspacesInfo.map(ws => ws.id) + } catch (e) { console.error("Failed to parse workspaces:", e) } + } + } + } + + Process { + id: getActiveWorkspace + running: false + command: ["hyprctl", "activeworkspace", "-j"] + stdout: StdioCollector { + onStreamFinished: { + try { root.activeWorkspaceInfo = JSON.parse(this.text) } + catch (e) { console.error("Failed to parse active workspace:", e) } + } + } + } + + // only connect to Hyprland events if running + Connections { + target: isHyprland ? Hyprland : null + function onRawEvent(event) { + if (!isHyprland || event.name.endsWith("v2")) return + + if (event.name.includes("activelayout")) + refreshKeyboardLayout() + else if (event.name.includes("mon")) + Hyprland.refreshMonitors() + else if (event.name.includes("workspace") || event.name.includes("window")) + Hyprland.refreshWorkspaces() + else + Hyprland.refreshToplevels() + + updateAll() + root.stateChanged() + } + } +} diff --git a/.config/quickshell/nucleus-shell/services/Mpris.qml b/.config/quickshell/nucleus-shell/services/Mpris.qml new file mode 100755 index 0000000..567a3c5 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Mpris.qml @@ -0,0 +1,136 @@ +import QtQuick +import Quickshell +import Quickshell.Services.Mpris +pragma Singleton + +Singleton { + id: root + + property alias activePlayer: instance.activePlayer + property bool isPlaying: activePlayer ? activePlayer.playbackState === MprisPlaybackState.Playing : false + property string title: activePlayer ? activePlayer.trackTitle : "No Media" + property string artist: activePlayer ? activePlayer.trackArtist : "" + property string album: activePlayer ? activePlayer.trackAlbum : "" + property string artUrl: activePlayer ? activePlayer.trackArtUrl : "" + property double position: 0 + property double length: activePlayer ? activePlayer.length : 0 + property var _players: Mpris.players.values + property int playerCount: _players.length + property var playerList: { + let list = []; + for (let p of _players) { + list.push({ + "identity": p.identity || p.desktopEntry || "Unknown", + "desktopEntry": p.desktopEntry || "", + "player": p + }); + } + return list; + } + property string currentPlayerName: activePlayer ? (activePlayer.identity || activePlayer.desktopEntry || "Unknown") : "" + property bool manualSelection: false + + function setPosition(pos) { + if (activePlayer) + activePlayer.position = pos; + + } + + function selectPlayer(player) { + if (player) { + instance.activePlayer = player; + manualSelection = true; + } + } + + function selectNextPlayer() { + const players = Mpris.players.values; + if (players.length <= 1) + return ; + + const currentIndex = players.indexOf(activePlayer); + const nextIndex = (currentIndex + 1) % players.length; + selectPlayer(players[nextIndex]); + } + + function selectPreviousPlayer() { + const players = Mpris.players.values; + if (players.length <= 1) + return ; + + const currentIndex = players.indexOf(activePlayer); + const prevIndex = (currentIndex - 1 + players.length) % players.length; + selectPlayer(players[prevIndex]); + } + + function updateActivePlayer() { + const players = Mpris.players.values; + if (manualSelection && instance.activePlayer && players.includes(instance.activePlayer)) + return ; + + if (manualSelection && instance.activePlayer && !players.includes(instance.activePlayer)) + manualSelection = false; + + const playing = players.find((p) => { + return p.playbackState === MprisPlaybackState.Playing; + }); + if (playing) { + instance.activePlayer = playing; + } else if (players.length > 0) { + if (!instance.activePlayer || !players.includes(instance.activePlayer)) + instance.activePlayer = players[0]; + + } else { + instance.activePlayer = null; + } + } + + function playPause() { + if (activePlayer && activePlayer.canTogglePlaying) + activePlayer.togglePlaying(); + + } + + function next() { + if (activePlayer && activePlayer.canGoNext) + activePlayer.next(); + + } + + function previous() { + if (activePlayer && activePlayer.canGoPrevious) + activePlayer.previous(); + + } + + Component.onCompleted: updateActivePlayer() + + QtObject { + id: instance + + property var players: Mpris.players.values + property var activePlayer: null + } + + Timer { + interval: 1000 + running: true + repeat: true + onTriggered: { + updateActivePlayer(); + if (activePlayer) + root.position = activePlayer.position; + + } + } + + Connections { + function onValuesChanged() { + root._players = Mpris.players.values; + updateActivePlayer(); + } + + target: Mpris.players + } + +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/services/Network.qml b/.config/quickshell/nucleus-shell/services/Network.qml new file mode 100755 index 0000000..58f9369 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Network.qml @@ -0,0 +1,309 @@ +pragma Singleton +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + readonly property list connections: [] + readonly property list savedNetworks: [] + readonly property Connection active: connections.find(c => c.active) ?? null + + property bool wifiEnabled: true + readonly property bool scanning: rescanProc.running + + property string lastNetworkAttempt: "" + property string lastErrorMessage: "" + property string message: "" + + readonly property string icon: { + if (!active) return "signal_wifi_off"; + if (active.type === "ethernet") return "settings_ethernet"; + + if (active.strength >= 75) return "network_wifi"; + else if (active.strength >= 50) return "network_wifi_3_bar"; + else if (active.strength >= 25) return "network_wifi_2_bar"; + else return "network_wifi_1_bar"; + } + + readonly property string wifiLabel: { + const activeWifi = connections.find(c => c.active && c.type === "wifi"); + if (activeWifi) return activeWifi.name; + return "Wi-Fi"; + } + + readonly property string wifiStatus: { + const activeWifi = connections.find(c => c.active && c.type === "wifi"); + if (activeWifi) return "Connected"; + if (wifiEnabled) return "On"; + return "Off"; + } + + readonly property string label: { + if (active) return active.name; + if (wifiEnabled) return "Wi-Fi"; + return "Wi-Fi"; + } + + readonly property string status: { + if (active) return "Connected"; + if (wifiEnabled) return "On"; + return "Off"; + } + + function enableWifi(enabled: bool): void { + enableWifiProc.exec(["nmcli", "radio", "wifi", enabled ? "on" : "off"]); + } + + function toggleWifi(): void { + enableWifi(!wifiEnabled); + } + + function rescan(): void { + rescanProc.running = true; + } + + function connect(connection: Connection, password: string): void { + if (connection.type === "wifi") { + root.lastNetworkAttempt = connection.name; + root.lastErrorMessage = ""; + root.message = ""; + + if (password && password.length > 0) { + connectProc.exec(["nmcli", "dev", "wifi", "connect", connection.name, "password", password]); + } else { + connectProc.exec(["nmcli", "dev", "wifi", "connect", connection.name]); + } + } else if (connection.type === "ethernet") { + ethConnectProc.exec(["nmcli", "connection", "up", connection.uuid]); + } + } + + function disconnect(): void { + if (!active) return; + + if (active.type === "wifi") { + disconnectProc.exec(["nmcli", "connection", "down", active.name]); + } else if (active.type === "ethernet") { + ethDisconnectProc.exec(["nmcli", "connection", "down", active.uuid]); + } + } + + Process { + running: true + command: ["nmcli", "m"] + stdout: SplitParser { + onRead: { + getWifiStatus(); + updateConnections(); + } + } + } + + function getWifiStatus(): void { + wifiStatusProc.running = true; + } + + function updateConnections(): void { + getWifiNetworks.running = true; + getEthConnections.running = true; + getSavedNetworks.running = true; + } + + Process { + id: wifiStatusProc + running: true + command: ["nmcli", "radio", "wifi"] + environment: ({ LANG: "C.UTF-8", LC_ALL: "C.UTF-8" }) + stdout: StdioCollector { + onStreamFinished: { + root.wifiEnabled = text.trim() === "enabled"; + if (!root.wifiEnabled) { + root.lastErrorMessage = ""; + root.message = ""; + root.lastNetworkAttempt = ""; + } + } + } + } + + Process { + id: enableWifiProc + onExited: updateConnections() + } + + Process { + id: rescanProc + command: ["nmcli", "dev", "wifi", "list", "--rescan", "yes"] + onExited: updateConnections() + } + + Process { + id: connectProc + stdout: StdioCollector { } + stderr: StdioCollector { + onStreamFinished: { + if (text.includes("Error") || text.includes("incorrect")) { + root.lastErrorMessage = "Incorrect password"; + } + } + } + onExited: { + if (exitCode === 0) { + root.message = "ok"; + root.lastErrorMessage = ""; + } else { + root.message = root.lastErrorMessage !== "" ? root.lastErrorMessage : "Connection failed"; + } + updateConnections(); + } + } + + Process { + id: disconnectProc + onExited: updateConnections() + } + + Process { + id: ethConnectProc + onExited: updateConnections() + } + + Process { + id: ethDisconnectProc + onExited: updateConnections() + } + + Process { + id: getSavedNetworks + running: true + command: ["nmcli", "-g", "NAME,TYPE", "connection", "show"] + environment: ({ LANG: "C.UTF-8", LC_ALL: "C.UTF-8" }) + stdout: StdioCollector { + onStreamFinished: { + const lines = text.trim().split("\n"); + const wifiConnections = lines + .map(line => line.split(":")) + .filter(parts => parts[1] === "802-11-wireless") + .map(parts => parts[0]); + root.savedNetworks = wifiConnections; + } + } + } + + Process { + id: getWifiNetworks + running: true + command: ["nmcli", "-g", "ACTIVE,SIGNAL,FREQ,SSID,BSSID,SECURITY", "d", "w"] + environment: ({ LANG: "C.UTF-8", LC_ALL: "C.UTF-8" }) + stdout: StdioCollector { + onStreamFinished: { + const PLACEHOLDER = "STRINGWHICHHOPEFULLYWONTBEUSED"; + const rep = new RegExp("\\\\:", "g"); + const rep2 = new RegExp(PLACEHOLDER, "g"); + + const allNetworks = text.trim().split("\n").map(n => { + const net = n.replace(rep, PLACEHOLDER).split(":"); + return { + type: "wifi", + active: net[0] === "yes", + strength: parseInt(net[1]), + frequency: parseInt(net[2]), + name: net[3]?.replace(rep2, ":") ?? "", + bssid: net[4]?.replace(rep2, ":") ?? "", + security: net[5] ?? "", + saved: root.savedNetworks.includes(net[3] ?? ""), + uuid: "", + device: "" + }; + }).filter(n => n.name && n.name.length > 0); + + const networkMap = new Map(); + for (const network of allNetworks) { + const existing = networkMap.get(network.name); + if (!existing) { + networkMap.set(network.name, network); + } else { + if (network.active && !existing.active) { + networkMap.set(network.name, network); + } else if (!network.active && !existing.active && network.strength > existing.strength) { + networkMap.set(network.name, network); + } + } + } + + mergeConnections(Array.from(networkMap.values()), "wifi"); + } + } + } + + Process { + id: getEthConnections + running: true + command: ["nmcli", "-g", "NAME,UUID,TYPE,DEVICE,STATE", "connection", "show"] + environment: ({ LANG: "C.UTF-8", LC_ALL: "C.UTF-8" }) + stdout: StdioCollector { + onStreamFinished: { + const lines = text.trim().split("\n"); + const ethConns = lines + .map(line => line.split(":")) + .filter(parts => parts[2] === "802-3-ethernet" || parts[2] === "gsm" || parts[2] === "bluetooth") + .map(parts => ({ + type: "ethernet", + name: parts[0], + uuid: parts[1], + device: parts[3], + active: parts[4] === "activated", + strength: 100, + frequency: 0, + bssid: "", + security: "", + saved: true + })); + + mergeConnections(ethConns, "ethernet"); + } + } + } + + function mergeConnections(newConns: var, connType: string): void { + const rConns = root.connections; + const destroyed = rConns.filter(rc => rc.type === connType && !newConns.find(nc => + connType === "wifi" ? (nc.frequency === rc.frequency && nc.name === rc.name && nc.bssid === rc.bssid) + : nc.uuid === rc.uuid + )); + + for (const conn of destroyed) + rConns.splice(rConns.indexOf(conn), 1).forEach(c => c.destroy()); + + for (const conn of newConns) { + const match = rConns.find(c => + connType === "wifi" ? (c.frequency === conn.frequency && c.name === conn.name && c.bssid === conn.bssid) + : c.uuid === conn.uuid + ); + if (match) { + match.lastIpcObject = conn; + } else { + rConns.push(connComp.createObject(root, { lastIpcObject: conn })); + } + } + } + + component Connection: QtObject { + required property var lastIpcObject + readonly property string type: lastIpcObject.type + readonly property string name: lastIpcObject.name + readonly property string uuid: lastIpcObject.uuid + readonly property string device: lastIpcObject.device + readonly property bool active: lastIpcObject.active + readonly property int strength: lastIpcObject.strength + readonly property int frequency: lastIpcObject.frequency + readonly property string bssid: lastIpcObject.bssid + readonly property string security: lastIpcObject.security + readonly property bool isSecure: security.length > 0 + readonly property bool saved: lastIpcObject.saved + } + + Component { id: connComp; Connection { } } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/services/Niri.qml b/.config/quickshell/nucleus-shell/services/Niri.qml new file mode 100644 index 0000000..bf5cff5 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Niri.qml @@ -0,0 +1,242 @@ +import QtQuick +import Quickshell +import Quickshell.Wayland +import Quickshell.Io +pragma Singleton + +Singleton { + id: niriItem + + signal stateChanged() + + property string title: "" + property bool isFullscreen: false + property string layout: "Tiled" + property int focusedWorkspaceId: 1 + + property var workspaces: [] + property var workspaceCache: ({}) + property var windows: [] // tracked windows + + property bool initialized: false + property int screenW: 0 + property int screenH: 0 + property real screenScale: 1 + + function changeWorkspace(id) { + sendSocketCommand(niriCommandSocket, { + "Action": { + "focus_workspace": { + "reference": { "Id": id } + } + } + }) + dispatchProc.command = ["niri", "msg", "action", "focus-workspace", id.toString()] + dispatchProc.running = true + } + + function changeWorkspaceRelative(delta) { + const cmd = delta > 0 ? "focus-workspace-down" : "focus-workspace-up" + dispatchProc.command = ["niri", "msg", "action", cmd] + dispatchProc.running = true + } + + function isWorkspaceOccupied(id) { + for (const ws of workspaces) + if (ws.id === id) return true + return false + } + + function focusedWindowForWorkspace(id) { + // focused window in workspace + for (const win of windows) { + if (win.workspaceId === id && win.isFocused) { + return { class: win.appId, title: win.title } + } + } + + // fallback: any window in workspace + for (const win of windows) { + if (win.workspaceId === id) { + return { class: win.appId, title: win.title } + } + } + + return null + } + + function sendSocketCommand(sock, command) { + if (sock.connected) + sock.write(JSON.stringify(command) + "\n") + } + + function startEventStream() { + sendSocketCommand(niriEventStream, "EventStream") + } + + function updateWorkspaces() { + sendSocketCommand(niriCommandSocket, "Workspaces") + } + + function updateWindows() { + sendSocketCommand(niriCommandSocket, "Windows") + } + + function updateFocusedWindow() { + sendSocketCommand(niriCommandSocket, "FocusedWindow") + } + + function recollectWorkspaces(workspacesData) { + const list = [] + workspaceCache = {} + + for (const ws of workspacesData) { + const data = { + id: ws.idx !== undefined ? ws.idx + 1 : ws.id, + internalId: ws.id, + idx: ws.idx, + name: ws.name || "", + output: ws.output || "", + isFocused: ws.is_focused === true, + isActive: ws.is_active === true + } + + list.push(data) + workspaceCache[ws.id] = data + if (data.isFocused) + focusedWorkspaceId = data.id + } + + list.sort((a, b) => a.id - b.id) + workspaces = list + stateChanged() + } + + function recollectWindows(windowsData) { + const list = [] + + for (const win of windowsData) { + list.push({ + appId: win.app_id || "", + title: win.title || "", + workspaceId: win.workspace_id, + isFocused: win.is_focused === true + }) + } + + windows = list + stateChanged() + } + + function recollectFocusedWindow(win) { + if (win && win.title) { + title = win.title + isFullscreen = win.is_fullscreen || false + layout = "Tiled" + } else { + title = "~" + isFullscreen = false + layout = "Tiled" + } + stateChanged() + } + + Component.onCompleted: { + if (Quickshell.env("NIRI_SOCKET")) { + niriCommandSocket.connected = true + niriEventStream.connected = true + initialized = true + } + } + + Process { + id: niriOutputsProc + command: ["niri", "msg", "outputs"] + running: true + + stdout: StdioCollector { + onStreamFinished: { + const lines = this.text.split("\n") + let sizeRe = /Logical size:\s*(\d+)x(\d+)/ + let scaleRe = /Scale:\s*([\d.]+)/ + + for (const line of lines) { + let m + if ((m = sizeRe.exec(line))) { + screenW = parseInt(m[1], 10) + screenH = parseInt(m[2], 10) + } else if ((m = scaleRe.exec(line))) { + screenScale = parseFloat(m[1]) + } + } + stateChanged() + } + } + } + + Socket { + id: niriCommandSocket + path: Quickshell.env("NIRI_SOCKET") || "" + connected: false + + onConnectedChanged: { + if (connected) { + updateWorkspaces() + updateWindows() + updateFocusedWindow() + } + } + + parser: SplitParser { + onRead: (line) => { + if (!line.trim()) return + try { + const data = JSON.parse(line) + if (data?.Ok) { + const res = data.Ok + if (res.Workspaces) recollectWorkspaces(res.Workspaces) + else if (res.Windows) recollectWindows(res.Windows) + else if (res.FocusedWindow) recollectFocusedWindow(res.FocusedWindow) + } + } catch (e) { + console.warn("Niri socket parse error:", e) + } + } + } + } + + Socket { + id: niriEventStream + path: Quickshell.env("NIRI_SOCKET") || "" + connected: false + + onConnectedChanged: { + if (connected) + startEventStream() + } + + parser: SplitParser { + onRead: (data) => { + if (!data.trim()) return + try { + const event = JSON.parse(data.trim()) + + if (event.WorkspacesChanged) + recollectWorkspaces(event.WorkspacesChanged.workspaces) + else if (event.WorkspaceActivated) + updateWorkspaces() + else if ( + event.WindowFocusChanged || + event.WindowOpenedOrChanged || + event.WindowClosed + ) + updateWindows() + } catch (e) { + console.warn("Niri event stream parse error:", e) + } + } + } + } + + Process { id: dispatchProc } +} diff --git a/.config/quickshell/nucleus-shell/services/NotifServer.qml b/.config/quickshell/nucleus-shell/services/NotifServer.qml new file mode 100755 index 0000000..0e7cd8d --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/NotifServer.qml @@ -0,0 +1,110 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Io +import Quickshell.Services.Notifications +import QtQuick +import qs.config + +// from github.com/end-4/dots-hyprland with modifications + +Singleton { + id: root + + property list data: [] + property list popups: data.filter(n => n.popup && !n.tracked) + property list history: data + + Loader { + active: Config.initialized && Config.runtime.notifications.enabled + sourceComponent: NotificationServer { + keepOnReload: false + actionsSupported: true + bodyHyperlinksSupported: true + bodyImagesSupported: true + bodyMarkupSupported: true + imageSupported: true + + onNotification: notif => { + notif.tracked = true; + + root.data.push(notifComp.createObject(root, { + popup: true, + notification: notif, + shown: false + })); + } + } + } + function removeById(id) { + const i = data.findIndex(n => n.notification.id === id); + if (i >= 0) { + data.splice(i, 1); + } + } + + + component Notif: QtObject { + id: notif + + property bool popup + readonly property date time: new Date() + readonly property string timeStr: { + const diff = Time.date.getTime() - time.getTime(); + const m = Math.floor(diff / 60000); + const h = Math.floor(m / 60); + + if (h < 1 && m < 1) + return "now"; + if (h < 1) + return `${m}m`; + return `${h}h`; + } + + property bool shown: false + required property Notification notification + readonly property string summary: notification.summary + readonly property string body: notification.body + readonly property string appIcon: notification.appIcon + readonly property string appName: notification.appName + readonly property string image: notification.image + readonly property int urgency: notification.urgency + readonly property list actions: notification.actions + + readonly property Timer timer: Timer { + running: notif.actions.length >= 0 + interval: notif.notification.expireTimeout > 0 ? notif.notification.expireTimeout : 5000 + onTriggered: { + if (true) + notif.popup = false; + } + } + + readonly property Connections conn: Connections { + target: notif.notification.Retainable + + function onDropped(): void { + root.data.splice(root.data.indexOf(notif), 1); + } + + function onAboutToDestroy(): void { + notif.destroy(); + } + } + readonly property Connections conn2: Connections { + target: notif.notification + + function onClosed(reason) { + root.data.splice(root.data.indexOf(notif), 1) + } + } + + } + + Component { + id: notifComp + + Notif {} + } +} diff --git a/.config/quickshell/nucleus-shell/services/Polkit.qml b/.config/quickshell/nucleus-shell/services/Polkit.qml new file mode 100644 index 0000000..df4deac --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Polkit.qml @@ -0,0 +1,22 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Io +import Quickshell.Services.Polkit +import QtQuick + +Singleton { + id: root + + property alias isActive: polkit.isActive + property alias isRegistered: polkit.isRegistered + property alias flow: polkit.flow + property alias path: polkit.path + + Component.onCompleted: { + } + PolkitAgent { + id: polkit + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/services/SystemDetails.qml b/.config/quickshell/nucleus-shell/services/SystemDetails.qml new file mode 100644 index 0000000..1b2a149 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/SystemDetails.qml @@ -0,0 +1,394 @@ +import QtQuick +import Quickshell +import Quickshell.Io +import qs.config +pragma Singleton + +Singleton { + id: root + + property string hostname: "" + property string username: "" + property string osIcon: "" + property string osName: "" + property string kernelVersion: "" + property string architecture: "" + property string uptime: "" + property string qsVersion: "" + property string swapUsage: "—" + property real swapPercent: 0 + property string ipAddress: "—" + property int runningProcesses: 0 + property int loggedInUsers: 0 + property string ramUsage: "—" + property real ramPercent: 0 + property string cpuLoad: "—" + property real cpuPercent: 0 + property string diskUsage: "—" + property real diskPercent: 0 + property string cpuTemp: "—" + property string keyboardLayout: "none" + property real cpuTempPercent: 0 + property int prevIdle: -1 + property int prevTotal: -1 + + + readonly property var osIcons: ({ + "almalinux": "", + "alpine": "", + "arch": "󰣇", + "archcraft": "", + "arcolinux": "", + "artix": "", + "centos": "", + "debian": "", + "devuan": "", + "elementary": "", + "endeavouros": "", + "fedora": "", + "freebsd": "", + "garuda": "", + "gentoo": "", + "hyperbola": "", + "kali": "", + "linuxmint": "󰣭", + "mageia": "", + "openmandriva": "", + "manjaro": "", + "neon": "", + "nixos": "", + "opensuse": "", + "suse": "", + "sles": "", + "sles_sap": "", + "opensuse-tumbleweed": "", + "parrot": "", + "pop": "", + "raspbian": "", + "rhel": "", + "rocky": "", + "slackware": "", + "solus": "", + "steamos": "", + "tails": "", + "trisquel": "", + "ubuntu": "", + "vanilla": "", + "void": "", + "zorin": "", + "opensuse": "", + + }) + + + FileView { id: cpuStat; path: "/proc/stat" } + FileView { id: memInfo; path: "/proc/meminfo" } + FileView { id: uptimeFile; path: "/proc/uptime" } + + + Timer { + interval: 1000 + running: true + repeat: true + + onTriggered: { + + cpuStat.reload() + memInfo.reload() + uptimeFile.reload() + + /* CPU */ + + const cpuLine = cpuStat.text().split("\n")[0].trim().split(/\s+/) + + const cpuUser = parseInt(cpuLine[1]) + const cpuNice = parseInt(cpuLine[2]) + const cpuSystem = parseInt(cpuLine[3]) + const cpuIdle = parseInt(cpuLine[4]) + const cpuIowait = parseInt(cpuLine[5]) + const cpuIrq = parseInt(cpuLine[6]) + const cpuSoftirq = parseInt(cpuLine[7]) + + const cpuIdleAll = cpuIdle + cpuIowait + const cpuTotal = + cpuUser + cpuNice + cpuSystem + cpuIrq + cpuSoftirq + cpuIdleAll + + if (root.prevTotal >= 0) { + + const totalDiff = cpuTotal - root.prevTotal + const idleDiff = cpuIdleAll - root.prevIdle + + if (totalDiff > 0) + root.cpuPercent = (totalDiff - idleDiff) / totalDiff + } + + root.prevTotal = cpuTotal + root.prevIdle = cpuIdleAll + + root.cpuLoad = Math.round(root.cpuPercent * 100) + "%" + + + /* RAM */ + + const memLines = memInfo.text().split("\n") + + let memTotal = 0 + let memAvailable = 0 + + for (let line of memLines) { + + if (line.startsWith("MemTotal")) + memTotal = parseInt(line.match(/\d+/)[0]) + + if (line.startsWith("MemAvailable")) + memAvailable = parseInt(line.match(/\d+/)[0]) + } + + if (memTotal > 0) { + + const memUsed = memTotal - memAvailable + + root.ramPercent = memUsed / memTotal + root.ramUsage = + `${Math.round(memUsed/1024)}/${Math.round(memTotal/1024)} MB` + } + + + /* Uptime */ + + const uptimeSeconds = + parseFloat(uptimeFile.text().split(" ")[0]) + + const d = Math.floor(uptimeSeconds / 86400) + const h = Math.floor((uptimeSeconds % 86400) / 3600) + const m = Math.floor((uptimeSeconds % 3600) / 60) + + let upString = "Up " + + if (d > 0) upString += d + "d " + if (h > 0) upString += h + "h " + + upString += m + "m" + + root.uptime = upString + + + cpuTempProc.running = true + diskProc.running = true + ipProc.running = true + procCountProc.running = true + swapProc.running = true + keyboardLayoutProc.running = true + loggedUsersProc.running = true + } + } + + + /* CPU Temperature */ + + Process { + id: cpuTempProc + command: [ + "sh","-c", + "for f in /sys/class/hwmon/hwmon*/temp*_input; do cat $f && exit; done" + ] + + stdout: StdioCollector { + onStreamFinished: { + const raw = parseInt(text.trim()) + if (isNaN(raw)) return + + const c = raw / 1000 + root.cpuTemp = `${Math.round(c)}°C` + + const min = 30 + const max = 95 + + root.cpuTempPercent = + Math.max(0, Math.min(1,(c-min)/(max-min))) + } + } + } + + + /* Disk */ + + Process { + id: diskProc + command: ["df","-h","/"] + + stdout: StdioCollector { + onStreamFinished: { + + const lines = text.trim().split("\n") + if (lines.length < 2) return + + const parts = lines[1].split(/\s+/) + + const used = parts[2] + const total = parts[1] + const percent = parseInt(parts[4]) / 100 + + root.diskPercent = percent + root.diskUsage = `${used}/${total}` + } + } + } + + + /* Swap */ + + Process { + id: swapProc + command: ["sh","-c","free -m | grep Swap"] + + stdout: StdioCollector { + onStreamFinished: { + + const parts = text.trim().split(/\s+/) + if (parts.length < 3) return + + const total = parseInt(parts[1]) + const used = parseInt(parts[2]) + + root.swapPercent = used / total + root.swapUsage = `${used}/${total} MB` + } + } + } + + + /* IP */ + + Process { + id: ipProc + command: ["sh","-c","hostname -I | awk '{print $1}'"] + + stdout: StdioCollector { + onStreamFinished: root.ipAddress = text.trim() + } + } + + + /* Process Count */ + + Process { + id: procCountProc + command: ["sh","-c","ps -e --no-headers | wc -l"] + + stdout: StdioCollector { + onStreamFinished: root.runningProcesses = parseInt(text.trim()) + } + } + + + /* Logged Users */ + + Process { + id: loggedUsersProc + command: ["who","-q"] + + stdout: StdioCollector { + onStreamFinished: { + const lines = text.trim().split("\n") + if (lines.length > 0) + root.loggedInUsers = + parseInt(lines[lines.length-1].replace("# users=","")) + } + } + } + + + /* Keyboard Layout */ + + Process { + id: keyboardLayoutProc + command: [ + "sh","-c", + "hyprctl devices -j | jq -r '.keyboards[] | .layout' | head -n1" + ] + + stdout: StdioCollector { + onStreamFinished: { + const layout = text.trim() + if (layout) + root.keyboardLayout = layout + } + } + } + + + /* OS Info */ + + Process { + running: true + command: [ + "sh","-c", + "source /etc/os-release && echo \"$PRETTY_NAME|$ID\"" + ] + + stdout: StdioCollector { + onStreamFinished: { + const parts = text.trim().split("|") + root.osName = parts[0] + root.osIcon = root.osIcons[parts[1]] || "" + } + } + } + + + /* Quickshell Version */ + + Process { + running: true + command: ["qs","--version"] + + stdout: StdioCollector { + onStreamFinished: { + root.qsVersion = + text.trim().split(',')[0] + .replace("quickshell ","") + } + } + } + + + /* Static system info */ + + Process { + running: true + command: ["whoami"] + + stdout: StdioCollector { + onStreamFinished: root.username = text.trim() + } + } + + Process { + running: true + command: ["hostname"] + + stdout: StdioCollector { + onStreamFinished: root.hostname = text.trim() + } + } + + Process { + running: true + command: ["uname","-r"] + + stdout: StdioCollector { + onStreamFinished: root.kernelVersion = text.trim() + } + } + + Process { + running: true + command: ["uname","-m"] + + stdout: StdioCollector { + onStreamFinished: root.architecture = text.trim() + } + } + +} diff --git a/.config/quickshell/nucleus-shell/services/Theme.qml b/.config/quickshell/nucleus-shell/services/Theme.qml new file mode 100644 index 0000000..0289472 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Theme.qml @@ -0,0 +1,54 @@ +import QtQuick +import Quickshell +import Quickshell.Io +import qs.config +pragma Singleton + +Singleton { + id: root + property var map: ({ + }) + + function notifyMissingVariant(theme, variant) { + Quickshell.execDetached(["notify-send", "Nucleus Shell", `Theme '${theme}' does not have a ${variant} variant.`, "--urgency=normal", "--expire-time=5000"]); + } + + Timer { + interval: 5000 + repeat: true + running: true + onTriggered: loadThemes.running = true + } + + Process { + id: loadThemes + + command: ["ls", Directories.shellConfig + "/colorschemes"] + running: true + + stdout: StdioCollector { + onStreamFinished: { + const map = { + }; + text.split("\n").map((t) => { + return t.trim(); + }).filter((t) => { + return t.endsWith(".json"); + }).forEach((t) => { + const name = t.replace(/\.json$/, ""); + const parts = name.split("-"); + const variant = parts.pop(); + const base = parts.join("-"); + if (!map[base]) + map[base] = { + }; + + map[base][variant] = name; + }); + root.map = map; + } + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/services/Time.qml b/.config/quickshell/nucleus-shell/services/Time.qml new file mode 100755 index 0000000..a494433 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Time.qml @@ -0,0 +1,20 @@ +pragma Singleton +import Quickshell +import QtQuick + +Singleton { + id: root + + property alias date: clock.date // expose raw date/time + readonly property SystemClock clock: clock + + SystemClock { + id: clock + precision: SystemClock.Seconds + } + + // Helper function if you still want formatting ability: + function format(fmt) { + return Qt.formatDateTime(clock.date, fmt) + } +} diff --git a/.config/quickshell/nucleus-shell/services/UPower.qml b/.config/quickshell/nucleus-shell/services/UPower.qml new file mode 100644 index 0000000..a37cb6f --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/UPower.qml @@ -0,0 +1,136 @@ +import QtQuick +import Quickshell +import Quickshell.Io +pragma Singleton + +Item { + // I have to make such services because quickshell services like Quickshell.Services.UPower don't work and are messy. + + id: root + + // Battery + property int percentage: 0 + property string state: "unknown" + property string iconName: "" + property bool onBattery: false + property bool charging: false + property bool batteryPresent: false + property bool rechargeable: false + // Energy metrics + property real energyWh: 0 + property real energyFullWh: 0 + property real energyRateW: 0 + property real capacityPercent: 0 + // AC / system + property bool acOnline: false + property bool lidClosed: false + property string battIcon: { + const b = percentage; + if (b > 80) + return "battery_6_bar"; + + if (b > 60) + return "battery_5_bar"; + + if (b > 50) + return "battery_4_bar"; + + if (b > 40) + return "battery_3_bar"; + + if (b > 30) + return "battery_2_bar"; + + if (b > 20) + return "battery_1_bar"; + + if (b > 10) + return "battery_alert"; + + return "battery_0_bar"; + } + + Timer { + interval: 2000 + running: true + repeat: true + onTriggered: upowerProc.running = true + } + + Process { + id: upowerProc + + command: ["upower", "-d"] + running: true + + stdout: StdioCollector { + onStreamFinished: { + // ---------- DisplayDevice (preferred) ---------- + // ---------- Rechargeable ---------- + // ---------- Physical battery (extra info) ---------- + // ---------- Daemon / system ---------- + // ---------- AC adapter ---------- + + const t = text; + let m; + m = t.match(/DisplayDevice[\s\S]*?present:\s+(yes|no)/); + if (m) { + root.batteryPresent = (m[1] === "yes"); + } else { + // fallback: physical battery + m = t.match(/battery_BAT\d+[\s\S]*?present:\s+(yes|no)/); + if (m) + root.batteryPresent = (m[1] === "yes"); + + } + m = t.match(/DisplayDevice[\s\S]*?rechargeable:\s+(yes|no)/); + if (m) + root.rechargeable = (m[1] === "yes"); + + m = t.match(/DisplayDevice[\s\S]*?percentage:\s+(\d+)%/); + if (m) + root.percentage = parseInt(m[1]); + + m = t.match(/DisplayDevice[\s\S]*?state:\s+([a-z\-]+)/); + if (m) { + root.state = m[1]; + root.charging = (m[1].includes("charge")); + } + m = t.match(/DisplayDevice[\s\S]*?icon-name:\s+'([^']+)'/); + if (m) + root.iconName = m[1]; + + m = t.match(/DisplayDevice[\s\S]*?energy:\s+([\d.]+)\s+Wh/); + if (m) + root.energyWh = parseFloat(m[1]); + + m = t.match(/DisplayDevice[\s\S]*?energy-full:\s+([\d.]+)\s+Wh/); + if (m) + root.energyFullWh = parseFloat(m[1]); + + m = t.match(/DisplayDevice[\s\S]*?energy-rate:\s+([\d.]+)\s+W/); + if (m) + root.energyRateW = parseFloat(m[1]); + + m = t.match(/capacity:\s+([\d.]+)%/); + if (m) + root.capacityPercent = parseFloat(m[1]); + + m = t.match(/on-battery:\s+(yes|no)/); + if (m) + root.onBattery = (m[1] === "yes"); + + m = t.match(/lid-is-closed:\s+(yes|no)/); + if (m) + root.lidClosed = (m[1] === "yes"); + + m = t.match(/line-power[\s\S]*?online:\s+(yes|no)/); + if (m) + root.acOnline = (m[1] === "yes"); + + } + } + + } + +} diff --git a/.config/quickshell/nucleus-shell/services/UpdateNotifier.qml b/.config/quickshell/nucleus-shell/services/UpdateNotifier.qml new file mode 100644 index 0000000..1fbdc4b --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/UpdateNotifier.qml @@ -0,0 +1,100 @@ +import Qt.labs.platform +import QtQuick +import Quickshell +import Quickshell.Io +import qs.config + +Item { + id: updater + // Add 'v' arg to default local version because it is not stored + // as vX.Y.Z but X.Y.Z while on github its published as vX.Y.Z + + property string currentVersion: "" + property string latestVersion: "" + property bool notified: false + property string channel: Config.runtime.shell.releaseChannel || "stable" + + function readLocalVersion() { + currentVersion = "v" + (Config.runtime.shell.version || ""); + } + + function fetchLatestVersion() { + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + try { + const json = JSON.parse(xhr.responseText); + + if (channel === "stable") { + // /releases/latest returns a single object + if (json.tag_name) { + latestVersion = json.tag_name; + compareVersions(); + } else { + console.warn("Stable update check returned unexpected response:", json); + } + } else if (channel === "edge") { + // /releases returns an array, newest first + for (var i = 0; i < json.length; i++) { + if (json[i].prerelease === true) { + latestVersion = json[i].tag_name; + compareVersions(); + return; + } + } + console.warn("Edge channel: no pre-release found."); + } + } catch (e) { + console.warn("Update check JSON parse failed:", xhr.responseText); + } + } + }; + + if (channel === "stable") { + xhr.open( + "GET", + "https://api.github.com/repos/xzepyx/nucleus-shell/releases/latest" + ); + } else { + xhr.open( + "GET", + "https://api.github.com/repos/xzepyx/nucleus-shell/releases" + ); + } + + xhr.send(); + } + + function compareVersions() { + if (!currentVersion || !latestVersion) + return; + + if (currentVersion !== latestVersion && !notified) { + notifyUpdate(); + notified = true; + } + } + + function notifyUpdate() { + Quickshell.execDetached([ + "notify-send", + "-a", "Nucleus Shell", + "Update Available", + "Installed: " + currentVersion + + "\nLatest (" + channel + "): " + latestVersion + ]); + } + + visible: false + + Timer { + interval: 24 * 60 * 60 * 1000 // 24 hours + running: true + repeat: true + triggeredOnStart: true + onTriggered: { + readLocalVersion(); + fetchLatestVersion(); + } + } +} diff --git a/.config/quickshell/nucleus-shell/services/Volume.qml b/.config/quickshell/nucleus-shell/services/Volume.qml new file mode 100755 index 0000000..d1125eb --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Volume.qml @@ -0,0 +1,50 @@ +pragma Singleton +import QtQuick +import Quickshell +import Quickshell.Services.Pipewire + + +Singleton { + PwObjectTracker { + objects: [ + Pipewire.defaultAudioSource, + Pipewire.defaultAudioSink, + Pipewire.nodes, + Pipewire.links + ] + } + + property var sinks: Pipewire.nodes.values.filter(node => node.isSink && !node.isStream && node.audio) + property PwNode defaultSink: Pipewire.defaultAudioSink + + property var sources: Pipewire.nodes.values.filter(node => !node.isSink && !node.isStream && node.audio) + property PwNode defaultSource: Pipewire.defaultAudioSource + + property real volume: defaultSink?.audio?.volume ?? 0 + property bool muted: defaultSink?.audio?.muted ?? false + + function setVolume(to: real): void { + if (defaultSink?.ready && defaultSink?.audio) { + defaultSink.audio.muted = false; + defaultSink.audio.volume = Math.max(0, Math.min(1, to)); + } + } + + function setSourceVolume(to: real): void { + if (defaultSource?.ready && defaultSource?.audio) { + defaultSource.audio.muted = false; + defaultSource.audio.volume = Math.max(0, Math.min(1, to)); + } + } + + function setDefaultSink(sink: PwNode): void { + Pipewire.preferredDefaultAudioSink = sink; + } + + function setDefaultSource(source: PwNode): void { + Pipewire.preferredDefaultAudioSource = source; + } + + function init() { + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/services/WallpaperSlideshow.qml b/.config/quickshell/nucleus-shell/services/WallpaperSlideshow.qml new file mode 100644 index 0000000..a5c4d92 --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/WallpaperSlideshow.qml @@ -0,0 +1,140 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell +import Quickshell.Io +import qs.config + +Singleton { + id: root + + property var wallpapers: [] + property bool scanning: false + property string currentFolder: Config.initialized ? Config.runtime.appearance.background.slideshow.folder : ""; + property int intervalMinutes: Config.initialized ? Config.runtime.appearance.background.slideshow.interval : 5 + property bool enabled: Config.initialized ? Config.runtime.appearance.background.slideshow.enabled : false + property bool includeSubfolders: Config.initialized ? Config.runtime.appearance.background.slideshow.includeSubfolders : true + property bool initializedOnce: false + property bool hydratingFromConfig: true + + signal wallpaperChanged(string path) + + function nextWallpaper() { + if (wallpapers.length === 0) { + console.warn("WallpaperSlideshow: No wallpapers found in folder"); + return; + } + const randomIndex = Math.floor(Math.random() * wallpapers.length); + const selectedPath = "file://" + wallpapers[randomIndex]; + Config.updateKey("appearance.background.path", selectedPath); + wallpaperChanged(selectedPath); + + // Regenerate colors + if (Config.runtime.appearance.colors.autogenerated) { + Quickshell.execDetached([ + "nucleus", "ipc", "call", "global", "regenColors" + ]); + } + } + + function scanFolder() { + if (!currentFolder || currentFolder === "") { + wallpapers = []; + return; + } + scanning = true; + scanProcess.running = true; + } + + // Timer for automatic wallpaper rotation + Timer { + id: slideshowTimer + interval: root.intervalMinutes * 60 * 1000 // Convert minutes into miliseconds + repeat: true + running: root.enabled && root.wallpapers.length > 0 && root.initializedOnce + onTriggered: root.nextWallpaper() + } + + // Process to scan folder for images + Process { + id: scanProcess + command: root.includeSubfolders + ? ["find", root.currentFolder, "-type", "f", "-iregex", ".*\\.\\(jpg\\|jpeg\\|png\\|webp\\|bmp\\|svg\\)$"] + : ["find", root.currentFolder, "-maxdepth", "1", "-type", "f", "-iregex", ".*\\.\\(jpg\\|jpeg\\|png\\|webp\\|bmp\\|svg\\)$"] + + stdout: SplitParser { + splitMarker: "" + onRead: data => { + const lines = data.trim().split("\n").filter(line => line.length > 0); + root.wallpapers = lines; + root.scanning = false; + } + } + + onExited: (exitCode, exitStatus) => { + root.scanning = false; + if (exitCode !== 0) { + console.warn("WallpaperSlideshow: Failed to scan folder"); + root.wallpapers = []; + } + } + } + + // Watch for folder changes - rescan and immediately change wallpaper + onCurrentFolderChanged: { + if (root.hydratingFromConfig) + return; + if (!currentFolder || currentFolder === "") + return; + scanning = true; + folderChangeScanProcess.running = true; + } + + // Separate process for folder change scan (triggers immediate wallpaper change) + Process { + id: folderChangeScanProcess + command: root.includeSubfolders + ? ["find", root.currentFolder, "-type", "f", "-iregex", ".*\\.\\(jpg\\|jpeg\\|png\\|webp\\|bmp\\|svg\\)$"] + : ["find", root.currentFolder, "-maxdepth", "1", "-type", "f", "-iregex", ".*\\.\\(jpg\\|jpeg\\|png\\|webp\\|bmp\\|svg\\)$"] + + stdout: SplitParser { + splitMarker: "" + onRead: data => { + const lines = data.trim().split("\n").filter(line => line.length > 0); + root.wallpapers = lines; + root.scanning = false; + + // Immediately change wallpaper when folder is changed + if (root.wallpapers.length > 0) { + root.nextWallpaper(); + } + } + } + + onExited: (exitCode, exitStatus) => { + root.scanning = false; + if (exitCode !== 0) { + console.warn("WallpaperSlideshow: Failed to scan folder"); + root.wallpapers = []; + } + } + } + + // Watch for includeSubfolders changes + onIncludeSubfoldersChanged: { + if (currentFolder && currentFolder !== "") { + scanFolder(); + } + } + + // Initial scan when config is loaded + Connections { + target: Config + function onInitializedChanged() { + if (Config.initialized && root.currentFolder && root.currentFolder !== "") { + root.scanFolder(); + } + } + } +} diff --git a/.config/quickshell/nucleus-shell/services/Xrandr.qml b/.config/quickshell/nucleus-shell/services/Xrandr.qml new file mode 100644 index 0000000..46aebcb --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Xrandr.qml @@ -0,0 +1,55 @@ +import QtQuick +import Quickshell +import Quickshell.Io +pragma Singleton + +/* + + Why use this service? Good question. + :- Cause xrandr works with all compositors to fetch monitor data. + +*/ + +Item { + id: root + + // Array of monitor objects: { name, width, height, x, y, physWidth, physHeight } + property var monitors: [] + + // Refresh monitors every 5 seconds + Timer { + interval: 5000 + running: true + repeat: true + onTriggered: xrandrProc.running = true + } + + Process { + id: xrandrProc + command: ["bash", "-c", "xrandr --query | grep ' connected '"] + running: true + + stdout: StdioCollector { + onStreamFinished: { // I don't even know wtf is this I can't explain shit + const lines = text.trim().split("\n") + root.monitors = lines.map(line => { + const m = line.match(/^(\S+)\sconnected\s(\d+)x(\d+)\+(\d+)\+(\d+).*?(\d+)mm\sx\s(\d+)mm$/) + if (!m) return null + return { + name: m[1], + width: parseInt(m[2]), + height: parseInt(m[3]), + x: parseInt(m[4]), + y: parseInt(m[5]), + physWidth: parseInt(m[6]), + physHeight: parseInt(m[7]) + } + }).filter(m => m) + } + } + } + + function getMonitor(name) { + return monitors.find(m => m.name === name) || null + } +} \ No newline at end of file diff --git a/.config/quickshell/nucleus-shell/services/Zenith.qml b/.config/quickshell/nucleus-shell/services/Zenith.qml new file mode 100644 index 0000000..e2cae5c --- /dev/null +++ b/.config/quickshell/nucleus-shell/services/Zenith.qml @@ -0,0 +1,82 @@ +// Zenith.properties +pragma Singleton +import QtQuick +import Quickshell +import Quickshell.Io +import qs.config +import qs.modules.functions + +Singleton { + // current state and shit + property string currentChat: "default" + property string currentModel: "gpt-4o-mini" + property string pendingInput: "" + property bool loading: zenithProcess.running + + // signals (needed for ui loading) + signal chatsListed(string text) + signal chatLoaded(string text) + signal aiReply(string text) + + // process to load data and talk to zenith + + Timer { + interval: 1000 + repeat: true + running: true + onTriggered: listChatsProcess.running = true; + } + + Process { + id: listChatsProcess + command: ["ls", FileUtils.trimFileProtocol(Directories.config) + "/zenith/chats"] + running: true + + stdout: StdioCollector { + onStreamFinished: chatsListed(text) + } + } + + Process { + id: chatLoadProcess + + stdout: StdioCollector { + onStreamFinished: chatLoaded(text) + } + } + + Process { + id: zenithProcess + + command: [ + "zenith", + "--api", Config.runtime.misc.intelligence.apiKey, + "--chat", currentChat, + "-a", + "--model", currentModel, + pendingInput + ] + + stdout: StdioCollector { + onStreamFinished: { + if (text.trim() !== "") + aiReply(text.trim()) + } + } + } + + // api shit + + function loadChat(chatName) { + chatLoadProcess.command = [ + "cat", + FileUtils.trimFileProtocol(Directories.config) + + "/zenith/chats/" + chatName + ".txt" + ] + chatLoadProcess.running = true + } + + function send() { + zenithProcess.running = true + } +} diff --git a/.config/quickshell/nucleus-shell/shell.qml b/.config/quickshell/nucleus-shell/shell.qml new file mode 100644 index 0000000..836bee5 --- /dev/null +++ b/.config/quickshell/nucleus-shell/shell.qml @@ -0,0 +1,87 @@ +import Quickshell +import QtQuick + +import qs.config +import qs.plugins +import qs.services +import qs.modules.interface.bar +import qs.modules.interface.background +import qs.modules.interface.powermenu +import qs.modules.interface.launcher +import qs.modules.interface.notifications +// import qs.modules.interface.intelligence // Intelligence +import qs.modules.interface.overlays +import qs.modules.interface.sidebarRight +import qs.modules.interface.settings +import qs.modules.interface.sidebarLeft +import qs.modules.interface.lockscreen +import qs.modules.interface.screencapture +import qs.modules.interface.polkit + +ShellRoot { + id: shellroot + + // Load modules + + LazyLoader { + id: barLoader + source: Contracts.bar + active: Config.runtime.bar.enabled && !Contracts.overriddenBar + } + + LazyLoader { + id: backgroundLoader + source: Contracts.background + active: Config.runtime.appearance.background.enabled && !Contracts.overriddenBackground + } + + LazyLoader { + id: powerMenuLoader + source: Contracts.powerMenu + active: Globals.visiblility.powermenu && !Contracts.overriddenPowerMenu + } + + LazyLoader { + id: launcherLoader + source: Contracts.launcher + active: true && !Contracts.overriddenLauncher + } + + LazyLoader { + id: notificationsLoader + source: Contracts.notifications + active: Config.runtime.notifications.enabled && !Contracts.overriddenNotifications + } + + LazyLoader { + id: overlaysLoader + source: Contracts.overlays + active: Config.runtime.overlays.enabled && !Contracts.overriddenOverlays + } + + LazyLoader { + id: sidebarRightLoader + source: Contracts.sidebarRight + active: Globals.visiblility.sidebarRight && !Contracts.overriddenSidebarRight + } + + LazyLoader { + id: sidebarLeftLoader + source: Contracts.sidebarLeft + active: Globals.visiblility.sidebarLeft && !Contracts.overriddenSidebarLeft + } + + LazyLoader { + id: lockScreenLoader + source: Contracts.lockScreen + active: true && !Contracts.overriddenLockScreen + } + + Settings { } + Ipc { } + // Intelligence { } + UpdateNotifier { } + // PluginHost { } + ScreenCapture{ } + PolkitAgent { } +} diff --git a/.config/quickshell/zenbar/shell.qml b/.config/quickshell/zenbar/shell.qml new file mode 100644 index 0000000..4cca9d2 --- /dev/null +++ b/.config/quickshell/zenbar/shell.qml @@ -0,0 +1,87 @@ +import Quickshell +import QtQuick + +import qs.config +import qs.plugins +import qs.services +import qs.modules.interface.bar +import qs.modules.interface.background +import qs.modules.interface.powermenu +import qs.modules.interface.launcher +import qs.modules.interface.notifications +import qs.modules.interface.intelligence // Intelligence +import qs.modules.interface.overlays +import qs.modules.interface.sidebarRight +import qs.modules.interface.settings +import qs.modules.interface.sidebarLeft +import qs.modules.interface.lockscreen +import qs.modules.interface.screencapture +import qs.modules.interface.polkit + +ShellRoot { + id: shellroot + + // Load modules + + LazyLoader { + id: barLoader + source: Contracts.bar + active: Config.runtime.bar.enabled && !Contracts.overriddenBar + } + + LazyLoader { + id: backgroundLoader + source: Contracts.background + active: Config.runtime.appearance.background.enabled && !Contracts.overriddenBackground + } + + LazyLoader { + id: powerMenuLoader + source: Contracts.powerMenu + active: Globals.visiblility.powermenu && !Contracts.overriddenPowerMenu + } + + LazyLoader { + id: launcherLoader + source: Contracts.launcher + active: true && !Contracts.overriddenLauncher + } + + LazyLoader { + id: notificationsLoader + source: Contracts.notifications + active: Config.runtime.notifications.enabled && !Contracts.overriddenNotifications + } + + LazyLoader { + id: overlaysLoader + source: Contracts.overlays + active: Config.runtime.overlays.enabled && !Contracts.overriddenOverlays + } + + LazyLoader { + id: sidebarRightLoader + source: Contracts.sidebarRight + active: Globals.visiblility.sidebarRight && !Contracts.overriddenSidebarRight + } + + LazyLoader { + id: sidebarLeftLoader + source: Contracts.sidebarLeft + active: Globals.visiblility.sidebarLeft && !Contracts.overriddenSidebarLeft + } + + LazyLoader { + id: lockScreenLoader + source: Contracts.lockScreen + active: true && !Contracts.overriddenLockScreen + } + + Settings { } + Ipc { } + Intelligence { } + UpdateNotifier { } + PluginHost { } + ScreenCapture{ } + PolkitAgent { } +}

    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

    ci|NmUm;NM$S#~t~a73U?Q6E6e&PGtxWSj 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%0AlmPf$KOA-5d^&UL4pn z%g;uDdbWcWz|-tiFX~+1`R(?&W_Pdzn9^VB%+OJM@2TUzMv(P%)y$wCOiZ1Yd5faA ziQ-^M-6-J}0f2z2&=9#KnPdMPOr$qCAnMcEfS0kPd}Zws@AWkXV*UnC9IA4(-V~n} zI8N75k0;Bp2l~2TAGy{=;b3`b*n|erb#mG#Xe~eMEdZnoAJ$2!_DexHr4->JtmPOg z(Y`NohkfcSdRJ|EkwJ~}aaxV*rqnOKw;9zo*=vv=h1VG7L>$cr=G|zJv;$JWPZ)tb zOTxGpFTOoJVPM}M#?!l)_$ue?>|#5xbrGZP#N~hz_NVW+DEBe{kDchNqgOrNjT4Ev zWgj=F8ux`VcVTv}@qh5H7%+(fJs`&}ynq#G#mqN}Hdx&*zoTeR^A~%R9j3ZjK!|kQ z^>s%f4c5%+f!>leUkL#GaStT8`Lr$F%-3F3YUdE|OvvIJVB&YLyJ6IL)iq~;$(qZ2 zwdZ$qbd9F|A%~;IP0%nub9JX6%M6b2y)`%`n?~m^bC6bUr1smS<@0SFOw8&tKr^v0 zUFJ?YzQmXyU=ixBLTQ%i z5rsKChQI2syW<)0rFDol$|R!it6KX3lbNLv(em6u`#WpfErpP2hr8vII3m1t!}kF0 z;~!z)nNUvIpQfHum{vXxA5roZAK^6WSTAerI(a){M%HCPLA(p#FWzBQ%cB<_t@~`w zdm=!EDmtPIP@rIi3gyi11=lm%4@WE5H9lQ=`Sg?1$~gU;QZv6xu22F4MSMWs`0^Bc zi4H4O$ZL;S4U?Ms>Q;|tLw%{vt&AoaAt%D7qoGCulR)w1dA@T)^tP%-UVsWQ(cSer zFKqC59H8X{i;;AiD88l0beg*ROa=oTPC+*yWO5Ie3A6`amQPYO!y#iCL1yev#2dcQ}j5 zgdo8CLjP1UevhMKpvWBTz7G@1e3(-Eir5x^*eN^y(<-|~4P zbI-a%wicRvtPt%oJZC&hgQWq`F;I}~4#T>A4!MwLuve&ix9@oZHEfpWhA`F2 z#&%II-S=5i_fmj4p>QVTvu|F_9hy*I@oXVL%>WHUegYU5XvI(8W_&I?h!ZaC5ogKt ze({{-9OnUX9K=`n!SdbH&qfqYK-{DF)xb8ZY&F@mr~3Se%LdJ41+zdkMfhtNY}(j{ zuO`tRi0_aN61^%N>u{?YDX(^nJ>d`3xXBVRN`^AzflG6&J+w}VH>?U==~!)eYpy0! zPrF3lps1DZ3Xp45H)5&iI=(^*MxG)AWc1*6FV%3Gu~445xCqb-4cSb+NGy7g{Mte@ z;`YJco8S`l9(;niuy(dT3HPIt=25|SN^xyOkmoe$PAD>LO;{btA)~VqvttawEW!%J zXU#$&?(k=?0qqF}+&rF^LgiBu|8g@|!iB=O``Jyly5bky1$Xmr=}M~r?9=Og-qf*v zjOs#vhW1Y)GuD?^WJquqi8Z>od0yTApiW}+)32_iLddPes(>iHX7xQUb%+UUcOK8H zVm7*e8ddvw`b10w zu~o*ROPa#};9J z9C)80CheM37v)5sqpd9OUr7pvn~>N(hWr)fGa>MW+D}bkQ?UAsEr_@n+RBc;2RKv~ zHXPe1y!>&r(bN8HRKl;RSrN`uXRJB$na35x49+lL)7A6OW)g4h&u)(qP8MSBmmU&g z)%f4tK2F!p4Q?R-y#G8C4eV7B^!M}xaE5M$(4-=_hgTHLHk8wGK1euvjJ3w4-NiVk=*(nfCHujmS7v%@X*xOxYV!8;N&xP7<#I-$_Dd3A+1B-sjJ$(5nUA&S{ zwJa|AR1Z2F{ymc7iX&ZH_R3l}g>nixI$nC?-*0Zv&b?4?N;w9abt%_xyY)EHgA1ey zj!=|I4nAi?SHZ7w0egY;- zAsP&VU!_C&>`;PXF_zfIw59h_2YU?GOF6YMe%)I-E{gxy*1_n%?yUY*Ec}>|MBf1Smiy6l+fE!DY~M%C@$TsQ++&BZfOI@d$NI*ioSb>_FR}>c406$* zu;<*$37W0x^t(nwT;i!Q+avS*U5%@geBpx&4XkA5D*ew1D^YJ7G73D#Y}sx^c9*3Y z1@Df1`3uH_W&uF3hV&Q05)U&N3MLGQKLAUUVYh4+YDc;a5EDIG&~xCsPOS~wBFQBA zX=)gY%M(zFrouIlcP3=66c(FJU}$SUS}OdVjp=VSvTTaCn}-o6WB=Sg5+k!r+D zVPYx%{mZ1z$nkTHo1PW|r?uavN^_NzT!^Sjv+Fm%xnIss+IEpfVnm=l9y(b#x%P;6 zhf?DHD0iRA5|jKUs{iH^d};0GM%yp4!GbjQX`B5L-3Qh-y=h#D$f_?FX!skF+&Gu} zZ)E&X{fKR!%+$(C+`LPERINoY2mkGmlM2eUK=OqdSlE31a=PMtZkC}HN%TJ-lSV}C zx5YEnU&&xx9j&Tgcu!KcM}f>o+ww7N*xnh^$f3zOB}XHN3nU@POz)(Ala1ATi4*rS z-ocNdmaXe9oXuUg&%LO-^Of6rDZ7)uWOVVJAV_kMO{XTG2t-t~KF*Rn?N&Hv>q%sU z375W?{Lf@d4!Q2$4269bgGnPZ&))qJGg)D$@XZnvMc^!4u>E^hm?q-j8@y}6gw<`d z#=@c?*Z&|W=UVGc*Ms`*;G?PlafgzrK@3SX2e0LwtN=JaH-?SNRr)d9W6nt8uc1j~5|+sD035@^o&E=JkP#73*FV&S*^Ia3g+!aPyQi8xRa{}V#i#62xe*+zq6Mt`fzeOL zq7HxGmRvAByeLu_vwQDNzD9KhR#N2uDxgeF+6Kw|A~E_t7jZjQUAocpy*wH??6qI} z+MfAJP~4;+?_yx7;nYuQyOA6YGNc;eUv6LL1N`cMR*8DkmH7u8a74;=Rb;?M7nDt( zO{k-d!0W{miPt6V*>j=!;dasu!;Y0-CItOcW&0jHPOMt%txl&nU$aUa2d;1;=p^T1 zs-Tj<0jkgSD-2$|O`<+?$}*r~KP0C!xs)KtN{RtQYN?|pGJgg#IxpShxQD`o{IP%M zdr$+&fLm_3g*CZ!-YvTxf@(qHI`G81Ec+;~=!n|)wsz0z1WV<=H8=l@Eg`8*o*H^? zL2wg?srxO>EMFmd#7_m>nzr8+X0}#fv>!<5ixPdTf)B8Maz1Vv7uu3%y)IrkM+N>Y3k?9VtZjyvY2R}MWh6vmRbvV8F3KjMPw;LJEBBj zgcw*$Z5V$!pj3@iCN+t#Q9?bc=6Z3V^e$BS13qzwU*W|Qp=#Xj8zVR z6icn=EWJXcS9tHRNS}$f^VxwGAs*X6@6rSD`qPU_q1p3;P=6H>o}@FWdkV97V&FMB zb%r7Cki&VQ6;*%VCW@MdGDvsmCIB`0NF%@KhhsQlUmJw6OTUNgitlJ zpqLSnzS}X#`ki;Twmley1eMy%EZr}(#V-^mTtiIB==;0qvZE1RSjwYl|tDp}^ZxU_`@O>M7FTp0eY0d`T`cO*H z;=h@#FFux%c)lJE@5aV~_%Hs>rm`IhqCaD55=3rhddO1Tq$w$yb=~#!omwTr`}w-< z3)Y!qy>{aGB#nO)jzf`5oz+X18{{v$dIO?@{zUZ7?2k<^jWdA z{)ZF6Ux4V}7_4qpvf*AHT)p`=9XntT)tEbdXfG?QJuB1S+4Z(p{G~3{iPD46E8_c~ zWs(v^^4{SHM*zqj63EH#E_F-|!L z>A9vCkQ|-dIY3wMP!<+6(<&Nf9Pe&SH5ogV@3&R;&Lq#^B&o-%VHUp#0fkP24MiOihf;LU`vfw^>UsFt8(IZ@Zz+rp7E zx}b7V(L^MPd^*gwK^-h$NGpB-o#ZM6R3StHrChX6qZkV0oX{u=g_F1+0;yD^* z9V7r;L@CWcs)96klJxvO?&P0iN&U(01W%g&8kDne2&y`c(HK)e|{)^Z^x%=KhsXqx*_QqR35%h<%g3#i==RfA9j$PFF zA$LWnQ&|z7Dn$Ym;mlgpC-Q#@POUWM$X%b*zniBV;4=-;AQLUSutw5r&wsUCCxx#k z*?p+|NJ+|yw8s_|h>C%51s;mE;Hu3F)p)5Xi+Tnm%)-J9=ZLo3SV`(>bQ9cD1#%b9MG|F9=U{L^~v$hWPEezFUdYIYX9 z3^&?2s~>XWlU0=i$)50i=igxvP+AF#(=IA%% zu%K%@-`i_n(lg*N@bHGh@S6fy9=toV5s_(V`PkX&&>%V&&Z4V=p5*L<;q4NB);TuS ze`kY%nO^kK75s3xvmF#F1t~?c)1Z6Q$xvaa%Zjrak0w#l7slKg&V1N2&C^#tp6Q>m zK;H~GnqS)Zp?#Fz2Td^w7^8NHVo?H-;;Q-b^YZ$0rIf^eH_%B%XSv5E0Ai>aAb|~2 zdT{tM2B@7)1N##B6uLnbN91SVvb|-(Y3N^)vZYH(F2(NWC{&mgywlatYX(`++jL0a zT7vKjXJF`?t+pFgV*%L@zy>Q6(Qxv2I_+%>PZF0aeJ6Ah{u;TcHxU{xcsVHj{hEQc z6GXok!eNXii~N2_V?#!eFl2$-p8S(X$VBb17n;e69%f1Z5AG2JbqA=R2UXN+1D5R0 z2I!sJ$=KPp zHNXYz9^?Y~7{^#3@FWzLLBs^wY;zfN=)f%p)dT)P62 ziphr4Ub}HcL$|`~EQ4922n!^l)cSBJuCVqkj1)=%sfV6n4v%w0wYO`(BUphAX)U|{5Sl!AX%C!n%A#cP^qW55G19V7eJss zzZw1$2Yed{y=Gv0Dw*EFz3Z0fqgq)N6+-h&w{bC(I4Gydjm~}BGA-VgoQS6qQ7$KJ z#SH@Ris=WQ{@cBo^rNCRBqn}Z?K?F@X5c_Do+UR^cEiezR|WWL{g4Y`s0pL@v9}t8UiOVMHBi>)gg09@so&x3TPN*S|vxZ3(r_=u7y2FJJik_1d zfLQUp^%3*&$JwaKcZf_ZNtVTv7QS~^F5P;(#hOu)&qI>jxd^G>T2l0aW;ZJ)^+~k# z$_N&|UA(b@eUBZwv@Q}_PA2hdb!rhs@F@+yoLg)j^d~`l!2R}3iG@XBT#8`V|H3B@ zdzX?=G{Q85Di6sEwP@r^`>U?M8u*SQv&@{b!lVvB6~uS^$-!e*$KgLd!l{u25aYS( zn7dzgx&Avh0XKrX11R(ir?BXTr1tmvL&JQmA;R%djrg}z5=I6xWKuyq#Kx4pi@<3I`NJ3&Wv_y{>X`ItMJJa zFcFIQNaO{s4g`~4=p@wkL}d9XI@k!9i4(ePFFj0AqxH$Bu>9Y z;=_lA->QwLP)62MoPRS*4|e2-Uhk0>;73<%BLbhe#6 z9|u%}_7B{VIB&K**8P~5bx$_WAf$UsIoV55JZ3t8u6ZNT&Ns&u5V|8`1I@0FiK5$S zo=&L2@zLJ3W9C*QUdI0}w>j$wKb6zM%`-R*KKo?y&o%1zLnZa>Kgv z=^Enn;_CNBMJJzlpp>rd@mJY7%o@8(_SG%G=x3v?Z*K#|F;P4C%}W-KZ!Lz~bRue4_0JyJ>Y zLM#=>CfVBgG3XTwgpG;ia*HE29pN_l~*6NcigJgs@XFrQ+c?dzI2O1?>&`Dh6=RtiSoxD4KF+p++_P@oWM(D=T?0L z0{5cC13SXek}w?6taqmo?;<}FY2n9F;Vhsc0zS_m3tBI16e&HBt-n9bNsL_# zYSYcx22xMM<3u?(T(2_Ck?O-IEHgznk_wx7?iMpGJC^)dY+-uXQpMJ1y)9bww8~(q zWc_5jL2@0k*9D+sS99Dp4w4IxD31_!PMMh|WRX{b_6nQLrp7Mbf2wgg)d_H4D zdo>+*r5fL2eos7ruK#>EStt#pMLHIAu!P&Y0=D@`@))Cv1#W(!JN6C2Qu=F>C*A+E z>br!JyO|zYuUkdct0y6iapp(i7!Wz8^4atDAY=Dao&s@Z?~OQw(}$RXgj-Y~U2-+s z%l7l8UG)k|+|*e$67kIRC+S*46KV#^xIvZLPbE)!+olYp?`wlH2e^rdEZ1(?55Kx$ zkPUtHQj{RUpPU^8X5wfp0i4DWs{OSK^NOEE3tbM(CM*QS`1&;i3b&%H;$7;#YoQuB z)z1g|Z%Y8f_F~TbL2URU?zA{!7p>K=hQDwu56qGP3N)K6q=+33cQkp;cu^nwke~s? zGwR2wgP->Gd$#%h^jTO9J1SX!V7cO=!f}i-RpQ3f0AY~_Cb9c^>A(vE?J2`)T-9)Z z0CPm!E@}oS8gVY^nSF`olTGW4hP{RF3-yF(aPY z&W`Y45#f8{XwjACRjl;+mKZtkubNYfC-m2C7zS)AhxEaY80Lo3+FqD%qDm3ZWnyj- z3IVw}tLD)jWB$|f(lK1jyG-!7E#3-F(nJNg*Lgk@z#n}%n!IC7EHbwwrW&C~r!8IX zg;f-EgVd8g>TI*!P%8sXnQ3SWHyY6nyF5k~u9ftt+uw|>%M%z&_~K4byTr}86{?~k zu_RjOf#F(*gH%3bkGieY+9%(_Dx%q4MfVsva`;elvY4cR4Ns{-@oQk&$Zco%&(T?6 zU}47Y+C1m3syXi`{p8Zko|d8xfHtXN(T3og%RPid+7)880pG`GIcC+C#xatt>ItWu zx(YV9|2JiIgNE)rqw)VPfI>Zw^s9jR>HVN7-}n#g7m_0kbD$wsDU&tM5pn_2-Wh=+ z1v@16iy#+n9_UQD;Sz$k?0*8u1Egai^|vp`mg>+ixficW;ezDJ?s*Z2tdNTec*u~J%|!3I&Kmh-c)oy z4KgKdXPz=D;#@s!S*|MZ=?H_WcvlbxH8>rVUxq_S;_gRt-T)>wCRAUs$|d2p*&5H6 zM5?;9>f%eg#|wzbt%+UMm_zE~eB9oq1Pg@hu)iKQzmaGu28(kd8KqnKUlPqwE;Sk0 zn$*f@v*axH1BjPsQlDm8t9GPvN8EAey|Cs8pVjw3M(;`9 zsk2jh_N?VtmTD_+g|0l*wB}0M;IojT1z$OVbHlX`p5YZo=*%v(2QIdCCGs2uIfr8t z_*GyJ3H^0%1LsDbGC(9C6_V5H1a)>^ocnftGV8lgfx9*)G zy%?cGlrJ=XoYkI!f>W$IeVUPX!lxi?AUsrKBXChaW%h|(IMtHqhTY%o?guvCf>$ND zBer298$Xq@79-ZIbj*m$E%csJgd}>9-a=?<(#L9>ss=mnZQ2-Y9LBn8+pRZvLm6bi z+MZISIip~5{H?LnwvjfKh>Teg-Z`Z9o8O8L<8(2MZ} zK~FC=zVf?ds}9M`Fhv-{Im_7gEU*XQG)H{0AYu=%PK=0iXf6+PYQSJk5ip7?3U;(b z>l4O6ZEjZtNA1pq(`>qDNx+)Jj9M|2#AY>n<8X0k2%fb65HnYF!&@j_$hx{dh(5A zC-}bX0xVWVv(*VJN(H?r6qYB#>1;ZclMGDk>hBf7 zC$6AnaYe<@^%vt|c-Num<~$X%U#mr`V95B@4@^g=mYhX_KMs$kj-`F|+7Hip&xn8w z-as;3{%nE;B_eO`WqOK#80J%CGho2EQXIT(Q&R@b_snt4%Wz)v&pfkhR&mnym z0cI!Z5*|F_{M8{mT8&k&9Iu;jvhjAjUT~sm!P8{QJ#YYqQRb;QBoygF0ll5!9x{ZE zDqq3w$uyW5a~+R6hbl!P0p$tb1tBhwsVCPSUq~xQhL>nVQ8+^R+S1U5LCs}rrLIe^ zM~4mOzg2EKs?&riYe2B^!WBGb`3-ragQ}Xrl2rKDl2WJ*Rn8JozL@TLEU;uk;wFBw z3lkmk2}{(y!^|?p$*}Rn|5}mavP%5L>o=W9D_lwI+{yX|$7Aj&*8!Imwe@9`wyszs$S_+CAofECQez_}6}?;HP|B{@q;NXoFF`iiIwjl<5J{g9 zhh*!yhG7tyQ@}S2}azhXOAzn{<$pHi&c# ze4!1xtJozXRQlcSE5UWor5JR*Fplt_WB@aXG?{_R)qHr&PH!(gr}73@Qs^j)U-mTR zwQ_d;+}?7TFtGzp3MqcBv~Urn+$73Iv$6$2-SFmi4f-8ENTdQ7cCL`1(zRpkjMzmG zGnzXipxN%d!&wrshs(G>+FbG~66|Vr0&*ys(JbIQ{f_!Ek~d&?{lqMs5mG(0mZWYz z9;=UbHDFE$NC7p$TGp8PR2OC7wC#i~w=6Tk3)ahCw|{;w5QmO~QgA!jMd@fH+I$@_paU%S9tD)2Yyka5>wy-BhOA0TlgT~Jv z-pieBkLuX#rM%;zqw4dFn&6W^i7qsSI1P>SqTfDrRlhXk22AhnJ)jO**q{>mEU6-#xPSMz4{{Qm{7x1)I>@zB$DuuyozMc4N zeMHEtT9vT_69jKhUcXz(7wb8!CZn=UEh4_S8S(s*3#~L-SbUgnaMqwzGr=sc^zte! zGVvC=QAlepN;ZoCwKjH&<7SEug!32mv2*Lg(%glN?o~|;nRKQO!86302l~2Lj-qD4 zDpyjo^cmKY3RjA9MmkO0zXLrOor1OdMCe&f)mpL*%IdKm_V`}`gUCZctPer`ZV=9a zK7fHyk&T{S6T+VCcF&L8%XsCVZ`O05kKQWC6KlkDwkgN*NyiU(tt4d=t?!QuA7!>% zj3-X*lT8-lV(>{(K1XA*h{Ww0_>WX?zy#vFc{H|c+oAbt8wiDAl1_73gk9&3-e75c zuo337R|aQB^tf4NQf7<; zA)n7S&+?`4yBn(h&@CU?e>+}{&?)B^xg+7#>K$v5a=Jq>12DTma<(E({zoGGUN!SU zi-olMVMGX-!h99RiNP0~TOA)HLJ~Wf9J-MF5i~KM58BbRmWv(W_CUt+z=DNX7@L;p z96{VdQk4vuye{qbI*-2(Uh#CLmULp<@3}4!<;R+B;x1>u9 z-C&R7Z3O$VNkemdOEHc(@TB))oz9w4te_jqn7`k95&rd z$pMGR2xC9`qDWyZN1g`S={~DsKif9o+@22Vhj2TsT)MfH8W?~&pxfnzH*7Xl=;>&u z8|~4bpQuKTC&N$c=neqj&5NhTh`J~%ToE5tkuixtCOb|yB_va>1^bF-t-n`IsU@7^ zJ{X}t;-702vdi%MO+DGRL_BVX;5*K)ZrS!Q+5Z7EM|u^Rqk(9`KE93ny%vAh6nL@^ zqzO3fi%m5_M6Ie585VZMtZM8epPF|DHf_CU8aBKT>C}SqG1;=y{`2SPO1+Q+FUR_F z(*DR?dXvQys}kV#gl~d~&aRKBW!N-FFzDpeaaX)?yANnSJ}EuQP)}$?j3xkTIbXE} zS7R?1j7UKB4}OpWC!s#gR=3H)VE2EQ)*Rs>iR|NYq&ikGj%2^$VuFsV;0VE!E($(@ zXkTP{3nb?PVyo{q1k0#h?AR!f*F!2FR}2D`?0Yh}b6) z z3%a8StCU;|2UCf2L6}tG54BinN?ajgUTwWD0Pn-Cdb3IcCelDNN`@pdIXf@l>;tU+=q^|NDKHAN$Hys;HfMkf?Lc6;XQto@PsD})N3YKGlb>=XjN8P$3;tcJ zBdu?8X$^GDmTICBuEBc;$!YU^$7(XPWp507cgwDfE1x0K4WlKTrhp@MjD!_x3YtjR{37-Q!bGVibMV3S;AjvP1xU>T~8(m0nfV5itHzi#X! z!@Y-)+P{#_7ZojzTs{wD)BNjtHAZ7t+pQ6SLQ{RVpog$?j-(`GMo-Q*S)YqbxRCE} z7)^&okulQ^D}W}GVt2D;j>&6MkMFJ3#zvs)7vYqF;--Yn@T*-1-m?S?;>=o#5B%g+ zH@|h?{f-DYAf4sSK*z~DA|=?iJ66PY-G>Fzfexn9d6V*=f{nDIAwHe5h{w(S*wHq+ zKk&&HM3=)2`aDqpY|v7{s=kYnBmsDRyU(@jMHb9E%R26vfTO{@4@Inb;+5ZV-%^Bo95IenW<`TBov`btCq&v`9lvff1@~4 z#4x~p2ni%Mg=*8;4NBvp6jmIrm=nvP(2!T<5IUZoa;0BGtMV~=O;%pR=uZ_e(y#Yv z2Rk;ds)1MCrl=xJl#aZs6kCXMhEa5#y8!BYfWLk9An`HolZw~UOxEh!J}UfyJd>Q%Zc>sWH|ROD)1>A4UST{P4$`vx^f;Hsu2k;f#4{6KO+ucTxr%gz>mj5JcKP}|*N^SaR{4lz|Nhoz zYS}AsNnp?3HNf=oTt3S4=qo+6Oc@ToksL)D`}k_9*DyUKjwMn~v%D%@c~h0j1h3_l z;R`U0z-quusTNjT>E2eXoixNm9)>O)j{ho5LDgcIx!_s(97wmCQ%<5SKs1IdMEXe0 zI;Xj2MT}WZA6Bt+guBi8YfSjnvqvghz0tLp+Oca>5mKBtT1IeN=t%eI*L9ZTBaXHAn!dsorG zOwCKlfqsz(h%<*^voYMN-$8F>7nE9~u=wc|eouo>FxY*Y%43=Eu9M~+-m1XqC5?s+ z&YvhF1a~x0w}q3t4<=wa9fr-)Z8i9t?;xX-d%w9hkT6Y}OpG?=4223ahMn=S%>&6B zE0QxHq|tu$?335OegUZ4+Nl~O5vp@ji5ToWKrJPkrV6u4PyFV|mY&+>2B+f@Z2=|G z#h}zorIx>003YMV-d`H5;iONKm#4W-s%37tX63naxNvd@k~+6Y342aCQF}y;sejfDhv0&L1u)G z3agWp?8jAWdc!XIL7Y(Xo#JoRO@HB<8u3vfLQl@WrHB|Z_qPWGA^pHKiJuyWx-EoM z7rwsT0EpSV81VJE7> zYgHQ~?r>copR>(RmHx~ho+HoO;G3LNe5GG!={|R|DCuiZXVne+SuNwhzv82By(h|? z)4zsR>e;F8zx}b&Cf~*z?(*8HAPDdLWPf?-qUbH+Q_D?;?U!F5fH?V^bz)n2xr=U&1t2Ys27W zu)3D2k>70m7q4*^hRtqwhJU!HKKQ|mc=O$z#H1oE4l{4_hv43P(PZ+w5pFm4)MhWY zxxt^bbAh)Pb$NM}kxz#kchvr0n?<#-;>`;i=hE=bo+@~SnUUMb@qD|()mlXv+(q_d0xm7YUgG+tpPfS559aJz3K91=7R?0bJ+sbjxNJ3@%{0vHLvKNnx1K zeIrPo&sukqlHmaY5jP_Jg9Ta(VJgN+lQsgOUTJ1~dZ@n-HCg6fw7<4>IW9o&W z`Iwy?k8m@oTK}67pxKsWbA=j3&whTNJ!*5aO1XX3)lsrp}7N zg`Y8a$o-1W{~T6=1{m4$pX=%KVpkM5RnHj>;Tr`=8w2!AXat3v3`*P6b}(AtdJB2AshQ#WRPBg~Vv`O?eDz~mrlicnIV`Rx-WM!nJ4LU4$ zg$gfB5(Ow=+Z%FkF!NbIukz*sL7XyP@_iT3bf7hF;tCP8Ya_|ocMle-%fQx59TP#Q z>{#y=BGdcdUxcR|p=hFERZtMQ-1ag-41TdKM97C+9POfMZ&sCDgjRkB(NXgiY>QR* z2Xx&1su#ml?ZA#t^LK=0AT!jmJ6ip-D@?md{GwwxIMNlMSi~B|ZSmo)Bqs)cW+Ykz z^PH~!InIaxj&k3o6Jx#pYi<=-Oc#Do5sdYT6kvRawEuBaWWWK^q|_+AHd4q6Bp=(| zgjbQ#=y!DEU!K8{OpRJid?DzZ9>0cn$`5<rQG4{o^#R(Ht5_g*?)PEz5jqMf!0`xf1~(GYqHXCW2~oI+U?>K z;F>vwokW&nfG$&87NIR7V#;-86og^aA|6ahPS|}h$X-Ob2A~9;aoD$N)|k*w3ED|1 z%N)@0@U|ykhJ{lvVL9SGgn671!SY#+iQOo!!VSJ!LHX#NTfa`4C*>Wf!flx!&Ua|s zp7}}x8q9N54iw37@gAyBQ7ZV1wgj5xFi4NE49VJMgUY=OQ__R4e`ym6#c4`-nVAkka98@rQGiXT%#aoEYNv9NM9`$aHZ$p$RGngJ)vmRUK_PU$-3j}1p< zL|p9aoe+y9aM@=YK!3FHxXWnRM@Y9KU2|P15xF81?t{8vvzUn&T+znn-Kx+oXTLlE zn8mig0i9BEr;TWM$_0z9jeP`K_l+)_b#<<*d4!ptrvcAK+uIAWD(S%C3(H^F74x$d zuVwxUcMJ14aDc-5_fQmeXD)S*cMFOrBXjXI0C`~-wI#-#`QeTlYgjEdO~(=wJUtz| zb_b3uvcA!DPITt`P8q92N6;+xa-In}N1xj9U2G`>J02HMo!7<4s`8#d6!) za*o{WS<0=S$FP`INJ<|)|9k7JH&TPI^+4Eb5mwu;I!c^JuPDl~pY}cT>^lMah|RiB zOa#gbGt^Dgf6h^vnM0EG08K!$zqxMy-uQiCv&XR_^g27)#)6_-jH^R8#vzW@%iK5v z$vSGP_qIS{8^Tt%L|LyTI8jTNk{e)F+I^sHvr8Y6W!gaA=Ycz zoKiA0?6ag2-FOT^Ns-5!BeCy9Wl@CcsHWvP3}R%8xX+idco$-J+*gWzeaBE4Bru{> zlo|Ql<`PI*8&q8hRndTfbyYal9bhrQZ5(pR07l4dENE!B{ti|uwP#48jLCdJ-#O0R z?CQeKDGXlP+pg=n#su$XQJ)xr?Dav{bxpD%fpDE^qrTffG}je061LMTU2Vl@DpQ9OGty#yOSZS9eNAq`vlA2c;?%W2dH7-IlQdK14UO<)MVK)@ z`dplolEji^?pJZWNuc$t^lCnYV&$8*cJ|{lIDNVpKTm?s)!3wsl0|EAOCsipnYEWd z5|{sF1W)uAkj?t0{YwUOQ!$kc_y%BT7 z$eavCl?#TsYA^RoH4a&f_AtU;sSeuTIlth8UJXEdOcq7z1KxINzeW<2A|*=}Xj9+n zMSN4U47)(-zFXlXob$?@H3IVSg8jA(Tof1^1B-wkYk|N|S zTxECxiu9?1*J{Y-;3#^182 zI_;=%jIql3hgBR72tuvU;gF}OT+%2h47Z~fd%O+%!D33?^|%)Y5GJg78=|OSyqIzh zeO~jF#~kNT$>kXPj_&I$z+qS=bZ|^iXSc;qdSbp6OiTTCXa~%M_s*{g!qJk%kRLwn z=~V6T8qh-SMJ?Zi&;Y!%u@F zT5t;0LCzA3(p^Ufa}g|n`m)*Bup?Zfho5Zx@9Y3xqo<#F({AHoN}v>FnE+JD-0AA!Tu1K;Jz zV1FFBFL5_!qVC9Ihzy`F4nrA1I)pj0WAciv4e&Dn82(KyA@_(kq835dL>C&NjXn7F z59l}S$;?nEkHigcgs@P9aJ^LcVNu0fsiQ9b_h9x@N~ao-geG}N={!sJ1O;nGso41H zml^r_Qf1M{w*(dK-xJj)97tqw(6BMmo~RHgG9g~n^JIRkYSO_CJ6akG8w%GmV$;Ce zy$Nh}IIrLs5P3laHt=K0#aVViLXU2Na?*`BAU`D9;z3BKwk zh(eFbl~kwBN%!!48ZzR%jjC3Ntm2(D?o~*0a=`%`=hqao3<*8B$fsT%ydN6dZU{_K zElx{#BPVCbraT=&5AryTK2plrq?Uf7bIY4*jK8Yq*oY-*t2}ZSrG({h4rnnTFaNQc zjBVkaCY}Vvj6p0OaJ&m_BThrv#?)P)$1qBIvvgb+~Tg_7^3J+6HO;xfdv`vK?j%y>_k_K9N!2?&wz> z3c4uxG)*S=-`4ctK0lT)y{bhb&py!0QrP=<^E$w|R;XlY&l6t3DZJVC4cvAIL4QOd z)o2{j_Ko!2K6MGX2=GOSu)326mR(RL=jJmKLJ=HkB1PFq!bNf$MJfckC1*exSN7cs zdZDBcZs`J@_50{3@2U&xhcL)!Tgw{%Pp{PFYCeV3>ARiqW=g6r4E`Kplr|6OW zl85O2j_d9(fKi|>?0med5)}B}DFKMqjv9>P?oG*%qh;nlFGmFuvUsD^;1r0ulNW>E z*zMiSF|cV2AO_Wi&(UTzij_&i^uSHiYS_b~wL0t!cq^y+qajlYz4zrS`u6Xu&~yT` z#zv~qhtsMbF9BMv#ESyLlj*97ara#S%MmLBph?J0gn;bR#0?-o0{{vwjhPqy$VGEUK!+$g3`kQ*Sn_N%hUn=u=_i0F#l z6Y+KxKSx`#^xNV7uie}|kQX#2X*0@Yuv`-mI3WiGWpnbnu!VaI=E$3uhL(u92oO{? z+ilWd4WMQ!EW!d!7Ns}@(N8QI9cd34AP1)=$-UPd#w)D??)7X+^cng#OJZ6^uOFKe zM0D?uTS57Bz13gggjj-$yo4)bgVJ(&G8B~Xv55UlSa~Vd89>kB3 zhFD5deuar8Djhs3p87Ljg1P)f;yZY1vCSd>7)^?L2VFb^n3^U1#eac~A%YUH195{M z4O$ba);M)Z2~@ZUHfPlU$L2ehnOBe4_y)U)Im1jg&1iI5IGeYD&2Yr1bpAVl?f1GZ z=xJt{hU2)N=b6B(CtTeOD_D-LW}oaD>|z36$B@-7i4b!fvVvC_j&5fHCbYPbcF6UPx6FRxY*_}&P~Qb?McUyAg}WkWFH z7Di)TrpmZtef>q_N{nk^&E~s*cw|BlKP{qcQTGt3&(Qe=$`SZsm*tIiUf?fZDO&Dc z!|CjVSjCtDDp24%gSu{W{~a+=YcDj7*Sjq|d%RhAiP}gausv0xp4NP$b>8qz!G|Y< zZ+~gO$yhvcM7s2|M^-g$gxP$i_t{W|v2ot<1zenO~ zf`?pa+BT{%uv5|J-_w=EQ*FAWTfPqLyZa1VCW5o7W@L)gzScc|GDVpMCG4tskH{Q* zwXU)g@;mu!luj0Dzb79gA~@47(2gFp0So$(OxTR4D$Nb?%;%>{!eU^p90F6YH=7N_ zc6V()i>gZHrTBs{xo$w*dU}rt(1S(uEN5mNtTSwdP#-6^J;uVXrP%rH%<@%FEf%Tt zhC1&#P{UjRU4&?+Z2yeEs`o}bEvmR!z>T`N(AO5)G+dJw`suTpA!@$ZLYT4@Be#&e z_3~_^oCp*xPl|sUFWKg_?7&;N)WR#Q*-5TjG9Czw_)$RALc3=ca1)i1H{<$18K=Vf zqMdu44`h_QWT>XGk=vRTj@`IOh#wppNdJgU&Jrp*ISNmqA|*JpoSZBC-SzE|>6t&# z=f%TZ%*!NeKyCin6@aRHl(DiJy2@@Nv_z+$ZFxb7FRElL*9XBT#gA3~w6aO129yP@ z3T%ql3x?u6GcA%wFla}=%G@TXpvw|{@{A9#|4)VtJW`iC<{RP$hgMHy$XN+jqP~Dh zUtH3NnQzpe?N~|akm0#jN0o)UgR18{tU}2Z?cZ(DJ@d}{HfYh(ei>|C4L&#(b*n(| z&W{ou&7a-SPX~}_S>+|Cuv>gQNgJ{a)M}+Y2F#@i`;|@w6=N{y_EzSIFdLxu3BrM9 zVH+HZ{>NowoF+dC__X0oA@bkXF-24ys7?pTnh0BLm`X8bGoXLbeDUu1X#Pu;t*LYn z6u#Z){?sFPt!UqMDHF{%mVyQ+HFj#f@ZmXJ0f4AG@sd;t2d!_bXTq}*p6qY<2uUd` zD>u$r_tV_XiyT0AfR6kvXuoZw%p*i@mR^|sRV^yua3Z8inn}5E*LzG{8RZ)_5M$Ct z*uHE$v#(ITZFAqHxY)4xmw_lBaYp%fLW%5R2rbj!+gE992ZV2^g!-pRmyl5_y!r&P zIa8kI_Tj^>;i=q&JnW6nf(xwRSex|7D~YtCc~e_hMu|@?f0`d5%;TyZntPsE$XBdY zeI1&C4nxykuuf4{D?Cb-Rp#=2h>851c1fNh8_n^E;4UY1>?_vD{n6>RfdKPmoz;7# zNt_6#fs8+sR>>bP56rb?0yaJWyb*bT)c5gOKSI- zdsB|@4TQ@_%4cc6mq!Wf1=Ml=eUnp`&k>#3)xZUA4|bDQr8H9*KuI?XRVF0xyhUQurr=H#DhMU_Ijlv)|cb8ILq#W3kd2ZO$S z*%OH(Wk-6H`-i+(QxDY&n+@iC59@rrxBGTJ6MO}Lll-}?t6^^iJ3l>W=KS{}N{fmm z6q`CJ$Nhk9IR+#3D+$}2Ba->$Du28|QPFOsuYOjkM_J@4x8m}ImYfj3(vogn@Pl8r z=MrbW)&8QVTfyFC<5`PI`NsG$$r>8BYW7mc-mUpW8)`u_#f!(<==Km?U77o z)G~^NP0e*S77TGm_Vsbm68OV_j45}>cwbyU6nkg=qaH_(wDUoSxfsxJ=U@eZ2;9U6 z>>r}BHdcAe_BoH<8H?B*=><4viVyTseP5knLq#ij^7?9mi^vPG!jw*T%Mz08PHHU9 zra~5(_~`@C=lic$FCTYZ8u`66^=XRD@xp#?O*o(2`4AS7TBvQCFSM&HO5(8(e_T7v4Xu7 z{tw)TY&|81?Je7BY#!BC7ai${ZtVtYIau1i1Ut0>m9h?^g-hg6Y&7CPBT$WUd*w(P zSbP7B@S{!eIkV4z##ELIB07Gr5wrWXmmDf26iH)WYMTII>3oLF-1@q=fEc45i)=0| zw~xKFq1F5|Wu0!|noo9wG4E!XxfQ`)NAXEN#b zfQI6980W*QeM=~ttS;+6P%5{0e-J~_5pDz2keyS>>&FrO2qSbA*t^y$ftl$M6RQ0C z4KUB^5*3zcH}PT>fTOJ5MQ2z(dAMYs|% zf??!>{Sjq-x!fHNmdVIce>5yT^=vVeE)&WOF$?i%?!P%~^=;R11;}HiAVi9veo2@E z(YiI5NqMLNEl|0IsqZ3U_Bu@snx&^;m%=DXQ?5HnE3kd$0FQn|6+I6>s^*H2b@R*Z z7#)$huDeJ zyU+*OB;lfd${GbGCxG)V)Uv+S6=4z)K8O5gsC!wogu<$)*wI_H z<8RjL{iCKGl>01fxtVDW@iXN=2aWbi_Jfy^>L8g|G0fwmB2fK89 zHnOZi4FtV0ed$5SXL!IIa{sb-Fi${}PIx88h;+o)>fJhxO{IO;nm(|khL30v|gfI)akKAg`{_ zGx~!@qXdF`rwarmK2vASGYZDbV^_{IG?$hsbt6v#x#%soyZ!sqKZ=QJTJO=s#9F9$ zDkrh_X%n}+dk+y75o<@5*z}iEEX)+34cPODK-viun)uW5Y3njTYVp?&h`@0D{3Gi z@&lv{2uIgRwH*MKs7DkK4C0pQ-?!{7{|#WineVYM(h)pi@-cL|1cdG8u}9w z_)%w8j11d{*EF1`V?a5}Wqy`_V!jly1@Rc1fHa{F537i(NMub5$-4ZmC}tB~2zSmz zS4(@E)>=#%wJnHZ1i!)bR4rV2gu|=x!iM75N7s8nfe!q?g`f>RqKhWFj#yOBZT#(- zPIf^bENG9iKJCG+uR#ljRSuR;))Tif3Fy<|U*<@`X`^^LH#vOD<*)<2Yvp6Q(Q%+Q zk<+RFh5uGq=6k5eiF|dxm({HBaqB_EZtt}?pHV*6CLblrGtHfKu?ED)sE~p|!wAO* zC>3v*igEjb^`>l$V!k@t2-oA+c8JBhU%^pVHK^rrP1dRP@#+7;qf0NgP`h1E4m z5Kln0pxEOZaYkdjBTdxe=66JTRAGZMPF&CUl*5$GhSJjHhA z*3_kg&XCk+ra6_(Qv7HuE&<&E=zre6gvtufHCnNaUMGpT(7of9rhQTzad)0*D*)RXsR? zpmb21D&UrMhEEiN?;pteRYa6kao}@?!fV3izPapTn#?vcRHI3@RUm?Ui-lx=E%%M` zaLBxoQ0X}b5sK3D3A-5i9rBp3l<;*tTTFHZOo`vg11H^w;UO1Td5q{$3{AmZzgcx} z0L~|tiK5}f3Fko%w5HY%YBnl*0p&n_wf_3B+0QB-`h#tk#&9ubEl;)-Vbm+D@6YZm z4Qy56)^fw$oznLN`bb?l3g7-zlh(7)A4_?MnpkqJ-Eltz?!~>Z+euJqd-b0MQw^E| z4KNHmKOR+lo>m69{C?dSbhB$%utz_K@MxBgfa;gd`elu`(cksyRTX{LSCDT(`0$ zFLGM>QyVQxWOHFFL=m05`{#&cN(}W*X}A>EMHt`XP48BW=)$q|s1gnLWtAYj8@`ihS`pTSREm;Y%ygvS5M;~R zCoogIBg$Eh;=A zy{h*-olD4ck7H{4X)KHb+Ogisd~$KFjqK#7t;7EwiO~!|eR`x(2x~ktr9iswBvvo z-axs8TyQpQ#Yd-3t$U~nua@1^ev)oz^kE5_@t{K=2m6cD@W;ICg>;E1)2ahW?aT>!B^WulSIB*tn~{FQhYyE%^atEDWjRsqBQq}L=cXm z3cDJzNP-e~Rv_;>&X{5*fBU_((&(}jgs;6c3$};Dt_@{BntwBQV1{#yWU!R00 zT(DVtw(vD%Uun2t!g zP=7breKENAOdGr7bE4gnP}8E+a$2otnPL>a9$4s8w7JgY=daVEXiqy{cT&rLlJyyF zsN0XitX)vwhi8e+cH;kLTHe2v?<~&Z1+}&^2`v#xM(!RN0^atXRwU3Yu|m9>loHz7aT8T*;-4_o_o=r?W?_6vI<`nS!3)A)GZM=vs~u-VXKqS=-5vu zat$TuciGH-RjgVT{avE+(j$1V1~JA#09CFP(T-%7YCOt5s8S2*al{JHcE^IaA)HMY zvRzcl1OuWykjb17VAWG0vlf8FK37bfsa$|>Z#ke}b~;5GY-r3e9x>@f<)}7E%e=Mc z+2GiVn901iXGLZnGu6r))EZ?RT&_OS{3Pwq#zTI#6>B5JRiB3p3L%+Uf6LFC`i0LdMuf`}7;6cyM4XLjub{)r#*DoGIrho7^H%%&VS z@-He|T4dPrP7#V9;_`XbNp%U9V73W)D0=bq2ge)m?^l0FO-Q4(Ob;p*?RIg|)z|Uc zb)~~whHF3U4^=npSSIX#ccV?qsGrA0>`Dv2BL=;6HAC1@oc96$b=|^Mit_LjJWcnI z$3tHIyPOe(PY`#hQ``^86VK28AM4*~#u>o8yYHXKV_4qMys+2X-cyH9G0^zrntU&~ zok_;gOh1WR9OeyYp;6t(;(&I1Bq@w7H$muT_>s3HqAc6(VS3B#a~Y+dFEoi}yj?%Z zmGUbeKJyV>x_x3~$@`GMnG{pKQJL%An#=zQW!Z-(evmSfs+z2MB|m&wfUPl5uC;AK zeVjl|GS&GtW7$tz5$bl8w-jtM-ZYHKOw)glJ3oQYXY6hZwI(`El4ctp z+u115o*gv9RxiF*oN~(D2ECiY$F*-rF3y@Fu`<}2atAs3f;>&vD*yX8bI%g|Kxn&H z{wN5DQ^Qy<(6A>CBv<3$ry4_GLjx|L@!!Z>K%r6PBD`+164ECn4u7h1)BDBFJ#g-7 z`3~n|-82}>cy}E)PhwrthY$VcvWhnST3MEfcNRF{)6=QYmk}d-ktDEETxdFB7=f#?1KoIXD=-@LMNKg?ZFx5wC4pmD;e#@p96llT zu>SI6c;zC$n^$w(t#Tofmas6t;xsNUFaTz zVzKt^>N-P;r`Lo5mEWc2UrQ9inD90mw7aN_hecZ5@o7W!mSHtcA zo8g@$`XRd9_QwRA2&Xyyk!k3(C2bJcCGSs}>Oy(Qe6%B}OG~3a8|+zns3;^_Y(GpzZV^A507iSGkJrEtb%jK7nmiY-eNDP zCi-L+vTR^G=e%qVe;^upBm5hS!7*zL8CLeaY@)}FVTxPGdK zZj(+ej#SW2llr3hboMO12G-u^HT5cq8A^uE0cG7VOX;gPBq6#Wn-wW-(I~i<*xsHm zK7p2_qzS^47qyre^SOz_Pyp(^aez?$dA)k^gl?{`!g05#T&*+AOkZXt+`R1BywqLx ziJw~T(_W*1QS-qIz^xp?iYgg!> zqhp}@t>zSG&W;`K29cuxj)Id8-}IZV5EAFL6^-061nwMqHS$CJ`%Eeg-F2VUbf4xx z`n9Y{5K@jt5jlVpvEKSE)b_On`ax*DfT~x9)VO2m#E@H(G`o*?BiN!kNB;p;rXtUO zepum2vx|b&Mue6PK_JhS=huwU?onDBtYoTEtzQzSR?jBolP32-B-5E5K4}>g6!HW zJyP=KkXrc>Q@k~>t)-T-b`_>Ojv7*ZO6|1|OMepnt#>Lyw7gx1hwj>wp;fGn58vIRS>q7IsiZ2SjnV`!F3kd{%K-T|@h zb83)xj&O{l`oSf25r=;}Yv5PjL5^RAcdCF`YZ%-TA85STg_3VG6Q5I+!RwPZg44Z- z>OfV-)?IW6*LAcSr7st0mD7-pjxKtxKZ+BbIPulT+_c87;i~4c_r(Jkg{%niQvy@t zwuTrJ!1r_8!jE0o9mtDsdQYj?v0K(17ngbfud;pK+D_2 z4~X@$9Sb~W{u0Yqrqx7yVsb_7mXw{BK4yFj_6OH7{(fTdUdGhfzw{eLo@cZYAW~i_ zWL_2HepjmduYO0?umXAox4swA&>1Vwt9$0PMbX{pK-Uy4AxTHnjBHkoVgvo()?#Vd zf{%H6v0b(FZ`dhaXBgnQfP_OFFuz>8e9U9Qo?~C^#Ay~hK$jV#g#(N>jzPp&5R&|0 z8bLf@zGp3b)tPW!29EY;bU?bm?+hoQb`Uiz(zOvM{Gm%A+OliFLQK+55kXUotFY1T|+!cM(5oWJAY zeRB+=86E?NZDRmqi2xLnk zcX*d9()1czL?^Vtl+K4+#V(8KkgwM7?J>uRNqn+WCoI8s3%O~dli zXFM{$yO%Cr&7C(S-m<$pW^fjES0e z`>j+zqXBu3n%t&2v0M@;YWh07p=94P3(EHa^OE4y!m7|UJV0NV zlAl;(HELPYLH11+4IbRFKrslE$y9vr2X}8--a+Ow!T}+{ z!m8o$p(%>BX=BPOZoeq^AFHe&P)%i10Dc^eyX25dwNL>9Zb&_(Xpp#-3{s{X7X%Tm zl9}a|#Ss^V<#PH4xsL`g!SNmu_^=hGsP(r61M6+P-UAmz{LhRyW;YKISm8rGt%gVx zKZt8y#VGa+f-o(q)dOUF0zQdhECd^7C87LbnR29UTK`&2LK7eKpq=@yK1SOpaJc@! zcLS6oEQ|@fpfQ=tMkp$olKoK6XDXLD*c6pQ9*h{2N=oRp^PYbDRlGlIzTFyHXr2vg z=6RwSElIMr;Bq^;(M{P+Bhu5nrD+^eoJUZ1R+wI6Lw4E8{D$?$xZ_Y>^B=In1PBMr zyN<)CQ5HOREIy$#)O_0+Js$;WSzBK+vGC&*j8=5YVr%VP6g_Hk zMuG?}L2GZTpY@}rF7-oUkED!IbS-?A6GpzPAMr6oGbt{H9M%*P00Ok4u!$kjcCId< ze1I}UI0^butWw82eJ+et?Kp{{TAc~fI?0zPsNPzzKr>U+2v90qMI@=CQni{ZwcQjCVh`$sFfm%0o7Up4S0JMAj9)yF&~cA- zz2ZUhPh?^wp9eehG&dWb9Z* zYFnhOQwUbWz=h_lcSmx3vn?rWGa3g|UW7k{!seu!}3QlRp2boVS~ zjb8%D<`XXE>==o#Jy3^`z_2t;A;3vT!!Xq(h>Y8H^ewiCvqXMJ-_wt6 zYl4s7u^VGHvlJFn&h&k%!6Eqy-ApcKYFJl!-W|e-a8VLgP=~~1$`c+!*AfYm_nf*4 zdgj=RlmSXEC)A(H%zx}PLg;(XNmE$B^`1)QcYjQ&J<6Bg0;FE~PS-S1<3a|PlTypj z3?+!aBGbcS_7Gy}8-qR7=^Jveh#tc6$=0C_fFj9ghs*vKvHQjz-?iHf1)gp#MbPvS zwfEni`A%@(GeI{t%ByjcwpT%l8Z#1bRt*kSG#U|~E^e(}u%z3SU<dVzMT&>YPwvY^;wBXDk?*bpa;6A z)xKDEwXC5PS%7<+Rd7Aw2HTL9t6LoG#XkPye4+!vf2*1E0kG#ZwN*@`!&T^|ce#}@o!$HzwGxO!MsQ2AD+hxcVnp+JEPw!S*?*cg47m7h$$ z_na)qT-qXn4sDlhYDv`;**@40dGHl$BA|Nthjha|p>g~y(lQAeTJXZCS?F&pQ`upR z>}7#-D+mv&N-#NOlkzuMw7ba0O%L4ERJIo6oLEA7633Gz8{)!ycuL!M?<3%(fKs|2 z8^DPT%r4VnNWKK3{d1i*3k3e);t6pa0%My1a)BMA{#@hBwHwMPNqb=Y9L%~fspa{V zol6PviIO+R9;PWqYrk0IEU+o7BlS>DYhWDr^R#Mm~X2mg-*It}XxJeHte|Z~eCcJgGJ5J55 zF8#@K#xCW8*hJ&|hQHZf$3ei6RfBiPOb@@(77v8>Z-QESceBvc&FK=e__;-zfO+#E zaLi@7r991lcikCvsXC?gXgy6%8x-D+JQ~`*4y_mkk`8sf$UZT{aXx2Fxugpdd>;6E)7fyOGw|H3&`eozinB+oU%N5O8O>|(1T;58bdv64{)7ddrNmbR2H752RJEe`U#LE-EejBeWfM0?aNM9( zP`bmPkjez$;zhZ@zU!m1HvkL(-h(kN|0>>zeg8Yk6~gj5h_Vjoc@s?kn#TH_*WFZ$ z$jgh3wDIMWeM4yFJYqW+OA~Er~7{!Y;iR&}IMz6h;Z|)xnnPq|^ z`m&(P@82*s;4(5-kDzv4)tjc7L3(N@C7We=;rVIthqD>eth`HSz3OR^_Sb=z%?Iq| zU7sUx;JWpSil&N)iEcuIB~|EI-5>)?@6y81CnS7XSE3=>hx;4g>8_%$GK=5$Pigpk zFIMXWi$!cC^bZefat`!*O;_<2M-9Uh2B3)l7$|~sRf&^FWn>mof6J@P%dw!3~=QmEbFu)hT5beBk)Ccien zl-}PW9I0KX=RS0Zv0?%gfT`~?%*}GCy=A{H7LVvYWHF>%eJe->uRv4riiu)fdPwu| z>y`YsHSi!g12Y*rfSEgLYZ+6j7Jx89{!5)wvr*bqGg(aFYb=>daXz1zGSB%CjL(F+ z-|KiAIl(dlajr?SxO^o1nNz|EMCZB!Lr20+7eO@h9BVJj&x^$f`10Px|3k|m_X%CL zZ-B`1TdRq~8{6NP=zxB6M9w(Hd$vcX3QGQ0QmhqZ!E0b)Ab;aDe0?~T^tJZY*qhBi zQ%mDLRoj^jRP(#8ZlOp$U)Q|Uxr08oI_o#SAV zZ~nm@NrNt->Hhs`EltcJ{nhQAQMh zvve-4*&RiZIRj_WWF{yN>eHzT_M?pN`*`l3fZgRk8hTbbW^B(4=reMXZJD50Ym2F} zE)eVszxc+(IhWmtocD2OQH$klaTJZ@{$lbJ1AIU-@DmxLkCwchg1=%PdK^`2zVj{9 z6#N`vD37cjAoFv>O>^d#xl-l}3zf^55M(mgjp;bbhl9NQG>m|2_i#}Ahr;(_7aXc@l%L0jI@?x{CBbJzG)iF1); zc)gv|2l77!Av@g+CZPW7{xD7f0d&G?vdSH5xGhHQ2w9_n$GdEuGYO&SyZ)BuA1Xy3 zLW)HbosJK!b%VYDT&`Y!apm{|DFOvYPqc+xm%M$Q>XFgk7ZTDxSV2_GeR40C+z{;| z?My9b+We#(~YWAjWA!==V*XhtW zxfxRR?>X&$eTqY#gk9=f7!Sk=Og=(qLei8EhhGpcSyGFrQ|&r=gPx$il@3MI0OSw# zc70I2a1e2k;5m~uWHpb8YWdtodc!T$cqosy!%$uFbi!+@7M(cSY371EL#HgmRLdW1 zX^lyDw+%bUou`?2`jAwgUjH7XQJfR6x3Ay`r8BX9Y+2?QPaEbO7XsOIw}vZ{cCMId z*ezD;i7Of{A>gN|K%T!S9u9CIg8o%C)Vt0Z-PJvi@!zm}Dp1U?Rm_4H`g$VC`n#jk zM-uv9*4KCK@J#O&M#uIAzR%1G=O20g96jM|w^xE} zodI=Ef{>iUH(h#OY?rhwF-MxTTaz@Vk*VxbjUCqh39e!ttszLAbf5}lQ%o9*NDc?W-|LcQc zv*M}8?7h59tJigo;rXNK(`VR0B4VcP8=Hj|)1t8=%0UENdzEZW6}^CZ?kOiWs+Flr&T z9@ENv$^!5?w%ih0aP$VHp=Lq3AL}>QiCMj3TYApCAdJ7uc|SdgwaSQYX@*|modJop zqeQmy+{riL;iFJ6zb?D!ADX{R%>`l8s>#)9IUAnZ7jbtp+KJ5qhuDz>S~Y4>DQR*J z@#V-#5@3e|*bVuRp2l@t^q6~1YX?MW1&K>{Pc36t`n|M|2e}Mcgn04QU zHF3FFqeQv60f2R*Qws>*E+UAs4J4q<_>o+x$7yQuH5A|ao> zl}{z4+PZFy@7o}lcNP!w8jC4Ld$Yf@feq$DTfHM_*CRa*KSiF>0R*#9qre`})UWBr zF4KZYt;v~0fSrW97kwAkQc=JmT8W`JT%SU1o*T~b`kO&!GQ82h2vMfvBd9AP!{u2M zu@pY-fCI^s@{HGI^xjTdahs@-|r&=^h3QMz8IKh{J zTWcjFCDFXoRInM9!u9t~oitH+JV?ARhDnr5>A61uYH?{6j|JSye|uw_E&m2ChRv2F zX`lpr=WtD-$;qQWk#UWZs3e*EA{9*gB*5vxPRx#5{A@wDzGpARv>#|2IZ8>rf3zVu z3qtzPotNm-xvlh4mtcO0uw^skPs9~P%|QAq^tv_A_%T6N7i8x9oETyug4=Iy2=Czl z4WM-poNsMa1V;pi*L_qUiO_@9c3es>;uL3U8$EIlF1$;g&~4w?wIdJ4VHS z?f6xx|8i?^b-NT_G(Q0crc{$eo7-NnDVf82@Ll7caiByFa8E2{GeJ#6Gs1DyNZtHa z;V+Hw$QRhq+x1Iu|nTQ};Dte!T zK5V(3%JyfS!)J=wdbSCXCs$u+lo|RT#79@N(IeBrYM5JRuCC zO$P)4JhY8uGqW_1^lg{Ue`kY=5D*LKmw%0@h7dz=QN%mbi)0?TIhF*ZwV(+05gF?$ zy!XvE_ei&j`=sC885aKtoLnzt6IGV|eY8m0ITDyyAx^X)TI{o>k;=$4g9%#z!`(wW zM72_mMWh-|Xu0Q~-Ldgqov9h(w?nS1jbr2fPU?hgr&i<#X39^Z<{J^s)ABu%;Q~@m zH09xCp&4Om);FL-1GvC(!uK;Gg^5!;oijwKb!vLB`Pq4fEf#K?fBQNOW+dl zbN@9BWAP?y^Px~PRB~OUH_yYRgT84i0)bfjJ6@Q6Ij-apY|4^duZZk=4;&Ri9x&fp zs!U_7Ybl;KMF;v1>RZXZ;Os?%@ke;y@d*-yuXFFK_l<{6; zkjTAYt$usMp){^gMN{YVOQF4}@`}S!T3f>6ft@6NsJhfwCE-m>XrgH}*n-@$Z>xp2 zV+OF}rtd~trOhM|SQ1gYvg_~|zg*IDGd^~y_V%#+0rYf5xqe`Obr*V-e42UU#r?rl zc7)ZIpDZubrTE(~kX?m%SJy(MQi3hbKN?P(pwm5@m$u1NF+8>2d0&tACeopnuM=yD z0}FP-mUsNY|F;Nh3E%M4sC12(ZtuF9C?QKM_BQGoggW{!)CRiINg%N9S`%&ar@jR9 zb+=7E^&wO>SD#5br5TX4N`oInnM$MnPU#ykNcXg~uX&39{{8KFkGc7#f4h8Ck@m11 z_6>P;@&aLtO0L82`QWIcDN|`+b~~xXRgF8VfU)XDcmw^kUz#VCRo9F!PF^6#xtmN2e? zSiz^%`lfc~HZ(44fBnV2KxnVIp%U9Ktqg;1YW3f5vHSWQf((Zh-Qu4aKXK?R`m@`e-EJ4&2z)n>ypm5C-EEP=6>@GcsBpnA>C-+eh94rkHh3Gfc_QnXOIz-haLz9b>F5OHh7Vm-$yg>#KO`2cL#0`6YJc$YDg~7+ z|Kl_Fdd~e_IFEiQzA7G_?XKOTlFZjs0&HQV?3t6?3KLsM`y5*xow`+m!OitweylGpyYd);VPHit{%nY#>pdA>Og+= z-9*6NFQL=*`2GNst#qT!32bPI%d#H(QD0scVBt@gf2I5^+vu&-(ComjwcFwCjU#mc zFubq3%MCAt%8)A7$1b^=sqwTw$OA}J`6*N)5xc%)$AvGfBFk)OhFLu`H@fOZ#0(*Z zlW_qb(`mc^YP=6LP5UNq6}Dgad(7ddLAhL9n3!P&u4S!lcWuLdI=jjMYe+rdx?dpc z<|@sx=+D!06gYZzAb+%O;jr*`({TQR{=}UKyGO;76ZUX;pStZHO5*CpJ79@$QVfCdK&biICM z5(Jh_m`a$A>n2Jnx(fp9&;H56++gzXNon@U!_z+>0wLR0NPTn@v=FysHn`bM1JHA5 zhhhCy+J)Zg!+&&q23lODLN~XrHP+kf)mwtcKGGn=@E@!8AkT8!0sqUW+>?Q+Wd;q> z7B#f8D77rPf!~Ea*l8CBA0O_0%U%=j{wQj5#B%jFqgVfx73_K&$`tVLNda(|nsZzq zY9wL_0~;Fs<9EJW25Eilvj8$L&}OKX_lCHVQb0EHkK2*a#)><;UT#v2@Crz?mziLj zT)a?aHg(*?SRqf)?9ngaO=TlCsb0^j)jY<@|3L(}PZPLo>xu?Ua2xA^~qdCVU4I^A(T=Y#)CVao`XL5>u|_HL~Sjp#9=re7U}i=6p8( zY@_j8G0+xY!fFXj_@7R~WY;(B?-ZV&4i@Kbb1LsHyQ-`LDpR1`#;8W7PPK>j0GP^y zY*3`QR%eXX@>{6vziON*M~rRlV*f3WaPZb5e79O&moEJcps>F#$gAa!?3Qvx$unpR z6|W*3dQYqMNbp=uc?&55eYz0vnuS|Eo7I9pk~T|E-}IO_ZsZh@hf4avY*(awi6o`2 zei|m$PU6Jl&V!gr-4dGNFTFhB=|xvkn19;7q@d6%t-BP!-akU;oxx+JqC9QVU7|vo zs7v+BGJKx*tF{-5^>rbalG_bD7%V9<)8i=D(c< zV!J&G4OYaD{Rx>Cda9Q=JmLRt(_^eDhBJ@uVkx3@V)Zt*!38*bsp-^X23OQ@L=B4G zKJ=I~?17NQ$eoocKZ-`IZyvnxFy(*yBr*C4kwVhM3-GbMNRA<-8{)n4{iDyV7>0Aq zQ-mqqmrO50oD5BqapWF41Is+DT-!F&GY}TU_9zGz@ThgnKqJ{c_}*q=TDR$-qnc@UBx2`+oGIA zV&gS>wTzJ8ymfc!40Zb~ev}Bb-L9NK={LX;)33e{UKe8~OoV?yU6wJLiA1x`XljZ# ztH(^@@+rF4X7BMRhr?d(-k}2&Rjw+t6Z&ndW&VEwi9xkY?trCm^)9j?YwJ?3)Dwjw zMR?uBX7*eeIAWl^cprXN+W^qo^FXWNmIb8gVBwW|e3@AcRgcxmSt4wOk}^Rb zU%dHyN$j86%l@&}T40q`Of4eTP9%K}8(+Q#bsTZGK2&;JRfVgSov8jqME+Xju?#vu zQSH;9nsuQMypJ6DS1e7<(!xTd|AAgZdADe*Hav``UE{hnxO>v-q9A9eWQ`&S45UP+ zz3M)=J~O#Hm(>RlFNV?FVhE7lu z{S}^Lh>oP#u@z$21*!f!`ikk`J zC){br<|N89pt!R&Zwv$0s8{D}+b}n2dn;2M=xqFTe|E=BtdeKL%}+XF!L#XN6{gUV z&Mq5c9e2iB6t9QqXdwC4@% zzJ-WoEWClhQHFmkK{3yBaG3I@rgcdN^_aNUP*Y2`0^D6$@(x)zp79owvP?{qm^4F0 z6ksqyhp;B^MLi-R`b;f*{2jm(GsKRoF=nvcimiJFKcWv7JwSt-Oi&g1Y-O1)aCRC= z7@#W$#lBbxJN>rDc!kdcNPFpv2(*H&wy0T>FV~ zi`b+uR*-HkeRlXWTBthay0w_@sgJvx)rYsQ)bgVT)s00dRARVfrL(vi;ZZ~1P?P<1 zoZEST`L|Tv8_7>Jx%m$62ffXeC!4fCUE(?!xoGLAlAm_*JwFr9O1D20#8F!I)+0)< z*Dq1oMLS$a!%Ut=)MV_qo3|1aS(h_`9@JF_oSiD(?b3l1%PiF}osg{3+0PltO5rl8 zvZOPIk4T8zFMBNjef%NGs0H`(D;-6|Ellf7(NJw$C>l#i0c9e&;O@`PorHC2FvOu~ zjUsD0#+xkB+^F{nX#dfqIhpvHc4HSHk*Pyw6Q*OGAsYq$xMPFPLvljL-Nizv;memt zsE!}u({kWua;5xk^=n`*w*K|Z9CG14onj(`eP+gi*4;4ZzJkTi*liZpVSWc>#(j`k zklSn>pqY;_evF<|P^zS%kaqGs9kyx)g_@QHsD>`Kjj#c<#B?VN9sPM(v)&f9 z!XafU@}9$a$t89=CMxb>sSCay+B}1k-#a-hD%wxOgWI`_q2kAI=Vwm_q|ONy^@p3Z zvsSzu^~oHkGLH%`gVyUNYre40%j)^AV{Uh)t0a4lxt$_^*U4fPqdsP;l_aXIM`}j< z_tcqWI2d}Jo@mZBnPV287k*!3mI<~@+S1z0Rp{lZnKliAv{9Y!`s5~6axUOV13BN) zd4FZ--C{aZAt_K-)s8OO7 zdQCJGf=i?suh)mVy=;hN1QdkLpHZ}<0~`Oy{J@}2Xxtyp0{}Fg8UF32Uy)|G;8iFk7+=4OSRo%zOP+4jx$|YPec+QH&J5hO?HOwRtaaR+U%IbfVA$XK{)$`@G ziFLLuOHO6)9UdSwzL+v0)0zyTIAM*Ed!g#MZS~K_2osSC?754BzP6u~h#x%s7l$Ya zblJ*7UP<9t>vWlyvZUe%kiGcrS{a9T_5OvKIj}v#`uv9{pu{`*kZ$SM2y6J<+%QEV~Y9js5^uXkOvCymmv1B8}y|&UM_UkSP8Aki67)hhz=hUpAU*( zLP52`%4^L~ZWiq|sy+gMHx;c8`gs|2=lZg|rh)Pg656S6}}_f*^=Kg~ThjVY0;+HNw>r)~?q{j4;})iSVeG_eYS zgPmCnZ~lz#?G+C~PLLBPl=gY1UIHXa!_81n;WP)|gB?Cx7#>gR&m4q7RLhu7tmDaZ zC3*bO=^I6ezo%I7Eo{B+oVWoHUhhx{MU=tK)dj-Y2=D{&cOml^69W+Z%{xKP(r*gB zq(*;YL&XLwY^XT0vC<}&L#iVNj|Z-Z?jzTZ5_iS2hJ*yGc6+Wp?@ec|gX5{}B7UGn z?faBPiJ(J#=;v-VgP|4XU(!1_Vnjm*n(2{+Z5W z;<9=UtG_vTB6)+DI~1xdwRX;_ppN81l3VOsdOb&m+uF|JqT(bevUugV888Xquj)}j zdAC%}DjXSml&pS2t5WT{TEUU$m`L9;=#1pO<|0vkZhFyXYBo_wC;i2L>e48sw>*pvR_9lx}$-R)Nk zq>naKzB_-Ps=|hrPz$ZU_Cm{-t$0+J2xlM;A4rEKY#`&?dx!+ z;ggegx7Ev-XWzZ#5cjr|p|O+=nqaBiJ;)`)t2O33@=aRsKg+iO0Ta;)2WZxYSfp<- zp@jlT3kRUBAVe+i3Y11E4GpH-JaJxwafYeaLbz!3m#i-sMuCxThBh`Da`DH3{VX1> zLv<+B`$!qik(f22!6_VQYC*fP#}m^?MOYHaEX7F0DTRnAAz#VyCosT8pnh9U_`0zZ z18M;Of}8(Y!rmvGKCTC#qa*$aAKcCKO9_W8`i9A@nYf`IkjCl2BujKp?k z6GE$Bso7HNZD)8rlZIbcOVm!-U*zg9FB(6MCl0ZtSCmHGxp4kyusXmLQ>Z%XUt|^3n zDtv&>-i-ZM(3f3@*Ri3yvj>>WalcB7ynoNISYQ_|562i`lNevqKc};wl=x?Pz(AW-}=O)&<^pPD<~s+J|$oQ4$z`(<>CYR+1f0aPLl>iSL) zg`&q{v*=?&bue272xmrhy*|MbkAUrfaa;g!p)vyRxDF~zb-o}ChwW_wGz6m@(9?|y zbU`;*xUm)KLHJSP9vsT-+qjx{!FY{Rs}Ff9;I!d;IWrfM$shI6#b#Je1Tr;7>&+~( zJLbRpxUnIC^p{p**`$>eOP_Y+s4-%<1yD zfJWhAyI+HWoef?a^8kmk@EEiQu@ZMSN3x6Ap5w>P z?1vK%cWn9u1!18xV6CU^)*jKf^wK6DrkWb)0^ovn%hUQdt1xP1o%#66R#YIa3Svx& z%TX(Nzb9HZ_K1#Mv@9roacE(DBbTq1Ok;%?06Su>hqI(iL3u{vq5$#s;fyUyvC z8f~IOQ!8aLe+}qqZ^0f$25!~;{{EK`VFi&i_oEJZLCN^67D=Y#HgaRT;*|dDW@a_( zn6-*7&e4%#dFkg07JQnEIW<{4xQ=9Y&h_;TRU+81?4QQhT6yc~{l`>bp>F}Vl#QHI z33v+%`K)^en7<*Oi;%xe-AhGw51cB)P}hgwdz<#8&ib|E$Lm_U;wtNZqa`Sk^C*Fw zBKBnr&jLiI%G8%0@rkw-O#O4h6jK066a+1^xj`G8P0rxgd(;*f9X+Pl`H_1>tKC(5 zoYOw_tT@i7T{AVu2HBhli7-5;(erip_Q1R&NN%3;=gkA8tK3^UYj21$v8_;reOAK~ zOy@?H0dlCaun<0TTSB!PBVJ5#I8wtukiZXuw$TkYQ0(uoXfba2a zVG2@usQ+37QFTa7>wLZFEUMGj5vV*9rrFCYHVeXW=$Ed2Fz!!|k6>Rd>F02;$4Y9` z!j$&CHENTjZel0=s4>~5nD%;26k(MT{F%?{tz1)7ECN+!=w;?DRjX|KPQ1^QqCO7b z_-Ra4@c~Sq_SjKEQyBC7kT7{&j3L@!M2(6T*LN-hWZl|T{oUa0KY1MW9G`CEzvM7W z#zyX^LGsYG&#`}9&TC$3eAVNt`7}0Z+T2GNbn}eqTANrUUp(F;zg1pf0>=-}x-2~R zmXMwN_5!THh-d;%qhMS&ao!dBa%5S15IED8YotTRxLdkKiht_m<~06P^E50Ms&lFb z*IipR;89D6yB*qJ3lFi%+2m1F9Ie_gy17f^8qQi3QJ5@VfC+*qy!3KR9_|RlGQ?5Z zp%VC0db#Bd;dG~lTqIVCsNnyb$9THN*sGMd+%FXnsg5v$P2lY9z4l1nLaI7cmTMOH zvQQtcHL~&#)6A{I>XZ12Z$&6tpPI_61pXos(@i3M0S;)-| z7rl|*7xe~taK$6=PD_evgf0MSBLhbP=4S1Tg0Le#mMspx=z{>MKOY9AtygGq%!T2Tz} zMKegKPpau*fJ^Q9u;ovwY3tDrY_U*N~Yi;Oj|QU{xPzwkPfu z&d-!6p+>o6j~pFWAhYl8-*F|dqLzz$2wQ$GVx`kH zwc<=$Hwr%Wu3Wr6-{Zs(?ad0ekya0)-5cQ#E^em~$4)XJ_jVTNTvrEn4OpWcpig*r zGE@~_G^|;wN8>lO^{&Fry)PY=Y=SAaocz0E)w;+r;CZfLbAw2?K`pDxSzDD~PGvJJ zD9a3DsSSKQLcXdETKUD0GwA*r=;-}cw3K=>ix~z3JjW9@8E2pf zh*D2NFI-^&iA~v1~A(DND3VdpcSytby-1_AY|i=$SAO; z!74U##YUp8>>x_o{2-@R%=Grf1u^ zTXHu#wjA@gR+$-SHF3?SCu~|i4z$m2S_GseUx)+O1`HC~J3;k}=;8ckdFI>6irws5 zL!r9bK-U;}yJXAy|8zx-pfA+8DG#Y_Gy9cPYdeKIpZGUgjW&87W+oHdEx#-R)zX@x z|KwU;wB|At*Sm^E94#g$=%xi3oY%~z0JxmS@ge0>Zi7-m1J$3^A+?S32rp&`P$t?9 zA=M?aXOV!rZL{6MqbIQZNYFz(G;65|FzPTab_b@tL*|no9t+qB^aI++d3?HG57ls8 z`+`V<62@UAiMH6sQACX&U!R}M{UIRwM%dYhQWpasdU%1O-kSc+VT8K#p1SpoZtie@ zbPCXgvb>`C7^tZt8;0p0)gXGzIO~WfT>kx=Circ4G;;ELRe8h?P;YMYfe_qbo12?Q zjKee9NcB&fHGf1bj)bOt19IV;{={ziwUJzCWRtw2J)L9D)wPWzdEGYuiPZ|s%u!X& zQVfazUP32%h-f^_G}KPqj|Va++wZDFrOxyQj$8ljNaWO0pW&@XUnZ2llJd-uq~1}4 zi-I?rSD?2`a@1*c7OA37OKa@3vwH_~&`*#GB#hbMPNcgZuo8H`Z3NbcEee^_y*@jH zB|X5^ihvkVS4FV2mKB<2AZyHusop097mdwzJnq~NShj;$oJv80{4aZAG-lSXe&cnuIPvv~G0b-%{dM zVR#y2?JbNSUTkDk@+z-1?wPnEFvu2;^D@f-=U`+ydt!rw{}qY0ftSR}YZ0?Yp*s~t z9rP+n-`u10RW*vCB*MDkJi0_^rOYx7R}D!6F;WX-`7g7w+UL)MaHg$9dj3!x%WCg@ z>W1HSxMrWE*nNd3E%EYlmOBkbVBb;lI=OjI=%=`nRg$^mJ4?Vz8ja)`Pp&)17sixW zBK;zXlH;vc$`Yl`cdUZ-7BJs40b`G0d?b+h@qW%JnBTrh3&aV4t zV$X3t31e^Z=*3` z(t#SBRp_Km^zIV9!~M2D<7#3Uzr!Xu*FI-qNWK}z+<+k3;haQZu4_;h&YX`xS2qoc zwr1KdjGP@(c9+n+TaT+#@Txy)XJu{nZ59-x7ELhLmK;f#;0KtTsI1xB4bGMlnzT!gC3Et<^|V1^BQD6`{mG$mN;Uu93y?N?6>E zrKQ)N7||^&7$m&99h3-~tD2)Cice{#T1BDl{Z^#GRv{804G=wkD&9VGX~^W;w;bQ} zgN3{4WS>O$qGkAxFkzR}v8zF(@8H~f&?fP+@!ck_?X`F#%A(w&bYT7) z>tKFk?g2GI`e=-pR-?EsD~rdMe~;t5U_uF8*L%Byec?(@IDiS{H4cTcx|dY3pcVoq z0jUG#4HTC^e2I^wx!*UCQHf+W_~zcbO;_;cK-~;2%{h3b`td`Kc@;rdV*&*VSNoJz z3>jgA6Ho>&r<=F*u>NQo-_0~H-Ud%)ss4$8`EMzHbXr^4Z(l;t?xx(MeBF9T^8TXaU`dn{-|FG;>g+ zMRqa+_KeZHFS4RHc{Y`P?k@O&?3FzNypibZfy}a#t-dqzIRf@)NIGv#XO}{g!il042Yfz|wQv%#RZ(WUaJNd+G ze>>n57{n&H4}pZDpid1cjHdG-dR!1>*H~ObLcNyX(Gd-B`UibL)S|QPJhFs^!AJ^~ zY|o~&byCnc=d>RkCK{{MXqsHm7{tDLJ0ZH=r@0Wb4)@cROtX;ui@%ZlYFtT%GarA) zkwL|c+D$QDJgvr%WlLH9bNXii(B#|uZ}|#N$V@_kTSg@dsT6w2&LRZFw@h0F^oyos zXAwi*8Wef$@^0`B_8H)WC}f+a16~&1eWvb`5?qCLFjd)X}Isl9^6{4lQ}{w zr6xiFITzM%yZCW^6&F$Pglyb^nC1DhTICHM5cXXz~6&89iX1x;D`G|NxlE5R?0 zHJW0g^r2;pRd;3B3Q)>t0Rj5My(E+uypWo(V3Kv+NvnKPSwJ5!Enes4Zx29KAh|5c z9deI5F)B0k_wqb)7z*&)BECN7N%nv(^{m(Q z9m}NAE3T_W`atqYuHI(Z;pC+wg>l;N&(tGq2`jLDeUa0-@K9{D?@OD1GIKQ{od}qJUvN<|#qv%mW7~17 z9o!z4^3vh}$BvBwK46HpW`OM?BF)-gVoajPyE8Nq)rXkm@~IK4HhNddLK*iP9+wOR z-)B|v|CxG?O!FLmRZ&LOqVu}}TIr40tu8WO8py1W;fy_1-{D@3>3$2Z&D-9h#(BJR zucROPR69^-b>)|bTRfzldEvFO7QL^>6GoBez?5R|o}a@u{2vJMSrl1aFl&G3?xo{R?#3~XwM5xzo_&RuRWG4+nUV~8dLjqEn7}cz zbw(zefozZ2zw}II%fgx7eTVLN%=U~Exw&EQ_T8$(dAa<#p@Hnl@N9eN5uxzoA;#4x^tm!fU7)94f1jm+6Def0hldZ7-72i{bmQ{j5u{UnXfVu2#3 zI2luC>faL`1-24_;f2;#bp0Mk!!xN)MG2^vG773a9Q#u>(nC86_`iCOOBQzT_EcA! zXJ?jvsq!MY{Ny6RHwk!`41Llux5ll#dJWMn!tl5h5Ku4gnPew=YE^hUGN!RKPQ?fAm< zpswEduee*t^^;>LM!^MxYtmxJ`j;$ej0Cu$-4mS{DRyg)Ehg-2D#T(ftjG3xS}A02 zS&nk_rx_qvjq*6Fy$oG}Z+Tjer4kT5`3tuK8-JY_VV~He?^+pZ9`WiA1&}Ak{@1Ed z`_6_l?Dy~9kmY#`eq(P&nCDeMCNfSfd_}xnOu&aX+lFkB@3&wcPcsqw$Iy*MhU1}Q zP%?rko|I!wES|ftug|}RdiJm5XW2$Ywy4GG=v0TnWI?`O!bqIRn4Sdo!(f6TX3H6>}vvA1)r5Njnu}Hp9->FE=|TIvx*uyioSPovvHuW zllgKY?|}o?uylwIrkuuUo!DQ}0sN4}shJ_R=Pc*`-)c}&E4a=`6JW>O! z$ye!SJ4loDz3bBTk;kl7dRM=lTA=Jz5PaZW2sG{KGiD{Y6d*`cH;nIghx)aYD+aR? z-0+>LIz#`iz1}QVLrxey_V{*-DWhOUiKAJ!YgpY{6(IsLTLZsZ%K=TfIMKWt5W549 zQpq^%<&kl@!l(^Mx}xG=NjkLGLJ^1B3g)~eeQ@__*-gbfFEg}%1VwsN4ot4Tv&W`I z-QZt4j}hDX`tyL4sCJehzETte7s~8kH3R0Nn}L>3Z3;op=-DVbwv&mRD(N{sV1C^? z`nGyz^-u$0;Z+jq&Qh zL-&Q=TW($3D3x0$yLKkhXc22%V9qR;EDcZCxN=3>>mUD4y1 zS+XiPmC!A<1}0iy%E!Bj*&~p)JmOBmFkB{E0S*R3NO9NoyN$`*%4U;@U*BeW4fs~8!G6sxO4?(Sj@iKe|VmJVS za&1f1A*DHVZV-q(h7I}>f@2|S^^)-b#_&>SKM7IB%w*hYl6^w6crp)8ANi_BsHj#28G`r0T+jqaz85xBsPCjX{B8*s5(QyT$wjm^l{}QQlq1}jlqwP!mUO1 zg|^sp@6;Xn!LE;^<-LZ6Q4hYYInXydUyOBuJR_7%jy0K83DoEgK2Hxf^y(bAsJf=n zdV5d$iY%Qc*OG@iP=#Lg95%YIkdjfjzBd#*A6)E#7!vR%nX^Nio2;v{S8uXxn#WwZ z95n1#hi_26^kmctiCPa3&kebbAm9dmjg~ju2Nk?8ifq9ICY2K zp)IGTa*IGg$aOXU^m=`|l1>wk0~RPEqJrA}c`si80N^mq*2!Q-?h&I{=>$12mNW*B zO-5BnQ-h)j$rSdk&cdgw?2OrnC+%UWg@p!m8FQJONn>ALn_90=dlkL{*&tm@NN9{I z>|B>=pCCiI)=NTqJRhz{VvfgGaJIcy{Ao4X%BNdFs32-TWC^KaV<{tSkC2NQ51wmJ z$FGLgHfzSHxC3SZA%PIS3|gIf2p2_|OQcizk<}u^S|9Xzk}0;nP2diz-U<8TSx5h9 zK;R)%ro_zTM&czWV*@ZB*~0`S1jfud&+P4~wHmasfDyEDDdk$AcL_gl*pIjOvKU$n zsmJ$T@%T2Y%nOfHc&@`|Ed>UDFIO>K(M9APy6~GS??quZJL}J3%EXl} z@iQX=sD%|hKVF;4%%jZTBOhnBIsZiN>~3p%95t`e^J_%eNSMGKmlgyqS6~cE=zCO3e{68LunIJQ=9f+)T=)# zj90h9@9PA_*$LdGYz+OXH3VFXg<3JB6oL!=tTgr0smwy4~_CTWJkb1_SRUJ%nrq9z7= zg@s_6PrLnv^!AgF$5uJAL{@+Rk*R)lO^`m`cbNE~dFgG}v~1TN&)G}{dgRSUjvYWM znQSXkD8eB66Cvzys32H%Ng#GA;|vx9eE+VsZ7d@-(8uG+vSanbcboF~L5!yHOLbjP z1;x@$b6mxvt4>v*ORM9v)i4S8LR|OmE}jKqKgIy(9juQb|ESvgIwcf+w$kv~pfSe<_-`(s^7IKanpp*Vcf#MvPR0TQEApl?ztB z>^x#NM3x+B$RoIHPyiY;h4HIDpGnT{=CLXD?cf?#LtD`&18BKIN>r-UbR$NtX&GCD z+LIrjO}9dLgb_=$wWO(0StP!J12sZoB=4kD_@}T71djJoXWi~Od=r6neFbm5YeJo| zOjq2;7y%*65r_;#r5mWpB}YND)M36pk3?_fGZgWaOjh&Le{!#`<<rc!@rsm)2{*a9l>Z2qjC1oj_Z&A9}`c<{764f6Bf=!TCO+2nPKr*MfZG+dH z6JP{W156uK+J9zlkTpMYq5yDg$U@Kz4u5g(D8v2ol#7q+33Lwmza`|I= zcuP0Jt-=4_?De^dNUvrcqcn+8^?6wcq-=t0BvWV(wGgteU0p$2%F5=B4 z2z~QDEABY|AF_6l+9gU@3-TA?F=+Lhfp9hk2JgQo-Z4w1<%sjS;^iJ^V!p7hQ}4yG zmn?F;eEU#A{EST?IAVv^m9BT+ZDMHx=EjNd-7!9V0&r2;Zx;4#SR`+HoPeNA6}zUc}B*K{s`Qt6_0V)Fqz$fL&Kn12r)eqqBJWgIAdI*Y75 zpBX0p_Qp^7hA*!2o*EFDguf?KDW`lkEQQOYb58`xeEs609zxK_ch%Hq2172iajhp) z2(wn218MZSofKH-LXUYNL~3LJKLO5K16qp8Pq`zYEy)7!K`|B4zRFUZuq;HfX$69g zmRyb6pp+VJC3y((FxqMtOl2AmIU3!OkXuFW8`@?YS_{IWg{~A> z9VP9VYoRmH?oBLDmFm>i#B3D==qd!rl%#`3!>9EJ<`c9sp!BS^pb0^kYIl2whjrUZ zeQ{sd0)xlMe5u%Tk_$_sm3>%7E!FB5+K3VP;3vgrmfh2-cj;9}GjO#v^6&{}9NQ$KN9aSV6s?x2Y3af<&!=GnpjYkgZt{&8eKLjv zEE)wc0DCIZO`|qV<4}m_F4v~7RD5FK8XipDOVgU~Zi~lIfyc5?BbCk83GdOJzEPBa z`K??mhHHU`8Lgg?Pw{ngVFQsfZm3%6U@>T6`OfRiC%wyqD2K5%;3AZ5v4sTBd$ZW| z;IFMa)CWd+S~MOUh821*(_0Bi=VCEn?tTg^4pi_%fUqp@P#8{LfV%4hIe2~x=M*@3 zsrl2KSC04Ar;I&N=PI9`@$m62=HW%gL`alq&lxaNGlftBn2m+2Sa9GL4WQ29!Q}#F z=@t7-;IIOx12R#G3AXr^=dJ&CK$#9P(>}@4vdN?CqUO-_B{(s`O%FpD&vvhC`}eN3 zo(_swFRpAu*gP=6ykN%Pv+FshDV6Osa`-%g=wp-*SSY!0c%ltfmS04arQLVmRh1?5 zNt!H{wk;>!pv0?$FJ1sul>n(Y86RSOBn?(Blzj$QVJSay7GBA#*4q8lWA8jbv5DAX zbXD*IF%ko*_4epU9e*T6$#@LZ8Ev`$#pgzzuo(_hav*HMqnn|7%-<)axOv>kTThCd z3HC0A*&S;Ie);O?^13bC`b)?N`8lfyN*+ir7`XpQdW=4`%gDtw#`u2^5^}`iT5*q} zx(T9h?E0*d4!xgx^S(c*PktN!LgBzyRybG>jXDD}3S|o-yClSF^i(2rCi6Z~zDTes zO_!_>>(1VAIh=g7iP0jTe(LIW17xw7vc0^_?mVYGS+Wjxsp{aj%(?^^54h~k|D&8z zN|X8$1X^EZgNf!z5&$a3WnuduNV5289uQ`NrfeoGV_`HJy0?E&0*9|-pJxRD-Q8!A znBiqIt$3lcioyfP0-EoFMCLc>3UsMES85lHxRXm2of+3>awAUIKdSUzLi1D>ir49W zX^PeYgaJDL^tj*O!D-+sN7LDUZR*1Q^wGUOhHfgVRSz1&m1@dcsRVL*@9;WH^#&4> z{3<{QBP`Q{HJqtM01TFvJhyV^HE_k5^Y1`N;>RYE^QYyn<>Hjm3aedurAlAs5JUa|E zYd_R}OyFf4EFJ#@zYQl73Vo`ID2b%p}VLiR(9WjnKJYRB2fb`2+HR5xV8iW(CImt$tYeO13(MmCFcc8Oea#BnDzKL;!C=yI1seQ5v1U78l(PAq zXqjF8RPgtS(=I|LZYbRStR-}Kn2M^HU;$%wGJV@O>#C<3TYSfZDQZ7aKOp^d-H!j+ zl0GzQ&Iy^zi4Z{mrRqwLD|$W@6`<+^oV5J5f#4qpxLJ4u;vIFVmlt0RJJf2pJe;2h zczu0l_i@(G)Z$;RX!$qOXwoJx>3g89Bup$BcAvCp&V7H`$IOk=w2FvIN>Q5(n7h=Dv zi2b_)wZ5v!%KFOE+n004k{MI&ikKpfr3Mb)d>#&(U%mFiF!=z1G_bUJ)h3gE)pSkBnc(PmX5P_v7x3JSQq)R&^6DA^}D* z+fTYt`p@UzA6<}d!cJ~04VI_f1R{Or9Kt9_<5cvt6Q7Ui+;j(oYv%?tEdMiaL`aT` zHlYNTgQF#sBz5F|HU3<)(9Ow3C6O9E4fSpI|KJuK#vunh1i=&s+qsJ$ir)`B7tysoHrtwoRPFHk1yB+m)BElsddc0-&o`a49h^ z2SSJNxHUbY=${&g^Qk07F6Z2Sm_OdPf#|vi2kEx0X$=2U7F)HOSi6s`6 z%$iZx=X~j3$q%t@^fxZFKf-1&mgD{5N~yU%_n^S;7iW82-7k-zZ%?U&K_GT%`TjpZ z?K)^p7-=+5P0+)^UL1*k-*;`PJCigDDN{a-Rp7`@u6#1KYGI>FOQEn)AvpTJ`Q z$$ZWJ4aWXhe80RfrT?8AuEK8sS{+ts+5bfkq3ZGE@UR9n+f{|=r~J*9AWmBt$=fkg zVEh&0SjOSjHlK*UiSA}`$ud{ijB}Qod%=PO7-X|V+YiQJptUXOfO)@IPS$14y4*9- z?j(1_%Aa;qm!&K&YD#G^WZNKw&zs31iu~lm3Fd#kBA%GcQX`~%gQ1A(!GChT38{lP zS?rt!_^BDywSG-%5WK1bjhNK=TicC=oLFpy$-v`yRzSQ9YZ$p-Tydj9Qr14e7kIr< zZ-yASD1ry3nryeU+QDNjR6o+`+uimyM~?Y+y)im{HF5m)Y$`TFFnBx|k-N8#2K%Ok zm=i>ESff@4n4~ zrCS85VDdSeb^S{q%;B@m#S_;Z_IE+4UjTF=yRCvX_xO~>f_e+n#kB9oU^jhdc4!%Y zs#<>F$N!l^^Hl-JCN*c*2DBr&CLbICd?o0d34olsyBydr*FE-LA#p~``p8=ciYC6- zqI8nB@KXl*6U*foWBMi|oXIC@WQ)C68$N(BXr{du8}%V3W}WA zG_qKF$g!*t$(A9K(69(NH!d+VL97s!HjDPnM#<9p8e$M_m3Kw&CXbf1 zAC{Fy1`4h>bo~iEmg{oiqwUJMobTrR5lpkVt55T5{BfharYb@j9*fOW2cfBmX?Qrn z=brdR3zw^t7p$Hv*^}zU&!C~42;+ASigr4BP};Rv&t-_~e@Cd{Vzz-z4@-+48s6l7 zvRBYg${sptBr=Ms=06Ay)f?nhZryp(4sc1_{ zPm|CiDz-8(HHt`vUUm2;I{VzdkCRpr3kGnT8wE&q!JH@wijki}QN@g(XB0BLS)*~_ z>9GZYg6fss08{xT=@d%JG@!H)v9FeYsJt8X5>S6Wc=RdU@4ucx19uv8>=DLaz!EOh zY8VzKjcd?4RLS3unEAWbh9#f%SFN>lrn?TgPPyN8F#C{j?bd)LhZJovaka#RzUsk} z5U%yN62Uz0L2suO1(khhdEvH}^!7nlN7W^7-)C?&7p^Z-h5v&Z*x@S8;y z_J_+aV(_(pdTRL-h0;}X$2TyXd&%JZvH1IzBZQrz=Z0p=vU`ILijOmN+!~-f1IoR7 zZ=lm5Gml{JuXv6Yx&E#Qu9Tx3!iHm^+NK7@$5;@w)<6W-|LlQ8D)dPxwI@F#_M-cY z_Js~I29XOyMX@+}f)CQ*K7ImFE)P9uG~CWIVs=|EJ!3R;lYc2*r>|N+2Qj&PsA^(? zPgs=vi-bncRyI#uIo~u>wk4c|)h0qo8WOEvpjQCQ&-7pVW`vL-fJ!rVL|1PR`y;Vlp{bQugi2H2W{!>!C;7Czxatg?Zay=s7Z8OuiFv1@$6-9|2hF;=@yuY_ZJ;6DZP^!HWH!)nVOF9hZPfi(akG=*q!fgbxYV^QBbJPo} zfi1v*yFNK}vk5!Gcvy+L19P%+gHkPl!h?6o`3a3aQkQo>e6U)0w=W?PQtU{tZ2GZ|OD$4@z& zEZ5jSQrEonZSR)r=Cxl*`S}HEZu{s-H^_tSeDLyBL%|)9C?%)6+E8&rjOGpEhJO;Z zi6UtzWpkaf4DXy5_U#)T$cBSukO=rY*ZBatqx%Lgv#5ar{u|Hqc}H!kOSXTSF#c z6NaD6>YFNFQUcdiX!(8biGIBg5}Zc=+vPrcaAi^`>}9SQx0`d(EE8wEtDq|$=Nm8T zjRZVo+1uCyEze?r)cF5C@hIXz0euJ8@**tnY^GW6yJQuF0)jcAa$=epLW|ZZQZ#MrM%WNuuW>xne;w zGH(*>Cv%uEd<^+U4i|)tCCUQV@UP`q6VT@2f1JVJoxrjl4ogM%PEo|4sb0=E)XNJl z9Zw%rT50=cF?D)hl6sJgQhrMJ8fjp17n462J%kQt`ZtsgGA#s?N1!iss`z-(czFXn z8W0KEB9MRU#RNjGtS2tg<>6n{iTTWuii@Z&2MsXyTdFql6#(qx0I^&DC=XQHAU_)+ zPggZI%Jk%1gf-OMcvtL6_x7`$ZuamR!*I#`O$PuJCmTJdW_X-Oz`jZFVcc)tzz-*C zcHVyo4~T4w4|m?Jx^dSpfrI=|v5oi0oaOA(>=7t8=Wp2+p9NUYlu@R4$x$e7;wmBV zOYYYg%>TS`L0V|#HbxB5!Lwa?WegM?oGzD;dnMiBM5ojXi=m(QWn*okRmA4?jGnjN zoux;-Kdc0m_~B{7h{Je$TqbYTY6(Kx1FvO%T2kE_GNkk-tk9e{O%b5jc@T%=3C(}$IPTO6@IzF`+rw2 zy0^;?a{y~7BQF5I&p*a&9^zA;Ay{j2JChQ+JIm1Hi(f4ELSqM28o5W0=&$l2jpk{` zS~;J~Vh%~Q<|AhQWUegavftaG+ob~-Jj@Idx$Tc44&=%4APvgehe^Pu{I8eyTt83! zV6PdSZ9}2aG`wJK1GqiGP2OIo5tz*PU$IeJJ}&Y6Q8ggjqFD5{3(3}Olc2V67oU}7 zuO@0Xt%bX@3(Fkpto3zC%6^KMi5 zRA+yn8T7$fKab3x@eur~?vs~w;!BL2P{T6`nFNI9LDy2(Sf?VdENYiZNNLR25r=U` z840Sil!ii&KJW&nI&EgR=Ova`F5FI=+835ZJuTZDfoz+!#c{uQfhS>t${z}UUXBKg z$8*ZTkvw1^?}fK)Ys4mSO?z#;AQVCsWCTb|XfDSS?^!uX)cwL8+kS=2p)3EX7xB5=h_Zbv$4m=Ga!8 zki%4lkc{CJbB$x2BBv{fVmlAVoe0y3dIbORp3go|c_zcURZc1OR z1?_Fh7m%5|w91RtUqVu*?R{=e!$#8B`}8+?R76rpcAzSV97o~|(xv9kyD~kI?JqtA z60z4%@~Q31OdCRHon%sw&@2{Bm<(|Er3u`+$mqaNUoWSj!XSL{_fA| z@~+NEOzivjh|#$*3ws1}Ll_pQ138+={&gFi!&caAYoSsr&cWReG1C*md=Q=E2%~E0 z)Wgn2)?CZIB?(`oEpn-tSGd5QI_Jf$pmjuOOPuC;Y#(^=e%kU z2sed+8?i@=s5!nPBv{jNLBz>mf4het1B)?(BmUQSy~;%GajSLTf-V#zSb3_!)8RZ% zj!039w630!DS$>hq{EWqeQSPqNB%$Rur1nnB&QuUe_U0U)X`P`B$$Frk6zup*uPM? z`+(2>3Ab|5i?Dm0cV>F+mYSoMjZx!lOw8dA=N*dtF#;EIcUw)MPAtKGoB5sjl;hpz z?!`S<{4A0Op*^~ZnP}M6{dGH#LBkg_OSsa;@Q6iMCWucX6p%ymsbHEiFP++l^Qo-2 z3`<`ey4)#xnQd-)G{SaeXefZ2K^-VIOUlov*U)q*g~|TT)J8jCfrQz%i>ev^&3DVB zEt)!p6`rE}xh7%#*U#iWQ1a1F#6YQw;?5&QjOL8jF8T_@=BAdJ%Q~d*o3ac7!U4sA zg<};V_vrSQFJ0|-dq|7VtdoE158b+ru&T`BD5v1q!L@R-A$%q;R7ZAyS8~OF7g+gH z#BU|)rA6v-eVfbv*vk{(iX+u`px&0-`utw_JTI%kN#>xMN+TS(D|zp(-XW43`qUWJ zb%UTqJTU-CMXPo|#p0=y$?BtpWb2%E9im;vkJ@?AyuC`9AgTQ;usRT~wD*}#QeWcF z_l(KFk6<9raZhw<(1-)9#8!mjRLe=8C;Oo5^He!4R^c9g-Fg3%(Bx-yi1)BDfXxsb z^J&}r8-Xdpb$^6&9$f|OKb_y)pkbE2%E&=}IVbCzju*4;E{eFKgf#NmYae>LaMR-R z94ob5?S4F>cL4i|L!m3p4o+ur8Hqd=&uNgKMOvqA0o1E6t$r}9DG2MKU5=6e;2 z{pNa`kFP&d_^|@n^U*D5_CxTyud-V=iF2fWV_YlIj*O)5qL$b<{I1ud@Y>wg0x4ZA zzV@ewDYg6OaC|Iv2vw)-dn`EI34iZ6_eBoc%MSvJy-j}|;q|fMb1HMZ;`aP|1t``O zg^b+dyOL`1IqRIcpmUi=IpH|~7XWoq6b~X?WAVm%89@E+cz;aw=YCQuw#C|@#0vjG z4p{A34OIySw$GDeaG=p=oQ>vh{)TX+JY~y*F3TXi2V@9<6%DfoGm5?L2*%C|&t%&f zC;CrKRc=;lvLitikAIls;x5**4iWGVMA7>Uu8qkqNz#z5vD>t-ptlFp>F7 z5DoRwuRvXPao1HS9fFgf9L(S5XV-CaD^+g+^1B!h-zhY#3@aZ|SaW{ALt|SdygSC0 zz`ghVM8u{pmi=5X)sg2?1=86nEACs$UC7$FdnX2~R}NlmSJ9Rt7>R}!3qLq1tdEd& zIcBku72NWU1agc$`d@#EuH)kPRCz();#{KdJQ%!Wrn5gk*|>r%Rzf$A!KF&exC@W7UA*Fk_j;r12(>=r_|#*sLC*N!&NA2wC_>*Sos z5(}heW$ewK9QLxvljSL!&Bp!swTPp(OOta;CXSI~GVV%O8HB4}>DJI-fUa4pJ8$%h z9uy2Hmw52@_=N_?flc7d1n@XZ|ADD7Ag@wph(KmDjy`g{q}H40y+8l2)yxG;H7MkT zr;=a)U`EihBTKMGd@N}?c^D6W)<;@|wMT}BJhvI0pszBZE{4c1!Kor)r}l%HC+Jtv zKSo_`x$PhR&<9i~PYetBDO}Ld;4X{CnrYW|-#@d9}Cy-6Fb>(N58 zyqo!;6#IDskbR;npTsI)8?u#n0zztphSZ1>xU7$^)oBt0KS*=nF@)W_OcqG{Q3UoA zT^4LPLHIu507qRwjg2BzjRHG=M$y{1@V7U%=2VU~a4L5gL5C@=toL#R#Cqzz8-K#j z$uIGj;RBAg>YXFlzu6lQ1Esb2T#EIL%7SxbCpL!hlT|~T04CrpQ&TS`mA!l&u!0RWEU3;-O33!fdzPROC+e(G9TArq)c3Dh z$n^T3&AOv2c=0EYcc8$&8sYwZ@c7(JIN$0+1H!O5B4Ex$yIjka>SK1CU>SaGV4!k6 zT`-$f2NI4N;fPA@e1w{m3y!uSi&F|#*)m0H`)kv!Pz`Y!V-{}WOsLy!ajt3^@cLef z+MUB6F%?zcV!t8Wr|`PnB=hDuoXE|wR}d%dUMIU%7WBh^IeKC3C)sK<2lWGj(}*O| z{RJlHaaptmW$E+IGYD%RAmMGZ^} z5N~sMRqZu+mDi3K?v;#^cQcs&)dwuoP;AZHyD5L5SA3)O;slVH>+5a%Hzfzx#*G4| z2#=5pcH~K^2n3zm%lL;kJuT! zfthRY$P*41$&Cp0j&1;MCl8BvF8kScY==K|EjH5}UQ`ld7b$b+hY5(1gRb4IE^%&@ z$BQmdc}{yM|1%UY8++TLrKQ286{a%RQYnx_t6XgdCRKm(Y97`7NE6PCu z4?(89VfW-m0U%iela|UfrM^fSk0KO~$~o|P7_ErPo zly_b%M?EdQyxV%vYgAe)+dTuW&wA0qh(Zaw=d{bFvWRKCq%WF!iYM~AQTg_ZAc5Axn?1ICH4#{JDWhtXAV7&iyf7Q z0Xgb1QZtQd?9=a+gPTY&ynijOzAszrAgU6plz*`cWV~wJWcl>`V@j3KZB5i8nddLm z0a&oiVcjV?1KVDtk8%cb@Df2$5DDQqcUp`Z;B1c_!l=>akG_n>0pfeURPOAc;LR^K zWQ^vw)fF%ecU?oyRcK+O!EcSUD)Vb7edg7v-A^@tG0TMdG-D6Fv4a`8zv#->Q#WO6hFyfSXdX#1fd$k5@yXA2uDxcL@j2U`O-II_of9si)NGv# zxZwic^`8$oWgnjXPW1fM6U@w|j3c~XMFS$1GXgmVfp*1gT{in8P=_#e(b;N{bX z2ZI)*-JMq$i?4aFT*GXI3JVV^p)s^?G6Nx`hRYXnxK$-E{?UNHn&CZq`T%}wQJrTr zxEF*fZs#k%DDD6rQ_8p&XAl)dO&rFX_kUg`PkX34BUiCIsd+Hp7LBtNcGtm$UDqmt>Z=97y2*E(=h1jkxmm-88Fw zT#%C}{jAv&S<)%T8fFe3pdLO>b_i)Ny&6E%8VtnM+|c#bL*vsDD5qI~uybD2!i;;h z2AcmCgH@Z*#k!C|rKMYV*ua?`Frra)c20vA!awlxBt$&j@zj%F8nvto^Vj|Q`ziil z>{z=6RCw1${2 z{dX)SBbZgD3Q`>xG!yI(H*nlEmm7*O6+m(3zg2yZ6YOX3+LYfZ8noToJO6`j4XBes zeYOH15*hokN9Trsa(DOd$Jv%=2{E@TyS%mwV8Q3nv4V^$;ReJ44pS<4Tx2z7%y_1` z6_ig=BP*Bc2ep2T*Mz;v)ivU!G@z*C?f`_KCRfobv?wMk5+!b<^u72Tbs|zK1`hI+ zb$0PWhmW={r8|sk+k#`_40624WD-=ChYDX$~)R93b* ztJ9odpT+rQt_JJD6@+kdu`fWP?8wKib`~k{5>$}UBN4Z}h^x@5zg$i*I8HzV$-~g! z%p@Y23c{33md-3Tp7ExKpJN`v3b<`0?5<4CDgUTp>9O#uK!5_PA_L`8+Lh#rkn>&K zi0!Cjt?X0dTZ>1ML2k<_PU;CCQ)tq}=JqhyRQvt5H7$(nSNITR#fAF?W$bC~2`;r0 zRGPpG!>&%+ZT8OTN6lLUk)_^_#0v?+NbB8uJ_tUM>yB!flTrLb(|Oh7tv-cjXUMRy% zQU{pBm`FBNddtj49m*CSTY0<)6O|e!^ETMJ9AWOl4GR&Ep5N&R&UHa^Fr% z?9E287=V4`Mn@i1h|?m?qBL~zleAf08qnz6$ADO#45S`$OHnjmz7|eob zB#g%Pob}4o1S+0MkkZU)&Ht_K9|%Pdc^~iBq zs6%csj^^*3m+${3izgdXXq00pDvgOz{Lr>?UR_Io0e@#qWi|6z@Rrtk1(z77M$+(< zPo18(dL5q-Bx0(~Ous+3P_{vm0AvN1HOf@6f@SU%lC=-L+uV1>e=?Jckm6bWapyr| zElPdi`K4_eJX5JbWm{`qgvzVDKS_AGYn>e*iF4rgx~X=oKuGl{a+~TXvPVXrl62{7 zCEJmKFe-D*nyw-7xA`G{#2QXauFf?g2hJVZBdsu+dz&j3{N>~W$pztkM1?$-cJEm`0pPF!br{qJYfxe7rI=&XUS=ODjeXqJEZbijtg4$I zhZscd5h*dh3k{J@LIiRasfPzefmKVb^u@X$Cd!jDh0 zj`wYnpy%6|iw&2T^Ri_Rjl5VyvbCO;eb(8Fv-n{rDIi@1yN&s~2l)Bx83sQt&w>PL zAD>l@Bq=Gcu)|juj+VitZW{NKQge;eIZuA5I zQ(^7XLsh;bq{xb%CS=|mVlVIf4awAAwCL7~FGNTCGh+4-A5knLl&_fZx~>h~E{G?R zg<>FGIucfz$hVX9OWo|Ejqf^sy)fm1f5CL!mGsk|hrxsmDmJ|uIGkm)3IE9y0wV7- zf-1hX;?aF_UzlHkn=3-^;n4OylMDHfe+bTIcP*!vPsyds zeWyR?sD}#*c(*GPMqbj#zCrk;Pg$O5w?SI@*&(lqbTuX!yQ$1Gms^X?R9*gcF&wVp z6w*4q>6d97UH^$yx%0kAk+1I()6M{#Wjdnw$THJrO{9-J!c10jdvTKD063#`H z-K?MruO>TK?z*dW;RU_S;*)=u1t7Mpill6qCNbwF1L*1k7o=fl z;_d}6vLz$p5P@OIf~jAAMv9Xz0hhkQ0Xb%am3nB#mu8G;qq)6h^@MI~N(`Ok+$C{@ z=-}aqt#%p89*gCK*Ecd7o`78lYS#&6aKtY(#+$LkW{~}o-%3_;W=iCHbVry`=%P^I z9xb+EK14GgO3nKtnd7##ZL}DAZ@#id2r@2x?Kp)k>JRRLH!?RV3bfP0IcuASl}YJd zSwuKy0ePAl#M%Bm?nOOQ0e$*VMJ7Sw(!PvmX}jYfiSK8Tbl|%&qfTtq4*JwM zfN8b#@)F1TvsFNKb7gqS`kQ#(9#{YDSbU57g-j3YrjlLxj7FZdahY5@HjLH zk7dm9!w<2sEeK6__E(5hE$|rz3ixf|fJpH=^Q~rl4xi^xK#}X2$ ziO;Aw!wmP)-LDB{PE>eg$K>c?D|!}|8g;`{tK^s8z2wgTV`rg8q{ztv=C|-vivu#E zdA24E&*O?Q#gfQeRP!5kWq*oRy>{5FF_ew&xpO;9w^P>l9QE=&$h=|giW%;PN*ii~ z0lQi2*)m9JWZjhFkkJ6toD#Tao|~-}lqNcyfWr-=N{(1EllRrOq^$;2^9FWIY`;c+ zwuS#JupC~2aQBd!dj239MiJ%Xr}F=7Uv=aq>K%Vzv75$07fXqH|0H<*K;go*1P2YB z{4kUuq#ZfIj&NG>cQ;B;t!={?|1G*;W>f}iYncSpsb^qH5b20N-0}J|PlhSYZi@;@ zqC<&1rDuE08FK29p2xi#NDu?Q^%8Q}hXZ{Gsl|7xIEIC;dOqRkjakie+v&%(8D6K> z%*x66lOC2#Kx}U5;EftR9y)-Oaq)7}*I(9HSLqrNKdWIdZr7X3r4q;nOXteRb%$p; zX&&{LLD+Wc4w=fK_vMSwPh*vMUVS8u(>COhM42LpbPj9SS$veU%n6M_5 zmmukN?Sr2&DShX}jg&c8Mb?4rXd$kUog$R&FuM>o4-251JyKT^y1bA<0~>E(=D@?n z7Y{Tn9gJV>P>5!&YNv|}aS~yCQYUtHPER#%Xg}+oLilCTp@zl|cd_M=`4eblu3!;~ z2Iya+QcO&xa~T#OnZ*Uob30=lHn{h)Jv#pd*HlRN2by683Z5muoGX9FZb;T<)8Q_5 z6P?APP$RlI?T}ouBNGN&etXn76CenL(eap?7t>u)6Cf?D8=5mbb?c9#J)%0Hll(fD8#hJQ% zsN+-Fun-wtFSi0eo#%Yb0cJ<~I z--;N5(^voZ)TQz!%54itqOd8 z`j{ibf`%0P*Q}m*zz4yfHnA(2Z>vt?GnAUKBZ zt+cbA@lLlJ^|N<=rLy95hXQcjD?=81#tXcvs~qe6kKeu?-B;lN{q9~va;bYI*f=Qb z0~5ozs_RSe=mD))XOhEB_v|wGMD1o!W~WLj-T*kZ5vVKo72nwGlK0Y}J@FDxc#}*) z>ykiC{fa@HU0)!ktdn1nB%_$f{|@V_x4hfMr~R>k05SzP1cat`q@&ZH=5$vz$*0zQ=+9C3-0x!t`r5|C&X-g zD5Mtxt{9}@3W+GzXuVT;I+HbER{&Z(AQxx`!;Ebugt+&S3~Yw^v1C3|ZS{E)7ktU~ z$NHn*BCX=6(|=+A>)f>V)7K$?s^;AkDGu{yC73RP8`E=H&mo5Fzc&I2@9mKjRz8Z* zDq+HUKmJSGS!U_WuV<%(SbM^?lT6dRAc7JZA{vVG4L}OzNBTk`@x9IL$W2YJtHD2^ zU|S!);{UkIG4vL>!s5Z>>6$Qk)h0PkIW6vFLXc2%5v+)pcQU z&G%^Se0bI}gHhPT4lq5eU0G&UVi_Yu9DWJlYww zFizhwG#JIik~EB@u8{FRXFU)q*N8u?%WvVI^Vi|*xoe_P1NLTbkP0*r`uS-Bt?Dks zE1E+g3V$B#H#Z~T-az_z{B^=G#mmzZj2V~ZhTiDGF7|YUL|?ebf!#SP^QAKBbx%^& zZBpgOS`Yd-a68sDV~Kv{&T()HhWC(fPWp4-H&RZEOme0a3Q;wJTN`eDf5&fQ13~-z zreSe#RPgG`3_+k@{q({;I4Z(NW;+35Wv7~DHttOr!@LMluxGGmx(l(iVS9c5ORNUt z4IM3*B|94-j~BOYFpw}#Z}w0mTRnZ1V5H4-ACd?npRotZ>5ae*|!z_tZ5@uWkD zD=I#t_FhhadV5~^^H{w0y%>Dh>BZuB=Sk{J)v4Znnn@6rK|RF#qIV+SnG7iKR?9S= z{&$Cf;{b^fO6Uk4CtR9kLuNiX+9I`N?|5NrSYhkSL$el6cj)KP;`OVnSUqSDmz2_p zguPd9?V+VbK`h(~;HlTGH0!-n$`OqLtaDLsjKzM-V!eUJm8Ja6P{eAY~S9kMR`9QUXS2&8NJBRKtuT#Ow@WS|$IZXKD zYXE)_uapn0|l~fPBZIBNdqA(ZC5|ZjfBu-k@=Z0D9l?btV%yNN}$C_I@3Wq4-Io z1!$a_eRHi&5{s+Bd;Tnbdvxy`anU^c#BgVm;E zf8aks6o>##+naI&t?ZZXeM$R@v8Qsn-KkVHX}o69s$f#X1whZTk*Xp1ONeQ3ggI3* z4UATc^_Drny!z(m7R+m1Sg ztTOJwc#X}%w{>=TE?!?=!LClOzjSa)fN+_Wg59j?aji|`^ zr8?z!Jy*-AIVV+Yb5B${UJ;Q%snaz+wi;|d_MZyE9S6H|bUnLZZIgPy0%*{4e@(B7 zY=M*}o~q2dN53^O5*5>vkrgXtfw}fPySAX^Oug`p2p;3PnB+R2J+6=BkAJvTrz=OZ zqSSg*yT>-)T9&tewy*amxEaa*Qx-;C<}NGx^-?;j6u9%UAJ-O~c_xt`ydC(mUnv|0 zCXi9rT_z1(hmk{+p;PA7fD}!82kU>bi5_z4YmX~M@79ppjSA}h%yS(pbOs1w*419x zdb-PRH{n3+krSRW#$OS(#@Otc_53*a2cf)ciS~i8^9FuLK42HvvS9Q~nnWgk$2>vw zOw{m}q+n7VMZ|v1KIOR=exIUyy*CqpMgztk4Ab0fo)JYPqVm8sTrjyhCYxK;x1)ik zoRo1c3!eKdQXMJ=Cx*eDHW|3}qN>-*^ZNMh`y!@RM+1g_$uWz(B!TIs=9c)-abX%J zc(?*hs{qo6l$i0IDZ5XR`@JoH}rd(c+KMOAeAzY^qN~%diRd8#yk8b;TIVr zkiWS)iP%QC%5cGRCZ5W8-c3pyZEca&NVol2rZ1gR2oFGyj{-1yzR#5|qe3W}X66{V z2y>bCwCB9Wl+~$+DH7l-6a|&9NPB5`1!7&Sqh_;x~E0&Y-HU(b$e9V-Zws+0E>iZ78)lcl4 zO~J_eWl?VLm6X@VTcNu-3jVNBzhf~Kf61=m891$wTq8-D);?hoooq`t)Qmkz zQ<0&d&(#plTpkU+=k?u+PD1#@xgLh$q2-tFHcN9Bz@Vs~D%$rsiKitAV61F?W3WR? zez}XZNs~ff!#<)X^VtOFn_E5qEPVa_n~k{Bu4Zl(6JSJH!co2FE(A|nbEZEwsVj(k z3nD~~F08(Ts}6JbxZIhwe*KMAjw2a{dvv#u&zlcjcm}+7?cu;H*uZY)?(Ja-;h~Hs zy~2b6LPYSZrl@bd_vvc>vptdDqQGmWOtktJ0-is$+pbaDuK#_D`xG~WIx6YJWgvUD zu8Gkt-$5W#x7BtF9vwzdS=Bbz{H2;zYUI6$Nv`h}4$r-`P)eBnO1f^Vy0iK#;181h zomT{dVnFoSM%Ifw;JyJwY0ewmW)LRW)?pT6z9X-!@B6Sn!-sy0I87QcUr@LH=(E>B zo0}id9ghE(ASrM6nBJ~mpNU;k?Z(jrW%>EpzK?8b$)gXzJID}SL3p<1Xc=XCa3}3L z{nyB>?&q^*(WOlOmBfjK*w>$t>o$ro&$)h@Qvd4GHtv^KT6DqmaUGsGiN0eYevR#! zDixnp*TSvws+As(Ka6oe{SLS+#v!fO^Uxyce=gN^8R%l&H>f3Sy|)Z_c2bEqzU>ua zqP%7cyx1Apr<^&xz&`#gD2RjwRI}Oe>$i~4&&;8fgp=g9A3qN>BNrlJ2m3n9a=bj0u+`0VczSNV$6 z9?wnw(22Od(aLO_AN3wC1;=85E+xR`9`$=E)Kxznkb!{&bmnU#_1J03%MJFzC`=0C z_k8-D@zvTDCu3o2Z%23f1)@RdJ^@2$ZL(tPiwp=Cblu;TQDy>3pv2$Z3GsSx7+%Ls zylk#>#AaSZaEHeVi+6YtO?ZuS0eSRf5*%~#d-tmkfuWLVUb?DiG^Hdriki)u@t=PIF}$Mrui_AFx*l)f8Z-aABNLx>3k zLB)Lld;#Q!PYo$QpVh9KBE@P?)RRF?y0jYkkd z_4#4DbF2noVz+TXAyQo%NB_>~TewOHD}yTBi$_W)U>ZUnk5`$I$TE^hpTzK1Nj|6% zRBgWy@>HW;DQW0iI=(AKWlaL2*uYeCCEoH~0d5z%yn39nBK8l2fP1QamO4@_*$wHv zcfovWYtf6#PYmnJg59%`Z(4SeEt+_nzlIoz?lF}VtxNX!bYq)om%2EVomZ1!W~4!h zWgVQQLN3>4cP@{x5+G|*NJw<*pmFjsvl@MIOF+uUYZ74_8xC7F=r|kj4XHi;Bgxu+ zakPmicA~{*;QbwVQE4LqrSchclvbC~jjB)qr4#KVU(+iRw{oZF#s`7q6O|YBzRiov zsF`jP7HTD}_`I6WDnW&x;gu8z%3lgqU#98CN9P^}BzvAdVzPmdkJImwPY#fhs)^Vu zurnW!?gTEo1`-T*_sxkAV0j;flMOq&KV*u>^cQl6%)Sea_97-7T8byOZwQ@FEI`q# zXW8FX*NuiL^g;0`^*~uch0fqmHG79QK}=!qiaXj3`auK9udxaPXUt1tx|5 z-^Xs9(I-^yNC=nyacOew)%xgDiYF_snr>!qkOcrwK(N2+(T%W{a<6y?UpE;%6&kO2 z3h)z+9nc1G_W!W3+a%re0So~0dLp&@2uQNh8tup+L;sl(_;BG1M-+Egm>{!k*|ibu z`Y#B$hMG)tqa8aXzwCbye;X^%VP~qcD^qP3ng4*&(GU?{UH4t$9s`#?f0CopO3Y$$ zcYKBL87?rXROMw_wCSAHwi0F%%Ha%X?!biYNFoqF<%KA*v5JH95Ql>4fyG$^>d`yZ znr9Rb6qjkrzY;4>_u`#*8qp(3D@{&rf z?#A9iPSRR$YyS8X2r-Hig6ue6F~OWa^;x#*~+LY`kLxf*7gROkQu zEIFa{^DLTsFLr62Td$Oo6^ZfVUl^u*?9>ZtGkZf!|E^t4HzJbB zguiy3wIh}5cG-c)<{_bht3>Qv6NgWI@eRILOI44Y+_#a}Y4eSsrOg9ha7?aQkZ=UU zxo2>Mof9|-Tqzt_C4T)(DGIy&*oXU3JzCLzTiDVdahhV7C&6j@nexn5?azN7)0$hW zS7On(PX1#Gs^G6X(UryaET^X3Ox%yUR92vP@5r{gY+kAy3rxrr(tOhrO4*!lAxaH|B6^~*BWJVFmx8K_4KY$c_Ush@Z8Ura z+LeTl)@;m2C^M8H`jGjCR&6vLY!0%VKLg@+XLQZb(VtZl8VKSX^)5}Zn_?#W)x6M! z1@8~o@y!s@G}{I<;iJhY6o70I;0A`soav?i7$^ zZy(P*g*MotM!4(MiUCbqKQ(aKpQUUwg!*=2lJ*cmC>Cb9?us13qsLN!)0+V4dC%cK z^<*b{q;U@9#V8c~6Hu@1&|k0o45D{%p(KIeS*q`5;WCSUawf+$C^ z-Kl)DEk{xN-k?AQq65}}dR|_#G7yDpoeY`^SLq{#iS>g{wHi^c&J4A!7CtoIFao*p z9nyPA2a$+H_t5mT34qs>?e%xuBmaqezlF;5ujzjA(K6R@B-*2Hd^>HvWF!ar&h#au ze3GZ{=00tci9O*bfbh(n&1sqUv8K|?Tw3jec!~T;Vh<34E`>1(dPH|94toa+G-lrh zbt|ju)iA3)X8ibkwwRUmCE58z%fJZQs}3j!^k{L|Jwr_^aSt@WdppmjclJFE?&xkG z>>uzJLI!WHM)7Q0_u-m8IlZ!aUB*;Vboifn^XSCgu#3VV?u;2?QnU4C1UmCE!sbNPQg$H5L{G?Z*Q6)INk0}-XK_W9xzp>{IcY5R%hI~|i%K@QseJliKMsp0 zE~k>lB1fhLe7$4)Q?8rkdwV2?ODmZW-faR78hJz%1dDs*L65kW5JDE2!y=BUP;q22 zj?=jS`N3QTbq`R#Vqezk8<`?TX`oXb9r@I4NG{9j^Srw4@G+xDN9DXn^$Qsn<{VqO z^gIJ;iPYZ__O1_q+`JeivmCmf!6zWg!NB<&|7!sgmIP1t17$o4(+pIkBL4jB{i^_i zWX9CMNXI;V6o(aXAvW`9F~a@B%HZ$+q#^6#PW%kgnAY0X>pmV%r!~O+-?v#eLn-Di zgJHk?q8n@CM_jZO1{3<2$Bj!9Ngx?d$8_8@2KkUgsmJ0fJ~UOIa@-~bS4qCa@1YnJ zHS*@G{X2GXWk#xvuTKk@l&%Y2OsNPLPIb1zSbzQSpV=3T?K4fV^0GCsce<1;1U_G3 z(A`^BZnS>lr7)e?qO6Tp;FcYn(fpG__<#{(%iXPM6qLaxuoC_b=}?mF7n&$_cV<%| z;$P~tM?E(xQK+y-;dUdZ-RW%&PbG$j?{9e_xh)OqmF6{jF(zvjqRB1fx7p>u=zfFA z4T7ATNdcXxcb)ES4EMf-x$mR!BrZ(Wk5j#fO2_(E!tXlo$}mrYywZwGxt$QDLxEtX zr)(9z|7rPMzXo+pHF|X0)VMuSdvYn1M_vj^(Z?3cwNH=Hd^^NlwOXQQ8}NRn2**4#&QZ{ z2!#%38NT(~M5a{hUiou+8NQ7v$70}fygKl3J^D<2(z-h$B0IU@PXj=|=bySBgUcsj z^&Sdo4_bs+zZ^&v?2t$Skm&IP1BAj773CSjQHg@Jw7n*p9Lg79XTiOUkw(N+jfeFw z_>Tiv0C3}vOd09E2yF%@YR@xgA>-c9%`O}JNy`g$zW*T276>^a=IyOJm@}wUvfNUh z7M1Ak4GZAI@+*~!YC~GL4M#Cl7cK9VykzD0%+E>i(yNHm+uVn%i~oWy3hTO;!_C@G zvTX$UqMY#UXFvo3APkSGikH*an3pomghLH+lOf3-(?-8a6J4?I-A><=hj~TK;}2JD z@h4N+?740Fof9NMz+nqKAp}!sxe?0B)}U&2&ILDySO^g|%3Xl1JsrrO?5#{gIeL2Q za}1Hs!0I!zR-`UTp+@D;Sp#am(>qx@70uz5&}2s=$r560pL)Mfbbp?sjZ?dAdLTfNB2BamV>JPI?w!Kz_*Y@$%{1}H{vC?w4uH28@ zxMb5uka(ZIJBrwDY0}r8^y~PfLy+C_e8^^$It2kp#gHGGM_647Vf`@8RAOQI87Erv z57O+|`I;yRM-|?RI{`fzooTDcdAFN$eSWvQhhQ^Tnp17 zVURu`({8|72$knS|J|$M(V|9p0IyK!VaAkj@IVq3ANwi9@r=&AgLu37pSNP|_Th2YfJCfFtwmf9AG9mG&LybQ$~Ri;_1vmJqJ5#DnK;oV?{FP1`aw zUzoT^X6linzn^do)Y^SJ06bRd-c>zFSv%U_@=MSn?rjc zF{^EPiB(|^5PTiCqsx@qR4NuHGOMH3GT3?|2_jr>rlwtX?)Q2IhVsYV#N2WBkH4Xz z8VJslomi;Z9W5uFo&yF;sbpk+N z-hd$eur?kN6hlb}1`9!*XmI9a|b zT~*jkKJrXBI$9|nV1`}TZ^uakRLI6l?VrQ!EPEvRhAJOSA^^5pgiS zX%>LgIHs@6UDPA06|Y?Q_QqC;;@Sxu?8N#QDz?KcE1^BmS~kqlXCvTOHIVEF?!hBISaO!`#e5P0jPTil$8Bp3l;kN#a1K`DWdq9z*u61=i+Kz zMA|%UyGir((yKx4n9!!?>j?}q^%Mjg4@aCd726-|#hT+IV!tvZ?=H{2A@uqtX7*e; z{easQpuME_E1Q@jRL}t?A4?Q*EY?8jMla3T2bhn}2h2`TOa&=L~$OW*0hyu3@aSnorAK5k<_u$Xg`%x*zTvQu;6y4u~C@3)^teLXu zMSNZNLPn21RW-6zL4Ckovf;_~=tg>lQhH-47pnjml>xD6KGhkeX?Ggwc~6&#GjNi} zhHN_Kf;Ggf9!uXwQ}~A3`#{tfXR)GkX|)@oyi{PDOd3D^P@}YQt9CZ2 z$=v}MY?2E?nBD?OVxFxygm6@iPfO{p#8Fuib5={`XEEX_5il4^oKI7;e+OQI3y9WW zW+$0;3g;T%?rvkvC59l5T6@gA&bf0%k?y=W^8B81mM5PI7|Z9erupDt{pEMd{h>MH4pam~$|yHhWQlQh8#CWq!1M;^z|MPb3xX+vMb zL48)au|ahb5ix5x0v(_=g%a<`2YCibsuYKB`n?r5q~yQXjGpX_7SFZANdaZzdO3jH z9tr!c*>8+yF~CD>ZMeWbV|GM(Q04FVc%+I(DfA3?_SePnn#usb1eo^igRffxC=7fH zz%S-K((vXqPSQfK3KS!~*BXHi+h>&ML+l~*#w=^f%|k9>WyBf*1IxN<0Yd)Q5UxOt zooA2!qB@+~G@iv}hcz`otq)qCS2m`WiI_n!LJGK_4cXQ6 zq;!Lg`E)*;w7Nt-vm@CpcKSFJA=~!e)`Y~~7)pg6edM}`Bwt9wqUsZylsbILcqV5m z7I${(`}=vXs%Q)@J&5bKh`Z=;zh6fVP}mgP0v0KNHsy%j#}gm`#RFv(Ckna#Km?%p z?DfEDmWjMl_jqq5Dqh2hBTb%J&LPSe+JhGh*o6cKRxHFv?of`6q<>AbdvFOv7tK=ov}7u0!%k<&cHT?bfA{Em5D?^u4fS;dS;d`9Ip# z;+C%09Gxs1?3?L29-Os&*sxEv$V#p4n9@PBPL_AkKn9Ae{H0dzn*iYgM+g`fiA9mi z&J4;vFgicE;!yRHw^sc{lBseD8h->uYy@TUA37PCR|3O9^pIqzWEl*V2$7G1B^Dp^ zR0xT%HtZ0T@nOpFbYUA;bY;a1CK|DXthXz>4~;IFTIUC`!ia-G2;`|=vHW7(i&o8i z5?9c+CvB}77Mj{VMFN;2yt9Twp%JQ~e=2G;@+d&}kgd%Nw0>7lueZB-;PS~ZtsVSGwn}?2? zuJ&i?c3Mzy44no|n)YT2k$#9h;EpDoXmo%`I$2M}wiqanqf{QRi6J((H@_f!Ub#Gu zPJI-qZGKlFJGKj&Scd#m2Xe+$ALUEw$QGrR%w{dUu+W^42&8nR^S1%WlqI{@7S0d( z^kXpmupv6qJCP?8W+4LRqln3leBxC`gkepc(`Uh+5?un`h$P_=#>dEl|FC-Nuuqgs zZ;NtXz)P97c^Do)M<%zy+NKQNb&KXp@SKR@`irOgjQWj8rJ=h(NkmajlYsE_r8+CI z^Ib2_?uJNg#XioeLR|UTW<((K$qvlJRD?m<4V-keDvkM>WStuXX#gX33R6EM~t3h=rA5K_Kts?c>_q$4#-FIe_Tk)vIFo z1+Q1}iobe(3Qr5GSrYKezN|k4$vx{inj|be3#a~2C6Q_vY7?2*LLlUF)H}n8v7{qZPDZyoNsT*R zcTQ7)hu&zrw$z$j?KWAKdtR0isP~v*RYpfO;ZWC-}6sSJuEXjpgL*!UwU3VWD}B~K@e-2%Cme!nx)4;l`hV6WSsgS zVapTT+-yBxAB6{6Bn_}Q$vi^|ESZd52bS#JjkCh$NZIg z$Og`p$;ZqWx&cK$>F#?r!x>cmnSirhj(S%A4;dw}!0<6H<_<>{@-3dUD6NEX?@RWw zYS;F4JoNRyeMnCx`P0Bb;eV=Fvq5y3okeefXS*uDr3qpLDg<=9Z^?#`MHnUnouTMhV1CePbZoA#91REQs|t*MJ%rDEu_jD!w$JzW*^kYpkS=Q^D*#a8k_{g??1{NrHp0c-!j0iu1OBZ5tI7 zoDPt-1UNsuk>Hrr_L}WhB%uZQ#0J2{l7AVojU_0Ja9S9^5tQX%u+=yXy#GpRl(FM2 zQElr#XH8{_mcTBr5G~7OdJFiR*t{fYqyrvtE452EI8GmpiF9)nAsE92T?vi`g(v={ zv?_S3^yOSf=?ZEmC#I3oT(#z;neE}w%G)*J9ChiMRt68evzbU#G9_=lWS>NrVHph^ zMYPx7{$lT8mM?dd3WmDmrop5yl16Q`EvFZ&+Yv>l$WfvZsxOLaEt81m=< z6lc9O5;v`8^z9;=bBQ>SlPiS9IT{wn91)+)QR~`Hr`x1K-1FvIN`Rtz{sN6;HdI@h zj=u8vSYP5M#4t8V{yZjw{V|=0%(i<&(l6IHqI_u(cuWckY8U*`5oW^&JrX!(O`=hS zLldsLA4IgYE{|0?QDQ$DAy*+MnV{*9-u=y3Je9VlSN%uft!Q8$JL`aeg^beXZ^5x7 z*SBc@?}>Ry5zDor4ph_y39eiBULZRvPY=aW(~0a`l#d2Dt1`#^0_j0!5j2mK}i0b5*d;?N)lI9^epCR+IlR8Wv zG^@yri{M49@YrKOWn*MaE>+iRytfGr&$<;3!wYTGxr3>Q=^~=8m@;(g?x=Ryml#1e zVck@lS8F`n@w-ji-KxMw9vctEF<74(lIywZagEJ?e*xMJUm^{+(N0hi8YbCW8uk35 z!ytW-*Ko6WPeWtKJ)U90dPl->J|2UfXiL6dh@UbbwzCgBYTunnrlKCPi+2X;!*0Z7 z<3>`(yyX=6X9@BuzXco9RjKY9?3~HzAT7ZbOuRsTDyYb}Rscug_DN>EP(kZ@B6stn zTxT9J>z9KvS{;FPJkC3dob2lct0bedEEf>-p_*nPsG*`?3b_#cmEYxF~za3!efQbshx;2`z z#I!k~Ic7JI#%LSh*JT&v-i+@U`*Mkx#!UsxTbpbXj%p+uUxr5;C(A$Gi@DEAX*ABO zR_uX_W!e-fb zy$FqHEp1*_9m5eUQ%NMJ59=BbslB;~3zhusS2%{ZC+H{7$PQgMAH6Jj-v=U>l=kJH zIh)STO*Ei5;cdC#y1hQm*0lh6=SK`AT6*CPU=@WEXt|h8)i-Z6bsSrG2b)j65+bS# z$F>F(Wah9I20hRT?Z2kC{gifT9-0gYX552fQS`gf6BdnqPBmsGpb2|#XFxlq3sxcu&-oD3c*SJK6Dz;4TjgsKDU z$USRegFXQ+x3F{hd;pF*R|r#TpCXCqtlm`+Zi9SN(#N^AsQeD5j|Fx5&2?%EfZyHh zvLC!jUfVtQkkbZ458mso`Ha<(DFghF;q0{CuDaR^Ml`{K?yz@qtiqt`ywj3$BUd%C zUb#{E3lEpO#3<8ki|y{h$cX4F-+iL!MnQr3Fu-M{{T%@)2Dp6N`EbJ?g_)t0rXCJw zrUTI}9?CN?yvJw_*$&yro#9WMCbjHG-Pt-SQzW`-^di!JQbZ49k&Af&G`CaM%YHfggtko3& zgAcqFjC!v{Tq}@w30R!u0dIpjOQzW8etp*;6Rhtwc!n81cU0!Xzc0T0rEo_ZlS>05 zg*V1l=s$^>f{PRj=6+CJuvD)c_11UcI!GIKVGSdT6G5WhKe4prKboVn!04@r*f}X+ zAS^VUek9u#x3l`t7ri@i44kQR5~;8)@rGZ0_m*JL2B=a9dzhDueF|xw&H^vEa2DLQ z-wJIE`i)v+a|Q&hV&0z=qi^fDBXya26p)+UaPlkGG4ChmpaOi?1p_+AzPUFctS`cz zMlqB;_9=7jiCH>WH*@BZMrcU^ZVJ83pc^Uz8Sa-Xd0dHpDkLzUA;*X#zX2O$4V3n=8zK5dk!6`y1gBI-J&O6pKDs|!?dpkfC_$PG8yCBmd!6IVvbO=y*d&L) zRyuC)tMa^gv-P75s@EQ34ssXh<^9s8KWpM}Cm74pCU7l-C4k+|EB_>q`>1pySHG^{ z>?J9S^w2Jhoa5&muZns?L@t}*a=WcS>7$Zp*pP-t?rfQKS6&T~O*=6LgyCD*k_)pO-r$9_sR#o59@!Rqpm`G-gZbqcPE6EwtvU2WUB0i?n+BFN!MuK{Bi? zXr778`i=MFj^fl3qWEoy6KAA5LjKV#Qfn=afYvs^Gt;ZYdt2wI-tGi#aD_YsG!v`u z*xUv548e3Q|JczPn%b{PYP>BPe(KbejA%kWBK+|qk?G}$a&?Y1)-;DUT_|g7DC8d; zi@iGgUuQYf=%HM(i^^92F++KHay@*2MIE*C`TJ;9=wSWBDEcYIvk%~Cbl|*XnYG;7 zeG_w)s`;qHdx7{Lb0_P0nO+|RLvZ&5L3arbAuV)RZ`IM}HqzE2I@oW&)f?CPeVsh3QRf^PI4h299`gRpNAe!`7|Y{xsb^q74t7)>g)-cATZFk?gHb%$v_+` z;RQWT!}dSAluieG0)rLv&GkWuV`wB~!FEkBER`{6*qviT+FN3oL}m7n<3HtRad+ub-AlEWN zW!I8#e@L{BVByZyG9;E<*o|GNtQQ|hblCANzQcSZy$Ro`_!R0<2!+h)fs$Y8(PL#q zYf#J^ESJrVz@; z$E|zEy_uD#{u$LJW%;Cq-VTmcR&8ik9XepJV1c8f2)s|U$M>?G*~vc0MEU16aP)jJ z+SbY2&7?!qkUsbzPg&!BNP}=c@|88%-^*)(I=8X!@=$h&IV?t)Q&j)3yp215-gd9C zmas1wB7r|hexQv~8`r)ziI7$@OZbJ9@oREE%|3tJHF7bv#XB`JSB4PFL&xUFY0(y* z)8voFps~ayB8)ASRli?)ZMMPy zo-*NaZhFdlz4;iu#BlcDD{j*+0e+W` zRlS*N_DP4Bk)i#@z4xJzNM~6lpeQ_1j4mvdW@Q$e;IfkRWkTh|;70!n^351o?u|Ro zT|j6xgrP!79+L6WQU=15A;yPPPR1%?p*Au+7RGd}DA5P7_$sG8>itkhS6lfuil1Qx z_mO5?T3JDE5>BG>-sUqRz_>Qf!}QTp?Q;7O%M7H$Oh)z=g`h(lreR1hT8vth2gLYf+w&hnfZ$N@ak zEn*lq5}&{H(7}bRQcTC_n;Pee7KL{onv(?(km0~fN++7)QVYksr&ee{#_$Dawa|h%;*riZ% zA2(rTS=C}!2lw7l#?x6Qz&FNE0;OZNR2zK#8CSe7-x;TFaJa^*0!-w=sHtr7$fqfNKIGlBgUFwPsiEmTeIe8^Ap1z(u`@T=Pc zEK$j~)_iBv&9eCyBqIid;@+XzTjUF(9RAl5Th$si#V@CLd&|z~ZW8_CYK5!FM4ElS z{POYmC3Ne;%A(Zic;>fo5fVlO!GMDzu6Qsoh1ei^D#iCq4VUY`lu>}Fb`}@?vmr5f z(Y>W|k7@dxxXI$Sb4R+8i5KY8U5fkcJF^{b8XNzO3v%y{c*<`bScW^s-KITt@tus@ z<+p06zG^5niWGmAWhV*syqqqB=T*UTU;v{GZ3nT{DX(TJj_)_?Mf- z6guf5N!anwR&pW=N?Qk|}&K|41Lfjsj==YD*@QHD_C5P^@E?dzN(NvcEIPx`H7516YV2j=g zuI4Wc)Pvy{ezdR&RqHdik}3x<*apr~Mn@8`=ume<#pVnW!L~kNy?l}Pn7${GbWep3 z84pp0Y98ldyRtr_{L(UroGl1=rcQQo`uu#W^kpw+@@52#{!vTwDCIN4!(d#$VF+Oc zSNXuO^yPDwZkDVLH!L{JNR?plNPu2vc2LqzkmN9o=BOLTP7T@;77_NaRl`iJRc*I;g@WD9APS0yyuXsCBW)Pw@>lt$|B zAP<<3Nicw=(HL*%ByNkQ^jo5+M}PAkk;OJ1ly;WtH?;I}HOe zm+^GvumDm*$8*BCsYJSgq*519+`s}gz$aUhMFbQ-DqWHCBEX81<>=!SxRtVp%pQq9 zumF?W|IiXE{VtN?i5wNm2gwRCTV=q`U*?ZGt~n}ul<3G;jFc!?Yu}aQ+4OGy>ZB%&UdLNv!o4n&(M9g!)&^)$(S@+DCf)SL&P!6u zb04q0D%u}lLbW(f;joYlZv29+XG~P;DLRIAg~?^>#FvRogK z;Q8JRjWnOCykp9lLGk=bZ6h98{bU^5pQD<3+RjXFnFFhp)p8mGMHQfggz)S=Pvu%2 zpWA-buC~_98n=b&3v>SPEvJJ-Vyji?aQZj`z+sQ@gl^LzbPX{cuBFewL+zr@Y8^jM!=Sht1lKjc^n2o=s*;}bW+ z=rjBa;Hye53Bo4D4_&rAygM8}z{9-l9c4~#Ril3?oU7k9HKO#3d;2@*Z#_uiT~))U z8Vo|$8gZ)tXlS}MN_d&5Jm&e@8?gGiP}DO!5Us!$cO?pdbs6p>Gd&ZJQ2tTDrToNv z44Tf~QR}VbO>h=|K7xFPyfcC195a8M!~{i=JCHxPUu18Pp5iqZ1AC&|qzES2Ga$vb zNVZ`K4Y7mX<;Dd&Gnqjd4^fHPZNxSvt==w+S|;A~Mq zQ8neG3V&F}knRBYN0oDkG{T98)`g6%(K6ij9f?%n=pUUR)#sib!PvyMx1wG^Z9zg0 zQEc%KTax9g6zPuiD;2Y`!Ub-LiZ+Jw$6~iGe_r#|l;U$N(5i_W6NG1kc_6~#J<}e9 z%NAd^ffz5BhOQU8{u3tx&q&4P;$w$Vq8R_arBdEw25tMA$3*a0t94C`FB}OcvqkJ z3IXY$px{%Nq=bbdRIP!rv3Wb!xnks}2OXe)0k6HcxWi!Oe>!I|%=R*jh)ELxRezd; zRlc&jJYA5fWXQ);>duOTbueUQpfTPC zUlhjhYUGNvV2kX}sNrYPIIr#?dY(@eYqX!)Fq9(wGm<08n#%C}K0W9Lhs+^fa)(z_ z7Sc89GikA$hR}>vOSDCCn!#P#^@;M>!`dY$VZYax1x(|6)P$+e1DjX1P*UUQ2sPAG z^;zwOLhtm)#UdzR2>5AM5B?q``PK{HdYPI52>W3_m+g>P6LS7hr_n=y8Mtd0%+o`R zIquhu4`;ME>;;jLalli*Zu&vn2wGIsSpb0;*U<FG1kkTTg*1_xY=qTvI@j?=jWz}syxgQ_F*rArbt!UdEu zP6?Z^T|ax)!(MZd;An z(hEv%xO%u<+t+bNbU=k?DeTsXOBO`2ce6KtW$CqS24LY!^|}wM$6IMOKWPP$K9wP| zLriRR(vodw57(G}g%PEYAHSvn@&I$OSgu}I*ryi3y1oR)KQj|>`ExD}20y8@Togd5|4hk2vmMUF^;6JGg0{`Dg5Z#DHCyP-DTFP(qUH2^0z z+>rRc-9!cn7bRYW(l(x?HL1LHh`RO9EI-^=uc&?;Mkk;u=bVd5SV5RFI5D8Veoh~3 ziSBX>Wa8AtIlWK`PXBjduZAR}n6Fo1n)qJoD;vCV$rx>`i~wc7gJ=7==z@GwwA}qZ z-4LTcSW8L8JA!z|l-$be2B2g9F|0B0o-V$s9j>$uQCbrB{)9E!PO_%lop&wJ(y)kF0y;DdkA4#=r}sZx}!`dO-+660773qJyRi0u7M;pz+AdJeHGj z8hjQYFgv|!R7@}p_-;oyB)!T#D^XG(H_Gf&c7GeeEs&&Hu*#js5qwsgAI3@4_LmOI z@z+Q&z;$5mks`kB$aJSosK-a)NoYrLF5KonV5>1mjqcY+rya^PuRm|lyN~1?$W0Qb zBh&i{yd7GC8R-zrPE3bE)bOi+*;zxC9>TY`nSER68YS1xJh3aU#KpUq84VB3Op_GD z^1Q(KV)1rBW7C(6wsX6p_M{xrxkRW3Xe?O}X&)4gE@31uPTxS(vB(kydq%zq{cl=) zJdWw5N1d3#sW(q)*gQ60U(D1bNJGMdIy;^VppL z_zSJr7~~}rC~-}*98YK8`RqM9mMB6M-JCGRs4Lb)M`xlT<+b-6Ds^&t;SV(5MtLFF zVXdLb+k2X^a`b^GG5xeyIsrhJ@;@v_zw?t1euUEwD{Cc-SyduX&|g?`%A#v*Y4?KE zN!iL*dme!7m4TS>K@iMaAA(IGN}14?Egcu<(-RICtPdhY^cLCCTKtcOYM&$>Qof2 zoBZU1L%rT+q-2nWW%(dvlDnr3Mz308?HV`B(2sH`%oJ(w`&hN8E&aczGR{@0K4an zxWls4?jlj9`w2L=BP$w~EHt{Wq--0GeGa}y$kVp-jjHF412E39oksZv9=+zTF?afo zRt_;9^&LkdfJKQ_j+b9ut{h-zbSuT7`(@{if@{KtIqz%tv0gku#8r9&wCKOgKwAZG%roH+n791|vMhh7ydV#$_%hI)+i0I>{&w9V{|?I zyfqIQ`v`YcE3?<$f+rObqQm8Z-|Wt(q6Fk&U%*MS6fSz-nXMub!|P?io5DG-53w@;NOg^F` zIu^Dq4Fo~?XrA`g;LRBn1SvQSDUY59gKMq<#!=T>t-FUCMM(1(T(-Jd5r3F~)1(vw zN=3yk|KvoyebMjT*Mj5GflZhWVMy{~u_e%rtH%T7Q~Ry?uvzd)u#+-qArECcBP4d* zhFZq$eshF)C+yM{NOV7iu1UpZgImuhWEnZgo-QKwpjz;wRf)mO4c~iVl8Z`+h}}6E zgE6eYLjaD@Gh;2O_>oH8%sWwnfP43+z}HYbyU^?*=h9wyvZdC?o8IZADlccfCcx5Nx)-+x~+5TyI~#hP5+K%{R}@j4LpW8Ew=3A zlxb=OFsu%uyDzzccF>LY;ei1O5h4P8Iim^QUOD3$ef(kW`9^!tFxRnm&U~tn=&?|n zpX!95{SLKMUm`4~9@ZQ?3IkX4(_?OIfn>=d%LugtM6BUtF>zX~QoD^&H?QYMcy z)H18v3D0q0hH_TQG8^|GfkNW57Bld5zI zDfNDFS`o#o&@U&>ddr*D8VojxOl~ZK^le6|1HAYV{zrAhgUu8n>!^EhbO$@JT(F)% z`uL4dme6?qps`bPd8}tSnJb$9m3T2U8!D$90?1=zy;6?uepvDVY?#D?53rMbDIgbN z32O|MN1sWjLZ9=oXo@rUhI=aXME^0$Y5Zd0?t{yV8-(+aeVmk4a+*kmw}f0dl7@IjP-uvba$Izamva7%cR~03~Sn?%jgI z1|^V%uw7T};+2(AbcdW^F4e99>7NG=jM1^DV;cE3-!0(|nk_^!1Kdp$9_kWpq&%bz zZ$J0kM5p{fVFu_?w3l}_Lw%j7h3(#9%H#{&^}e_>DSq$ ztTG2%^vDypsTQ_EznzWD*-G17A;wbF><==zO}y00aL$*6YMLATgAz|h?D1(utHeLw z?D+lwtaMUQ#LfK$(=zE7UX*AT+jkrgC7z%*1>1qH=p0K{EQ5H()djmo_DbawAJaaN z?zmIDb=25$n=m~?iY!R&QCrzw_N8{iXK&|=O(N7`Zmixm9}G?|FmF+FnzE|UzW+WT z0|_@kP}(J>J8YpvBL>Y9_(59E9>fZY#yv$cQgW8%Noui2Sy{YMb497rnmdBMwWE$7 zOPqZgm$tz)e6|+t8RY`c#FoY+m2zqY`oQ}T9KxQ!Dclc|je#&GdBhlsnd%TRF#D_k zF-wRalHb}#iIzksQm3RShj)fXhLKg! zZecpi`%7n&BW0PqdgGf;1?%>Z2;RP<Sd9)h6^c3yV-basK{I16S>crB%P-WsSsmKW2BWK z>4$BCpuO;=?(YCehCI(gF#Ro|nHPEx6cE8HIMxyr&k>EsSN}( z&eL_bb1YXA!N<`(-OfBxtafWR{7llLjL@Kr^|AKX~?({&u_A^v^53|YH4OmT76))yz)+Po)3zH?^U=2-}%E1MZGe=ixUk?Ky zK56WYyU8IZFt*(h=FJMn&GV&qJhJ$HENV7L)S8FyF|d) z(eCa?@X>VaIxq!BwrR8uFg|XQbL;Nmy{vxC69C^bRE?Ol;-kuRKAi}=-PBY6J@)bx z%>O&FkzO#MS_AOrbf#^i*J@rZLb?pOn%)x4c1IImQ%l0Bt^^>hztFwG?ZhAh6jv)X zAjZL|3F}bL(ptXmGLfgJMDA7Ma@*{5ZW51;Jjr?OShtixjYYaqY51ga(q zBg+-l4CF+RY?O=cBvIa`$b2M`^vGJ0C>48U@FwBi?(3)zjv@vD*ZHGxo`=HMUvRJ_ z+mXub0tv`5xx8YE2Y|E;cFK-F1OB*(b&0|nLLkYSnz8`zD{~j!v21o14hT_@|8S8L z+e*KqudLG^%L2j7PzJPRb$i`{fpBRehxTb@$uye>u}*pP=b{3`UM*R21@~0N6M`EP zZP7S4&)3A_N1C#s0g)4(4^^hXO9$vt$BbxJJ>HBRVO($p3;6A}pM&6g&tV|Jw;^z8 zXGSB5C{b6b-ca`G*<%1dK)}Ck4a4xl`5*R8*M$FvPOOXh;(SSjKxsa?k{Oc2SD&%X z&_c0mtlv_r;cO9q+z5Tt{O#NG3*2D6XXr9RWrl^LZ)XK?!L*Wnsm)xmr!}#vgIA2z zF7Ysc9~o|WjM`J2Q1>*9CRDQt5) zqQ&2aw;|w040V?c9Uj-eF%{Jp*)WeXQ^|vs3CGvypS}N?* zi&M_GO}VIPPM{U)3S)SxDRHo)h5e_GIsi2H%*#^EM^IMRuv8v2$&J7sW`O9>IWg%s!V4@ z_rC^yt9vpi)GNSR&1|$!p};;8J?-i*&pQzw#0evga<$k`1U@e?N)^qIV(d}FYhsM? zSAl`Kd|Pq|5#f@4R)p}~7?ozFzeNfy1lB*t&LA#3%Z`XY%XS!0^BN(5d^{gGNTjk@7J_pIj84jsY?;}~v>Fa&=v{rkia9wHy zwfAn|(PN5fH9jGhvV%jfz!b+p+jc!e?bo#?Ma#>z-w!luBdL&~pJ0*5s|94eHmxpq z5N8;?JS{<0csK46xQ%yrsEQx8=7o)f3r(_RWVJ5i8YOXTXI1<9&(Mq99so zL@&XcEquuKw_4}|h$x67_T;OxQzm9|LK6Zh6a8Y)6g19}@+wj=7{OFrvt zevq7?M*R06YxR*Nty6k#mA%vh5gt(vb^SObYFtV^HUw^=CXVh6e*+j!KrlJNdL$@Q z{>~A3P10YvvP8HF9oNPOxhJFd0F@_7DgSA+#l_W-y7~eT+qZDBUD1jWy@w2R{ zqdFf7sF~cr_|RH<2=p5juNy^7;98cRCne+okVo!CFpQ8XRRriEP_eQrsC%{i@rtw- zV6xxMqr7^)WD}e#Alq8ZS07n0Xds{9o86I^_UAEzodn{zT$C9yG>+W7pk$)dw^dnc z)ZL6mT+ffh78HNnG?vVS%@^lITX~!@m359crzGKwLzN^0!FUC57pNBFPDgGZ!fq!x zA63uat)%!M*5K^Lo5S<;Rz&R?PGod3+;NL7{M=Q!?wrAF#Vuvs<-~ICEeuVqUku~O z7Ev8%jLeEx0^)=F(;LY8f}Wl@4vIVHDxgrQ<*G#j$M=|Qnbgv8yYqJ~hKtreU51_` zGhugE~%ou#^>F(7rFncp-QU!wD(OVx|g92PM%pQ zCaq_@0KvV`8wS-h1RXBZEneg!hYHmO4cQCLiOBX@*x2J0AOKA$0DZrJciC24sQ644 z@`wLRbO8Gv@Cwf*>lyA7^(t{ewiNUjjyu~J*+ElJ*B<6EYzhE9Wt z(auIviH~^b=0b64HGSp zpgC`v;#@=yWop+CvzWv2+)}Jh=jQuZrBK-jx1n+;=807tSxU*G6neW{@E3c3&mrZsf37xh&uHXe-wxfC% z(47>)5klH9)_*nhub2qbM?ymYM^AOtktU=cX#`bP2KhHO$B`nC1uGV?k>pRU1i87m zeG^gg*}nXF_6#yeF9zgE2T@59kP1JZ^b<%O8$vrDKV?S8<*O_5dgpYoH%!H@EQj0$ zxKfr7u8pOMeTS)7Z(e9EU!E27iSA%^Aq;nGUrQI9`6OlAxZ_CccJll)M5$c(CLfZV z$!iJ2a_cLt{583Eomn#)aeRfYgmfG3oo4!OX8RzRLp41Z&)l~&4HBCi12u`wapH9^sg6#jS+8gK2v)yrqc}^2 zx>}++C5!aWLAYUlxyJ3eLgmKKF+aV5)Y!j{OuT#Ji6YMCAmIUx&~}6T8tY5sLB*p- zX6&-pK}v*A*@xrV{bh?4hn7?C0*fmPbWV%ks*2xH?OtZxmm2w>Zmi(hhd2sRB?A>j3fzl;gmO6k1Q=oy8oZRz zd@aK2FD3#)HKjRdcMzy+q-nS6GP><71La4e_zP#T_O97|A#;9Tw$Wq!S?sM7cpI4x zwZR=&{JqANMc3vf$86TdNz1rW{Y}+BucB~K(YKwr{Ug3*zJCycnZ4I`W$*9%k%Kf< z4sA@|DMgyP8!B$dLDOZBrtDtYp{bwcmli;A|X zSBK9sx#T_411UcoKZc5%%&hvR$ncUcIhSeEwLC#eL7rr!F~5-@bZTqSu?Y3IF}{ll z?#cv1%jQ4C2@Pg%7vUW z!Zbt>{HhJcHc_1o#I{Py)-R$>)D5-mP5Xw;+Y&J}z59ugSR0!kt(BZGJk}9^4w!l1 zdi4oOQFH;<9UJ_XX!y>_XK%p1IO~ZVra#cDqz!}jGFuA3)9T5kcQ%}KkrKmLS*};6 z%QE3~pebEF&{}XvVbm;K5!wc3Cag#N2{k7zndV^`N%p?=okjdC=Ol(yPWGTZu70pa z$5k9ZIdoNvJ*T;ah)QL`}8a{IyEUQIlBHXI!k7x`14Zy zh09*CrZMfF|NB}pD!k#9XsCgL2HMJHqHCrl++C^Ze40iCg8Fu*EIy5)m#i-uKcwIZ z1+D%!ytCJPIeph)n%#e@yD3APGciRPT&IK{>X&8EES?9Zr*OzxH@?5;BW9SQuy9k4 zdk&@N$)MMOGghFh95ouWfIpb#{FC9u;F=s}Ny@8caH&-gm}WPzO<|4c#IzaID^b|-O&bML4N3jWn>1t=(J7?tL%-8Z> zEe&YO=uEa-s6^3wxQ>Ispvq+cIgVVnOL2nf@*Xj?ZKieiSf`~P-SA7z7hCCa zhXi{=5uCqH7z%(vTxn-U^GEReyyd%P!2h3M*v6o_Xf zH|i47ftuR&-_d)Sob_IK@$Wb5?H}~hqQKX34c<`{YF73tHo_SYS6N2SWLB*5p$4YS zTkfYVrtek{?B#)Ilka09T#KNR4ng>t#6RoJea*3J8^m8S)cok^pr_vVj(LKI+lq z@5_<23T`)tV_@tgW5&3XvzO7@kqo6gKG0ie(QVIrVTgRu*Yj3H_5S9#MAMt(D@|{@ z+}(W!dS?q#G($Tmx&dZAZn^*V1q>d!v5d(OZL*oD5!au;%MVub^rGib)8Ek%Iq>SS zsJF8Provy`C0o69+LbQma0w}oEUwjGuMb-`)A-HVL-muqD{4&0%tbE(^ECLDZuwi* z;H@s;@`=x%sv;l;uhwjyfSjVPMw)jy>PjDM_wz4Sv5@4befaM>=dE}Ag)#*cgNZYD z4jfMVEaHhl?3|zuR^xG^v1seDV$fRBzfSZvO*GxZ%{oQC2Iva7hG0CYxRO|LIb??z z1LDGQHK#AV){oIED#Wd@xx3x&KwhT>MHci14!lxkaEAf1?2UyDW^!ZqK84z-bN&lb zBeh+q)YCa-wzFuc?BWf4SjUoe=U~GOOMd*x{{fZbU5(%RW&mO^8MivQU!H!!vd_RJ z@uQU_q@j`?iTTAih(OFhWT1tX0x2uMdWe)>GII{C4EQg>>QC2%iiSXbs?)iirQSZ=GRO+P1y2d+zZ8g_vKT zz1bU#rdTl?ZUj0eo##c~Hl?asNN|L+#hEi3dMGppDcZUZH-v-;+CJegVkX}1(e@(+XjxGe^(O<+{1d*90_Kq?V6qjX$%D*34Yi@M;scBt73@H5I;kc zNQgB(RYEjvoKOj^{X|y7>`p^&h1#N7=ipbP_6<;UWf4HHbk%nS6OB#lm9Yaar=#rfaf^y>SUJI`3KkRkfO_M#iJ;FxEKceU3+ofGB`t-D%oa5^L-KR}8d zTYSqe{F@R&#}0zWPmSy@#0YjSY=#$<5>jgNWMh=(gDiTpO*{P>U%o6s&w8@kiDU%JDZ<` zH}Q$I(M=Dqjhc?0XEwW`uF~m^}9$# zOgtg5^rrm3(IGrLAQADCzcv`g8-r3S$RP`opT(he2eb%7H8@GgI-u+eX&TVTbajd) zl1)e{@ZziMDGFKt5DeNSx1!I1uu_J!%s4UAPE^AQns?r?U=%}Dxpu8iGm4u~ifjW` zQ>QZr9|()$j6_xvwE$%l6$EGAy#3o=l{$}Y^@-6@n+JH_5pyY6dTATV&i*DBlUPL{ zwunUHr~{$o%rX6;T>dHg4aBpNi7&DUf)FHjY=~^j%FDG>iz!uo4G;pUp|d`EdzEkr zM$*3UNTYz0+yw{QQ)~9yajy8Y)M!lR9_XV zXOaDOs($q59EmF4MMN5Ko3~IRfzoPmaTG6Vx4Kgo)o!PH1kYiLvbY7dehphVdYW~# zmk0sds!bZOldPP;Pzw<9?Xa{5!v9HpLRFAcYmlJAM2*gh?4gpOa<4)@xhmRCushQ7 z94Y?rjDlkDcRBdvW*=9NuMx;5&B?F_Ugt{)2z2$x@6ZH@$yXiTFRsnEHTTqmhO~t{ zz7pn8ow?nQ`|-L#Rm9$DzwDvWDY2M&`BP`~yP|JQoSjZDU-{Sd7Q=NRt(g+&2J~<~ z^i~VCtGza&9KxQI+Z8-ROXyQ&xMPP0YWzn+@lr^Mqq+y{Lx)*AT6|#xCZ&Vj@;~uT( z(9k~{yP8r*Ikxl1m5oGhRxNvgY@jYOno_+w3WRJ2yxhDR0NHrrRa0{sc{)4{VXTht0(^c zctp)iG0Z-n&)O;X?EMK>V$x6iuvrw_Ay9O-nheRAy3U+ zCq3F_nsFk~lyd14E7YPDL%t_HY`)tLZYz@8;GQj@z?4@c)?JW-+JM>_0k9Yy_L;n; zD)v6U^1ayz9#ezHXL%WxhR80KN=EwS%FD~=8L<#vw{}}tR?};t1Lpse{ut$UDd#cq z6YX2MIBat2r2lvnLrY6y*urd?Z|XLI-sA}BDtm3TAPjO8K^Z+cY{Gh^+~jKs5tF!( zF|qY8HOJE$MiLcs$LN5{DJOC!%zaj+HogBqPcy<%p~R^_d_&>c`HjX^Lj-sDf4RwiV#V;#jhb;=)j03|s zYU_$V)aC##B;g?YzUsHDDBOqHRIjx@rofipRp7btJ{m@reOv+xtYYWq46r#gu@7RW zl|yuv2;g*Uui}bQmr@^mh3?yONoA>n>vU|&Y zgln@y7wY6oi)!lizT~Ri)aTUEl4TLjQB_t*OM_FDsL1YpT#W6>cwqeIn8y}3%!wv& zl_Rl$OJooZQe1u2yr`%cd+l75PM%26H|(yfp<%5swACDJZvV<{v;xuX+7?@Ok{~YI z(c_(SQtL|E!n!`eu<3_Hxthtlhq*G)s|)}gjX|gKeuTk1fB!VV#j=FxB8(>S=n3#* z$IDlV;0bXZ9D+~6o45mN7NHY$PR_pnNhHX8&vi_y-(Gbt_+Q&rb173dR@Mt4|9b*{=;l5Lcxh1t%JqTFD+K8Ox)ZRw>2M1R zz?p;HSa|Ti)_5H#A`Ph@k-2${QqvL6W9exwW7>GC`1u+vrq~`i^F{+!;G0OJoKmT? z^zW+nvSx_lE5u8{MFr%M^!~uEkf1T871gB0muUjRtuUi9)_}Qe32O8tKP*3Ebb~rx zJO%2JJ`dtux-aYh5+!SW~2NUcx!j&9X<-MQ(E=AG**s>@8 z;w18sU!8&hLH!CUZ@axOMY2@@n-9ss9Ii7wDrGeVbWC)IqL!slO;|9_)J-!EmaJk{i)2tE)~8#ehJmmx_+LA>B*pj9+>u* ztuhU<)r0II<(}i+hr$DUyv0<)LVgFQMg5v3ugqQxl2|*aak1#C0Dn?`8+@;WDHHau*34O?w$RnVRaLk{|OBAJVX8Zy^NDs-AxWuOl`Wnq%nmB9EMOEAaEsYl&^i9 z?C;wJU_mD94962=2LisYGoQZiKP&+()KFRks9t1c&jsIz@Fj~{)yUc>9oZ`d zucPVrtliDp~E@y$cIPU|7Jv_ z|HP-EnePc-IMwiw;nM6+yJuS8S^8|WL>3TJ?~5VR6;r(Xr0NbYZk^tR5oic|;F8T8 zh7GTD$i_}vS7)f?Px8ESW>htfF20$d04tMMzxTr`b$NrpP-AegVt% z)V~JyJvl!PvNIa>lzhE#K3}e^0A5|G_3ngc8k3ED$4^SkoIhRi(5eZKX)c zZ16OIDQgpl)Qw7-NJ#h2A*4lqu9%K`WQfWj8O(87emD0#g2)ov_8B9A=}wUZEv&@B25NU7aS z!eNtlc;k5)5h z*@y6xvIXZCI6(fS?PA>}cbmuG{R1S}jxEgSnt}8EL!TtM4}S%DY@zNBw&g?*1;zJA zz4K+fAgyAL<)CJ)dX6ku2*x|70E1LGUTNlaN?l`Pp-NeEq zX+=qIdeiiqtiybdx*fBq)=Xz7k=yUxGsbzH|5}&SvkWB#Rl@*zL7@LIOc1$ z8@theZil#cH(2(5H@8+_Y35FHeKVW-)A`fK@Dcc9H! z+Q22p*ap#$Hn@n}lH1b*AJg)V8BQf7EvWVVBO2=qB`i>q8-N4#X#yqGx<$2w83Fbp%QKY?m)h#axf#c$= z9%Y@MaqTXshj~v@E}SH7Ey!%%T*>5SkxY*%rQ7Ta%7ViI@tj|df)W4a!lCJ$|CyBj z#YgcItReEjM=A6ssZ1jxyl2uv4HRSHPiqPFTb}7;mkJD68G+eTem_W3k-A;OY(JDL zo93hI4!mjqh`QyZWOy6YYXz4dbstsHcs2siE|$#v-heAHaa>Wff%RFv5qNcju@J^m zUmdc8Oc?|*Cp*}ymz5_vGoy>%)Z-E=Am#bm&g16WzfRHp@_nzPz~m=clR5bcAoK*x zE+AxfY?@Q-4P$zUcKf?`$ai~H9xf#0Cx&J!o~AT-{|h#2(*vgby6k&AIxbyrsQ>Gj zp!$JMDKsNPAkL2uW>uR`SHg+Zfo9uAi^6#YupXc!Gz}&qjFZDL4cO=HmcWb4Qn@__ z#E;Pr_0M-Weu4>V$p@N07?FQM=H@8FQN{e}gi(KH(_0At!SgDIy)8g$U#kF5M>-_2 zJL!=+V?mMN;`YQosh(C>dJ4Kca>2?MJGH^?0l^@E^YZXq&4~PG>ITY5~7%1P6en&j|6$S5j!T!i{Q7$uzU@ZjsoD)ATLv9RBS) zep*y|@q_lEB{*#IZP6BaEqyAH-XakgT-_U;qodA^qtgYnVZo&ph%Uk#C({4xZyimu zT2TFbYH#CzNhNq@-2y_6swB4>@>D#`k~UG2IxpAP^AjiJ^4=;l9YFS_n{KcGeXpj4 z|L>J3sW-po_!C>mTo(K?9WVKl-|wyS_oRs*eNOvN@`EBcq^a*L5FUCodM@eh8U_K- zE=KUXRBi$a&sXN_%e6#9TCd9qT%e`3%=xM(b=58s= zK5BPK$w=X=DqU)cdfeyg|28p27#VB-&C@`O4r{KLx$h@v>?fo4uQq&<@_MiG8Fa}$Iea5I{Ac8^xVpipe z=dF;i1`y)LV6uw<{Y~wVOV3SoM7v%OVPx}jwZyJHgAqx0 z4wrAaga5VA87`8wtpf4e-G0Uspr#Wp{Q46o0p`OuCI1y8qberhDMZLZhW_`GU5PbP zy%Z#o7ldpDYd2N0OoCdqrgwjVff7(&2;>C{b%6L2bEt`h37UspnkM&J-y6x>Rs9)!y_|lBs|p|6ds1?}%0bT4`-fi|y7S5)#_^Tu$;Qos+Yq zqWSb4t0W=z{TQm%P2k^890bDl(mHtJhprm;n8e!T$B&xz1egpMI8{gBb-WzLXen20 zxsxC7ODoW+Jc?48dE8rl*5^M^)oE=FA#f8Vf+5=+{Pt!^Q*^OFz-oAinJMP71hAFa zOIIS|-(ww)Ib zB>i_4fHqcS1e67`U8^7M7j?;jKVmPRl_VX1PCcbxkhM`Glv80HNA1{F$yO(oYF zGs`rD7QD{m#o}{4t6?L9Bq%eE&FCN2xvYU>w0=rvo5D*_8ZeisfL3_tF#mcstJrn! zTlnC+^nEfyJ3Tt;Wt>(CX>4jFS8Dkk(~Oi0MIeeZ#I!94%qN*ADcZJ6_M!hkgS0n1 zkA=XN2@L*miJG*(`D|zbGww_{9IS=K)04QPB9J+-vO-8Qu{~Z|6OVbm{N}rfP*$@s zqgT>e-z?YQiuAj_ul4jZ8YyO+9Hj8)*rr+^vzP$`htWX#!MJMN44EX%fHY7!zj&lv z$bPeS1m$31i^3AIjq1@{iO83(WHOEjyIK?{*V)4MIa}!kQSB7kHo!|BbdCF?%sSvl z+TnN)y{d(TC=Aw=?)-cAwZT>Z4dCUYUbn3PlgQV(Jw9z-RS2?JpKm7cXGfHu)hcf6 z1FGdm(MbJz3k{tL6Oy^sF*;|?9>bH;&@*%UGLqhM zWdt&p6I$28PW?+V*orr5cHj2fM^eou`Mr8Fsq;~dar83yKPDT0Np8=5V^;R-O5id@ zT1OZ`08y{l@~*noC-#bRgApq`so{f>Zz!}-!WE;ZsalQ?(ln@!^2;$LpMMsTWw@=i z3&UF@ZrMB~kRr1jqpEf?=2K{HQZzlf6gdlWadK;$Rqz*bIbm;SxLz_MBtHX8VYLgUtq04XEyjn|1e`= z?ct9Ii?l7Dj&rTCM?RqSFVHfO3{^rSe&icG)&{7=?PJ8KWud9~!iIo`HSM0xV*YFm z16L9-XXXsdDkrJ723&ruJjOV~Q;s@K+qo@RezRH_;5a>&Q z)L4ID&Jsi2Psl(D?7GV8$z8oJMQk2lHTD!85&skl2WCPp$g)}f8t)qFK)BZ`_+wz^ zc}qSx<^LY}?B*Q4JthgfX;~#y2A9qht{Qx%;V&8i`(;bs0<%B6uYUv!!Mw-3lC;R} zE4qybWbNrcnCI*mK@}$N@4njzZ~Hq<*iv33dnsA#B9a8{U=Y`L?bi_3kuuBcuR&oQ!SAVW`9_xM6g&yV zb2i4=e|MKsk#>H)HJUlSbwOV^h{?`3Q**uE1Zvve{qkK?w;7SpHX|(tQVKD6xk+#8bHP$( zG-2o{pRk)E{dAg5j!7o?VM0AlP^t9aMMRA|4+#u8)o+!kLb%$)y31ZEY$#l=9hE33 z1S+3`X>?ywjo&i5-woD8C5o|SO;_bmyB3@cr|uAl?U^vCJokN^_pu;Vq*da^P7emF zIwS5w>1nHY+@~m%-FyVA<;KgyJIp*kYj`vp#-D!l1Pdvy&-b{n2N56FLFrO!;NYBb zE#z>IVa)e09#|)UV;H>^pq1I%!@W`yxUf3?D;nZZUuRX3t(H?R8K>onc>r|^Xx2R@ zShtSO=PNHsraH}M_OyPZY_}rF8-N`Q$N%5|9)r-7LVD6J0d`v_%Pg%st*AjwqV!3c z4APLOpxT98;`DWn|LCZgfF4al$$w!%_O&zSK z2=*aP8?-KY$~h|zL^vHT| zYgks5@$$N8C=PsJX{}GFd(v$djhG?bx8mlkG@-D*y*jM4dAVDkGk3S~@~6oSzX;Vy z7;jz>Rjp%u!~yMhst`iA`1K4=*7Sz*w9`lT;I7=^DSGdkq@IN%bwaFP&W4lwyRqY#=JIKgw>C#gW+oIIBem?}b zZKy4ow0S$BCc6`GTOLQJs&qVr9N=iPMu7mcusW2zCJBKWV@=$5MjiUH1b43KE}yKH ztpYXaQH5ehcubw3g!4F33#6&(SlXGMGXq*sF?g3vIVDb~htTHYpW>2zS|dsS-!Ytf zua&NlleaVMK7n$E;gp4@OJHe~M$g0@t{fbT7Sjm1qi_$_2Jj>&gp0I<5C*GEbL(V-=K1c1+Cts zdrF67tAOQg=CP-9pE*w1_G$=F{GcSW>Gq3<5e@od;!v;75onRD;xqCKeew{Ojv}n$ zD)!XRe7&9q=~ix`K3dvt&x1^wjAERV9At^I~+}3JzXjWhCfG zphw02+xJ$WNy~H|r90qLP8ME?{f@?OF}vm#ng9ICH-d_+JU)jX&YmvI4+GK8ENJwd z#-4xcw5e)K@rLB-K?t;NAPytQ8$gp$pp29q3%&nxa*aL@?7ihNUNHLgyrRFNu4_SQ zhAMU2D-eUiCDi7A&EQidvGuADgBgiK!Ku8$Bn*hQ4d|s~! z_uk2dH!Uwqh{TZbkdVwJwCaP!eZ7GF>u#(2B|EV+3^BfJD!4iNeqh+@g}$~Ly0RI$ zpAwnsUIm&y_jaWGUcnqQU(rc; z+H?rTt#`}+x#{xMl(VXLkPG^_#$Llzf7)>%vfC3QQ1UMcvpd)PhNQM3`IDvGHE`+R?LPdd;{8)(vek?-uSZy; z7tJ4uZ7V-l@u{OTGv9EVVr1ZJe)i>rkc_`PV`=mv#hMrKEUspK>VeEuO-;6Z$GwlX zZRM}&xAW7i z854dW+kCllB8?vW8MBhHT)Th^1v>ive&#q+SiGNBs45&}8l|YtzH0+L)3p*YLpQ{S zlCGE~;8xL;#GEI!NCc77W1h=~i_A-FtFZ8dhTol@v-}?OD~yB*^lMz_%q7ppEq^N% zj*sl;5+u3Y^=$!-(TEh#^W3;eO7io@A&dJKH@s|ua*wIN3Rw0`*WKn9hutnW0#J%c z`Rs?KqNL33#-Fn^FYVl4-rkC(i-{)dba6~WAa9FdZ|!4 zT~1%L75%ox*rfTn#c#`Y=_P8sMGNd%r|Fmf1{qtm3M#4Fq_<=p)SQPIV9p|aIj|Bw zvZA=5ESTd*koGmEx8xQsDtO{k8WU>%D@J^oWqEWCEA=RA@a!U)*r#R`{WZ1lsQ+r+ zKh0+!h;8qnOF#fbkn)D3h-pm1aC;I?dnfUZw>~B=*yp!n*+1_-9MMA0QP?6T>E8> zq$|7i%G9hS-j1p@0zhXSPUY{iO9jeEp6K1sBMWeu3J6PTQN6(h_M?irtwWJ+miDzpYYO zL_~j^%2l550hc67$5rNJ$_`T;t}|=dx5GVyx;ir&WMxr8IfN4)VQF10QkUE^b{XP@ zudew|TOB0w5@u_?ppK4E*sIUg>;Z_EV;c>{BtXeDWWHr_zE7tiahIiWq8s!F zrOBc$sBL%vO)c+dfYbOM$vwtk2EVLNfIud60_Sih1|1Csm&MQnEi$c2Mh#)hjWjHh zp1{s8!CLd9&5lSP?Fjwo;S0?>>Wa>~lwfgIyn`i$&JY~5h6Jj(;wYUrAsp3{tcpXi5URXjQh96_97-40H|Khq5RuXgj z2{?>1hIUrm-0W&^;IHvCvxnDOA&aAZ4NFtAjbs-Uz=?dc&m1&qh zBAw#MyWsUBQx=Tmq)r_ka_$?29V&AZ-x{D!vY`D?SGg1=ZT+~pbKL=8k!DZM_OI`?%ZKbz^ zz_xIgUdYl2aH7d-Mu;;NVG0K?f%;7R@t_)5YH~j--W0hSUP>q{#>JLjH9;zlUE%{h zIT9i#CbO`A%v6E1xzN3b)FCtWe>p!DE6i1}kqmJ_M?olZCQ{C_%lBsvUHcWGZJj1A zP8qPOV)zPObvbb|uI7&FLe{>!LRBq~518s79AJT^19|5?It- z_tZLzqcaE#HbbrM{X8RG^QD^+Rp6N=I(^gDm%30K6hx1@TRF{(C-o`5bi@pO4WMDn z$01c#!+j!nhVq3PTcu{0AWHI3RmrgQ)nCqOoakmeex(;=(o%ZiQx%If?cPGy3`-tm zo?y}j0;1{sPL^CHbNr|ZRD|6`o|V<+vH)(1?jao$3~MQZ`ZX_tsnI>!G1`4-AS`z6 z#B#s1Qt79#zG9sX;q5Y3JPU!hMrl)ul{HISN2rB}cvu@sd~aa`)IPqj5J?+(mLJ={gvUMl)h-_-*c1EK{^xM|18!2N z(KHv@>RL&n4bKdK0g=i<^upbFp`5|h(t}g8blO#=X7D){8y9u?`)NPs9jz!5$|L7c za~bDWt)A|$fkAL1opYXTs!>SiKeSN)GV>b+BpOvn6_Q{}+^ESf0pO#Z-~QZz^|p@n{dP7!$aL+FB@ z5`{dS5~*apSdpZc5*rcKWdf;_j!&H4d1;17)8}4zFM^fOh={GGJQ?ekI{m-^8UqYA zwGh^bo7$jwjrvwrjuwWmMXSR|Jg;gRPOUkQ=>o-94p3`#!;hDiiI)#+(d;W)&;N#G zOJ%>DEhTnGiJ!u4Oq}eJwB_hTk)5^b9j@!Z=OTsoqIFloig>UTFwE0dzNXk|eEM;XI|FC?d(%5fk5A0I3!raJA zW6!t9LtRdv7eKrzvB&!h zh&rIbvWg=UOw$Ck;lff$467sn28t;6ok;t^iAb_TxyNfx}0WcwuQkTddp zt&vGYtK)n_Ecj)??{JVDRcgf0s>zvgxcl zLgUUtoMVU?j97f)Y^lod5l7c^jN{A7(6JVEaNAz|WYv?;rk7DeMQR~&c7$+&yA;QT zq%0bf9y6~r8+uR2KG84Y++(X%!kV`^qFGw1qw);oso_wQcoj1m5gwTG;`->Bvcd6Y zU!&PuKl}B&g?mat`!4V+Ira9b)}ksmCi4fzh#F#m|5`Nf{=$63j+vG8*iUVCPF54h z7pX{pfzWp{IuD^i$?nRp)xj;#9u_sMiEK!WTmXWxuWPk)P$jqgkv~#wzJLzXrDj0} z_k$Lg%%iKM2zulHq%qUGhG9kwcQlV=wNX|w7N){IXP%9S+G@ZI5zHWG5tDV&W7u9( z)?X`aG7D)7z!55uoA*V>;O6%=F2L z81MIZuhc@vty_X`W15D))iuZR0|jzY)U}p%{R8fm3W=fWoq1t}D)6hDc<%lD0f(c(Q|hl!*W!+*l--lY7B%cfZ6WJg+APYaPTGR~ zL!M&<1-x3*MomYo11d+Z;LYV7n>7;XA&KRjJx-SnGAnJ<{8gauF8{ZjHvjndoeFNPu9>mucLUY-uOAj}7^fd)(L@O>KP3YC@PL9|A@X%aHGS`a?VE+}n+?U}gnHxU zWX@NIjKyBkw0@)mZQQ+X%1On40IReg=-kNwCt>~N08#OWEhM^YVf6Z}m%yq91=K;+Z-R^Wm-{lsz(KwJ`^jfBvAUj8UVA5r4&K?U5kY2f2w`?SP zAXhRB3vE%HB4?WNvE^Rl>H?lasXF85vtRIUTz>wx&$)WXse4yxSE12iP5%k&BK0=e zPej7m|L|K+;x-!{U=0QF|9R(F-LSNQkkV*}MiMY2JsR;Y_4p+-F%ISM46r@6BC^dH`Y;G277#C3bhdgBXjkj{A@nQjgw-H)$ID7fKlv+;hw((uB z&rg~B+x!yz)JW{(^kkE{BPxn%_BBxw3DK_p?SFQ)?>(w;POd1^l3Y(|)=z}X-bfZP zb?FYyMr&7>Lg%a`rKz5?NcNim^9c`1d4c!Y&BCq}A{++;kfjHIlVU5sjK)<^7o)d_ zePmVwu&CA0j@gQkbg1cfF_;wM2E8jQ1wvNMq*e8t8OYG5XJO4O;suE=Qc;6HZf@qC zOak@&&O%h%5w16T*djV3xpL>c;kE`}Ycjn5Miimmc)+lLb{U#3uN`%Z3L)g_8(%nA zEtY+`;TA;VC8J|EQLIx4g>a};`Q%_8XcuyAf5S7aCDBVIL-i$AGyL#J^t!JdP?*HMK4F{!d(t2 z*!ghmJzMo#2W*wvEZdBm;0X~otJMA%6X~`@_Ee#XPJU3EPTuRc4fpX7yMOPa#+mCE z1UlD%L$UX#1U(QB^NN)65|OosYphPG(Tsvt7$?W;*e9+=@DSy=^xR>4-~T;O?YU$E zVJhfN&b-(X?qvx7M3N*Xl5c<4C1gRc2tRx)aBfe+uS5vxbz;TFSSyXn{rIi8;7z4% zAB7OQ9qrxH!P+xZfs)2iDqfZia)Lrn&edu;Acm^P9||q17cov`DDuC!@w|03m|)8? zRczBhEDza7l01;9ZF>Hb!2@tZYi)x56u)dC@yjKpLrVlyb1bSLq+J@1(8X8bs?M?E zgI6`EruXfEW>yL*q+4igh!yk9Vf%7MUAAdi{-_@3znji$zzDo)s%)1eHmHNE&?>XI$RmjmcGYyy+hE`-0LlspI69eeTh2!}zy; zp};HT_^a2LE$om~B8ME_iv`RX(^a%B^G&Oi*cJES6eya5rFOGH8O^wR8)U9_YZd_l zTZ=FQEBKcqs$c7QnIQP5G8V&SF{Pb-uav|=3UjL)_fyhb@X6Nd4Y~;Ccd3Y2Eg_vW z648qHo*?|W-w9- zJ0#~)Spdf6zpZCIbf{wn41oDv!2zTNEB#gRe z7q8pUdS}MOpKaWHmbmQbrMhkSR_XZkbCSlp){POGT;LJjcN{z5D_+w)V}5Gcl0yj* ztrb0S%qf1bIw{1g{b0U$!<4m!|NQLJ+ zkH@UGNi!Y>vLgM(!uZg;Qg5x#m~JI*M*FyK(rFIpo@~=^o;(tryNS@B;~TfazS?%U^majty79 zKkpwk*xq$v{t19p#LEx;bqn_tkdBVN57{D{ITYRHl}+3a+~ve{W?l7(+<|rdbu5cs z2m>zq=ILM*KSuIDSRAJwyh!9P+blB$)hsvOrfehtjN!0ZaS7Zjw-;vJz!K=&_ZxsK zo*UTdQzsC4+Ghc$4yvw%tFh-6l$RkQTT-})RU4!7T8H>2=Cn@quL>}+*qq7QO~ffD zIytCLWMWExwGZ?h{HiCyDh&2dy$y1b%Lj-QIP85Lsk50!O#7(ZQ@O}~u5YGWdXJ5l zM3HJy;k)Ghsh|TY;EhUnrQ5(0u+xHt!*vbB7kNv^2L*}oj3N@AfqI0FtK>+Ti4+)R zPHK`&@xtA*D_SNhZPS07eJGJl@@>S=jm{i-PAB8=k+U3ff?$EvZC7r{r)zE%iXyfD zk{1Uwj%-DNCxo;d?{z)Lsz07>?43G(z7`+Za*AeiVJA%|IFAP?l5pB@pDTihbhoBM zwW<>6bML@oPu}NbkB&1Z)A>RxBaL&*Oq)YHW~$cCVea#Z&UIGO;$}-F!N#s~T1RL; zyJKQohj-?6OoEVeBq&=1n6+z;Q-hq7z3tu-b2Cl|%KTAzvaG$TBazTyJRy4;6 z$!pup_)ly1tw@!ZLm6X=^h{CVi{kx;OE6VE>#VvD3|Vd2R*Oo-ZiqPRPiWkG>(hdQ zx950p5WlKq$ZVWvyY^FhbCG_~pz1)*?nu)&J2ieorx`-SqP)x!E%~8!e}Px`;|b`U z@@*Vk?|9+GQ8&Q6dm__-|3us~)tt^aN$DF5)77DU?cTVjamz74pl6Z3d?NR03V&h+ z5@+$$trxS+TLB8N&el@7%GQ$kQ|SVCKbt5nrZ@>{zsxkYk-*ATX=%+*MdHonBGffT zm>P3vieMy_^mQ3C_?XrCFY@cu>u!65BGOF1`L(u&NI!K3Z2@36FA13&lhoS}3T}QW zCu&*x2uD=VaAA5RrrJx(M$RFDTX4yF1rs6RE>TL>auMw4E93ka24yf(J)B)%of|Vf zZV=;ga!uAF!-BPPQNZN*AJK;EMlW=aYXQ0l@v2*q${(-Do_PT=X8HRps{2ok&!2vu z_?AM!DiruHb$I3MZJ5U=Fr!D7v`@umHql` zEdi)OKb&t)&;41c508d}+H{0AUa8Ttud8SOU>zd{i(5E!LCHmS4+|;!RuG_z+jGAa zPwN=0dx15Nt8xDN2MM?_;xjM%4+(;!@1*lCQ}B6q=Jbz75KtGJ@@>QL1G8;9db-7X z+r7MkxAR+~FjrJGRN8wphyf&$N+>;LA=8TxIO7|d4Bm>heb6FKoWD$AL;Es~=%wGo z=!WIxX#B{XPlr7DYWE@^-Z)g|O6^MCu%D7V#Yf)4RbXt7O7f zF?<*E5{J_t{Pw#kH3m&vTF4_`oo-B|k?Dw6?E~O|3Uy8go6Mt6S3He(pz-7Bpk4~~ zrr|9vXu9E-K#nlJ(G9vlOFL;f8ws&-KuY#^g>|(MK6q_2hNGBNCZ5ORS0nQ$b7-%% z+oa7+EGSq>O8)#^-Je$X4-xjpnaWnnmQ{vQy5;Vb+S#w6KWT&f z)@3K=4-KxwvM;I{tA2tOIXqvDE=wlkk4`GMOP$II^*4bTx_vP9ah^?K{jj&is{lNv z%5;)JR*@|>r&d8g?6Srzz{E8#t+sczYI&Vm_-8Tq@b%W2{zd}5h0?P=Or&zO&g z#QP-kXb)8(XZ+UN>*=!f|H5GU>jyCt+>O=B{jn-~^RsMHHD(?|zh@=J~c2&(mtF(D~=syA_8SCt0xlOHTN22MEZ6kd5*znPuVN`JQWhVKE(0?q%9+7Hsml3MQs zYPxhTa!%w9Iu#S2MCrRnqO@2X>j7`z_3=JbX1j?t=o4jW9ZvbC*uL!?r09^N77Ft4 zQ@_2{7;#EPDC}u)#RG1Lhz0Sj0!dzS^GYVXS^6qBfH^G$uE|a9m5(%*)YI_=2^vfP zL>(V^3QPg#3uo)Dor<*#rxryE_kQ*J8u4HO+?S)OZ=sH^>K0?Kwhc*C&7Sbx6l$dM zg8g{^etHbR);x=B^#iKcwX{l3feM~v0|rUE*S*PDE|?yN5^lTe2k-V8wqjnb{i6Bc z$q%3{F`27OR6ih-=4);#R6~D}z6Aql@O-=(0Ak05*OtcoW^-Ko(P}r6E^BDRu~SMR z&=DZ`PAL}dF2Akzo#8Q2C74Ma1Hj_%?1_e^u6OFSdz=*!%297fiSPXJihBdk7CUlWfSZj%n93QoS`~n&b&rLSm=QAdZ^A=Kk29SyR;duST~fSzrm3 z9a_Q=@sclJP93$on@=@#8RU7jr!+^JM@#Vw?aPU!dQYJ>P%(QsM>b-ZC^}!0v%}jfI)h(O$5(l9uC?-%RTnqxa+fhK`Aaa(w zGutoV@wqd*B^S8qO%VO!nUAXpES=%&G)HCBJ9BFg&`@#FBF(UcXK6Ak8X-P^p};ro zz7FuFPedl6-S5CnX$D?;l6AAqLL;sYT( zRp9l2v`=+0GuNMwwk*a*SNU3Z_rz~+8U$MxEJSc7a@X?qO|WSPRKr2^W&nW@qex9%$crbRS#pRp@|>Nn{>y0g!hmU|$Me zLKD3;&vL7X+n7k{K%6Hh*^9P9aUfps&f|xR6F^@stLrNMgl1gOC6E2?nSQfH(tp2v zENA`Pi%s3meUS>mmKB7DD-4~SX#cDb(Dst1PlhRhWYf^Zje$UgpVR_T+u`@Mdn2M#kxL+ZXo z>Ge3)4B-h*PD{UB_!b#+kQ5JEe1E&!mg3xAuF0TLK7);MU%;GH-l-_MH(DxPR^edY zq3y2hHmjh#DdgyLOuN0;`1-@2f2s3Qfa#!5L(<=oY}WU5iJtXQ9BjT5L~>U)ZnHK= zPiEwfsVVW)NTyi8;vwKLeRjr8a-!_m7*kokRfvpBA?&35pJG@>Xoz=&yyLeSV7nDH zo1!X}S+S&_dUlSPik?87o{s2pyD9DMh+Y&o^(^oSVu@#jD&=T>p{iXtrju1#C0=22+^?TCUM2 zP?YR1@TF3ur$Hs(|1uzhHbJ=^C zt**m)xQxl5LQudUUyI_r?|dP^y&xeEnf-VBe;*_tT-Vq0rW2RLR2t456XFpe8&(p^ zZ&4pJx%a?j@zd-?;Y^3ut%*4}?^DzzQhO{yBu{L{a;6|m+oP5JIC&2$->W4hliv23KMZwrniNX)K=FRqT2c+-FA8>qKWS${V`qpLG5kE18qnZF20 z$Jq%?X|NDBTTD#?eg%(VLwdEl=Buhy`sgNr5iiaBu%o!=cJV8EC5RgMS7qoH+nx~N z`}>cdD0!j+%OQ_ci>zdZ0^e>G5#PEL+I^f*z1r;)vuoP>V=DZ%)Qzmo`-e#{god1< zGe(QS6Ozd|;D_+^w>ZL4328PX0o;nM61~@qr(u}LS z+XEeiym6teY@E4czHuaT4|^RvSc!w+qsJfiXfhtPyuvu7r!bY3&3nR)E^D=cq#qb$ z*HwtHqAHd0;`x0_GdQZcE@ijK~uJ-dLGX6n$y_u`UY@AOFAF% zgfoaagOc>xy!NAw-P?!BY)EMM^xNZ=dwUW>w6C6%0)wsuecrp;yoyW2KI`SClCo|j z|6im?NVHHwX1}BTt|eDxx!F3GH6P@(Zrr*>PPXV10hoHP575sONEB1*!l`-#nlQ<8 zVtxkB!r3#AnQ##Q3XlR*Rmia4^Rjmrpd&L{B;WNt=dS(lf5Gd`Uic%#p`D@2hWdrF zNk}UMoKJSA;2Fe64xM132IOD4uvrBG7$rHq9iklPJa48W!=4 zpEdz1g|4`Y=1sI+0%yy#g{VkSsdoMPeZnb=-~=Fw%AN{3g5q2DV$mxM+H1aH8%$(~ z?o>AC3c8ITeKH=?{sdWg`w&_(>Hgb8a#(uYw}kOg+AX@c6n)4IZt={k(VNAh7Pv*On%s5{$)w2{BO(oR{PrtQ(72tty=s5RHJa%=l9SB#{@of4*%Iub{1yRtM zLN(z!xNK;O6>y34rT9i_UaUlYLO|D+9_ z1E8Q2gzJlL2u)@y@EF#=EA4WNPs$(aepo6tHe`>`hhOrMbX@b9nhach9yCqT)UsmB zqf{NDoHQ$<$INf5RyLhBH*&jH((&^ehWmbmWkS-aiN0dbU!IQI2I!STK4JN6Pvnre zlTo?@TrnmDbx!5nmq9IQM+Xe>OmLYm^*%3)3u)c0EyWs^fZrl*zV6-IfIK0Q9^G5Ha9=)F1Es z8Q^!ZNv)^dXMBfn$QuITtfu<%qWmf}R;NQ#7T=@-JsqU`dB8-+dC<3ktrP_V5sDE+ zH6|8A;aRfz*`nv$m@X&LV8R)qQo&U2VopH}gJM;dekUW8NUyq3JvrbNp1^f^^w$AA zZNO~21pbM6n?7$}?iQtFk~$EHJN|V11;)TR(GsLpofPS1(tdnu`Q*2+fWhArN?+he zu+*4BZ(iHMqH9a&7K5k}_hp_iM)8?sz@qYE0I$7~g_*K#;8FHDHO+K{NcI-kRWP<) zz-_7~K(1)fZggPQH88{+;C&#UnU3AG0E08WfJano0jktJLNo5nJXYaIVs(tm9XVaE znSVe)O2Sg6e?qA8>`UP#FJlq`KL>WEG-3~QCHA@))8)!GF(ls4X{J(`i{K2hv3JOj zK4cK>FHtd?-Wb=+2C01bu9bprvM0v*y>y?^{tL*6_DF-wp2-1wmtO~Q%n4?%@rPwr z6JGPW)^zgJFFL2ZX59cZkZetZa7)4hlPc+#=*?s!S%YWsNhfAVw~s5i)wWnO@eD=# z9B3U%rw4<55C4x+G5DADF5y??AJ@e1Rs8y-cTE53|XzMkMHqN=VM|ohWgH+!v-BggZl+0raW_coQu& zb@?pXX=f+LC7TqFJ|07*ZsGiiIfA(;Y$lJwI#OPc7$RUGShYoZC41b~h9}p5b~8!p z)A6R#YZn*^f;-fCLkN)pDHM>IIJ@0kFxn`F;ZZtssy=RW6Gadq+As7&gdkWIPw+{- zsaI(-DnHnD4Dm_jN^*w8m4jZlmCL-Q5r6bThsBW(y_;XGKJI@ots$^kx~#MkSDIrA zbt+ zx`|SUp+n(Q+?eH|x_2zi{nu)Wb_D3ZPZE!H0c336ml!DqVF>25b$A^;Z3gb zh1Z!bKjllf+5*nc_DX-3gWALs$Ly5Jf)P!%Z`F^%-!VS}*nDbIHbGz(CUf6q6tu}U z-~rA&_7gSIE%!p9iOP~NAL87XWXLC(x2VAPs~Rq=*rL97v2+Roin~g*o0Oajc5^d*+vhwY`Q=!9!|cvwf7A|Hs73H`5!H`h%VXjipCmH zJw+tYqHn&&O&SpBzRU4g#Z^q(*FQSnqPQL$7cniy#TJV#>5e9{lM$#35$!b*r<&mt zlW2}r49~J5P)8OHF<%y0A|Ya?Eg1ct8~NAf%hrJX#WWT0`H|HKK`W6#T<+lWTB3sGZAvd~}P@)LQsI~T8h{rh5Gg)fjEe15>3 z0F3JpYY1am(cv-z?mv0x8Z5$kp_$Tkum$mJYm!*Rm<8B@u!th6Cgf9`VL-?Gh`>r7 z3U^0{hj<&9hpmwE+&cP~h^f4|7T&S}**_1vgC4MTJ81KNM5y<3^?E$C#IUcj=YY-@ zy9(70S~fAKS8E*+B5+-Vakt4TBINrMMe@PR`sw4f_M2fBM=Edt?DYRybXS1}{>$qX z#^S$oSB6t$n&nf2o$cP&ZvSH~ybfFq{9F2yn5!rji$l9TSOeVO=+oOkiJ*pCD2rmE z6o8*AO>kfa6n)3TTEJq`C+8>aw=o?2Pgy2Ak*@;wFx^gkW}fBcOc1(J>qPgqUYMjJ zRq4&73em1)o6pb1J-&L-hLzqH#}24oN5hH+edVn8VGHJ8t1lPo*2 zHfO7d{d_h(`m$r-0*W}n)~WIGozw^PXy=>Wzq^DnA%A~ttet8tgrkZPbK~TEuagTP z0fv9`dGTyEB|eRs3r`L=2cn$#tgkhb#=zn|KxXzFzS(t>udRdfiI)gjVS{zmGvrR+ zFt&A2l_B(ZHIK6(D!>PdeMdn{xhC{2j-y%rA-M2d8N@>@uI1oeL6Fy{+B}90Mmp40 zxNg25&;ta(VuB@gfqdS!gC7hkSa2wF_YdtgD@G2`y<&BibBotWjRBuA>22)-$5;yX zf)1Pa-Rk<6`qC#?&zsgpZ)p_Mf}nntVyAN?RWa66E@;tVoi--uFMn--oRb|sdME1$ z{#XzA;2OUSNRL~Zh%~}O?yQHJhV_#7`b=UgPe|b_WVT{Y1sdPkm)eH>h%lBZPQF~- zNo}{qRafIxBLnUfK8iYyALx9S?cR?c(#MXv7=E?XRVBOq?O&CbA^mV?&5ooF6+nUUTNNk3%)XU##M$|jrFcYt z6y;Ckq~#1cx{O*K+U`mNRb664{hKY>T_93qwzA)zgAomvsZMz~@gGcbSq#(cEG?UR zSB#@}=!~ChC@(SpZZ3>3w1q+UH3Yv1PfgM zBT*EYi&FQ^Shtac>1ieSL;*%4H@^o`>!}vumMzN061Y$pXqSD6k|)Bq7zhWzIw@hl zf8S1It^vtQMm-9wQ21@2>2-NaZ?SNrV*=4k5>Y^cZo_&0Y0B?tf>jSP4)nocI_pU0 zj=0OggE$n9K2{apoEYdQb#&UfJ%_3>Wju-beHq^T{Z15#rHq*iQ zO@wXa7_x8jFoIrNN~dyvbLwDP-ml$qw=>F9dK1X%vf!UJ!FT(qtu{UE7P5(pezJ#` zfxq!-8bDjQL05+Y;S;@eaA@3qcd%5HMMzD3sRz?eD2(O<n z?w8R}WU4)Mwul)TokFtavJ7DOecP&hC<5*uvU-5Y@48I{6p_xlwlU_l87*YZ03K#^ zXUo4?HIV4In=OPDE6TgFt`AQvTEgx~v-1F1ej>1k<4$O4=Y|(XITp9_>vYb%%L0C4 zkQ>hx(yK=p(YADfkY;jDpH`!mPld*X?tD&sr(()K9TLVIoKC+Ijrm?(JWglrXn~#I z6G;_c;=j*GtVw+yneM3<-TUrl_Y5&gjZ9oN6lz8xSbssNLwhc|3HRX?XOtq+q#!S0 z;+t5jT-=DL9nK4{IM_D|$H@V64)0H}xi3SfB9GSUY<+y_yyK}e^9k*v{}edab0~5gdy{jIKxZ!3ygIiMuuMoV+sYQ zHGpn8nP^NY-}8TkLj@XC0pxeUJr2?h2LsAv|K2BDyftr~*$5eY#eB|NDasG?r?lVnlhJECx3%n>}r3_;oXXkZ*_cvz{ zSucj)gKdM&(iK35ZZ{kWF(b?*t0NC{rA8K^b2%OxtyfKoY3Je%=16__^MJOHG`H$V zAVIe3B1%=oJ`ni0G(-t z;0BhcufIXlTMC6tIBxJc0T(?3)w}nZ(h<&hf9}3$$oNQtBx84|fqKOryyKbY&;0Y! zPS{%D6L}uN#I18xK`hlSYk?c?0`OuOF@PPl7$GoTA&aQ$SW4B~{O+QkhrjPki*5&` z&I@10!PBu0z?BbH1%=S`mm{kf<;ESv{pJ{A=CyF+w5oRIZeuTPA(3Vkxt%-sFZ7i|S`r%L7I_>|Z zdR#qsSbd{z>D`DxDGFv*G&SPHx8jt&GtMGhLsY=Aq*+(%3%Ezh%MtbD>S&DJoH#}k zC|R-$J+6(+2dd714AbtG!oj3TUYS)%F}DykvTe1co2F9xnwm>at0<9%C4} zTyd7#UDT9O1Ovsh0mhDHg85IRTmPpi2K?XmMp!N-B`d7ZjtT5*38b;d1+NH!I|JCV&4sq8*b*xv`J=aRouGxWS_BT>-I(V*33#XeZCr_?!yhl3R zCX8Zy?=kJ$DcAXN*Mzm)f^l$8?dhpVgQFUY7@_LzE7>kdhqeuRYEkyH`+)c1`>7fc zBI```aB#<*t@_}MwIIi+w($b}NbW4sVkY9(_;4b2%cj|ou-pOs2)N?z;@R~x>>Lqzmd-W$8jM*Uu)L(petd9r7f z#qeUwD;`jiTQrQx%w8iVjMa7X)uSTq!Sht;t?EVTqW8LW&Y(#iQb|MMu5Nl{sD(0}h3O8#3ksz+Nk0sqbYmLaoM%LP9u z0~y%2ZsB|r{xDcQ96YG_0M;fEvG`V`H&nx?yFPK=s3#!xQPGYgei0R@Dh)*kM&Tck zr#$UiBzL%|J?q_yN9{0;2A=w01m!{4ytD%Byqmg1_;5?X; zyhPX(Q;<#_ZkSl~^jAfB&tgGUkN|GrDpa>h59{v)aMTy`d{*3ti+sMj*PLc4x z9GpaG0}m;c{LjXY`rw!pv9R&EzZbB@LV`zZDhM@dxTM3~|9LowcKx4GRSUESFtfPi z)G*6wWvv{qcJe7om%vid-YhQ@C4@Nu^@Esbny>GWoRyEZH+h}>hv&Q}>@=SLVhqc1 zbe=Kac3W__JPLyyrb$s!2d-JfX4l1?F&2xe(am4DpBWgCrqN zeC4r!S~o^is4Gnqd-0TAjrf}L-DB;kM?_nAA$pZnXK5ILQUKBNWtsb(J<^Iq&QW)? z8WkUtUn7%ClUUc8NgLArMj0DERdLR%cjodQBBep3shd&=Kya&@DEnl@TDs zbF(_X&5q!u$9cU@H@C#UF(-&)?c-muW~0}$cRh%ju1Q)RsyQLIfRUK-Hc2*S??iTN z7MZk-P^k-6Gy4E$m_Pn#{ayRMd5|~`SJ9m{ueWHMKJS^=<$BB8?9ZuHagcGL$Dfh* zK#{EhHzW6JCQBME2W0gcDLkZvm1U2C*oJZyLAl z$AgM=be1|g`Y|qosKgr1a3Bk~Y=;3hP|^$#7+sNj)ONV(4i^U$l}C-F&J@YcYWwVb z#b_{gh>rN1Po*;Mf7xXg0eB6JUt#bo1O(Q0V3Ni08S4IchyR{EY8mxWi=!8t*Aae@ z@ucQ1=m4lFqrktu7Uj)wu;sD`gr4&SW{(T)tz7JU>?ME?+x}5UIbEU1iv`)BwtxIP zn52~>KvpavN*lbUH(l(-i-m3@@-J53h(V2lE~-6%%`QXxOjoGw9SJ5}jBpukxKV6v z=QRwfQN;&rq`@m#jn+VB&hhZLSP@k4usj6p9`egw>pQ84-A{p0j6mJc!X0)N5xR4d z1uNU)L^8TV4vRY1dr_9+N8^fSHP38>)$5_B>M6Bh4t9~0=8$O|mGKU`2~L17729X^ z-BVZ{`zh)ewR>5Ah&t_Q*u_mcbIMdEiJrG9KyK5 zuf&5JQo^pgTsm|el6YArk@~LkLoTK;$vtz&jxMTRQT1#_p=a&Z0})4^8TYNAry8V} z1;o%ry{s+G3FRp$7$8om@+nkeyOa|%%7xn9Qm?XdNQGa89Sy(QfgL9s(4lDDiH)u+pPLTr!Bhh zR;J7e88mrw#STV;%gKJ_bccwS*R*F@$eOAj*+tP86 z_JXdTf;4srhbPLFa-5I$fd~o2!&NwG*iJP5yZD@u!s zP1WInML^#*lkb94yP`XdPje^KGEasE)P3H7jRg`ja(dd=qMye57d1PKG4SfMzOxoe zJoSRX3^&L`yWc)Br`j2Vmj!v7O57_j>FTwb@Dy4IfK<7O^At>_Zb4ye=sh~IJ z&ps7$jGh@j!19kG*<&xVjIWxd+^KrP<{3QD53*JERuTn{&k{g@y(m9c}jQ+YYlz2vmQf?44<;f{$zo=tKGYir+n7GQ$lOgXB)oF12sUza@&RHwC zmGsGn)f-xUL?8jix>x+LdDEh=RRhmjsD`61tW6FVqD=Sn@C<)QPyx}BSiV|Mp~ABRz{$lP%gb!>c7(v)97W2aNhZT`f9ioO-Uhbx9&1e zNT0qDOPXl>L&eh-3qa+PR%qYhloxGXMhc8dF|fVm$G=$36#$&yd{Ky`(A8ZT^In%(}?3mqf!h%G*Jiy z0+WNg(n^dXr$hc1GkGlb+k@bnO?t!Yg2zDoh_KuFlnJ!X?BwUX021JN;XVoJDMK>W zhQ<66+5Ur5c1R|n!+8%aUEe^(`-y%bO*8g(QDnQVpKEdA9f>%0Q`LT+^&Dll5h`*vMoNC=7UhWKnKYgW5i(64}~ zW|Wh7v!A~qq63y$ik>#hs^!8J%@-PG+2B!*WmF>mEIESE)(e4NN0gA_BB-aNg(p#{@?EbEHv{NSd3 zmwNlMV2L)oC7&ZNl)k;rv1R9V62phPHrZ!Tf=?d&3Z1dFKOhh6#-o7XN%f7tWORWZ zJ9uz`bXgIo(^y4tntbfW8Bxnip|_i1c+&~W4)hl6OOwfJ#& za?)JEJtR*nn)lQ_f&|_g0#c@8iTR>YFu<`P<8xpQt!mO*F^gMh7bE$4{dTmsSx#}b zv{8vxNt?1e(d{fMW&Qw0wlfvmP-A(vnBsR=9!pAuciksymI5<^mQslm^vd(4-Iu3r zL$Y%IUnL&Y8Z7bDi(CnM-I8HA3E^8Q+SU5d)Z2(bj4z0~0RuR3159MwIKG3;RAFHf z3}5IsO(x`fpFzdvs`Cy3gz9m4p$OCk#0em_EKp zcdQi4=%M`|uuI$I*rGJiuQ*r1Jj-xfPtV6sEeQ#GsKBbsCO<;{hvjI15(2yp_$Ici zOu#DNkFZI({so7G?S`35{n`ug{1Rxf6t~K3u3hGkD71jkDaCHyosjMQIsRl}u8`tZ zA_>L(OPODKw*~R1>cHuZ<$~WlHtUX>6wgJOg`Q z)3oP|Z-i-|Ge%xpPZpx{;GKQbfq{p5=qGi#K$-M0I~chL%x-`2!N5#7aHxP;+@3E@ z)@Hv2fR4mEJ57t%f%$QS@8y7t%rEqTILcIVvbJQz`vsz5NjER${5AR8_5hn8hp6=% zZjdy|{s5~2{*}La3wy#FsZFMVF@n2cp?S>aOvqku{54J(mS7Q-k5$~EGsxyzg<|Lf zIM5+pt~EP#5o`divt{>fxTxZl`Y5K5ShJ*4v&vb3^#~9=>92MjFXMOG+^(TS=7}lf zW$!$uf>!ybC!wvb)2J+guZqh5p+2(u7;k&=UK{m>&xpVdSdR%{1oybsimuwvTDSo{ zik(GE!kSCp6RNU$`6GBIrG`K@oN+~D+Jd^mCzh#td#wTT5CD7%m} z`9WFFGl6Bs3|eR2L_CURc}gJ)m#e8|JKwb?BkkV)XZiIGtN16H365?&QUBnLN+)4U~KMaTn4&<+uHz18EEAwKYI?>|pr?W2E{`x*T7K;Pne3yGFpe3pbD zw~*;qUZ*%VnuNGcW|rIwybQs_wwCljA?*Gb8}52MUi1Fw4~!EFw3-C0`X)nNQ1a75 z1w_g?+5Zlf-g94AD&O)O;~HY78@EMH63*Q+GjotN@E`)Kq5bVs65W3~0Zt@wR7)lCZ|tf>?w6 z)YCV#Xxp6KmLv5W3Pu1ObjPqd?L8pLWQwRebP@qOpqC4q1DkJTAmKemyi3Ax-i1J` zGi&F?f6%(e^%U&0kVNOqdwPubj*u^V9|DJ#4Cc>{Q}~*DDw-H_weY5&`MWD;_g&Oh zzaD`SH0wQ~6Zb%{=YDbXGehba4*}F}e7Hxj-gKTwk5mr^H#x422PN;;a20oSX>~c4 z0@7TVr3j&XZ!F`6Q$jjEZ1oax)(NJy(;fc%r|z7x<~0ZjVORtncNe4X2f4+E$5qAa zpR3;ntk1^yzT{4T4{+GLrw*VIy*#s?zX={rp|{)Z@&eKr;|x4ps>;RT03g~_SblN) zGJ^;mpjM1)_mMG|MVcgn#gYXO`!xH|Gkd}!X|A560l2RR*NJENHp?G)J}D0t{!je1 zdp&lHLGM*|ygpm+e|WOL$lu9TjT)-|{mrPYn-*7zs~Gz4QrDM{)dOEcAaT|!07O8$ zzo%*=@ipCZ*856*1&_!?{K|(nC-q`8ZE{HZvthj6M2J3VPj^YW#DCj_aei0l52&37 zj*QxKA3n0k@1qy|K(15cc`0-TJ8~AMZ`wq6-bw7iWgt1_VpkL6K}mNd`Dq|?99Bf| zJHlE-9E{g9w<*IhkNA@%HsVaHCGLqR8fCA?`(c1mm!q7>>PI;$=&y=IPbqS28V<1K zX78bUY2~c5Nb+Gp2L9T!gci@};g+Z&7>H?7{^|bZ!#1SY;X}qxaMx$;4j{&E4Uz7AC3tp%(xSy-=)z0X=a4wyP^S|B|n%~ z820MkzX|=L1|VS3x`fx#TDNg7ZjxwSEdRzO!SQbA4fE0wyKVa+on-VXMg;)k5%BCW zDBPc#=rY2)9khl}7hnKc77E#*P_T!nFZ_q7RXO=WHI8#NHD7G5N&r45_>pjDI z1UE^nd}9BrT`LxY_Ks_>3Fkvn{85w)L;F${7}&Tm(!5seUYxYlB==xWBzviebqeW# z-~kd`LroGb>1I*+?#(?u<~X@*YI{>s`@JeRZcZ4T(!eidCzF^c2#~8E_2ZpEiee_C z<`+ybEtz%z0-oW?x6OlxoXabgt??jL$UrimaG6=M z8{>PwInhKQ@OZnuxGqCf-w&|hW2IF}r0Fx}>%e<(TmfB`)kHqe`;NU2{`durcb47# zBg6Y%!mGHE*a;PPP!F=OO=;@XcMtTM{~;p=XFGPbCUdXxTVo%+G7L=v4`Yxid9j0t z2^a4u^$B?^e5HhwlA{B?rl+bxXyvN00dLvR30t<|n)rzA_=ZF07%67;#_QD)e}~1T z{>05EiFVHfRs{1;o}8QEi)x`e^0+krmSBaNS>Hh+cZp?x-?h-?RRJ>^59(qSnFS>h z6tSW>NVF7+tjY0K4gA(-iTAUU>L#cBuHBx5x-l}Qvri6);A&6`B81Ss81yxc>sO#v`3S_`87HQCaj)SlhLlaWB&ob1|_D|MzLAiJnu!~}o zz6E(&LZ4&oX)Tt+sa*KN^TqSd+-x}y&QpZ&)*!<=(uYbZ({HlMWS;Pnf24FxP0mVz zRSptomoKvJ&gy5_Yyk{<4FDtB@zky1^|Ksd|8ob4jrv|XvLiduNeT2y;-EZ$ z$bFA#0bCc&5y5-;c$CO}!vDph3ZdiFE`#D&Z2^lnwI$7lsMQE*>dv3}9;ESPP?h-dGc&7`1+nev-K`(zw`?t0(zMp^Gi$+Ax zw-~H(Vd&VFl4W+FpV<8RN35aObA`l=K5?*4_j7N;Vh=YT5A3~0ONU%sDC^Bb54gG@bPDgQ%e4T2%KF023;_8%U#iL2s1%ocCHbXopLpUMiqLJ7F z55Z0ph9#dG--7|sQtosM5nHd6-?$W+k!5v zK1&iX1zX85rXPLAn^)9H|G^AaA(a9y@rwk5?LgkM=_;jHCCy2R)OF~a8S_n?KRiA? zj@NC7eoijB3}849?T5~SE_XHERi9*g_Pmd0wk_A2L7r_uZKq{58(=c{#`qLWE47~P z^)FbY6qa_@76F z_pSKFvSr|L5&I2lIL;^`OiI~#N2J&^2vpPA763XIBB#*C*j1CPC?RZ!&9*0F;zx>- zB@<n5RVYJhS^LATs@`7HbQpfs^?TLp&Zu57Y@nw@y zI-nspj9~PU-H~2|^dC(p<4tA z(N~EuR=!gHo_cymYoC0@gI%x^!}2*z(Oni%^Ks9sVCNDBH|w}ESd>*09~Sqo4$-C0 zCLm%-2B|rA!s3N6bgErJd`~TZASmQ1h2p8tjQzrvmb)Z~8g!i1Q)Eg%(fd|wh0tyr zYF>imzARigqfHR1wN5Z>2w$`U>+SdttMGukr&Y6nA<`3*ki!C2k8cxS!Y z2Y&$GQ3*v+weuCNh-83uzQq<+b~b|jx%JcXQ{{SY)3<0)$CYVxFtV8N1uO-B!=sk( zy+lT2D6vtDsWX>e@zO!1SDz{0M0@>v9M_5q_=G%n2Eo#8LJrpnoQB6LSjo0rC|3J8 zEHFpYAl+t2yyuyK)+MC7+2_h>Ot@mKXoB_}zy?f!Ed@0^pT4D%qKjc>FJ@^}ons4c zL@k+Q&JszpMz0bsnC0&@A$5apgoos}DtQ8VZhGgt%YjewwvL_JYlERMk2Qf>@!(mR z5Q!1hDf}uu3!meMnovtnP2!%oT;XR%f$WNWn1tKU3ha&)r8*STmq=Ou>mjD0L@2af zeQip%!dUMRpWJXJ)kKFwVxd&BNuK(Ge~UWE!_V&~w}tDjOrgy)q~x)FWM)9mNpA1_ zcv?JJC+dKe{0N$(w&mUz4_6VO8j_|l$x!fTrTCGbBjOY5dQ3`Jd(_~?wOIN_lT-nR-%zP6r@z9ehU(>l^CJtk1q?mxzY|**;`k_Qfre4c zNW}#K(Mct=?2;HkGj%KL>|2Y7vN7SB4*GAD9m9%_Z^9V7!!JxpdySYet~>XXPcO?B z%L>?H?4~GO@VFafLebUEEGIzAbw4>Ejda(tW&gCWDaeh{{Px4pc89zLCncM}^l4~eh$-^zAhR_9HOnW2luNe1@ z4ONGa>Rj_NmZHLz+vmQA{oB%&` z8;deyA&uy$05qUmBD&E{a2g1ObdywI<}uT(HOGy5UE(Hoc~O9LjjdSHEx#JvVWE}s z+8cfZMY&|+eV(b?j^qLHrtu%KpI^MrGG<)1o%0bRWRWyWaTi<3txcCQTDz8(CM_w} zN2wb7lBEfA+NW-c!s@~{J%dCYJ5Ec}2Et2TCSxvy$~AV(ax)%Jq^-wEsWE-L*qUlq zcPa$o)*^B%?JN>7sL>y$;aZC!KH_|xmFyW5dO-6kFz`@`E2+|t*-0<3q*pWau~!y} zOgWze^g8|saquv4Mmg^<6HRSqiD0gd5&+uwNs7IAENuG57jsP!A5t7W8;uA}hhKPI zcLRbJ&>{p|46uFZUW`8Ke4c4Q%3mOIb^3%37KcIL7^ECo03_B1)W9IW4k}o-V8=J7 z(x$GT3V_9_4qwy?(Fgi=uluZfJ-y~NGvo5Whi$Je?jBl$({r9DNVLfbB6Hro%3fZ5 zlj3k(C)_?G9dJy!KFpV|H*#qCxLLOH)=s8(r;~H2~5k?a>FtDb& zt7fclTiXc7q|~->DSe=)g)*_CEQ-n*+gB1+k_Q`ZL9b83>d}0Xl;oNA7T7at%`bL6 zbW9jWZ09MYZz6=zt2^5XDQiL{`6vq5)jCh>^Cjye30{++GJxT`vXtJ5Y=YgLkWePz zxQ45Whh_G#za|X@YD1$C6xdOO2hW64Ea|)C>)1DOb`7y7=}Ipy_N@P3%8?|POncQ{ z&soFdYohYFV;OzF>1QTzXLGfBPI0wDf`&B5Pqk#p9K9Oh4`omLzK6;$Z@z2;z!S}w z8n>tU4$zpy0jvrI`OXi4##Bjv+p&*=uI=hX)W@?!az(;Fd^I)${5gtnEx+^8-f4EP z2d3U(GnjqReMXGOHCf+zGg>WKP9W)mL{IV?Sg~o0x%H6wV-du0`;AW|`n1Xi$Xn`7l=*O4z$1AN{&E8l;HFx@d zm(=mF?>8_L;q1LHLjjFfKncsBOe*SdO6#9X77Kf;J877(z+`#30Uj!i!c44%BSpkG zhKpXLgi8t;GjNG?vS|(IYILk>t=L&?4d}5CnC@b?EMYK&=wcnEyhKF_f#v>`N}}>l z9jhv1fZI#^hwgAeOnc&DLL*7Shrxwdn|)89d0b+0l5aMW7lxxy&(B6o8D3c ztOkv8BG;)4?2TrbMo=|}`L+?QyfBFRo1L7%bHQa|y_7Ox{aRa)Bk!D9rX`wu;oXTEWM# z9=gzdpw{Z$Q}>ry1=`HldY`72>hKr)K7JE`<;y?_r>;D6I(v*>)+Ps8H=d(C;vUIM z=&Qg99UOX-joW7AaWohZ6%z|%_(aIP!s5E=O##ARn>p!KsAqi2VBt3T_}EgUtxc(~ z*&%J?3R>TexJ)^4!b0Qs7I#N(u<@3VY@&S2o9M?XMIn@O_I7zOxd{ z;${|uF_Le&UW0$=w)N;p61bq?7W4`$}PXRav~`s{QU>L}Ir(0KEGN~&U=yxmanxhv*GKDJ|n_l=h^C+XRX^Pau!R__CRTdxD0CHs9+^e@`at~eeM zLFVx;je--^PU0y_4j+P9W!T)ZJwBpGS(GTP(LxO5cj>>{>m`moXUWpG(L6Z!n^6hr zn}w_+1#;3J<%9n({V9AkMyzA+kj%FtaqA3UR)l{x>JWgRgDpfRnl)ZW5)GpLlc5Wj zdLAZ})c$ngTo+So-TMjW6D)~Y>s9Kjt)lk!`JS`OtV-acvRk(HW51dErwjaf&=s~sngn`r8#%#k=3`zFUw60;7rEwcFyeru-9D>ofPyU7N2KlhN zzTSd)`m9hbuOewoYAE8V_64sY_3^FynjKV0dGvfbUCm3NiS=jRnMTT_Pc(WNtYc{m&` z48ua)!cBU~2WJTT(66>sNQm92r3cNImi44Va3 zg*2Sm1$G}l{Wri3IZK()y9pul?rtJibl|OOC5v!lSCkCX4LUo02 z7AAfsd23cxNd7wJl(O5>Wh4{J5LPiwc!ur=1PLGC#6Ti!*0Izl3fiCcT;6N*m5Xh{wD|3-Z{~L-aVDq3N_HL8yYB1dznv`j zdx?fG1&Kx{QMS`zV-ggt!6AWKC!@?MhZ~!eLAF~ zttl&>-P0hc6JBk5ex4`m@37LxfKJcn+V%_@W-7J3z6HxnJDRp~J z5;9zPB%(5(s><6r`7YkY9>d&*gRKNgOvq6C8}=PftXZ@HgS@k?48W)%Y)F=1w3?X}k`Hl=p!cKu`SWfN zezfz^N&aeU$YOt9 zxVt(fW%yM-BG^cHeOJ=XK4y-D1J!VT=6#OGRc7^sS*|%l+Y4(&4^bUN8@I^MwvGATPfIkc4DxKwO^mgN3u1>v-yUMB&rF{FL~@~TRsC%;Cn1F zLtjSsuPV@z1P)$KLIU?;BNn-Bm#@$hqKk{4%!a>FNw%Yyii^i+01<$RnhNb~UeG2) zloSfd=rHHUFU&)S*(gGt@8TnIuf6D&EEufp+q0Ak&C;nYay0b?E@DDg$U^?~kvHad zX{YE!aDPMj8vJkzem0|sh+n6e<|r58@o zM3hf_Lq2X;aU-o03B}|4X)Du&Y3AB*zxLcatCF{H8~moI25any~GL&(-pf+i>!6;Ea+Z5EMt&@i8A>&h&a$g1yN}L zwyy*woKzD;9vN3r==sVoe~@&5CirLxTap=gEg7c#iotXG*GJ=Xi|8(^CYp`Er%26B zKUwlfJgCX^rg$Kw#pJTJ7>Jz5Pgzl5#b#$0Iee`1HxM5XO5 z4rFORqhx<7&s}%)+x}D!$D^OP^RXIiKL>~j=ms=Xx zlo!l#dQ1)@hdxQljW>8(UtKe$lldz_Ix8zgfYe=iEP__Yn};%pe`j6C%5!5R2Opj3 zL*@=`%sYo8?f;ylswSsK#?-%Ps&lO_a_xkwpNpXfmK`(3kyT7oZPS%K}-q6SSJmh_J;*{(r zy4P~r@*SQ5L4DWbPpbksFa~*ca$RfBF%b{3PuXrhQ@BAJB$HnhP3rCAVtTT;6?LPn zU~g-h6?RZ}sL!O?=->DX`jZ;{r|@D+;jSa6=O9|Dc|UX1xiFUm&XX5+;v(LkC*P!ZCP>Kzh z0erB>tZe-=#!nV+SkyX{F!Rz}p`h%O#(`?KpfzJ6KT(Jv*kzI#gNj9m3Y8WL=6!I^ zDT}Q>-AWfKLV@L{O9LOKQ(NUcm2TF55(4ie6bFi|ALmVSi2P~(R|1RwCQcgVJDYAa zGC0msNmy|n&&5QxFdQXHMk>OQ@?H7TB_{D!1r#=Bv$vu|jZ+RwdxqoU?db^ZI}R?$ z($V?iE$Y~HXZt8t1sA|NAcmz<(7M!`g+9%k)alm}eM#`BBxgf!z<@gd7~D(SNc40} z?xn+AqqZ^HFmbI@rONt!Y)72;OZQn<$gcGM2E68+k-jR@JOU-z-qsS2^%!g(#L07Z z%yM_36uOtj^1l8~XAK`tw7ZXgj0$J~aSu#qVx$(f19YXWG#%^V-mA0mfRAtz(wdPp z@`ZeRq^mXOrHapJH4ww;+h!b_7@5DM)1v*G|A`3`mv;TZqS&)e5LUlwUGYI<%p&RG z6b>gQ=jaX2-MLohB0NRKppK6ZZGgla`BMbUBSc(8UtU!$l_v9#aC9H?g@=_Cj22Qp z%~onyhp`O6uY@>>;uda~^cf}?*|PclIPlP;91j5oz9hi_%XPbW=I1%yd*B$6F@@c$ z+>Gc)uL6+!0QLHG%|z`$!j~M+X+sqp?SbA^y<+)nx0w@ba)w5yx^Y+?&9`|f3XGgAIyoPAKFR?oGz+XnFGjxWZJ^c$wG2i;~%=b~^PZm+z zTy&KypS=t-B_f=>WAAX#lo9ru_9kPO=xo*5w%;wb68yC3kAG7!%YOdes8kRENXN=t zIGWx1vg|Z`Z(3x08O;d#TKQ$DhAu#=L%T!_KYBb0X(I+<-0F`PuJZD|=Y~;!U%oEuk`2M!rO-Vmea4Ddx);u$Cg1OV|9DgI zK$AdDrl((QDAbJ<0YnHd!C_p}&{4yj@yA9)Z$~lo5xzus-f}%9avRMsjki_~%eX+E zNnV%_3GrkHJK^KsbO37Y(lUd&s=$vlEPL|IaQB{HhKt;>RT-eV5 z{Hm6|-I*q2X1uWNNo`*ke7eNdp?a9i74=m}S_gx&+;?4&p}mfspE(F#T{d*=fhqil zN%Kf)jqOzaKEGNa=dqk}on$VS!(K6w^V1`kzFC?Ch8rydi<9#ubVC^i()~+0$+n*m z$2%oPo5mKC(9;K7NG>S#nwGIP{Qb}AGdhs}lXVm63JZYx;uox6uPM!sK9N`>ImP&f z79@g|;Z881Ew_or?LUi)FZA=Fv-^58WV8*55*Sp()NqgJQURNt#OD6L!P$7H*tN$B zuky@q;}jOAgbK}QxmBjm{)y{nGwA>TT)uY9htHcMQ-HSYg`iI4TqH_)ISlK0yEkUD z3?m>Npi+D1XYtgJ0{DY={@d5rq~&a#JlX*^pz*v;EDc1tm!gw@R=-H z!LUiz0VT%5_C`#h>{nU`BpOj44(Ls;nCHuUw&u*G*oeDz+A|C3Xcv-!`8H!5klI9uE#dkNT`HYY_UAr$%sRt$L^QFq1@<;cNEIPMWQtGz7 zWDHRQ)Q$GwlDb*;5m66R_$rR6O~1^Aqr!OIV{O)or-lyKfgYEsSmn`2W)u|lHw%pp z*x6$nY$Wmhbw{&)97D)Q#B9;iImhnt;J;(_aH-CG! z-<9)Ck)mf3whJHDx#-CoLfW}`+EKq4c6uASfPAf z2$e%r@twmWI{8t1Z9xy3*TR;3tc#-V`vQ$-Cnl9tI->^PGRT+jTs~0D%Oy~TJ1`>Z#6RgW&+)A(6OO*U-u}V} z`W>^MGslaDCk^?pdc9;Di^gQUX>q+MCsl&&?HZ`SPLB9TVp3pg9gqJG)q9j^A(mb_ zzNJXIh_B>REBMw3yDB@@TX*Lbq6Lw{52p>)3Hv8Aj@cR*9gohgrBy)#K>j5n@&RbA z?Zg{+G&p1^$2Xm+C%V3O!|M4HuZdvX{(8XVYIG07l769E+Vj~5rQ#Yk%l=MEi+#f~V^DmhsZUx)G$hI2G|DQ^{pU3T zgKTf1n#8nD%)s&-<*IBbfqc)xx^Q<>U+?nWIe7I(Bw4UNkV={9rIV!`3~PqssN@@R zkpEf7Gj^T$bVj?q`?ay_0HUX;hR)fPdF9cyw=?SFEYHe&c%3XWO+g4c{Rm#&unr#1jolPELd zQze&1ugwe}tgS=B!T7KTXC>))B}|-};z;16n189y=i>MlAQ2TUJ%nzj)#oq>_$gqF z_Aa2){3UYCArni9H+6hH|5fq0836Y?OvA)fcUh8=;;7h>zJ7hh>&?V_X%CS;x(#|? zVg{uNF20%OE|7_U7uRwLZTiv_Vc4_uupYWuI`@reiw7V12%pe^M>3rCspqrac!o(@ z$H&U|`zlY{&bT{1aCr_tM@c~UU-TB2@Sj9GVnZ8}&{_Tm%vpB4|51;H{Hs(bjH#KV zzhJeGwp?fdz{Fo3k+!glrB;YoLuQA}pXTbbB|Z&b9u7KN-uBxV$eXKr&}V$bBOJrr*DQH;Vvvcwkcec2zEgZMnq9;3xXMLRDC4)$>e+5 z0huetWq|!lRuN-kl_yqbDZmjjo-Xdb?1+-?;wCjR-HpA=Q+hf+FAWk{M0lO@)l{n4 zZmB{bv)SKJyd{Q~8g&-g!oBFwl5E;PLycR}D7PCH z3Yw5E!Cq7Ei7a3oKz;NhjAg0u2}r95%v_CGni;U7g0cd@e3JF&BWjJ(4^}RH0tZ!i zHr}D&>IKI<_52t*uTaT+a~d$;dB|VaTq_E$3PvWZp%NzuW-kmYS4GI2Q8pU^KH}>f z8E&Ax@o_xCUy2Lra$w~ z+qz!tmJe+D%OkNpG*FeaXlhRi3awSJYEiIMEcyAP+P?;WzXj6YAhw_nkRZ2LHl@6< z;Fh+EHM6Zwo-qB!%ez_z$YJPzF>N${&}F0OW-{ zDi40hws!dX+V+YL+sGzwA(tv$VI8tnuw0LPXL*16om*2pBU!T;&>iSm(4ll{O7pqw zn`_onGWO8a)ja563366))iYvZDqi(hRD5(JS?uYQ>|ZbO3sC67&;wNCJZY~HH@CfX zNRLb~tzmAkB*lVUd59nEvC5ZF14YhGf+JPH+o*<4)Xhk`&Z0Ubw>gI0O1tWY57Wf> zZF9BN(F4x)-SwlyG%koUH3k~_oBs0=DD-SZ@p9|2(|vB{$4I*(GP>mXgENxO170di zfpzIuAIU^LaV*kL6hb+fq%;{T@1OcOrD8mOCe|uv@B<&R;3fqtyt_v4ybzG?Hhu61 zrgbicj~ze&jtE!yov%_=%h!Qm=LkF!8EOJ$ALU_3mo(w%y(XVU2k=JOb$-H%i2Rs5MXAbyC>N`aBW``{=rvnJ%NcV_CpFZtOKAEfM-4TCdxz^) zxm?`?C76k(VoJzx&ccoM#WuMQVJcr-hT6079}@LYebO_9>}D#-5|6~%$H3}~#g%64 zNA12@0HK?AekM%Y^5Z}x?>JF@V|{*B{qI}%-p;fHMHvRMlC4cuuT9>wIiDr3{U%pe zmn~L&#Tt6stQw3YRWT)Tw&F6i%V&nI31$h!udfbk+Lvuq6RmHINKw`y^#*d1DT&#! z#-wSP>{MQsbjS`Q;vX;2q|qLn{1o!jxAHp?r#{l&3iSRkb(&SvHd`KnK9;HrsVgGq zArBY0Q8My>)lRO_(Q?3dc>aQy`HM%C61%(s!82>8YXBH4yzS$cd^>F8v$^57{Gb)R z96)xddmQMgv?2~4lf~bS`@YuZEWIv-vq>jHWy|OgeZ_~xAgbr3vrL9GAI4b0bcL8odW-;)2U26! z*hYW1SF;yp0|PZP`)$OTVkyJVwM!+k!2)wS^+q??PuKtR*@+DUU${hh!-eR}ssVTl z^M?6cyeLc$0th5#Yw2iccQLIkkv;kmvZ#2Jc70O)?XK7?k&*z*FTu2Pr+PkE>fOK+ zUT8}YP+R*E)ur#d$gBg1D9HJe|ytT(RGot5s1 zf65VB>(vS7Uts#^*R$DUZ`E*z9o1tU2Ps-yLwUw|Z7sXuVwI1$mIMi6n6IP7!w9_7 zPCf{G4TBr~q{}0=)}o1G=nH#jOVMF7H6s>i?({0XN!U%%v}}xvkB?LQ)pbf3Z2(7bk7i{)%T)2L(Lvp3}E9bSud$zvd$W%wibPF9({%#;cI=!+=! zCIV|+{zCD(y)EbCx_BZ%rS{S7TaD z&7BzR(S{j4p<^GvI)}j}VGBM~{aLJbF3-Hg8+eErw|;T(-g*i43l_akTVa0UmYbrmNlAcO2FYeyAq`l5m?D+t~#uq$m+uX}SLY=3& zZ~%Q0I|Y5}=Yei=y5k%Wz*kUFeZyCT`srvbbD4j#ctdhqkhNPYg~L~QIqR!sRuZcT zO($_)nRXFt8?GYgn*?f7DTaQzMOiA&Ml9%BA=soFU6Lnv*l5&ujsvqDeE*oghYF-I zOS?KqKf2lbR@Q`;X_DXtZ8=FX{EIxQzNP!%6>$3dY6`!~`BRk~>c6C^Gd@2xnD3Nu4M~A&0BxI#{(F*Lj%?A1Kyj=zU3e;Hy9a`P?{3tWgmT ze1V_}{G)X@LdDc{%bco&#A-v)A7=~=d0bT+Uah7MvG{6+H0F)!1a3I6EHu!`?!}SJ zMHYGmrPB3@`>f_3T>dfODQz#AZGFpYa`CMj7malO2tV?OAtM5ZMDzoENXoiRDQfs3cK*^0m=5GL730#87;!+0M6_Sn(L0Oe6t zWp%V};39+fp>Qnx$tsWlm!_iTIQYgM^j~mWt|nn(6cKfX%Uz?LnKu0*Mm@%YvqvqR z7@=E>L=E$KGZKp8cd|xe_P*3K(uow&x_qPWiJH$7#{(E_3Olb$c(Gd{%C809|5;r! zkc+6Uv(#?VzF`4D?EuTSa1a|8Cg-D3Fip3Rk}=cmKnA?#ArE%jQIgTCrf1_5p>-wy zO#*tfpYMS5Fh)!Y!-I1Tpm>5yPJpjneN2xCI$C5XutDIET!Xo3*rzy)#A(>j{l2gx zk!0ZI$!4Y}5Qs}Y@9-ItNkS4kOA@xoy_Q@_o4vduEv?~*Bmr)z*pZjQvOtPOWW*-r1^;)Q6J|p@Xhk)v?6~+{P$yB=}He9pEC^#UzIY-J#;!8wV~sX?i^KF zEUEq;Jf+JDxadT()**4k3ZW{!2hDJQA#FbR^4WaZceUN#N6v!p9Wf!=uEzc47H-i9 zg1UZ}MIRwZI4*M@N%grSFJ5mQNbPMmLUfr!`J7=^~ z^ufVha&oQj>RI+%^aXxD_^3*;3!JkHBsXmI@Td>WCIS``*>)7Zfxi|*r>|Mouc%u+ zH6dbVsR0$Q4rs-tM}oPI0aMl3xHTk;b`M z{mG$Rrs`~eW? zA_C2w^D)DGv`lrL_Az@!Epywi9$8na*0-uwK(JM6)y@!`c`K^BJ!KIGke#b}YBPKg z8(ne$DE6L*=<^4Ll{8>fwZh+cFIu<GYIv4R<-XyA z*>03D9bQ-nlIR{Et~@2(tcm!V0ugHqoVZRDlhIu8X~*+8#nT*20&O7e9?dz+3dP+0 zC8nuh3&dHkxiv2Et=MVuKYpE-TbcMj9EXVwauI&o``?n99@@FbaqP(i+H?FZRI#qf z%m+3y(}sg8Qo}EFUs*lDon}KhX84|jocbT!Ixi+&!L3qSRC)t_4R;K);s1_(hf6Xj z*gS&$0X08IeO|mC24Z`PAgfP-Y#2r8Z8P5%Zb4-- zxnFqPxtxR|?%6ypM3<+(a&aAZ%MQ!!gw!8ECcY)@b6bwp?SGHwz6$s+P6T9=z2rU! zhMq&6DRh#Gl~nq~hT>x$KM1j+X9t>p_Wh;97Bc5oMQJ`!%|W3;3i^j@eR4{faD0+6 z?iwR;|A&vu9d5QD)Kxw-0dVEFtnb2Al_th)q|(aL`y*8a*sN7coaHQQcf?lPZF?72 z%Ak>#;EjWeFAR(?#q|;A=KDJTcH3BUL3}V0MS$zpquF`oR*+lJK+-FrtX$T-7b3H_ zj84+#0(Q=#Vqb`$S=jQ*v-OSW-Z;%S|drv?#X@L5lDSPLV4Oljjh(DZJTmL^ZyK7@-OwK3(LP#3oCGJ z8mZk5D{uK$D7n!n>h?$Nd~`D(AO;BS4(-8-U_2r1z{#=`3&FS;V8U1WJTNXBF-(HL>TN1ZMN%f_07jEHtPDG=pbC*Gsi z?FG{9TP&UGMB)`}IzqB(H}(MeLQ%cYeES|$Fu_XKV^^OyBI#nQ_@M>&IJvx8;q{^l_e#ks2Cc&+&z zEH%1yecUayxifc=(W5zWskAzi~po#Q_`yuK?P!*63sSGq1Mh=7m zDJ)sMc?x{ZjncCD4N=|%)}+h#gyyVLm(>0`)7G+G5KP&WtEo^9eDO~ zupAYSVos*ZChi*6K{gm-r%W3^3Gg(|)~>dryB`f$eX%{)(4D(#;KltRJTmf1a_+II z_?rg^q8fNvF;|_MJ_xlNQic=bx@E|W>#|7LRLA@2#D#5bh%IO?>1d(f)Vs@ z*tQw;kKLK({oh+lHVxC!B+6&8a|lsB^`VunQ?!w5K;@#0SI!`y374td8o-LBDv6Ia z8_@A5Y%o_&20eU)ksV)jN5Uqx-{?mV$_O!lE1}3*TrgT-7}@5znpsPlcB`>eFCNDO zK)RXU8WA%Nf3VK6x}Ton+Nq|U6aYCu#=mH-tQjiz??YW3{=Ksj5_g*Az}q!LYq`5Y zg#_86v{(DU^mk30{Qzh6dHL+-{sQT!h;0v9RfyA-kn#t1q>6IGJJ)D{J6oY}W!!@z z<0@NLwD|?MVBf1u|5)n3$JHxGRrh)=*)#o#`u;|WN80xTE3{%D)L4=L7sxE5_MWsi zE{(I8Je8CAz7tmMsdtc$MFgtSGEi}2%zo`(%=h*tTGCk~^c^bQ@k0?#Gk`+M;+tgd z5a`4@l-Ugfu{lFjoHd4m&ew!VAhOG8An4v>JqwjzwBI~i$P{5r<N@jz2S`#7eY*xZ&?8=L^ zFXb6@%A7T;$1noB)nUiBz+2STBf-jIGRk$h_6jY)J+{xHZ|WVz=4c!NZdI);Z%h=9 z6)>PvdJ5CdDeT2IZKVLHa&Flv?%j{ZT(niamJ&}5rO^^=c+fiDlOqDASQa*Wy7K_# za`3VK-~j|=qBfi&QgIkg!IPsxPr?+|17mr%~Nc6*#Z`o}xdzj0o zz*lv2JK-PC!MqGoC3?i5U06;(I*OUQ5UUZ8t%mC$lIH26B1}+s(T~KC;GpZ32Dq%T zpME{u$2MYsPyH3ZD`zg14+gBX@}0fB=#=;|0$@vr@B6pKR}ZmPCO>ucu1anC{sd)I zzNfuS=a>uQ@J8RCYr_tl7PO|MgA0=<23Lac*3)Udgp35EHB)_s z+tOW{hdx7CGe@RN`Vin-Jj*@7?)r+C zJxbPhy%}GbJ(HE8sGObfB4LkxW-??1vG-UGo9YEqCnvu@sEzY=hx2`7p_~r9_0fs0awpv)T>A5p5`T26hmLzlfMLftT&1s@#_BL2ev`8$v_7?sJhOEc! z%&NAN+@Q{O%enOt(_5Rr?Y)2Beu*RU^2GvK42H%1e_a8Cubw>jWXO@2zDi|MnIvdz zmmg_6T!+s0ZWz?uf?=GJ&uXY>+Uw|`d=s+~s9JPK;lV91SiJ$G92ss^c+Rd>@%F?* z=+NW$RgVo&<#0ZXzC9uu=04C|dF7Q%Ic)Bmg}`4ZuhkN@em0{ji7z|(7LRr$>l~D{ zCo}2x-ZA=c9es^qW_5%Qg!@(9tw=aWD52_UJ64x|?V9Oy$Fh9na%v8y!piHj%QY+w zk^n-%BVu@}zWxj>pe4XDhhmC}|6y8%Bc5_|d1u|F?oOPb0qe zk0-&}$7V9?0HSu!YF?D5?#mKec3TYF?_AiE0d9~e1Jb_$Y z#zu_C zx$`#?0udQeN~5@zW)4{xr~F4qDE?EC@F-wR;zIn@+tI9pq(?Q{Roxl%YNUbdBlny) zL_vImRD<*m%pSKfgYS!rH&HqgdjPBIa)mz8Mqj{Fdqm&r*d!p1;(q*(Quoe6otc7T zSF@t(0y13NFcsEL6K^RRPvkyoHG|$5qD6{8wI!EZ+E|?0i-jw|3cXJ8%$;*;@g%Kr zttbgVQEU7+&tg$tM0R54XFm>v)(`eo1?7QI;y!OzxH@iVQ=Rt{Jigwk@H~NQ9Cy}6 zhCdp0q$HHAN*S{4u}6m%}iAD-$J`G_V+R)(V3K< zp?~4RS<}C(sgHjPHc25XaqVlS@#+jqTqC6riBt!%(Pvn}H2do7n@$~1^de4$lT%B- zj!i??H39|brC1me2zBugLUn z^(u?na^1qLb+F%A?U(X7V=MYwujR|kBGvDF@t1a0_}9-K$z6+exN-@Qcy9f^ z*$0RnoXQg+W-UWG6zsCkkUk6L4w;w8LFB_M`9;|w*w_}y4jK;d7a{v`+*URgF+9-9 zW9AOL(Xk7G30z5!K?{b$SIbA^E11dy%x{7nA7jF7_O&)pZnNPGthA9m(D0`$z}{%a zZ$TIO*ZRriSNo5>cOB?TlB;yb08nChfpFhU+}RIm$$cmK1p;(U#V@~^f?^T-tyCTw zp#JwbRPue-lit5Rwktsfz0TfV;ALI9^2&XpiLygHjOUr$jZ*TkA$w+|?H81#i-s3J zJykG=Kn8&h70_4A@3gU_GLXYQ=4JzDO);i~kt0;vHalokK0hGo8I#&$$OFTx=A?Y%3WRnoz#k z&H{!$dqN-nwODPke=;znBDaC}>cMn)Ccc1e%o!;hFI8{eN$!IwI~0j-eqR{2qylyv zYR0MTq^F2CGu+`B)-1^c^jX#H$LBtOZ#~q!eqf_KV)_`RXobB9?>kY!?(PVrbs5V~ zgxBT74?(cAnB4+u^D+=TfRx4L8sqJkJO0rYF^YC_nBiRsp-C279k&*JK4G*xI6c4z zsO2r2#54Pz*uVWR%a(mEC7TTPO*NSzAy3`X zHd@SPYO3zMHE|PBat)2<)Q&Yi7NdF>t6+{ji7r9|4258o_2bCyESV4;V{g2CTua;> z)(K%{0y4aQr1MPJCtnBX%?^HL{azlE(Wwwl?&l0^Q`COYlWBgN3Gd2s)_PQh?H-M5 zT$z9PQ;GKE@b<7m$V2U`cDDIFBC(DqsR3m;LVUc&SKK?d%hUK-u4?| z{(9c97rZJp%W9thmn4FY+GA{>Zt`)I!vLa`JdJ+-4y3S3^Wp|ACV!Q)YoPhK`%MAg z8;JlzNNU=igR_L2Sn?e!3V@k5CkS&@ERYMiSbhAg5bP#S4jkC$f>Fr_A%87mkBiW6ENSUSv<*J8mg?&!l#dR zdTDea@u*FfmPAx8rVlfXpM2a8gfod6E;rR7Ot9BxTN|Ca7g}9{OGJ;Z%!{{mu}wcl zN<4eYZlDK*6qVWzSTTC@Xo7 zfRNgwj>~_5Gs!_6ra0dB$?Oz6{8!M#qj2BeOp5CO)@3u0?I;ccBr79$Z2Zw{|nMj6CZYGDd+~gY) zC0~87c`qs(t7 z-MMv1?j%JvbmFo>B2D=+b=*E5H1=1%R`v0Axi5+;wJg1nKB^ZYmmDhD;-I3I9!Q>-y0j%1uz61_0=iJ{eWTL{Ggvns#Z%ko>9em1(4s~K238C z9RkP)IfyZHyvea~;<_pId;!whGbA}I!zmyC`jC@XmqEasjJ%(+IvFN^;yUDF@Jt$+ z^c@=zrLiX>Qvi+4NsMOiiP=|)AnaF_N>Xlgr$fvMG?@y8j zcmeh17kUet`s608yF%kFK3efreYlo7Ok_C)VXT)1kq9_oRXpLL9O-lwi(eLxV6*_N zjQbrxhf1t7Rgnvne@{e&T zrL=HwbQhI6@;qx$tZPCQ8x!*9F4SNfnBT+M+ur+Eo}WAXzaiys-{G0l0y6ujun>KC zQD5}$(ki}3KQo(*4omibFakCl=|p?jq(~X<3%}pQUuS~C$QEnUFF|2qGUXAVKI|`R zTeoBvnY$&(Q!f#8cbtkq4dFJ`YaQZL=stDtI1a{2~DOwtOg?q2XB}?YN&KxW1`ogE%`mRyNI~N z94(caWU*GgaQOmYNLv&QJ8I}&ora6XW7e7kvGN4E+4g`DIB&nSS4KhJXJ#Y9;x**B zrOiSZLhrb9)@~B5(db4EGXh5E^IZXhHxM(ynx*`U5@RdMlrYs&;;g-JwBHhKAV4qz zI!;gR3@5UT0m;^C>GR~aLf-=1yjRan5)msJbZn5xKZ#^fhP2UURiDqKB_vCd#d|$T z0}OjXmD2uB=_X#f$8-)!G`YNy0-b@?|NpkB^nZ1a2QL5g;~c+}5D{o>x2~01@V^K8 zfWNT?6o_A{aySYOod8N98PLy2hIE=28P;zZ!xwkLNw8Q-De_elz?1UYIV`E}@QLHC zV~Kg^*29w;Y>(Va$fx8kW31nW^I_I;8T71^p@(TnWC6%_9Idm;E<8?-zG@6SbnH1% zLLqSN=sdM@5NRTdN9q^%;t707mOQr-r`GLDKV}1l3@|HnOL(J=G;Q-VK4zC~V4RlcgeWdNZvVGp$Z0nH zOtX1I7FIZNsn%+p>uubY4tJzXm2%)*jTaBoVhbIBD@vz))qA&tg=o6TVT&3#R-DDa zeAr0r(Z0o1>3*nBL@x#Z>DT_-oADLiHT2`oVDq-CF{ zSnZ|PEFGD~^$LOa7Dsz?)}qt!jti}lcUdLYy6NBUx>9+9HN+O%;g_o0SdWtE29Y%ZN@4RL`{MH=$I z3%{`eS4QPzY%{Kt-tySHyfGV{v;Ah4Jrx5iQYVX9=inBchi#^7;3@R*!YneLlj&L> zoFAGv3c1!0@&a~&~n(}u-(33^m&FCwF3 zwV{ROXmz6=I21?pc4UkdKg;3PK7ff)mav$fMVwrv#MMz#&hEgP2q*mrSV7!QOtGwQ zewS&9&TEEiZy#3ltdEhX(@&1AYO?PG4p}wPPgyng|tJ{9#FIS9Qdc;`Ph3g5=+kuCe~? z(Thy)wL#rFig+j+ud;eCxQ9Cxo3-}Y_A9Y+y8_nAnavOkO%<>G$WN`K6rd8n-WSO9 za=I}Yf;V_plBaEtxtn-c53c*xSA7P)2A{u4hi<;`wa0X${Im#R@WsC^KO_~Uxfy^V zj5|IM$fI*C!4?1wgYfqD+g#WHIT* zW^MY?-m?`>e|ac+^UbWv`?6Zvc-QEP#ImRBG;%H4#~LDI4PaRqBQM@x_LfU#pOw>o ze!F6!Wg)u-3=}sMXrfI!=FlK03;de+YP^~{6SZ1qrUVpJM6-N(982;|xBb>WwqgG( z;xGG*NCjnYUiT|GFdlL`if|hZzsy~uu}a_e>+rQHOsq5e+F78AWHaxCK*T1REI15b zdR+Ya@iJAMsE@s6#4^3gy--xbGuop0VHq8X_RDS@J^L~ptUKg!ch#AH{ds}+^djBH zf~%s)bACuc>(QqC?(-7hcW8kz2*k@C(WS9ei5=_i7$Cl%0o!Rr@syFm<|ZfOj+F+s zEkH;rw##|5emv$!XKlru8}Q3eEduM2cWCAc$N7%9!A8jPolCwf#xKX`e z5m9y-EUKZa_Sd%J&>g>bda4ZQjPnKa8y6zAGuhrh=fZjWHYjCgM6-jXmR0Fn!&`X? zy%q7DZVJCNyGyF)ih_%M69L}2z6Z3#kRQ)YCtxNfWQkJYuDwu&1Ey}XB!ZwdZ?5ltsW+3 z__jYKB9}N}VyKN~%rL!U7W1-AOUV3PsK`u6+b&rzCC8KKp!9?EA?8EYE?S}VXYSXl zG2Bo)6^?p-rwrwaprp z0)dpG?FQeV>IDL28$e<;Bqo*RG;}MfhwXxiVR6j*lI=Y}iV0q{^JV**QNemkNf5WftM+QZB8jz{MuX6u_c|E-T8Ljd`)w)RK$4t4(-WziajAW=ptBR zYx8!Eln46M!yiDpk372ft6tO5#>oMT(vFU)Y&6*BV5NOd%=EVTwgGVQB$?%U<@^D* zSXVFDrYSyz)UpXD4=9F>8z0A(=Q7Ii`*axE57a~InP~E-pDXsSa}*2>2dlL-?ms z`4X5tb+m#>q53vjFW~c}8se!RI@0e=-!s{CbqypaV6u(GNaMVyD`r&f9Oi7j=RN1P z>Le1_%*&UP-u%tD%@0j7=q61sJBR7d0D8iRo;%#dP#GdiW^LYQ$4HEh2K>OTN&=R+ z0t-!=p1DoL0bmWhtHD%KjmkLCv%Ow5k%SnqZ4Qgs$vLsLRcra333et2Thd^EnMD!B zd~&cRx|36B2z2y{T@GKT#wu?q6W5VQv@T094a1q&{>O3OQq^rr&E&xKY9~X2$f5 zif@~o0825bxv%$_U42xi~?`3U=5fbId>l4{Y_+WE*_h zI8-&gMj7O>t+id1%?)eRyn98N*72-BRBg(=d=b8S)=n(pn>uWG9!Ny6&I8ye_~;oO zrpz;uAsvsU@DvzQTFOL(u+P--sLb+Jabk{cNy@0DD|;CP13v(x5N55kc)B|2ZQjjG z4Axv7s@S_~21)i0t`KbUC5xEy(tf{DIUFBfA+L3<4b;HT*LivdVe|@|E?Ww8 zk@$er^7nRdjm9>it24kuM6~Z;n>wG-#Qe{BpI@G8P76*D^SbQ#))yL#UMzz(m2i?y zAnQg!;7e(SV8wW>W^oaC&cT+by1g#o(s!^ExIsk~+9yK+@<)DCOGG6vRd})H4@86$oWj1XMQ}tg@$RXXHCvk)c(uz#ivA>5Jsgepc6mir{WbT{gC(LLH1M zrU`iU^GL%@w2EM8EOlB|$fATlZj zz6hE^R_Q!cl~x|WI_U!-`_Cj5=6pq?+T&hxi({A9H}Jp$)ooDye#06G6?x?xPQy}e z*$T&x`!-{1()e6<%!}yCMbrI78bSs z+2Bp+Z@9OZQ@K`Uq zRz?6t93-k`^=_~tcV{q;{_k#3@GLOU?Ym>rAS<+!JGf@QCl=FFleCJ@UvrWZ%_mn+ zi2SQEFm5WOOZe1vyp8^L-`9GBbP`H`xh zb}@yHPf73r7+QiZafi9Tjak976yT>pZsFqp)< zp|qArX43&li;7^9>d{lM$fJxbJ$TK~8MsB$Tp6Sf30U`rq2G8W4m2MqcQVabW3COI znDk6z69YvXpkbjhrY5#Q5QUA=$N9aan28$6s_4!(d+zxZifO8}c)jSI z^T2nvz~+AtoonWd=rws}19X(U!cz!UriN>xG&*16MBI2d(+e3}A7o8}RI305UiI&4 zfN;f738O{EZp@GXMeodSo?Ke&nzRc&@` zh$=`xO^K%hnU)Hle#nYoNg{rfpyM>r2}mHd_{Z!;U$JnCb8Rf!aEb5id!>FyuP&7k zl#&5#qw1@y>44B57me~EZkiElMx?!~uZiS@DIskqDmV)ztn6)o9;kF)v_t*>(*IyB ziddM6VnX_^^D}rUk4%ur5pT3)gpNGUh$s32ZVWU#g^wZvpqaJI{7hg~Oq&=0*(G1% z%)?c$ePvB>$L{Dt{wCkL-N*qxB8EgcS$qb+^9+aR;ba#bqhN57qh%sVciG+p4;?~R zcC2-bKARi@AADdCAmv*e;8tr;%p;J+?~Q-)ChDy2R|U5dx$iq?RpEu9DbU`#UNPQJiLX~$N@8T4v8+%pt1#K3423_Ik4%?Fc&R@)I0Se&45%qv^Tl7 zl$4uh)VIoUnCP-*^-B;yl+u&)cG1IYDo#{1S*GnYF_I}oU_@-Ztp!BLutDXQs}~0G zu8OXfb>Dw@C+EgU!`N9fQCKCsar%vf`DVj_ijp&*=*fXwww;fsIOBjeOR4{k@d$4A zxgnLr4Lpw81!s8V$SJy$N4F`-rWuHHi$vXoPock1OA!rV;Ax>-?HpW7oCd1aUrUhy zJ1RA?t^=Vg_%An8VGz_i6UY;KO6>yQln-#e42cUX&@4`Y1G&?)~dixMjn)!lk(c5Ra}n{d~w zBNh4Mb|rqT=a{-?g32;=fcFTsN2&Fn5$ljHa=Pu-C4^I*qE4_yw@+`DxgUv)xSFRx zJdj=)Jp}v&n$>KU?X!;It*rpa(*K3Hi9;Xv8qhTc(jA4P)SH2w{!;VjlC&g)qmTJ8 zm2Mok$B=;XLToZsc0i~+SUK>54{~j$3hH4ztxUPsfrhw968O>53WQZ#?4%J%8iqRx zG#9MJUMnI;jxZoz(Ya+HU&@{6DkLRBg~JdDT|yeEb3O~uxRbPTcQrS4<3K(TJ9vT? zXbEM>*Vw;yFUUfExX%`>V*QHO37mU~Pj#S&%9#;}tCdnPrVpw!%dL?((kSU}p;9xQ zIBm9m*+Kfe3pnxd)oS+t2c2k2ntMy@Ya70QgT$_YyDFOn}>!c^mE0t*DN7 z>swuKd!&FR-^9=zKi+*e&~aSO9~^Yc%^-O8O1=^*#THp1mFq?w<1-qZns7}BIakX@ zry+wnLQXb*k^)>prI+}J)Mbg-{Y};8hI9B-!S}YX0K)9u5xBUu=qk7XH5Oi=kEQd# zO_DDQEiNCFCMqcvxjb`XkA4$Qby>Y^7|lq!!5}pFehU0sTIb9S(Fy64`NcZc0}Y|W zuW&^0M{HZAs*=DLHL6(6+I)>I*8`AM-g*~zEv@!k8Rc%Y^mR>{hyb&Xaz^doh z>u;0w3Ouuu<}{7-wR8KBQ{)Pc-6`y(3d>B&=t)Ol599z|s(){DIpc^xa}i{>Tw_pk zXu4wLxWE*{U2&}2@a8*r!AUc`BE4N-;nPq(?o<6WkAZ3(Oy%ShEjVPegoSs|x6ItW z@FVC6QyMrZ57A(|Z~qn|^RxzFO1L({()9yOolMIVYmJQJl5CbzfoV$9GhF;`^{ac1 z=#tgx_uAi}wKnix#?wU~c6s>UN__(FICOTJ^&QmSOXxcNK#ql^E=AETW#9jzhhfBOlX;5Tn)xVWy(e?1J^u=)2ZR6Wo4Vt* zt91<;PNI2VW2euvwXECsgh;dNFo8Rc2^`95lSpWp)4dQaqIG#_-i2LdL!+X)4Td zDGeJbG6>v(ScOk%e+3*nv2b#w=7%AFU<3xUqHM~jQcY8}o%;FvLW5)Qu z(r^E?Crhs3hP@Nd$$P;}HD?o`@Ap^2=DQ`{;lN1fN)-0}g`0~2?+E?NUW2_BleZaB`dOW%X}>;;#oO_f@dzL0%{sRpNOV z05f^B@GQz(qnzK6=)~`|4|6Jgd`ashc3L9QQNjWDs-G=w-3>spt2)X`w-1-kzDJa1 zR{`m^h`UjJrd>!$u5^2IsHuA5%%88gcipIHaSFOzvhWT6<`oUEhb&X*Mong`Nyrah zmN)okf_2{v^^`8owFoD_X)nXX7aKENlb`uU57yC(B+JmJlv}y#-(22KEHNj93Wx2J zWz~r&qW0hyO<(99pV#>QT$yV%AxIud2U(PCb zFUL5i{@Do+vupK%_=2P65pat%D3owqxk%L{z?~>pAZ3Ln0epKK16(=s}S( zorQ0isR&{uEer7Dc*!V?Nek6(IX*l@O8I73)$TvID6RLDHNsjqi|w z4V{eFljNL{tO)uem(_T}uJq-K!bESu-NG8WaQuD++JmJq4F}csw-VM zF)D;P6Z9^-g_Q4iR%@a{e>>L<4pSZPu{$0gGDKZp(Y{?;%!`lv3 zL!y|PoDKWD3xObjN_2mB)npBmjwT}~Qv|hLn~|{7IPy(fcrpV%;ILx4i6y;bgk7dW zqX~@k;Ep8YtkA*A2&L%N2N|tKs_Fy1lZyZ0lq<~PQr5A|{}XKzJ7pChXkmy75NC;O z+1BVX5NjDEtFN@NdVcEzYN(MNni6VIY;F16`!Y(1zfmMjI?8&OjKcOg9j z@kBv?T>0k?o-8|da67(olJpZWV2LiySEd_>a5@LeV8zoYIahJfE{DL2ZGjhiP~z0V zPDEbF>5!QEC!61gYoeB)ss($GVtMHk{X31nNWuV4M_Va1*zE3YOV53mMnI;%Rl-@m z`CC!YDY`I$yR5pHwA&oXR8iXaL*17ihP&{-DgC_-=q9ail~!urEwH7qQvF!^tsON4 z-FOO)A-g~0-(oGTY;wq+91^(j9a=kUYQEu7q1`1GpHTfxsU=^evs@}9I;d+3}3~eeK1KLcDoG-)fgQx3j+bK!QlB+bJYP(fjTX&F8Gh(Dk4~HO> zK_bF%ZW^=Gc+XMNsIHzF%2d|Cz6qv95X+18 zl3E9A`>Qr2TxYj2^j)qG>oEA3B^TojZMQDo*$NRmi3Y54y9Is!awz`(%UB?w2MUsJ z3z@n@2X6B zYf0LgjYB!;JRi1C)`yHlgY(`)>a@9c;F1EbS~tD;QxDEwyx#)^WWG2(0q9~QdjPYr zn)kru)JgFHLlH9$yu#cD%GE9+qzzNJdize7eP30<2x!Rpw<9_ZrB=3Zz}q)Y{#wqf zi@g{F-NkkT^5V;-y(At5`|wrzzqqRlr&SfNZn8j})$Y)DG2lRb=`{M65Yxlpt z1kDMze&2v0k_N^8^vWeWgtTL&NW(5L#%mxSowz7SXC|bw4+&DYWj#_9>i2;>3H34_ zDc9iF0^Hn56Z1+KHIJUOsm|5F*q4wuhZ!qDnIM0=f^i=k%+xhQwf8x~Nq4j0U0?q> zIdRno?yZ7v$E41nSm-b(fHz8c@E`mdwh&=JMRy*bPu)F%jqsmS`RN5)gDpdSo)Mk{ zgE~jaIUzFACy1SeQ2H`0S4jWI5hDBEP-V^9p>qsxYLQx&)Hsjijsyu#Nd(sZ@kvZt z%w-d=`fNtgfkVK3@4MsU+C6mgp#2%%5;Q2nHd6_&I(-e`RM)Edu!~m|-6{TDea$<1 z=KK7`M-s!m4N?`n2{azYC@6s_Eu;AL9*d1oq@|CYB)D$_MQ2IGVXfjHA^2a{=Wh1t z_lYV87kumR3>o+=i%g@cQ0x`4QM|T-R4PB@qt{x|1hKc-GBKF;(3PO)UvZw-yGokV zLmmL-*vObsc-H`YePA|kgqdg#KO^jCKWK9IE2Z8(<}$Y|_gqOVmTXR;ES>yI1h_f5 zHvAY9GhRL7LB)~VUo{sUJhd`1p$n6S?sfQ~9h`sed~;5j;?Fo7=UdtwiZ6z9Wp`jQyl zKJ7>SEbYxq$lxFPgdnVaQHj!Bf?;m--;tK+20`tu?mfk{b1SjyYklMHr4oG(HMGSY zQ_(B8I1FoS|4 z>5&HPNHWOoA**aghG1?jJv_dq6}hduWPQ!mMrVZ@u38n=M;&~*Yo6D-S&cdE0hIR> zhiu!Y`!=hM!TpWFXf;OWOO|vW1mveT(NJu(;3*2vntDDqIt~oF&i-^0G`CwvWS~G7 zViA-kk-Y^F-+2)TRD4Ko<91o_W*yZTzx=)iRN=}|4EvHEJ^|(>7#ROgtVM=HUIfB2 zvG(J>lTARgKbLYqEY!wP$k{(alu#Tm2(Chf<38u`t)IlsRl1uB5>ilo&58= z-3xS=qCn#|cr5G>&BSlfkh$$w03gRt#d_OzaU_+c@a-2r*!sO9CV;WGIzF`995 z_n2C@0Bl|haQ$P+GS}8L#Q&*ABHKQ=qZ@i2?o}+4z5H{AXq38wC%O1Pm-qB%1NVlp zM~%d5T?T{!mDLc3qIrGlR;RPG>!)bw6Ww<17qA3EDI)Gk`qU}XV_JOnYo>`pi~%Mr zBi0jOXPp`d6q>lbyt057!1xoEgM9%0K|PXqpJWc+LQREYu50VMzGsYCx(`Buz1#mb zl6vE{kL&ghq&T5(6alTn!={(_<<)rm5fI6LtLOBYmUW-JZo5=SE_DskdJ-y?<`y4n zh&#AcEl~wIvcHB6N=pkWpMmSFFRP^l)H=79HUo$eXS8lh&MkB6hKZdbHIV@?q^9W2 z%jt#nUZ0C|_zuee^lWl=@C~-zm^t?28}1`myR;I3%i=u}R=Au~sQj6rro3kW9v1ut zg4-YAX?bDcAe!nhd!|7o@06Eh(@7`nzA^jdN{=-Uan(y%C!4?=Hj`IC_1M%YDI5_k_`B+wECRg?&y&Q+)k2Yd#HW&b|aBGo&#<2vHCGoP{6 zW?Sz`VHXv(*~rEK#j+-_BeSl8l#grb%JS`yWIcJ=&CA6`vQhKRtrqvqhI~|Bmq)=c zC4j3{`!?s$9{sz<;RBY|@ZezPbkFS~%2vZ3MXE79PF|)9FNL(|V|Q9d|9ON5TrKMbH`wV#yA{%i zZVFBc4|9mCcfSvq1Sey8AmJ3Il`=g4FuORT(XpF62DxZyxOkjg0A9u`Iv>o2-`olZv5xT#dfCjacWdNj!uA#bc9PoS4A*TuR_+n$f8|5>9BdQr{>SKv&fGBLw!&R4iVkrjOyJ%j=P!~8L& zJ?A}NvmrFHwS9DVfD1eX5xZ7=FvBJ@sth6Wq~@B23ar(v>ytljcyq~;F|d>Cn3(o# z?hWS;RFm_Z5}A0IV5LgW@7sG+T7@JzC#47T&Hpe-Sd`+-@TsDV-jVar+YV;sf=r^B z1c<(F=3g1)(}I>!XZybDz&Q-}|YSUIN6^*jQzXvK0TB#+lz z0e}za>ZP3~s}lZkuU%vi|8#8Hma8ONex+Vek1%##O&}&o#n23|vJI&GH};UEmAoqH zl*QOV9p*pV0{FU;%| zm?F3}_rz#A!0#O?IjIeFKPIr(-!?{m93K&9arObcT$+JDh@;?>2}ND;x_ypw#G=I?_@NB_YTXpo8qJf zz)6?$L?PI#kg)XxBdBFwJ=U&lOW+kX{uJ1VF2CR1*0kkmd_7t&AY6H!q$h#Uosq6P z55aAaISG91%HE)5;}eA($IEg+&+SkJ$=|CI-w#f*ZO6>l50HMsf!|pil_}7F^~!=< z=SqJY*B+O%=K47Js+^U%wC4Lc%nW~&I zqcc&Ah!zPP5ooft2r+(l%Is)f*1$oMpB{9Yn}Go=tZjY3(wJTz1+gg*L3s|34Z~!X zV1E>>S8pN7P(i7`>Giz;`+;eStl=fN&PSO-uBUL`yqzbFp#3|Q@*dq86k}7|jEh51 zKmBas4!#aT#Lq~pqkwl3Eq>UI1A8I>y5DI?k~!rg%w3aK1(1|wt+tb)j|CA_x{?@l zhjPlg2-Q%Do%Pi>A5aj)C6g6K_UUYjRsZDF3%zH&2dgRG?}g7EC6;f zBjaE|K3}j8yCdwHqlLF1u`650aSMgxHn6b%Bpv{qL}1$xz|{?agP>Utk}6Gf(e7@ zb~!EcBmCyM>I?xaY80VcGlrTFm@|G3Y9l;nM%b<&4mb`G^=Hel9PgYr)&XI@%)z^2uuh+9?;)9o zMl)q-hWb*3%aW&S(7vbgPI0hHU$C-uLjywd0l_UjxKPE+mquL2dh-fYw#&o*m*T4vg7@lU_~T&K*MK)NTJQ7)*7*>m;1o{YhuCF1|h0jb1+U5-aTS_kyo@*M$rpYhxBxvDE?of zQ!Lr)co$DyXW))y_I|j(_V zv0NkyO5R=%!lo6$HxpoH3+we00@dW6G`FukBG3Hm;or0_sqkwFT^kE=pRnt#q2%JL%ggICd)m>HFt)X)!{aOKZsx=CN!YT*ST<$XDnwqmL@NN5r0;W0W0cB->5#39Bir zIlD|OM{3?S(19rf`ef^?)U0-wDH`p-gH59fNET{1)Xq(@Yhcs3+5REBq8jhDZ8EW> zk-JFjykZ*tmhd+)7_3?kmpzi6->SE65X|TP1}8_+)rJEuTa!OlZXuNz;E&YFG{;p6 zeho^G7JUDj{zs^im+B(B zMhvp?S|FEA4{@Y)ln<7;z0~E7<2aRcW~4^POD+4&;$|EL`oNfHX6*qvAvHj06B|(f zI6wSumQ!8&ei4NUL_HxPDtE}_he$bdSoW&xQh}luRqEla6Bo>QKY|6AcwKZ_c{(}? zK5o4#uxgP>2B6r7^2Mn+!+bLWtBcnbR%e7yE8cuBm})(XKDG%c`xjmVR#Zvg0HNjQ3+1qiJkA`SHGl%os{3(I;oRldgv%vOZEEjkgpT(s zHwPEbVvsqbAMfRf=dE*Hz)r$@5a8EvHm0vl_6TAM@~=a=aggG$^s^`XH-dl!Vvam4 z-c@7nB}7il`J;;73M?C(^bh?-rQ0pTomF~%ZrBX$yC=4E%KBv-V3>=xCJ>DI$N7ys zTFniB%tB(^dQDimDHq$Kky@|g@$t>07ZP2I!nNvG$0gUHpv4YW2}{UVYB$2E+5|ovh!MRzv-=6QFN0 z9kgxq8&3eX9Fdle!JM600XE(?gC*g*Fp8z*siJkEI;;s3=rWgQbA1%QPrwoa8XMH@ zjSo(zm$;E6WUZ~-fIq?lh+gZB?0^DMJO$k+F77o^fzPZl0hzvw(ys(4=1M8eV6~f zmlHy|@4{7ITaa5PZ2En;EkKz&<%`Y{v=eYO%Dk3AoN7i{o2;~p<%dtstW@pwl|7~( zk!OunM5)fZ?sS_x(xtFh5uP?N`k$nrAX-W52}Ehu*1l3MLdzCLSFS%=95sA@0;u!G zE(Mgv6R+BNUpWe$-ffF0hABDmKhMG#@IGhdRHXXx!Xcx9CqbSivOyh&jV9yzfxW6Z zp{EH{((ucK5vdSln@zzov6XejaaPv$W4|kmfcnbR0=9%|{3r$E^tFE;y%U75>F&pz}Emv2&E#J7pRj$yP45E8q?F z{;ASTO^p2ehof;~4u(Kh>l2JE9?}5l;wN}|R?X>KwQEV!8NzRm`spA#gO!2BP(?N) z-afwazV_Ulv+@vSsi~;oBfmD>dw*aQjjgNVvX?jsGw-u@GyfY-q>HgWpIG21J)FFm z=|`4r%UpyF@MY{tI^