From 70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 Mon Sep 17 00:00:00 2001 From: AlexanderCurl Date: Sat, 18 Apr 2026 17:46:06 +0100 Subject: Replaced file structures for themes in the correct format --- .../Modules/AppDrawer/AppDrawerPopout.qml | 166 -- .../Modules/BlurredWallpaperBackground.qml | 332 --- .../BuiltinDesktopPlugins/DesktopClockWidget.qml | 547 ---- .../OrganicBlobHourBulges.qml | 137 - .../BuiltinDesktopPlugins/SystemMonitorWidget.qml | 743 ----- .../ControlCenter/BuiltinPlugins/CupsWidget.qml | 321 --- .../ControlCenter/BuiltinPlugins/VpnWidget.qml | 33 - .../ControlCenter/Components/ActionTile.qml | 132 - .../ControlCenter/Components/DetailHost.qml | 250 -- .../Components/DragDropDetailHost.qml | 91 - .../ControlCenter/Components/DragDropGrid.qml | 1091 ------- .../Components/DragDropWidgetWrapper.qml | 289 -- .../ControlCenter/Components/EditControls.qml | 245 -- .../ControlCenter/Components/HeaderPane.qml | 118 - .../ControlCenter/Components/PowerButton.qml | 55 - .../ControlCenter/Components/SizeControls.qml | 52 - .../ControlCenter/Components/Typography.qml | 46 - .../Modules/ControlCenter/ControlCenterPopout.qml | 272 -- .../ControlCenter/Details/AudioInputDetail.qml | 363 --- .../ControlCenter/Details/AudioOutputDetail.qml | 544 ---- .../ControlCenter/Details/BatteryDetail.qml | 267 -- .../Details/BluetoothCodecSelector.qml | 332 --- .../ControlCenter/Details/BluetoothDetail.qml | 743 ----- .../ControlCenter/Details/BrightnessDetail.qml | 498 ---- .../ControlCenter/Details/DiskUsageDetail.qml | 177 -- .../ControlCenter/Details/NetworkDetail.qml | 893 ------ .../Modules/ControlCenter/Models/WidgetModel.qml | 283 -- .../ControlCenter/Widgets/AudioSliderRow.qml | 103 - .../Modules/ControlCenter/Widgets/BatteryPill.qml | 46 - .../ControlCenter/Widgets/BrightnessSliderRow.qml | 194 -- .../ControlCenter/Widgets/ColorPickerPill.qml | 29 - .../ControlCenter/Widgets/CompactSlider.qml | 71 - .../Modules/ControlCenter/Widgets/CompoundPill.qml | 205 -- .../Modules/ControlCenter/Widgets/DetailView.qml | 23 - .../ControlCenter/Widgets/DiskUsagePill.qml | 76 - .../Modules/ControlCenter/Widgets/ErrorPill.qml | 56 - .../ControlCenter/Widgets/InputAudioSliderRow.qml | 87 - .../ControlCenter/Widgets/SmallBatteryButton.qml | 113 - .../ControlCenter/Widgets/SmallDiskUsageButton.qml | 129 - .../ControlCenter/Widgets/SmallToggleButton.qml | 90 - .../Modules/ControlCenter/Widgets/ToggleButton.qml | 134 - .../Modules/ControlCenter/utils/layout.js | 45 - .../Modules/ControlCenter/utils/state.js | 17 - .../Modules/ControlCenter/utils/widgets.js | 90 - .../quickshell/Modules/DankBar/AxisContext.qml | 57 - .../quickshell/Modules/DankBar/BarCanvas.qml | 671 ----- .../quickshell/Modules/DankBar/CenterSection.qml | 387 --- .../quickshell/Modules/DankBar/DankBar.qml | 182 -- .../quickshell/Modules/DankBar/DankBarContent.qml | 1459 ---------- .../quickshell/Modules/DankBar/DankBarWindow.qml | 1058 ------- .../quickshell/Modules/DankBar/LeftSection.qml | 119 - .../Modules/DankBar/Popouts/BatteryPopout.qml | 633 ---- .../Modules/DankBar/Popouts/DWLLayoutPopout.qml | 302 -- .../Modules/DankBar/Popouts/VpnPopout.qml | 87 - .../quickshell/Modules/DankBar/RightSection.qml | 121 - .../quickshell/Modules/DankBar/WidgetHost.qml | 290 -- .../Modules/DankBar/Widgets/AppsDock.qml | 1011 ------- .../DankBar/Widgets/AppsDockContextMenu.qml | 486 ---- .../DankBar/Widgets/AppsDockOverflowButton.qml | 76 - .../Modules/DankBar/Widgets/AudioVisualization.qml | 94 - .../quickshell/Modules/DankBar/Widgets/Battery.qml | 165 -- .../Modules/DankBar/Widgets/CapsLockIndicator.qml | 62 - .../Modules/DankBar/Widgets/ClipboardButton.qml | 314 -- .../quickshell/Modules/DankBar/Widgets/Clock.qml | 331 --- .../Modules/DankBar/Widgets/ColorPicker.qml | 37 - .../DankBar/Widgets/ControlCenterButton.qml | 830 ------ .../Modules/DankBar/Widgets/CpuMonitor.qml | 146 - .../Modules/DankBar/Widgets/CpuTemperature.qml | 140 - .../Modules/DankBar/Widgets/DWLLayout.qml | 110 - .../Modules/DankBar/Widgets/DiskUsage.qml | 255 -- .../Modules/DankBar/Widgets/FocusedApp.qml | 317 -- .../Modules/DankBar/Widgets/GpuTemperature.qml | 224 -- .../Modules/DankBar/Widgets/IdleInhibitor.qml | 36 - .../Modules/DankBar/Widgets/KeyboardLayoutName.qml | 268 -- .../Modules/DankBar/Widgets/LauncherButton.qml | 123 - .../quickshell/Modules/DankBar/Widgets/Media.qml | 502 ---- .../Modules/DankBar/Widgets/NetworkMonitor.qml | 147 - .../Modules/DankBar/Widgets/NotepadButton.qml | 367 --- .../DankBar/Widgets/NotificationCenterButton.qml | 40 - .../Modules/DankBar/Widgets/PowerMenuButton.qml | 25 - .../Modules/DankBar/Widgets/PrivacyIndicator.qml | 247 -- .../Modules/DankBar/Widgets/RamMonitor.qml | 175 -- .../Modules/DankBar/Widgets/RunningApps.qml | 902 ------ .../Modules/DankBar/Widgets/SystemTrayBar.qml | 1893 ------------ .../Modules/DankBar/Widgets/SystemUpdate.qml | 187 -- .../quickshell/Modules/DankBar/Widgets/Vpn.qml | 141 - .../quickshell/Modules/DankBar/Widgets/Weather.qml | 80 - .../Modules/DankBar/Widgets/WorkspaceSwitcher.qml | 1981 ------------- .../quickshell/Modules/DankDash/DankDashPopout.qml | 425 --- .../Modules/DankDash/MediaDropdownOverlay.qml | 513 ---- .../quickshell/Modules/DankDash/MediaPlayerTab.qml | 785 ----- .../DankDash/Overview/CalendarOverviewCard.qml | 539 ---- .../quickshell/Modules/DankDash/Overview/Card.qml | 24 - .../Modules/DankDash/Overview/ClockCard.qml | 113 - .../DankDash/Overview/MediaOverviewCard.qml | 211 -- .../DankDash/Overview/SystemMonitorCard.qml | 178 -- .../Modules/DankDash/Overview/UserInfoCard.qml | 110 - .../DankDash/Overview/WeatherOverviewCard.qml | 94 - .../quickshell/Modules/DankDash/OverviewTab.qml | 75 - .../quickshell/Modules/DankDash/WallpaperTab.qml | 590 ---- .../Modules/DankDash/WeatherForecastCard.qml | 206 -- .../quickshell/Modules/DankDash/WeatherTab.qml | 1124 -------- .../quickshell/Modules/DesktopWidgetLayer.qml | 110 - .../quickshell/Modules/Dock/Dock.qml | 671 ----- .../quickshell/Modules/Dock/DockAppButton.qml | 670 ----- .../quickshell/Modules/Dock/DockApps.qml | 646 ----- .../quickshell/Modules/Dock/DockContextMenu.qml | 585 ---- .../quickshell/Modules/Dock/DockLauncherButton.qml | 296 -- .../quickshell/Modules/Dock/DockOverflowButton.qml | 75 - .../quickshell/Modules/Greetd/GreetdEnv.js | 20 - .../quickshell/Modules/Greetd/GreetdMemory.qml | 128 - .../quickshell/Modules/Greetd/GreetdSettings.qml | 199 -- .../quickshell/Modules/Greetd/GreeterContent.qml | 1908 ------------- .../quickshell/Modules/Greetd/GreeterState.qml | 30 - .../quickshell/Modules/Greetd/GreeterSurface.qml | 34 - .../quickshell/Modules/Greetd/README.md | 277 -- .../quickshell/Modules/Greetd/assets/dms-greeter | 424 --- .../quickshell/Modules/Greetd/assets/dms-hypr.conf | 3 - .../quickshell/Modules/Greetd/assets/dms-niri.kdl | 23 - .../Modules/Greetd/assets/greet-hyprland.sh | 11 - .../quickshell/Modules/Greetd/assets/greet-niri.sh | 8 - .../Modules/Lock/CustomButtonKeyboard.qml | 41 - .../quickshell/Modules/Lock/FadeToDpmsWindow.qml | 102 - .../quickshell/Modules/Lock/FadeToLockWindow.qml | 102 - .../quickshell/Modules/Lock/Keyboard.qml | 344 --- .../quickshell/Modules/Lock/KeyboardController.qml | 40 - .../quickshell/Modules/Lock/Lock.qml | 296 -- .../quickshell/Modules/Lock/LockPowerMenu.qml | 820 ------ .../quickshell/Modules/Lock/LockScreenContent.qml | 1707 ----------- .../quickshell/Modules/Lock/LockScreenDemo.qml | 46 - .../quickshell/Modules/Lock/LockSurface.qml | 73 - .../quickshell/Modules/Lock/Pam.qml | 405 --- .../quickshell/Modules/Lock/VideoScreensaver.qml | 200 -- .../quickshell/Modules/Notepad/Notepad.qml | 531 ---- .../quickshell/Modules/Notepad/NotepadSettings.qml | 367 --- .../quickshell/Modules/Notepad/NotepadTabs.qml | 285 -- .../Modules/Notepad/NotepadTextEditor.qml | 924 ------ .../Center/HistoryNotificationCard.qml | 277 -- .../Center/HistoryNotificationList.qml | 387 --- .../Center/KeyboardNavigatedNotificationList.qml | 311 -- .../Notifications/Center/NotificationCard.qml | 1073 ------- .../Center/NotificationCenterPopout.qml | 321 --- .../Center/NotificationEmptyState.qml | 34 - .../Notifications/Center/NotificationHeader.qml | 158 - .../Center/NotificationKeyboardController.qml | 556 ---- .../Center/NotificationKeyboardHints.qml | 50 - .../Notifications/Center/NotificationSettings.qml | 449 --- .../Notifications/Popup/NotificationPopup.qml | 1164 -------- .../Popup/NotificationPopupManager.qml | 239 -- .../quickshell/Modules/OSD/AudioOutputOSD.qml | 67 - .../quickshell/Modules/OSD/BrightnessOSD.qml | 274 -- .../quickshell/Modules/OSD/CapsLockOSD.qml | 37 - .../quickshell/Modules/OSD/IdleInhibitorOSD.qml | 29 - .../quickshell/Modules/OSD/MediaPlaybackOSD.qml | 319 --- .../quickshell/Modules/OSD/MediaVolumeOSD.qml | 264 -- .../quickshell/Modules/OSD/MicMuteOSD.qml | 29 - .../quickshell/Modules/OSD/PowerProfileOSD.qml | 43 - .../quickshell/Modules/OSD/VolumeOSD.qml | 254 -- .../quickshell/Modules/Plugins/BasePill.qml | 195 -- .../quickshell/Modules/Plugins/ColorSetting.qml | 104 - .../Modules/Plugins/DesktopPluginComponent.qml | 67 - .../Modules/Plugins/DesktopPluginWrapper.qml | 758 ----- .../quickshell/Modules/Plugins/ListSetting.qml | 132 - .../Modules/Plugins/ListSettingWithInput.qml | 256 -- .../quickshell/Modules/Plugins/PluginComponent.qml | 333 --- .../Modules/Plugins/PluginControlCenterWrapper.qml | 51 - .../quickshell/Modules/Plugins/PluginPopout.qml | 83 - .../quickshell/Modules/Plugins/PluginSettings.qml | 311 -- .../quickshell/Modules/Plugins/PopoutComponent.qml | 87 - .../Modules/Plugins/SelectionSetting.qml | 91 - .../quickshell/Modules/Plugins/SliderSetting.qml | 81 - .../quickshell/Modules/Plugins/StringSetting.qml | 84 - .../quickshell/Modules/Plugins/ToggleSetting.qml | 81 - .../quickshell/Modules/ProcessList/DisksView.qml | 346 --- .../Modules/ProcessList/PerformanceView.qml | 304 -- .../Modules/ProcessList/ProcessContextMenu.qml | 341 --- .../Modules/ProcessList/ProcessListPopout.qml | 535 ---- .../Modules/ProcessList/ProcessesView.qml | 769 ----- .../quickshell/Modules/ProcessList/SystemView.qml | 386 --- .../quickshell/Modules/Settings/AboutTab.qml | 900 ------ .../quickshell/Modules/Settings/AudioTab.qml | 747 ----- .../quickshell/Modules/Settings/ClipboardTab.qml | 463 --- .../quickshell/Modules/Settings/DankBarTab.qml | 1563 ---------- .../Modules/Settings/DesktopWidgetBrowser.qml | 477 ---- .../Modules/Settings/DesktopWidgetInstanceCard.qml | 460 --- .../DesktopWidgetSettings/ClockSettings.qml | 163 -- .../PluginDesktopWidgetSettings.qml | 137 - .../SystemMonitorSettings.qml | 444 --- .../Modules/Settings/DesktopWidgetsTab.qml | 708 ----- .../Settings/DisplayConfig/DisplayConfigState.qml | 1837 ------------ .../DisplayConfig/HyprlandOutputSettings.qml | 310 -- .../Settings/DisplayConfig/IncludeWarningBox.qml | 94 - .../Settings/DisplayConfig/MonitorCanvas.qml | 82 - .../Modules/Settings/DisplayConfig/MonitorRect.qml | 159 -- .../Settings/DisplayConfig/NiriOutputSettings.qml | 368 --- .../Settings/DisplayConfig/NoBackendMessage.qml | 60 - .../Modules/Settings/DisplayConfig/OutputCard.qml | 352 --- .../Modules/Settings/DisplayConfigTab.qml | 540 ---- .../Modules/Settings/DisplayWidgetsTab.qml | 522 ---- .../quickshell/Modules/Settings/DockTab.qml | 657 ----- .../Modules/Settings/GammaControlTab.qml | 663 ----- .../quickshell/Modules/Settings/GreeterTab.qml | 784 ----- .../quickshell/Modules/Settings/KeybindsTab.qml | 672 ----- .../quickshell/Modules/Settings/LauncherTab.qml | 1306 --------- .../quickshell/Modules/Settings/LocaleTab.qml | 91 - .../quickshell/Modules/Settings/LockScreenTab.qml | 458 --- .../quickshell/Modules/Settings/MediaPlayerTab.qml | 119 - .../quickshell/Modules/Settings/MuxTab.qml | 112 - .../quickshell/Modules/Settings/NetworkTab.qml | 1999 ------------- .../Modules/Settings/NotificationsTab.qml | 900 ------ .../quickshell/Modules/Settings/OSDTab.qml | 165 -- .../quickshell/Modules/Settings/PluginBrowser.qml | 856 ------ .../quickshell/Modules/Settings/PluginListItem.qml | 439 --- .../quickshell/Modules/Settings/PluginsTab.qml | 450 --- .../quickshell/Modules/Settings/PowerSleepTab.qml | 598 ---- .../quickshell/Modules/Settings/PrinterTab.qml | 1702 ----------- .../quickshell/Modules/Settings/RunningAppsTab.qml | 175 -- .../quickshell/Modules/Settings/SoundsTab.qml | 168 -- .../Modules/Settings/SystemUpdaterTab.qml | 142 - .../quickshell/Modules/Settings/ThemeBrowser.qml | 697 ----- .../quickshell/Modules/Settings/ThemeColorsTab.qml | 3016 -------------------- .../quickshell/Modules/Settings/TimeWeatherTab.qml | 1148 -------- .../Modules/Settings/TypographyMotionTab.qml | 490 ---- .../quickshell/Modules/Settings/WallpaperTab.qml | 1368 --------- .../Modules/Settings/WidgetSelectionPopup.qml | 382 --- .../Modules/Settings/Widgets/DeviceAliasRow.qml | 180 -- .../Settings/Widgets/SettingsButtonGroupRow.qml | 117 - .../Modules/Settings/Widgets/SettingsCard.qml | 199 -- .../Settings/Widgets/SettingsColorPicker.qml | 119 - .../Settings/Widgets/SettingsDisplayPicker.qml | 103 - .../Modules/Settings/Widgets/SettingsDivider.qml | 11 - .../Settings/Widgets/SettingsDropdownRow.qml | 60 - .../Settings/Widgets/SettingsSliderCard.qml | 108 - .../Modules/Settings/Widgets/SettingsSliderRow.qml | 148 - .../Settings/Widgets/SettingsToggleCard.qml | 120 - .../Modules/Settings/Widgets/SettingsToggleRow.qml | 58 - .../Settings/Widgets/SystemMonitorVariantCard.qml | 390 --- .../quickshell/Modules/Settings/WidgetsTab.qml | 1145 -------- .../Modules/Settings/WidgetsTabSection.qml | 2940 ------------------- .../quickshell/Modules/Settings/WindowRulesTab.qml | 685 ----- .../quickshell/Modules/Settings/WorkspacesTab.qml | 526 ---- .../quickshell/Modules/SystemUpdatePopout.qml | 329 --- .../DankMaterialShell/quickshell/Modules/Toast.qml | 444 --- .../quickshell/Modules/WallpaperBackground.qml | 658 ----- .../Modules/WorkspaceOverlays/HyprlandOverview.qml | 291 -- .../WorkspaceOverlays/NiriOverviewOverlay.qml | 322 --- .../Modules/WorkspaceOverlays/OverviewWidget.qml | 443 --- .../Modules/WorkspaceOverlays/OverviewWindow.qml | 142 - 248 files changed, 96205 deletions(-) delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/AppDrawer/AppDrawerPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/ActionTile.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DetailHost.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropDetailHost.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropWidgetWrapper.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/EditControls.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/HeaderPane.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/PowerButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/SizeControls.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/Typography.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/ControlCenterPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BatteryDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BrightnessDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/DiskUsageDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Models/WidgetModel.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/AudioSliderRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BatteryPill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ColorPickerPill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompactSlider.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DetailView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DiskUsagePill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ErrorPill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/InputAudioSliderRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/layout.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/state.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/widgets.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/AxisContext.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/BarCanvas.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/CenterSection.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBar.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarWindow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/LeftSection.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/DWLLayoutPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/VpnPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/RightSection.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/WidgetHost.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDock.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockOverflowButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AudioVisualization.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Battery.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CapsLockIndicator.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Clock.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ColorPicker.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuMonitor.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuTemperature.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DWLLayout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DiskUsage.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/FocusedApp.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/GpuTemperature.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/IdleInhibitor.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/KeyboardLayoutName.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/LauncherButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Media.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotepadButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotificationCenterButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PowerMenuButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PrivacyIndicator.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RamMonitor.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RunningApps.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Vpn.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Weather.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/DankDashPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaDropdownOverlay.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaPlayerTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/Card.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/ClockCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/SystemMonitorCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/UserInfoCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/OverviewTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WallpaperTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherForecastCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DesktopWidgetLayer.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/Dock.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockAppButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockApps.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockContextMenu.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockLauncherButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockOverflowButton.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdEnv.js delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdMemory.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterState.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterSurface.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/README.md delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-greeter delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-hypr.conf delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-niri.kdl delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-hyprland.sh delete mode 100755 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-niri.sh delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/CustomButtonKeyboard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToDpmsWindow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToLockWindow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Keyboard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/KeyboardController.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Lock.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockPowerMenu.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenContent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenDemo.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockSurface.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Pam.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/VideoScreensaver.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/Notepad.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTextEditor.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/HistoryNotificationList.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/KeyboardNavigatedNotificationList.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationCenterPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationEmptyState.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationHeader.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardController.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Center/NotificationSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Popup/NotificationPopup.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notifications/Popup/NotificationPopupManager.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/AudioOutputOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/BrightnessOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/CapsLockOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/IdleInhibitorOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaPlaybackOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaVolumeOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MicMuteOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/PowerProfileOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/VolumeOSD.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/BasePill.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ColorSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/DesktopPluginComponent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/DesktopPluginWrapper.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ListSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ListSettingWithInput.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginComponent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginControlCenterWrapper.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PluginSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/PopoutComponent.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/SelectionSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/SliderSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/StringSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Plugins/ToggleSetting.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/DisksView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/PerformanceView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessContextMenu.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessListPopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/ProcessesView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ProcessList/SystemView.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AboutTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AudioTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ClipboardTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DankBarTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetBrowser.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetInstanceCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/ClockSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/PluginDesktopWidgetSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorCanvas.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorRect.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NiriOutputSettings.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NoBackendMessage.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/OutputCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfigTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayWidgetsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DockTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GammaControlTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GreeterTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/KeybindsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LauncherTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LocaleTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LockScreenTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MediaPlayerTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MuxTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NetworkTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NotificationsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/OSDTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginBrowser.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginListItem.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PowerSleepTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PrinterTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/RunningAppsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SoundsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SystemUpdaterTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeBrowser.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeColorsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TimeWeatherTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TypographyMotionTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WallpaperTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetSelectionPopup.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/DeviceAliasRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsColorPicker.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDisplayPicker.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDivider.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SystemMonitorVariantCard.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTabSection.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WindowRulesTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WorkspacesTab.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/SystemUpdatePopout.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Toast.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WallpaperBackground.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml delete mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWindow.qml (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules') diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/AppDrawer/AppDrawerPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/AppDrawer/AppDrawerPopout.qml deleted file mode 100644 index ba07d37..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/AppDrawer/AppDrawerPopout.qml +++ /dev/null @@ -1,166 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals.DankLauncherV2 -import qs.Widgets - -DankPopout { - id: appDrawerPopout - - layerNamespace: "dms:app-launcher" - - readonly property real screenWidth: screen?.width ?? 1920 - readonly property real screenHeight: screen?.height ?? 1080 - - property string _pendingMode: "" - property string _pendingQuery: "" - - function show() { - open(); - } - - function openWithMode(mode) { - _pendingMode = mode || ""; - open(); - } - - function toggleWithMode(mode) { - if (shouldBeVisible) { - close(); - return; - } - openWithMode(mode); - } - - function openWithQuery(query) { - _pendingQuery = query || ""; - open(); - } - - function toggleWithQuery(query) { - if (shouldBeVisible) { - close(); - return; - } - openWithQuery(query); - } - - readonly property int _baseWidth: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 500; - case "medium": - return 720; - case "large": - return 860; - default: - return 620; - } - } - - readonly property int _baseHeight: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 480; - case "medium": - return 720; - case "large": - return 860; - default: - return 600; - } - } - - popupWidth: Math.min(_baseWidth, screenWidth - 100) - popupHeight: Math.min(_baseHeight, screenHeight - 100) - - triggerWidth: 40 - positioning: "" - contentHandlesKeys: contentLoader.item?.launcherContent?.editMode ?? false - - onBackgroundClicked: { - if (contentLoader.item?.launcherContent?.editMode) { - contentLoader.item.launcherContent.closeEditMode(); - return; - } - close(); - } - - onOpened: { - var lc = contentLoader.item?.launcherContent; - if (!lc) - return; - - const query = _pendingQuery || (SettingsData.rememberLastQuery ? SessionData.launcherLastQuery : "") || ""; - const mode = _pendingMode || SessionData.appDrawerLastMode || "apps"; - _pendingMode = ""; - _pendingQuery = ""; - - if (lc.searchField) { - lc.searchField.text = query; - lc.searchField.forceActiveFocus(); - } - if (lc.controller) { - lc.controller.searchMode = mode; - lc.controller.pluginFilter = ""; - lc.controller.searchQuery = query; - - lc.controller.performSearch(); - } - lc.resetScroll?.(); - lc.actionPanel?.hide(); - } - - Connections { - target: contentLoader.item?.launcherContent?.controller ?? null - function onModeChanged(mode) { - if (contentLoader.item.launcherContent.controller.autoSwitchedToFiles) - return; - SessionData.setAppDrawerLastMode(mode); - } - } - - content: Component { - Rectangle { - id: contentContainer - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property alias launcherContent: launcherContent - - color: "transparent" - - QtObject { - id: modalAdapter - property bool spotlightOpen: appDrawerPopout.shouldBeVisible - readonly property bool isClosing: !appDrawerPopout.shouldBeVisible - - function hide() { - appDrawerPopout.close(); - } - } - - FocusScope { - anchors.fill: parent - focus: true - - LauncherContent { - id: launcherContent - anchors.fill: parent - parentModal: modalAdapter - viewModeContext: "appDrawer" - } - - Keys.onEscapePressed: event => { - if (launcherContent.editMode) { - launcherContent.closeEditMode(); - event.accepted = true; - return; - } - appDrawerPopout.close(); - event.accepted = true; - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml deleted file mode 100644 index 6a5c6e8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml +++ /dev/null @@ -1,332 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Widgets -import qs.Services - -Variants { - model: { - if (SessionData.isGreeterMode) { - return Quickshell.screens; - } - return SettingsData.getFilteredScreens("wallpaper"); - } - - PanelWindow { - id: blurWallpaperWindow - - required property var modelData - - screen: modelData - - WlrLayershell.layer: WlrLayer.Background - WlrLayershell.namespace: "dms:blurwallpaper" - WlrLayershell.exclusionMode: ExclusionMode.Ignore - - anchors.top: true - anchors.bottom: true - anchors.left: true - anchors.right: true - - color: "transparent" - - mask: Region { - item: Item {} - } - - Item { - id: root - anchors.fill: parent - - function encodeFileUrl(path) { - if (!path) - return ""; - return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/'); - } - - property string source: SessionData.getMonitorWallpaper(modelData.name) || "" - property bool isColorSource: source.startsWith("#") - - Connections { - target: SessionData - function onIsLightModeChanged() { - if (SessionData.perModeWallpaper) { - var newSource = SessionData.getMonitorWallpaper(modelData.name) || ""; - if (newSource !== root.source) { - root.source = newSource; - } - } - } - } - - function getFillMode(modeName) { - switch (modeName) { - case "Stretch": - return Image.Stretch; - case "Fit": - case "PreserveAspectFit": - return Image.PreserveAspectFit; - case "Fill": - case "PreserveAspectCrop": - return Image.PreserveAspectCrop; - case "Tile": - return Image.Tile; - case "TileVertically": - return Image.TileVertically; - case "TileHorizontally": - return Image.TileHorizontally; - case "Pad": - return Image.Pad; - default: - return Image.PreserveAspectCrop; - } - } - - Component.onCompleted: { - if (typeof blurWallpaperWindow.updatesEnabled !== "undefined") - blurWallpaperWindow.updatesEnabled = Qt.binding(() => !root.source || root.effectActive || root._renderSettling || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading); - isInitialized = true; - } - - property bool isInitialized: false - property real transitionProgress: 0 - readonly property bool transitioning: transitionAnimation.running - property bool effectActive: false - property bool _renderSettling: true - property bool useNextForEffect: false - - Connections { - target: currentWallpaper - function onStatusChanged() { - if (currentWallpaper.status !== Image.Ready && currentWallpaper.status !== Image.Error) - return; - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: blurWallpaperWindow - function onWidthChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - function onHeightChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: Quickshell - function onScreensChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Timer { - id: renderSettleTimer - interval: 1000 - onTriggered: root._renderSettling = false - } - - onSourceChanged: { - if (!source || source.startsWith("#")) { - setWallpaperImmediate(""); - return; - } - - const formattedSource = source.startsWith("file://") ? source : encodeFileUrl(source); - - if (!isInitialized || !currentWallpaper.source) { - setWallpaperImmediate(formattedSource); - isInitialized = true; - return; - } - if (CompositorService.isNiri && SessionData.isSwitchingMode) { - setWallpaperImmediate(formattedSource); - return; - } - changeWallpaper(formattedSource); - } - - function setWallpaperImmediate(newSource) { - transitionAnimation.stop(); - root.transitionProgress = 0.0; - root.effectActive = false; - root._renderSettling = true; - renderSettleTimer.restart(); - currentWallpaper.source = newSource; - nextWallpaper.source = ""; - } - - function startTransition() { - root.useNextForEffect = true; - root.effectActive = true; - if (srcNext.scheduleUpdate) - srcNext.scheduleUpdate(); - transitionDelayTimer.start(); - } - - Timer { - id: transitionDelayTimer - interval: 16 - repeat: false - onTriggered: transitionAnimation.start() - } - - function changeWallpaper(newPath) { - if (newPath === currentWallpaper.source) - return; - if (!newPath || newPath.startsWith("#")) - return; - if (root.transitioning) { - transitionAnimation.stop(); - root.transitionProgress = 0; - root.effectActive = false; - root._renderSettling = true; - renderSettleTimer.restart(); - currentWallpaper.source = nextWallpaper.source; - nextWallpaper.source = ""; - } - if (!currentWallpaper.source) { - setWallpaperImmediate(newPath); - return; - } - - root._renderSettling = true; - renderSettleTimer.restart(); - - nextWallpaper.source = newPath; - - if (nextWallpaper.status === Image.Ready) - root.startTransition(); - } - - Loader { - anchors.fill: parent - active: !root.source || root.isColorSource - asynchronous: true - - sourceComponent: DankBackdrop { - screenName: modelData.name - } - } - - readonly property int maxTextureSize: 8192 - property int textureWidth: Math.min(modelData.width, maxTextureSize) - property int textureHeight: Math.min(modelData.height, maxTextureSize) - - Image { - id: currentWallpaper - anchors.fill: parent - visible: false - opacity: 1 - asynchronous: true - retainWhileLoading: true - smooth: true - cache: true - sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name)) - } - - Image { - id: nextWallpaper - anchors.fill: parent - visible: false - opacity: 0 - asynchronous: true - retainWhileLoading: true - smooth: true - cache: true - sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name)) - - onStatusChanged: { - if (status !== Image.Ready) - return; - if (!root.transitioning) { - root.startTransition(); - } - } - } - - ShaderEffectSource { - id: srcNext - sourceItem: root.effectActive ? nextWallpaper : null - hideSource: root.effectActive - live: root.effectActive - mipmap: false - recursive: false - textureSize: Qt.size(root.textureWidth, root.textureHeight) - } - - Rectangle { - id: dummyRect - width: 1 - height: 1 - visible: false - color: "transparent" - } - - ShaderEffectSource { - id: srcDummy - sourceItem: dummyRect - hideSource: true - live: false - mipmap: false - recursive: false - } - - Item { - id: blurredLayer - anchors.fill: parent - - MultiEffect { - anchors.fill: parent - source: currentWallpaper - visible: currentWallpaper.source !== "" - blurEnabled: true - blur: 0.8 - blurMax: 75 - opacity: 1 - root.transitionProgress - autoPaddingEnabled: false - } - - MultiEffect { - anchors.fill: parent - source: root.useNextForEffect ? srcNext : srcDummy - visible: nextWallpaper.source !== "" && root.useNextForEffect - blurEnabled: true - blur: 0.8 - blurMax: 75 - opacity: root.transitionProgress - autoPaddingEnabled: false - } - } - - NumberAnimation { - id: transitionAnimation - target: root - property: "transitionProgress" - from: 0.0 - to: 1.0 - duration: 1000 - easing.type: Easing.InOutCubic - onFinished: { - if (nextWallpaper.source && nextWallpaper.status === Image.Ready) - currentWallpaper.source = nextWallpaper.source; - root.useNextForEffect = false; - nextWallpaper.source = ""; - root.transitionProgress = 0.0; - root._renderSettling = true; - renderSettleTimer.restart(); - root.effectActive = false; - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml deleted file mode 100644 index dc2ea24..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/DesktopClockWidget.qml +++ /dev/null @@ -1,547 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Widgets - -Item { - id: root - - property real widgetWidth: 280 - property real widgetHeight: 200 - - property string instanceId: "" - property var instanceData: null - readonly property var cfg: instanceData?.config ?? null - readonly property bool isInstance: instanceId !== "" && cfg !== null - - property string clockStyle: isInstance ? (cfg.style ?? "analog") : SettingsData.desktopClockStyle - property bool forceSquare: clockStyle === "analog" - - property real defaultWidth: { - switch (clockStyle) { - case "analog": - return 200; - case "stacked": - return 100; - default: - return 160; - } - } - property real defaultHeight: { - switch (clockStyle) { - case "analog": - return 200; - case "stacked": - return 160; - default: - return 70; - } - } - property real minWidth: { - switch (clockStyle) { - case "analog": - return 120; - case "stacked": - return 70; - default: - return 100; - } - } - property real minHeight: { - switch (clockStyle) { - case "analog": - return 120; - case "stacked": - return 100; - default: - return 45; - } - } - - property bool enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.desktopClockEnabled - property real transparency: isInstance ? (cfg.transparency ?? 0.8) : SettingsData.desktopClockTransparency - property string colorMode: isInstance ? (cfg.colorMode ?? "primary") : SettingsData.desktopClockColorMode - property color customColor: isInstance ? (cfg.customColor ?? "#ffffff") : SettingsData.desktopClockCustomColor - property bool showDate: isInstance ? (cfg.showDate ?? true) : SettingsData.desktopClockShowDate - property bool showAnalogNumbers: isInstance ? (cfg.showAnalogNumbers ?? false) : SettingsData.desktopClockShowAnalogNumbers - - readonly property real scaleFactor: Math.min(width, height) / 200 - - readonly property color accentColor: { - if (colorMode === "primary") - return Theme.primary; - if (colorMode === "secondary") - return Theme.secondary; - if (colorMode === "custom") - return customColor; - return Theme.primary; - } - - readonly property color handColor: accentColor - readonly property color handColorDim: Theme.withAlpha(accentColor, 0.65) - readonly property color textColor: Theme.onSurface - readonly property color subtleTextColor: Theme.onSurfaceVariant - readonly property color backgroundColor: Theme.withAlpha(Theme.surface, root.transparency) - - readonly property bool showAnalogSeconds: isInstance ? (cfg.showAnalogSeconds ?? true) : SettingsData.desktopClockShowAnalogSeconds - readonly property bool showDigitalSeconds: isInstance ? (cfg.showDigitalSeconds ?? false) : false - readonly property bool needsSeconds: clockStyle === "analog" ? showAnalogSeconds : showDigitalSeconds - - SystemClock { - id: systemClock - precision: root.needsSeconds ? SystemClock.Seconds : SystemClock.Minutes - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: root.backgroundColor - visible: root.clockStyle !== "analog" - } - - OrganicBlobHourBulges { - anchors.fill: parent - fillColor: root.backgroundColor - visible: root.clockStyle === "analog" - lobes: 12 - rotationDeg: -90 - lobeAmount: 0.075 - hillPower: 0.92 - roundness: 0.22 - paddingFrac: 0.02 - segments: 144 - } - - Loader { - anchors.fill: parent - anchors.margins: Theme.spacingM - sourceComponent: { - if (root.clockStyle === "analog") - return analogClock; - if (root.clockStyle === "stacked") - return stackedClock; - return digitalClock; - } - } - - Component { - id: analogClock - - Item { - id: analogRoot - - property real clockSize: Math.min(width, height) - property real centerX: width / 2 - property real centerY: height / 2 - property real faceRadius: clockSize / 2 - 12 - - property int hours: systemClock.date?.getHours() % 12 ?? 0 - property int minutes: systemClock.date?.getMinutes() ?? 0 - property int seconds: systemClock.date?.getSeconds() ?? 0 - - Repeater { - model: root.showAnalogNumbers ? 12 : 0 - - StyledText { - required property int index - property real angle: (index + 1) * 30 * Math.PI / 180 - property real numRadius: analogRoot.faceRadius + 10 - - x: analogRoot.centerX + numRadius * Math.sin(angle) - width / 2 - y: analogRoot.centerY - numRadius * Math.cos(angle) - height / 2 - text: index + 1 - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: root.accentColor - } - } - - Rectangle { - id: hourHand - property real angle: (analogRoot.hours + analogRoot.minutes / 60) * 30 - property real handWidth: Math.max(8, 12 * root.scaleFactor) - property real mainLength: analogRoot.faceRadius * 0.55 - property real tailLength: handWidth * 0.5 - - x: analogRoot.centerX - width / 2 - y: analogRoot.centerY - mainLength - width: handWidth - height: mainLength + tailLength - radius: width / 2 - color: root.handColor - antialiasing: true - - transform: Rotation { - origin.x: hourHand.width / 2 - origin.y: hourHand.mainLength - angle: hourHand.angle - } - } - - Rectangle { - id: minuteHand - property real angle: (analogRoot.minutes + analogRoot.seconds / 60) * 6 - property real mainLength: analogRoot.faceRadius * 0.75 - property real tailLength: hourHand.handWidth * 0.5 - - x: analogRoot.centerX - width / 2 - y: analogRoot.centerY - mainLength - width: hourHand.handWidth - height: mainLength + tailLength - radius: width / 2 - color: root.handColorDim - antialiasing: true - - transform: Rotation { - origin.x: minuteHand.width / 2 - origin.y: minuteHand.mainLength - angle: minuteHand.angle - } - } - - Rectangle { - id: secondDot - visible: root.showAnalogSeconds - - property real angle: analogRoot.seconds * 6 * Math.PI / 180 - property real orbitRadius: analogRoot.faceRadius * 0.92 - - x: analogRoot.centerX + orbitRadius * Math.sin(angle) - width / 2 - y: analogRoot.centerY - orbitRadius * Math.cos(angle) - height / 2 - width: Math.max(10, analogRoot.clockSize * 0.07) - height: width - radius: width / 2 - color: root.accentColor - - Behavior on x { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - Behavior on y { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - StyledText { - id: dateText - visible: root.showDate - - property real hourAngle: (analogRoot.hours + analogRoot.minutes / 60) * 30 - property real minuteAngle: analogRoot.minutes * 6 - - property string bestPosition: { - const hRad = hourAngle * Math.PI / 180; - const mRad = minuteAngle * Math.PI / 180; - - const topWeight = Math.max(0, Math.cos(hRad)) + Math.max(0, Math.cos(mRad)); - const bottomWeight = Math.max(0, -Math.cos(hRad)) + Math.max(0, -Math.cos(mRad)); - const rightWeight = Math.max(0, Math.sin(hRad)) + Math.max(0, Math.sin(mRad)); - const leftWeight = Math.max(0, -Math.sin(hRad)) + Math.max(0, -Math.sin(mRad)); - - const minWeight = Math.min(topWeight, bottomWeight, leftWeight, rightWeight); - - if (minWeight === bottomWeight) - return "bottom"; - if (minWeight === topWeight) - return "top"; - if (minWeight === rightWeight) - return "right"; - return "left"; - } - - x: { - if (bestPosition === "left") - return analogRoot.centerX - analogRoot.faceRadius * 0.5 - width / 2; - if (bestPosition === "right") - return analogRoot.centerX + analogRoot.faceRadius * 0.5 - width / 2; - return analogRoot.centerX - width / 2; - } - y: { - if (bestPosition === "top") - return analogRoot.centerY - analogRoot.faceRadius * 0.5 - height / 2; - if (bestPosition === "bottom") - return analogRoot.centerY + analogRoot.faceRadius * 0.5 - height / 2; - return analogRoot.centerY - height / 2; - } - - text: { - if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0) - return systemClock.date?.toLocaleDateString(I18n.locale(), SettingsData.clockDateFormat) ?? ""; - return systemClock.date?.toLocaleDateString(I18n.locale(), "ddd, MMM d") ?? ""; - } - font.pixelSize: Theme.fontSizeSmall - color: root.accentColor - - Behavior on x { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - Behavior on y { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - } - } - - Component { - id: digitalClock - - Item { - id: digitalRoot - - property bool hasDate: root.showDate - property bool hasAmPm: !SettingsData.use24HourClock - property real verticalScale: hasDate && hasAmPm ? 0.55 : (hasDate || hasAmPm ? 0.65 : 0.8) - property real baseSize: Math.min(height * verticalScale, width * 0.22) - property real digitWidth: baseSize * 0.62 - property real smallSize: baseSize * 0.35 - - property string hoursStr: { - const hours = SettingsData.use24HourClock ? systemClock.date?.getHours() ?? 0 : ((systemClock.date?.getHours() ?? 0) % 12 || 12); - if (SettingsData.use24HourClock || SettingsData.padHours12Hour) - return String(hours).padStart(2, '0'); - return String(hours); - } - property string minutesStr: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0') - property string secondsStr: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0') - - Column { - anchors.centerIn: parent - spacing: 0 - - StyledText { - visible: root.showDate - anchors.horizontalCenter: parent.horizontalCenter - text: { - if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0) - return systemClock.date?.toLocaleDateString(I18n.locale(), SettingsData.clockDateFormat) ?? ""; - return systemClock.date?.toLocaleDateString(I18n.locale(), "ddd, MMM d") ?? ""; - } - font.pixelSize: digitalRoot.smallSize - color: Theme.withAlpha(root.accentColor, 0.7) - } - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 0 - - StyledText { - visible: digitalRoot.hoursStr.length > 1 - width: digitalRoot.digitWidth - text: digitalRoot.hoursStr.charAt(0) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - horizontalAlignment: Text.AlignHCenter - } - StyledText { - width: digitalRoot.digitWidth - text: digitalRoot.hoursStr.length > 1 ? digitalRoot.hoursStr.charAt(1) : digitalRoot.hoursStr.charAt(0) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - horizontalAlignment: Text.AlignHCenter - } - StyledText { - text: ":" - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - } - StyledText { - width: digitalRoot.digitWidth - text: digitalRoot.minutesStr.charAt(0) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - horizontalAlignment: Text.AlignHCenter - } - StyledText { - width: digitalRoot.digitWidth - text: digitalRoot.minutesStr.charAt(1) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - horizontalAlignment: Text.AlignHCenter - } - StyledText { - visible: root.showDigitalSeconds - text: ":" - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - } - StyledText { - visible: root.showDigitalSeconds - width: digitalRoot.digitWidth - text: digitalRoot.secondsStr.charAt(0) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - horizontalAlignment: Text.AlignHCenter - } - StyledText { - visible: root.showDigitalSeconds - width: digitalRoot.digitWidth - text: digitalRoot.secondsStr.charAt(1) - font.pixelSize: digitalRoot.baseSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - horizontalAlignment: Text.AlignHCenter - } - } - - StyledText { - visible: !SettingsData.use24HourClock - anchors.horizontalCenter: parent.horizontalCenter - text: (systemClock.date?.getHours() ?? 0) >= 12 ? "PM" : "AM" - font.pixelSize: digitalRoot.smallSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - } - } - } - } - - Component { - id: stackedClock - - Item { - id: stackedRoot - - property bool hasSeconds: root.showDigitalSeconds - property bool hasDate: root.showDate - property bool hasAmPm: !SettingsData.use24HourClock - property real extraContent: (hasSeconds ? 0.12 : 0) + (hasDate ? 0.08 : 0) + (hasAmPm ? 0.08 : 0) - property real baseSize: height * (0.42 - extraContent * 0.5) - property real digitWidth: baseSize * 0.58 - property real smallSize: baseSize * 0.5 - property real rowSpacing: -baseSize * 0.17 - - Column { - anchors.centerIn: parent - spacing: 0 - - Column { - spacing: stackedRoot.rowSpacing - anchors.horizontalCenter: parent.horizontalCenter - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: { - if (SettingsData.use24HourClock) - return String(systemClock.date?.getHours() ?? 0).padStart(2, '0').charAt(0); - const hours = systemClock.date?.getHours() ?? 0; - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; - return String(display).padStart(2, '0').charAt(0); - } - font.pixelSize: stackedRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - width: stackedRoot.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: { - if (SettingsData.use24HourClock) - return String(systemClock.date?.getHours() ?? 0).padStart(2, '0').charAt(1); - const hours = systemClock.date?.getHours() ?? 0; - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; - return String(display).padStart(2, '0').charAt(1); - } - font.pixelSize: stackedRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - width: stackedRoot.digitWidth - horizontalAlignment: Text.AlignHCenter - } - } - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0').charAt(0) - font.pixelSize: stackedRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - width: stackedRoot.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: String(systemClock.date?.getMinutes() ?? 0).padStart(2, '0').charAt(1) - font.pixelSize: stackedRoot.baseSize - font.weight: Font.Medium - color: root.accentColor - width: stackedRoot.digitWidth - horizontalAlignment: Text.AlignHCenter - } - } - } - - Row { - visible: stackedRoot.hasSeconds - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0').charAt(0) - font.pixelSize: stackedRoot.smallSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - width: stackedRoot.smallSize * 0.58 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: String(systemClock.date?.getSeconds() ?? 0).padStart(2, '0').charAt(1) - font.pixelSize: stackedRoot.smallSize - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - width: stackedRoot.smallSize * 0.58 - horizontalAlignment: Text.AlignHCenter - } - } - - Item { - width: 1 - height: stackedRoot.baseSize * 0.1 - visible: stackedRoot.hasDate - } - - StyledText { - visible: stackedRoot.hasDate - anchors.horizontalCenter: parent.horizontalCenter - text: systemClock.date?.toLocaleDateString(I18n.locale(), "MMM dd") ?? "" - font.pixelSize: stackedRoot.smallSize * 0.7 - color: Theme.withAlpha(root.accentColor, 0.7) - } - - StyledText { - visible: stackedRoot.hasAmPm - anchors.horizontalCenter: parent.horizontalCenter - text: (systemClock.date?.getHours() ?? 0) >= 12 ? "PM" : "AM" - font.pixelSize: stackedRoot.smallSize * 0.7 - font.weight: Font.Medium - color: Theme.withAlpha(root.accentColor, 0.7) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml deleted file mode 100644 index cced1a4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/OrganicBlobHourBulges.qml +++ /dev/null @@ -1,137 +0,0 @@ -import QtQuick -import QtQuick.Shapes - -Item { - id: root - - property color fillColor: "transparent" - - property int lobes: 12 - property real lobeAmount: 0.070 - property real roundness: 0.22 - property real hillPower: 0.78 - property real paddingFrac: 0.020 - property real inset: 0 - property int segments: 120 - property real rotationDeg: -90 - - layer.enabled: true - layer.samples: 4 - - function sgn(v) { - return v < 0 ? -1 : 1; - } - function clamp(v, a, b) { - return Math.max(a, Math.min(b, v)); - } - - function squircleMap(u, v, p) { - const ax = sgn(u) * Math.pow(Math.abs(u), p); - const ay = sgn(v) * Math.pow(Math.abs(v), p); - return { - x: ax, - y: ay - }; - } - - function buildPathD(w, h) { - const x0 = inset, y0 = inset; - const x1 = w - inset, y1 = h - inset; - const iw = Math.max(2, x1 - x0); - const ih = Math.max(2, y1 - y0); - - const cx = x0 + iw * 0.5; - const cy = y0 + ih * 0.5; - - const rx = iw * 0.5; - const ry = ih * 0.5; - const rMin = Math.min(rx, ry); - - const amp = clamp(lobeAmount, 0.0, 0.14) * rMin; - const extraPad = paddingFrac * rMin + 1.5; - const pad = amp + extraPad; - - const rxBase = Math.max(2, rx - pad); - const ryBase = Math.max(2, ry - pad); - - const blend = clamp(roundness, 0.0, 0.45); - const squirclePow = 1.0 + blend * 2.8; - - const N = Math.max(48, segments); - const rot = rotationDeg * Math.PI / 180.0; - const dt = (Math.PI * 2.0) / N; - - function hillWave(a) { - const t = (Math.cos(lobes * a) + 1.0) * 0.5; - return Math.pow(t, hillPower); - } - - function P(t) { - const a = t + rot; - const u = Math.cos(a); - const v = Math.sin(a); - - const m = 1.0 + (amp / rMin) * hillWave(a); - - const ex = u * rxBase * m; - const ey = v * ryBase * m; - - const sm = squircleMap(u, v, 1.0 / squirclePow); - const sx = sm.x * rxBase * m; - const sy = sm.y * ryBase * m; - - const x = ex * (1.0 - blend) + sx * blend; - const y = ey * (1.0 - blend) + sy * blend; - return { - x: cx + x, - y: cy + y - }; - } - - function dP(t) { - const eps = dt * 0.25; - const p1 = P(t - eps); - const p2 = P(t + eps); - return { - x: (p2.x - p1.x) / (2 * eps), - y: (p2.y - p1.y) / (2 * eps) - }; - } - - const p0 = P(0.0); - let d = `M ${p0.x.toFixed(2)} ${p0.y.toFixed(2)} `; - - for (let i = 0; i < N; i++) { - const tA = i * dt; - const tB = (i + 1) * dt; - - const A = P(tA); - const B = P(tB); - const dA = dP(tA); - const dB = dP(tB); - - const c1x = A.x + (dt / 3.0) * dA.x; - const c1y = A.y + (dt / 3.0) * dA.y; - const c2x = B.x - (dt / 3.0) * dB.x; - const c2y = B.y - (dt / 3.0) * dB.y; - - d += `C ${c1x.toFixed(2)} ${c1y.toFixed(2)}, ${c2x.toFixed(2)} ${c2y.toFixed(2)}, ${B.x.toFixed(2)} ${B.y.toFixed(2)} `; - } - - d += "Z"; - return d; - } - - Shape { - anchors.fill: parent - - ShapePath { - fillColor: root.fillColor - strokeColor: "transparent" - - PathSvg { - path: root.buildPathD(root.width, root.height) - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml deleted file mode 100644 index 515e74e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml +++ /dev/null @@ -1,743 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property real widgetWidth: 320 - property real widgetHeight: 480 - property real defaultWidth: 320 - property real defaultHeight: 480 - property real minWidth: { - const tileCount = enabledTiles.length; - if (tileCount === 0) - return 80; - if (tileCount === 1) - return 100; - return 160; - } - property real minHeight: { - const tileCount = enabledTiles.length; - if (tileCount === 0) - return 60; - if (tileCount === 1) - return 80; - if (tileCount <= 2) - return 120; - return 180; - } - - property string instanceId: "" - property var instanceData: null - - readonly property var cfg: instanceData?.config ?? null - readonly property bool isInstance: instanceId !== "" && cfg !== null - - property bool enabled: isInstance ? (instanceData?.enabled ?? true) : SettingsData.systemMonitorEnabled - property bool showHeader: isInstance ? (cfg.showHeader ?? true) : SettingsData.systemMonitorShowHeader - property real transparency: isInstance ? (cfg.transparency ?? 0.8) : SettingsData.systemMonitorTransparency - property string colorMode: isInstance ? (cfg.colorMode ?? "primary") : SettingsData.systemMonitorColorMode - property color customColor: isInstance ? (cfg.customColor ?? "#ffffff") : SettingsData.systemMonitorCustomColor - property bool showCpu: isInstance ? (cfg.showCpu ?? true) : SettingsData.systemMonitorShowCpu - property bool showCpuGraph: isInstance ? (cfg.showCpuGraph ?? true) : SettingsData.systemMonitorShowCpuGraph - property bool showCpuTemp: isInstance ? (cfg.showCpuTemp ?? true) : SettingsData.systemMonitorShowCpuTemp - property bool showGpuTemp: isInstance ? (cfg.showGpuTemp ?? false) : SettingsData.systemMonitorShowGpuTemp - property string selectedGpuPciId: isInstance ? (cfg.gpuPciId ?? "") : SettingsData.systemMonitorGpuPciId - property bool showMemory: isInstance ? (cfg.showMemory ?? true) : SettingsData.systemMonitorShowMemory - property bool showMemoryGraph: isInstance ? (cfg.showMemoryGraph ?? true) : SettingsData.systemMonitorShowMemoryGraph - property bool showNetwork: isInstance ? (cfg.showNetwork ?? true) : SettingsData.systemMonitorShowNetwork - property bool showNetworkGraph: isInstance ? (cfg.showNetworkGraph ?? true) : SettingsData.systemMonitorShowNetworkGraph - property bool showDisk: isInstance ? (cfg.showDisk ?? true) : SettingsData.systemMonitorShowDisk - property bool showTopProcesses: isInstance ? (cfg.showTopProcesses ?? false) : SettingsData.systemMonitorShowTopProcesses - property int topProcessCount: isInstance ? (cfg.topProcessCount ?? 3) : SettingsData.systemMonitorTopProcessCount - property string topProcessSortBy: isInstance ? (cfg.topProcessSortBy ?? "cpu") : SettingsData.systemMonitorTopProcessSortBy - property string layoutMode: isInstance ? (cfg.layoutMode ?? "auto") : SettingsData.systemMonitorLayoutMode - property int graphInterval: isInstance ? (cfg.graphInterval ?? 60) : SettingsData.systemMonitorGraphInterval - - readonly property color accentColor: { - switch (colorMode) { - case "secondary": - return Theme.secondary; - case "custom": - return customColor; - default: - return Theme.primary; - } - } - - readonly property color bgColor: Theme.withAlpha(Theme.surface, root.transparency) - readonly property color tileBg: Theme.withAlpha(Theme.surfaceContainerHigh, root.transparency) - readonly property color textColor: Theme.surfaceText - readonly property color dimColor: Theme.surfaceVariantText - - property string currentGpuPciIdRef: "" - property var activeModuleRefs: [] - - property var cpuHistory: [] - property var memHistory: [] - property var netRxHistory: [] - property var netTxHistory: [] - property var diskReadHistory: [] - property var diskWriteHistory: [] - readonly property int historySize: 60 - - readonly property int sampleInterval: { - switch (graphInterval) { - case 60: - return 1000; - case 300: - return 5000; - case 600: - return 10000; - case 900: - return 15000; - case 1800: - return 30000; - default: - return 1000; - } - } - - readonly property var enabledTiles: { - var tiles = []; - if (showCpu) - tiles.push("cpu"); - if (showMemory) - tiles.push("mem"); - if (showNetwork) - tiles.push("net"); - if (showDisk) - tiles.push("disk"); - if (showGpuTemp && selectedGpuPciId) - tiles.push("gpu"); - return tiles; - } - - readonly property var sortedProcesses: { - if (!showTopProcesses || !DgopService.processes) - return []; - var procs = DgopService.processes.slice(); - if (topProcessSortBy === "memory") { - procs.sort((a, b) => (b.memoryKB || 0) - (a.memoryKB || 0)); - } else { - procs.sort((a, b) => (b.cpu || 0) - (a.cpu || 0)); - } - return procs.slice(0, topProcessCount); - } - - Component.onCompleted: { - var modules = ["system"]; - if (showCpu || showCpuTemp || showCpuGraph) - modules.push("cpu"); - if (showMemory || showMemoryGraph) - modules.push("memory"); - if (showNetwork || showNetworkGraph) - modules.push("network"); - if (showDisk) - modules.push("disk", "diskmounts"); - if (showTopProcesses) - modules.push("processes"); - activeModuleRefs = modules; - DgopService.addRef(modules); - updateGpuRef(); - } - - Component.onDestruction: { - DgopService.removeRef(activeModuleRefs); - if (currentGpuPciIdRef) - DgopService.removeGpuPciId(currentGpuPciIdRef); - } - - onShowGpuTempChanged: updateGpuRef() - onSelectedGpuPciIdChanged: updateGpuRef() - onShowTopProcessesChanged: { - if (showTopProcesses) { - activeModuleRefs = activeModuleRefs.concat(["processes"]); - DgopService.addRef(["processes"]); - } else { - DgopService.removeRef(["processes"]); - activeModuleRefs = activeModuleRefs.filter(m => m !== "processes"); - } - } - - function updateGpuRef() { - if (currentGpuPciIdRef && currentGpuPciIdRef !== selectedGpuPciId) { - DgopService.removeGpuPciId(currentGpuPciIdRef); - currentGpuPciIdRef = ""; - } - if (!showGpuTemp || !selectedGpuPciId) { - if (currentGpuPciIdRef) { - DgopService.removeGpuPciId(currentGpuPciIdRef); - currentGpuPciIdRef = ""; - } - return; - } - if (selectedGpuPciId && !currentGpuPciIdRef) { - DgopService.addGpuPciId(selectedGpuPciId); - currentGpuPciIdRef = selectedGpuPciId; - } - } - - function getGpuInfo() { - if (!selectedGpuPciId || !DgopService.availableGpus) - return null; - return DgopService.availableGpus.find(g => g.pciId === selectedGpuPciId); - } - - function formatBytes(bytes) { - if (bytes < 1024) - return bytes.toFixed(0) + "B"; - if (bytes < 1024 * 1024) - return (bytes / 1024).toFixed(0) + "K"; - if (bytes < 1024 * 1024 * 1024) - return (bytes / (1024 * 1024)).toFixed(1) + "M"; - return (bytes / (1024 * 1024 * 1024)).toFixed(1) + "G"; - } - - function formatMemKB(kb) { - if (kb < 1024) - return kb.toFixed(0) + "K"; - if (kb < 1024 * 1024) - return (kb / 1024).toFixed(0) + "M"; - return (kb / (1024 * 1024)).toFixed(1) + "G"; - } - - function addToHistory(arr, val) { - var newArr = arr.slice(); - newArr.push(val); - if (newArr.length > historySize) - newArr.shift(); - return newArr; - } - - function sampleData() { - if (showCpuGraph) - cpuHistory = addToHistory(cpuHistory, DgopService.cpuUsage); - if (showMemoryGraph) - memHistory = addToHistory(memHistory, DgopService.memoryUsage); - if (showNetworkGraph) { - netRxHistory = addToHistory(netRxHistory, DgopService.networkRxRate); - netTxHistory = addToHistory(netTxHistory, DgopService.networkTxRate); - } - if (showDisk) { - diskReadHistory = addToHistory(diskReadHistory, DgopService.diskReadRate); - diskWriteHistory = addToHistory(diskWriteHistory, DgopService.diskWriteRate); - } - } - - readonly property int sampleSeconds: sampleInterval / 1000 - - SystemClock { - id: sampleClock - precision: SystemClock.Seconds - onDateChanged: { - var sec = date.getSeconds(); - if (sec % root.sampleSeconds === 0) - root.sampleData(); - } - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: root.bgColor - border.width: 0 - - ColumnLayout { - anchors.fill: parent - anchors.margins: (root.enabledTiles.length === 1 && !root.showHeader) ? 0 : Theme.spacingS - spacing: Theme.spacingS - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingS - visible: root.showHeader - - ColumnLayout { - spacing: 0 - - StyledText { - text: DgopService.cpuModel || DgopService.hostname || "System" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.textColor - elide: Text.ElideRight - Layout.maximumWidth: root.width - Theme.spacingM * 2 - } - - StyledText { - visible: DgopService.shortUptime && DgopService.shortUptime.length > 0 - text: DgopService.shortUptime - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - } - } - } - - GridLayout { - id: tileGrid - Layout.fillWidth: true - Layout.fillHeight: true - columns: { - if (root.layoutMode === "list") - return 1; - if (root.layoutMode === "grid") - return 2; - // auto - if (root.width < 280) - return 1; - if (root.width < 500) - return 2; - return 3; - } - rowSpacing: Theme.spacingXS - columnSpacing: Theme.spacingXS - - Repeater { - model: root.enabledTiles - - Rectangle { - id: tile - readonly property int span: Layout.columnSpan - Layout.fillWidth: true - Layout.fillHeight: true - Layout.columnSpan: { - if (root.layoutMode === "list") - return 1; - - var cols = tileGrid.columns; - if (cols <= 1) - return 1; - - var count = root.enabledTiles.length; - var idx = index; - - if (idx !== count - 1) - return 1; - - var remainder = count % cols; - if (remainder === 0) - return 1; - - if (!tile.hasGraph) - return 1; - - return cols - remainder + 1; - } - Layout.minimumHeight: 60 - radius: Theme.cornerRadius - 2 - color: root.tileBg - border.width: 0 - clip: true - - readonly property string tileType: modelData - readonly property bool hasGraph: { - switch (tileType) { - case "cpu": - return root.showCpuGraph; - case "mem": - return root.showMemoryGraph; - case "net": - return root.showNetworkGraph; - case "disk": - return true; - default: - return false; - } - } - - Canvas { - id: tileGraph - anchors.fill: parent - visible: tile.hasGraph - renderStrategy: Canvas.Cooperative - - property var hist: { - switch (tile.tileType) { - case "cpu": - return root.cpuHistory; - case "mem": - return root.memHistory; - case "net": - return root.netRxHistory; - case "disk": - return root.diskReadHistory; - default: - return []; - } - } - property var hist2: { - switch (tile.tileType) { - case "net": - return root.netTxHistory; - case "disk": - return root.diskWriteHistory; - default: - return null; - } - } - - onHistChanged: requestPaint() - onHist2Changed: requestPaint() - onWidthChanged: requestPaint() - onHeightChanged: requestPaint() - - onPaint: { - var ctx = getContext("2d"); - ctx.reset(); - ctx.clearRect(0, 0, width, height); - if (!hist || hist.length < 2) - return; - var maxVal = 100; - if (tile.tileType === "net" || tile.tileType === "disk") { - maxVal = 1; - for (var k = 0; k < hist.length; k++) - maxVal = Math.max(maxVal, hist[k]); - if (hist2) - for (var l = 0; l < hist2.length; l++) - maxVal = Math.max(maxVal, hist2[l]); - } - - var c = root.accentColor; - var grad = ctx.createLinearGradient(0, 0, 0, height); - grad.addColorStop(0, Qt.rgba(c.r, c.g, c.b, 0.3)); - grad.addColorStop(1, Qt.rgba(c.r, c.g, c.b, 0.05)); - - ctx.fillStyle = grad; - ctx.beginPath(); - ctx.moveTo(0, height); - for (var i = 0; i < hist.length; i++) { - var x = (width / (root.historySize - 1)) * i; - var y = height - (hist[i] / maxVal) * height * 0.85; - ctx.lineTo(x, y); - } - ctx.lineTo((width / (root.historySize - 1)) * (hist.length - 1), height); - ctx.closePath(); - ctx.fill(); - - ctx.strokeStyle = Qt.rgba(c.r, c.g, c.b, 0.6); - ctx.lineWidth = 1.5; - ctx.beginPath(); - for (var j = 0; j < hist.length; j++) { - var px = (width / (root.historySize - 1)) * j; - var py = height - (hist[j] / maxVal) * height * 0.85; - j === 0 ? ctx.moveTo(px, py) : ctx.lineTo(px, py); - } - ctx.stroke(); - - if (hist2 && hist2.length >= 2) { - ctx.strokeStyle = Qt.rgba(c.r, c.g, c.b, 0.3); - ctx.lineWidth = 1; - ctx.beginPath(); - for (var m = 0; m < hist2.length; m++) { - var sx = (width / (root.historySize - 1)) * m; - var sy = height - (hist2[m] / maxVal) * height * 0.85; - m === 0 ? ctx.moveTo(sx, sy) : ctx.lineTo(sx, sy); - } - ctx.stroke(); - } - } - } - - ColumnLayout { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - - StyledText { - text: tile.tileType.toUpperCase() - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: root.accentColor - } - - Item { - Layout.fillWidth: true - } - - StyledText { - visible: tile.tileType === "cpu" && root.showCpuTemp && DgopService.cpuTemperature > 0 - text: DgopService.cpuTemperature.toFixed(0) + "°" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: DgopService.cpuTemperature > 80 ? Theme.error : (DgopService.cpuTemperature > 60 ? Theme.warning : root.dimColor) - } - - StyledText { - visible: tile.tileType === "mem" - text: DgopService.formatSystemMemory(DgopService.usedMemoryKB) - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - } - } - - Item { - Layout.fillHeight: true - } - - StyledText { - visible: tile.tileType === "cpu" - text: DgopService.cpuUsage.toFixed(0) + "%" - isMonospace: true - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Medium - color: root.textColor - } - - StyledText { - visible: tile.tileType === "mem" - text: DgopService.memoryUsage.toFixed(0) + "%" - isMonospace: true - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Medium - color: root.textColor - } - - RowLayout { - visible: tile.tileType === "net" - spacing: Theme.spacingM - ColumnLayout { - spacing: 0 - StyledText { - text: "↓" - font.pixelSize: Theme.fontSizeSmall - color: root.accentColor - } - StyledText { - text: root.formatBytes(DgopService.networkRxRate) + "/s" - isMonospace: true - font.pixelSize: Theme.fontSizeMedium - color: root.textColor - } - } - ColumnLayout { - spacing: 0 - StyledText { - text: "↑" - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - } - StyledText { - text: root.formatBytes(DgopService.networkTxRate) + "/s" - isMonospace: true - font.pixelSize: Theme.fontSizeMedium - color: root.textColor - } - } - } - - RowLayout { - visible: tile.tileType === "disk" - spacing: Theme.spacingM - ColumnLayout { - spacing: 0 - StyledText { - text: "R" - font.pixelSize: Theme.fontSizeSmall - color: root.accentColor - } - StyledText { - text: root.formatBytes(DgopService.diskReadRate) + "/s" - isMonospace: true - font.pixelSize: Theme.fontSizeMedium - color: root.textColor - } - } - ColumnLayout { - spacing: 0 - StyledText { - text: "W" - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - } - StyledText { - text: root.formatBytes(DgopService.diskWriteRate) + "/s" - isMonospace: true - font.pixelSize: Theme.fontSizeMedium - color: root.textColor - } - } - } - - ColumnLayout { - visible: tile.tileType === "gpu" - spacing: 0 - property var gpu: root.getGpuInfo() - Layout.alignment: tile.span > 1 ? Qt.AlignHCenter : Qt.AlignLeft - - StyledText { - property real temp: parent.gpu?.temperature ?? 0 - text: temp > 0 ? temp.toFixed(0) + "°C" : "--" - isMonospace: true - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Medium - color: root.textColor - Layout.alignment: tile.span > 1 ? Qt.AlignHCenter : Qt.AlignLeft - } - StyledText { - text: parent.gpu?.displayName ?? "" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - Layout.fillWidth: true - horizontalAlignment: tile.span > 1 ? Text.AlignHCenter : Text.AlignLeft - elide: Text.ElideRight - } - } - - Rectangle { - visible: tile.tileType === "cpu" || tile.tileType === "mem" - Layout.fillWidth: true - height: 4 - radius: 2 - color: Theme.withAlpha(Theme.outline, 0.2) - - Rectangle { - property real pct: tile.tileType === "cpu" ? DgopService.cpuUsage / 100 : DgopService.memoryUsage / 100 - width: parent.width * Math.min(1, pct) - height: parent.height - radius: 2 - color: pct > 0.8 ? Theme.error : (pct > 0.6 ? Theme.warning : root.accentColor) - Behavior on width { - NumberAnimation { - duration: 150 - } - } - } - } - } - } - } - } - - ColumnLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - visible: root.showTopProcesses && root.sortedProcesses.length > 0 - - Rectangle { - Layout.fillWidth: true - height: 1 - color: Theme.withAlpha(Theme.outline, 0.15) - } - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - - StyledText { - text: "TOP BY " + root.topProcessSortBy.toUpperCase() - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: root.accentColor - } - - Item { - Layout.fillWidth: true - } - - StyledText { - text: root.topProcessSortBy === "cpu" ? "CPU" : "MEM" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - Layout.preferredWidth: 48 - horizontalAlignment: Text.AlignRight - } - } - - Repeater { - model: root.sortedProcesses - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - - StyledText { - text: modelData.command || "unknown" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.textColor - Layout.fillWidth: true - elide: Text.ElideRight - } - - StyledText { - text: root.topProcessSortBy === "cpu" ? (modelData.cpu || 0).toFixed(1) + "%" : root.formatMemKB(modelData.memoryKB || 0) - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - Layout.preferredWidth: 48 - horizontalAlignment: Text.AlignRight - } - } - } - } - - ColumnLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - visible: root.showDisk && DgopService.diskMounts.length > 0 - - Rectangle { - Layout.fillWidth: true - height: 1 - color: Theme.withAlpha(Theme.outline, 0.15) - } - - Repeater { - model: DgopService.diskMounts.filter(m => m.mountpoint === "/" || m.mountpoint === "/home") - - RowLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - - StyledText { - text: modelData.mountpoint - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.dimColor - Layout.preferredWidth: 48 - } - - Rectangle { - Layout.fillWidth: true - height: 4 - radius: 2 - color: Theme.withAlpha(Theme.outline, 0.2) - - Rectangle { - property real pct: (modelData.used || 0) / Math.max(1, modelData.total || 1) - width: parent.width * pct - height: parent.height - radius: 2 - color: pct > 0.9 ? Theme.error : (pct > 0.75 ? Theme.warning : root.accentColor) - } - } - - StyledText { - text: ((modelData.used || 0) / (modelData.total || 1) * 100).toFixed(0) + "%" - isMonospace: true - font.pixelSize: Theme.fontSizeSmall - color: root.textColor - Layout.preferredWidth: 32 - horizontalAlignment: Text.AlignRight - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml deleted file mode 100644 index a275397..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/CupsWidget.qml +++ /dev/null @@ -1,321 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - id: root - - Ref { - service: CupsService - } - - ccWidgetIcon: CupsService.cupsAvailable && CupsService.getPrintersNum() > 0 ? "print" : "print_disabled" - ccWidgetPrimaryText: I18n.tr("Printers") - ccWidgetSecondaryText: { - if (CupsService.cupsAvailable && CupsService.getPrintersNum() > 0) { - return I18n.tr("Printers: ") + CupsService.getPrintersNum() + " - " + I18n.tr("Jobs: ") + CupsService.getTotalJobsNum(); - } else { - if (!CupsService.cupsAvailable) { - return I18n.tr("Print Server not available"); - } else { - return I18n.tr("No printer found"); - } - } - } - ccWidgetIsActive: CupsService.cupsAvailable && CupsService.getTotalJobsNum() > 0 - - onCcWidgetToggled: {} - - ccDetailContent: Component { - Rectangle { - id: detailRoot - implicitHeight: detailColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - DankActionButton { - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - iconName: "settings" - buttonSize: 24 - iconSize: 14 - iconColor: Theme.surfaceVariantText - onClicked: { - PopoutService.closeControlCenter(); - PopoutService.openSettingsWithTab("printers"); - } - } - - Column { - visible: !CupsService.cupsAvailable || CupsService.getPrintersNum() == 0 - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "print_disabled" - size: 36 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: !CupsService.cupsAvailable ? I18n.tr("Print Server not available") : I18n.tr("No printer found") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - id: detailColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - visible: CupsService.cupsAvailable && CupsService.getPrintersNum() > 0 - height: visible ? 120 : 0 - - RowLayout { - spacing: Theme.spacingS - width: parent.width - - DankDropdown { - id: printerDropdown - text: "" - Layout.fillWidth: true - Layout.maximumWidth: parent.width - 180 - description: "" - currentValue: { - CupsService.getSelectedPrinter(); - } - options: CupsService.getPrintersNames() - onValueChanged: value => { - CupsService.setSelectedPrinter(value); - } - } - - Column { - spacing: Theme.spacingS - - StyledText { - text: CupsService.getCurrentPrinterStatePrettyShort() - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Row { - spacing: Theme.spacingM - - Rectangle { - height: 24 - width: 80 - radius: 14 - color: printerStatusToggle.containsMouse ? Theme.errorHover : Theme.surfaceLight - visible: true - opacity: 1.0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: CupsService.getCurrentPrinterState() === "stopped" ? "play_arrow" : "pause" - size: Theme.fontSizeSmall + 4 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: CupsService.getCurrentPrinterState() === "stopped" ? I18n.tr("Resume") : I18n.tr("Pause") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: printerStatusToggle - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: true - onClicked: { - const selected = CupsService.getSelectedPrinter(); - if (CupsService.getCurrentPrinterState() === "stopped") { - CupsService.resumePrinter(selected); - } else { - CupsService.pausePrinter(selected); - } - } - } - } - - Rectangle { - height: 24 - width: 80 - radius: 14 - color: clearJobsToggle.containsMouse ? Theme.errorHover : Theme.surfaceLight - visible: true - opacity: 1.0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "delete_forever" - size: Theme.fontSizeSmall + 4 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Jobs") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: clearJobsToggle - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: true - onClicked: { - const selected = CupsService.getSelectedPrinter(); - CupsService.purgeJobs(selected); - } - } - } - } - } - } - - Rectangle { - height: 1 - width: parent.width - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - DankFlickable { - width: parent.width - height: 160 - contentHeight: listCol.height - clip: true - - Column { - id: listCol - width: parent.width - spacing: Theme.spacingXS - - Item { - width: parent.width - height: 120 - visible: CupsService.getCurrentPrinterJobs().length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "work" - size: 36 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("The job queue of this printer is empty") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Repeater { - model: CupsService.getCurrentPrinterJobs() - - delegate: Rectangle { - required property var modelData - - width: parent ? parent.width : 300 - height: 50 - radius: Theme.cornerRadius - color: Theme.surfaceLight - border.width: 1 - border.color: Theme.outlineLight - opacity: 1.0 - - RowLayout { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "docs" - size: Theme.iconSize + 2 - color: Theme.surfaceText - Layout.alignment: Qt.AlignVCenter - } - - Column { - spacing: 2 - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - - StyledText { - text: "[" + modelData.id + "] " + modelData.state + " (" + (modelData.size / 1024) + "kb)" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - - StyledText { - text: { - var date = new Date(modelData.timeCreated); - return date.toLocaleString(Qt.locale(), Locale.ShortFormat); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - - Item { - Layout.fillWidth: true - } - } - - DankActionButton { - id: cancelJobButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - iconName: "delete" - buttonSize: 36 - onClicked: { - CupsService.cancelJob(CupsService.getSelectedPrinter(), modelData.id); - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml deleted file mode 100644 index 531045e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml +++ /dev/null @@ -1,33 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Plugins - -PluginComponent { - id: root - - Ref { - service: DMSNetworkService - } - - ccWidgetIcon: DMSNetworkService.isBusy ? "sync" : (DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off") - ccWidgetPrimaryText: I18n.tr("VPN") - ccWidgetSecondaryText: { - if (!DMSNetworkService.connected) - return I18n.tr("Disconnected"); - const names = DMSNetworkService.activeNames || []; - if (names.length <= 1) - return names[0] || I18n.tr("Connected"); - return names[0] + " +" + (names.length - 1); - } - ccWidgetIsActive: DMSNetworkService.connected - - onCcWidgetToggled: DMSNetworkService.toggleVpn() - - ccDetailContent: Component { - VpnDetailContent { - listHeight: 260 - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/ActionTile.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/ActionTile.qml deleted file mode 100644 index d85c779..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/ActionTile.qml +++ /dev/null @@ -1,132 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string iconName: "" - property string text: "" - property string secondaryText: "" - property bool isActive: false - property bool enabled: true - property int widgetIndex: 0 - property var widgetData: null - property bool editMode: false - - signal clicked - - width: parent ? parent.width : 200 - height: 60 - radius: { - if (Theme.cornerRadius === 0) - return 0; - return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4; - } - - readonly property color _tileBgActive: Theme.ccTileActiveBg - readonly property color _tileBgInactive: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - readonly property color _tileRingActive: Theme.ccTileRing - - color: isActive ? _tileBgActive : _tileBgInactive - border.color: isActive ? _tileRingActive : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: isActive ? 1 : 1 - opacity: enabled ? 1.0 : 0.6 - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: mouseArea.containsMouse ? hoverTint(root.color) : "transparent" - opacity: mouseArea.containsMouse ? 0.08 : 0.0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingL + 2 - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: root.iconName - size: Theme.iconSize - color: isActive ? Theme.ccTileActiveText : Theme.ccTileInactiveIcon - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - Theme.iconSize - parent.spacing - height: parent.height - - Column { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - Typography { - width: parent.width - text: root.text - style: Typography.Style.Body - color: isActive ? Theme.ccTileActiveText : Theme.surfaceText - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - - Typography { - width: parent.width - text: root.secondaryText - style: Typography.Style.Caption - color: isActive ? Theme.ccTileActiveText : Theme.surfaceVariantText - visible: text.length > 0 - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - } - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: root.enabled - onPressed: mouse => ripple.trigger(mouse.x, mouse.y) - onClicked: root.clicked() - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on radius { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DetailHost.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DetailHost.qml deleted file mode 100644 index a3b1156..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DetailHost.qml +++ /dev/null @@ -1,250 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Modules.ControlCenter.Details - -Item { - id: root - - property string expandedSection: "" - property var expandedWidgetData: null - property var bluetoothCodecSelector: null - property string screenName: "" - property string screenModel: "" - - property var pluginDetailInstance: null - property var widgetModel: null - property var collapseCallback: null - property real maxAvailableHeight: 9999 - - function getDetailHeight(section) { - switch (true) { - case section === "wifi": - case section === "bluetooth": - case section === "builtin_vpn": - return Math.min(350, maxAvailableHeight); - case section.startsWith("brightnessSlider_"): - return Math.min(400, maxAvailableHeight); - case section.startsWith("plugin_"): - if (pluginDetailInstance?.ccDetailHeight) - return Math.min(pluginDetailInstance.ccDetailHeight, maxAvailableHeight); - return Math.min(250, maxAvailableHeight); - default: - return Math.min(250, maxAvailableHeight); - } - } - - Loader { - id: pluginDetailLoader - width: parent.width - height: parent.height - Theme.spacingS - y: Theme.spacingS - active: false - sourceComponent: null - } - - Loader { - id: coreDetailLoader - width: parent.width - height: parent.height - Theme.spacingS - y: Theme.spacingS - active: false - sourceComponent: null - } - - Connections { - target: coreDetailLoader.item - enabled: root.expandedSection.startsWith("brightnessSlider_") - ignoreUnknownSignals: true - - function onDeviceNameChanged(newDeviceName) { - if (root.expandedWidgetData && root.expandedWidgetData.id === "brightnessSlider") { - const widgets = SettingsData.controlCenterWidgets || []; - const newWidgets = widgets.map(w => { - if (w.id === "brightnessSlider" && w.instanceId === root.expandedWidgetData.instanceId) { - const updatedWidget = Object.assign({}, w); - updatedWidget.deviceName = newDeviceName; - return updatedWidget; - } - return w; - }); - SettingsData.set("controlCenterWidgets", newWidgets); - if (root.collapseCallback) { - root.collapseCallback(); - } - } - } - } - - Connections { - target: coreDetailLoader.item - enabled: root.expandedSection.startsWith("diskUsage_") - ignoreUnknownSignals: true - - function onMountPathChanged(newMountPath) { - if (root.expandedWidgetData && root.expandedWidgetData.id === "diskUsage") { - const widgets = SettingsData.controlCenterWidgets || []; - const newWidgets = widgets.map(w => { - if (w.id === "diskUsage" && w.instanceId === root.expandedWidgetData.instanceId) { - const updatedWidget = Object.assign({}, w); - updatedWidget.mountPath = newMountPath; - return updatedWidget; - } - return w; - }); - SettingsData.set("controlCenterWidgets", newWidgets); - if (root.collapseCallback) { - root.collapseCallback(); - } - } - } - } - - onExpandedSectionChanged: { - if (pluginDetailInstance) { - pluginDetailInstance.destroy(); - pluginDetailInstance = null; - } - pluginDetailLoader.active = false; - coreDetailLoader.active = false; - - if (!root.expandedSection) { - return; - } - - if (root.expandedSection.startsWith("builtin_")) { - const builtinId = root.expandedSection; - let builtinInstance = null; - - if (builtinId === "builtin_vpn") { - if (widgetModel?.vpnLoader) { - widgetModel.vpnLoader.active = true; - } - builtinInstance = widgetModel.vpnBuiltinInstance; - } - if (builtinId === "builtin_cups") { - if (widgetModel?.cupsLoader) { - widgetModel.cupsLoader.active = true; - } - builtinInstance = widgetModel.cupsBuiltinInstance; - } - - if (!builtinInstance || !builtinInstance.ccDetailContent) { - return; - } - - pluginDetailLoader.sourceComponent = builtinInstance.ccDetailContent; - pluginDetailLoader.active = parent.height > 0; - return; - } - - if (root.expandedSection.startsWith("plugin_")) { - const pluginId = root.expandedSection.replace("plugin_", ""); - const pluginComponent = PluginService.pluginWidgetComponents[pluginId]; - if (!pluginComponent) { - return; - } - - pluginDetailInstance = pluginComponent.createObject(null); - if (!pluginDetailInstance || !pluginDetailInstance.ccDetailContent) { - if (pluginDetailInstance) { - pluginDetailInstance.destroy(); - pluginDetailInstance = null; - } - return; - } - - pluginDetailLoader.sourceComponent = pluginDetailInstance.ccDetailContent; - pluginDetailLoader.active = parent.height > 0; - return; - } - - if (root.expandedSection.startsWith("diskUsage_")) { - coreDetailLoader.sourceComponent = diskUsageDetailComponent; - coreDetailLoader.active = parent.height > 0; - return; - } - - if (root.expandedSection.startsWith("brightnessSlider_")) { - coreDetailLoader.sourceComponent = brightnessDetailComponent; - coreDetailLoader.active = parent.height > 0; - return; - } - - switch (root.expandedSection) { - case "network": - case "wifi": - coreDetailLoader.sourceComponent = networkDetailComponent; - break; - case "bluetooth": - coreDetailLoader.sourceComponent = bluetoothDetailComponent; - break; - case "audioOutput": - coreDetailLoader.sourceComponent = audioOutputDetailComponent; - break; - case "audioInput": - coreDetailLoader.sourceComponent = audioInputDetailComponent; - break; - case "battery": - coreDetailLoader.sourceComponent = batteryDetailComponent; - break; - default: - return; - } - - coreDetailLoader.active = parent.height > 0; - } - - Component { - id: networkDetailComponent - NetworkDetail {} - } - - Component { - id: bluetoothDetailComponent - BluetoothDetail { - id: bluetoothDetail - onShowCodecSelector: function (device) { - if (root.bluetoothCodecSelector) { - root.bluetoothCodecSelector.show(device); - root.bluetoothCodecSelector.codecSelected.connect(function (deviceAddress, codecName) { - bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName); - }); - } - } - } - } - - Component { - id: audioOutputDetailComponent - AudioOutputDetail {} - } - - Component { - id: audioInputDetailComponent - AudioInputDetail {} - } - - Component { - id: batteryDetailComponent - BatteryDetail {} - } - - Component { - id: diskUsageDetailComponent - DiskUsageDetail { - currentMountPath: root.expandedWidgetData?.mountPath || "/" - instanceId: root.expandedWidgetData?.instanceId || "" - } - } - - Component { - id: brightnessDetailComponent - BrightnessDetail { - initialDeviceName: root.expandedWidgetData?.deviceName || "" - instanceId: root.expandedWidgetData?.instanceId || "" - screenName: root.screenName - screenModel: root.screenModel - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropDetailHost.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropDetailHost.qml deleted file mode 100644 index 4a7ff19..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropDetailHost.qml +++ /dev/null @@ -1,91 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.ControlCenter.Details - -Item { - id: root - - property string expandedSection: "" - property var expandedWidgetData: null - - height: active ? 250 : 0 - visible: active - - readonly property bool active: expandedSection !== "" - - Loader { - anchors.fill: parent - anchors.topMargin: Theme.spacingS - sourceComponent: { - if (!root.active) - return null; - - if (expandedSection.startsWith("diskUsage_")) { - return diskUsageDetailComponent; - } - - switch (expandedSection) { - case "wifi": - return networkDetailComponent; - case "bluetooth": - return bluetoothDetailComponent; - case "audioOutput": - return audioOutputDetailComponent; - case "audioInput": - return audioInputDetailComponent; - case "battery": - return batteryDetailComponent; - default: - return null; - } - } - } - - Component { - id: networkDetailComponent - NetworkDetail {} - } - - Component { - id: bluetoothDetailComponent - BluetoothDetail {} - } - - Component { - id: audioOutputDetailComponent - AudioOutputDetail {} - } - - Component { - id: audioInputDetailComponent - AudioInputDetail {} - } - - Component { - id: batteryDetailComponent - BatteryDetail {} - } - - Component { - id: diskUsageDetailComponent - DiskUsageDetail { - currentMountPath: root.expandedWidgetData?.mountPath || "/" - instanceId: root.expandedWidgetData?.instanceId || "" - - onMountPathChanged: newMountPath => { - if (root.expandedWidgetData && root.expandedWidgetData.id === "diskUsage") { - const widgets = SettingsData.controlCenterWidgets || []; - const newWidgets = widgets.map(w => { - if (w.id === "diskUsage" && w.instanceId === root.expandedWidgetData.instanceId) { - const updatedWidget = Object.assign({}, w); - updatedWidget.mountPath = newMountPath; - return updatedWidget; - } - return w; - }); - SettingsData.set("controlCenterWidgets", newWidgets); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml deleted file mode 100644 index 4cdd979..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml +++ /dev/null @@ -1,1091 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Modules.ControlCenter.Widgets -import qs.Modules.ControlCenter.Components -import "../utils/layout.js" as LayoutUtils - -Column { - id: root - - property bool editMode: false - property string expandedSection: "" - property int expandedWidgetIndex: -1 - property var model: null - property var expandedWidgetData: null - property var bluetoothCodecSelector: null - property bool darkModeTransitionPending: false - property string screenName: "" - property string screenModel: "" - property var parentScreen: null - - signal expandClicked(var widgetData, int globalIndex) - signal removeWidget(int index) - signal moveWidget(int fromIndex, int toIndex) - signal toggleWidgetSize(int index) - signal collapseRequested - - function requestCollapse() { - collapseRequested(); - } - - spacing: editMode ? Theme.spacingL : Theme.spacingS - - property real maxPopoutHeight: 9999 - property var currentRowWidgets: [] - property real currentRowWidth: 0 - property int expandedRowIndex: -1 - property var colorPickerModal: null - - readonly property real _maxDetailHeight: { - const rows = layoutResult.rows; - let totalRowHeight = 0; - for (let i = 0; i < rows.length; i++) { - const sliderOnly = rows[i].every(w => { - const id = w.id || ""; - return id === "volumeSlider" || id === "brightnessSlider" || id === "inputVolumeSlider"; - }); - totalRowHeight += sliderOnly ? 36 : 60; - } - const rowSpacing = Math.max(0, rows.length - 1) * spacing; - return Math.max(100, maxPopoutHeight - totalRowHeight - rowSpacing); - } - - function calculateRowsAndWidgets() { - return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex); - } - - property var layoutResult: { - const dummy = [expandedSection, expandedWidgetIndex, model?.controlCenterWidgets]; - return calculateRowsAndWidgets(); - } - - onLayoutResultChanged: { - expandedRowIndex = layoutResult.expandedRowIndex; - } - - function moveToTop(item) { - const children = root.children; - for (var i = 0; i < children.length; i++) { - if (children[i] === item) - continue; - if (children[i].z) - children[i].z = Math.min(children[i].z, 999); - } - item.z = 1000; - } - - Repeater { - model: root.layoutResult.rows - - Column { - width: root.width - spacing: 0 - property int rowIndex: index - property var rowWidgets: modelData - property bool isSliderOnlyRow: { - const widgets = rowWidgets || []; - if (widgets.length === 0) - return false; - return widgets.every(w => w.id === "volumeSlider" || w.id === "brightnessSlider" || w.id === "inputVolumeSlider"); - } - topPadding: isSliderOnlyRow ? (root.editMode ? 4 : -6) : 0 - bottomPadding: isSliderOnlyRow ? (root.editMode ? 4 : -6) : 0 - - Flow { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: rowWidgets || [] - - DragDropWidgetWrapper { - widgetData: modelData - property int globalWidgetIndex: { - const widgets = SettingsData.controlCenterWidgets || []; - for (var i = 0; i < widgets.length; i++) { - if (widgets[i].id === modelData.id) { - if (modelData.id === "diskUsage" || modelData.id === "brightnessSlider") { - if (widgets[i].instanceId === modelData.instanceId) { - return i; - } - } else { - return i; - } - } - } - return -1; - } - property int widgetWidth: modelData.width || 50 - width: { - const baseWidth = root.width; - const spacing = Theme.spacingS; - if (widgetWidth <= 25) { - return (baseWidth - spacing * 3) / 4; - } else if (widgetWidth <= 50) { - return (baseWidth - spacing) / 2; - } else if (widgetWidth <= 75) { - return (baseWidth - spacing * 2) * 0.75; - } else { - return baseWidth; - } - } - height: isSliderOnlyRow ? 48 : 60 - - editMode: root.editMode - widgetIndex: globalWidgetIndex - gridCellWidth: width - gridCellHeight: height - gridColumns: 4 - gridLayout: root - isSlider: { - const id = modelData.id || ""; - return id === "volumeSlider" || id === "brightnessSlider" || id === "inputVolumeSlider"; - } - - widgetComponent: { - const id = modelData.id || ""; - if (id.startsWith("builtin_")) { - return builtinPluginWidgetComponent; - } else if (id.startsWith("plugin_")) { - return pluginWidgetComponent; - } else if (id === "wifi" || id === "bluetooth" || id === "audioOutput" || id === "audioInput") { - return compoundPillComponent; - } else if (id === "volumeSlider") { - return audioSliderComponent; - } else if (id === "brightnessSlider") { - return brightnessSliderComponent; - } else if (id === "inputVolumeSlider") { - return inputAudioSliderComponent; - } else if (id === "battery") { - return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent; - } else if (id === "diskUsage") { - return widgetWidth <= 25 ? smallDiskUsageComponent : diskUsagePillComponent; - } else if (id === "colorPicker") { - return colorPickerPillComponent; - } else { - return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent; - } - } - - onWidgetMoved: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex) - onRemoveWidget: index => root.removeWidget(index) - onToggleWidgetSize: index => root.toggleWidgetSize(index) - } - } - } - - DetailHost { - id: detailHost - width: parent.width - maxAvailableHeight: root._maxDetailHeight - height: active ? (getDetailHeight(root.expandedSection) + Theme.spacingS) : 0 - property bool active: { - if (root.expandedSection === "") - return false; - - if (root.expandedSection.startsWith("diskUsage_") && root.expandedWidgetData) { - const expandedInstanceId = root.expandedWidgetData.instanceId; - return rowWidgets.some(w => w.id === "diskUsage" && w.instanceId === expandedInstanceId); - } - - if (root.expandedSection.startsWith("brightnessSlider_") && root.expandedWidgetData) { - const expandedInstanceId = root.expandedWidgetData.instanceId; - return rowWidgets.some(w => w.id === "brightnessSlider" && w.instanceId === expandedInstanceId); - } - - return rowIndex === root.expandedRowIndex; - } - visible: active - expandedSection: root.expandedSection - expandedWidgetData: root.expandedWidgetData - bluetoothCodecSelector: root.bluetoothCodecSelector - widgetModel: root.model - collapseCallback: root.requestCollapse - screenName: root.screenName - screenModel: root.screenModel - } - } - } - - Component { - id: errorPillComponent - ErrorPill { - property var widgetData: parent.widgetData || {} - width: parent.width - height: 60 - primaryMessage: { - if (!DMSService.dmsAvailable) { - return I18n.tr("DMS_SOCKET not available"); - } - return I18n.tr("NM not supported"); - } - secondaryMessage: I18n.tr("update dms for NM integration.") - } - } - - Component { - id: compoundPillComponent - CompoundPill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var widgetDef: root.model?.getWidgetForId(widgetData.id || "") - width: parent.width - height: 60 - iconName: { - switch (widgetData.id || "") { - case "wifi": - { - if (NetworkService.wifiToggling) - return "sync"; - - const status = NetworkService.networkStatus; - if (status === "ethernet") - return "settings_ethernet"; - if (status === "vpn") - return NetworkService.ethernetConnected ? "settings_ethernet" : NetworkService.wifiSignalIcon; - if (status === "wifi") - return NetworkService.wifiSignalIcon; - if (NetworkService.wifiEnabled) - return "wifi_off"; - return "wifi_off"; - } - case "bluetooth": - { - if (!BluetoothService.available) - return "bluetooth_disabled"; - if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) - return "bluetooth_disabled"; - return "bluetooth"; - } - case "audioOutput": - { - if (!AudioService.sink) - return "volume_off"; - let volume = AudioService.sink.audio.volume; - let muted = AudioService.sink.audio.muted; - if (muted) - return "volume_off"; - if (volume === 0.0) - return "volume_mute"; - if (volume <= 0.33) - return "volume_down"; - if (volume <= 0.66) - return "volume_up"; - return "volume_up"; - } - case "audioInput": - { - if (!AudioService.source) - return "mic_off"; - let muted = AudioService.source.audio.muted; - return muted ? "mic_off" : "mic"; - } - default: - return widgetDef?.icon || "help"; - } - } - primaryText: { - switch (widgetData.id || "") { - case "wifi": - { - if (NetworkService.wifiToggling) - return NetworkService.wifiEnabled ? I18n.tr("Disabling WiFi...", "network status") : I18n.tr("Enabling WiFi...", "network status"); - - const status = NetworkService.networkStatus; - if (status === "ethernet") - return I18n.tr("Ethernet", "network status"); - if (status === "vpn") { - if (NetworkService.ethernetConnected) - return I18n.tr("Ethernet", "network status"); - if (NetworkService.wifiConnected && NetworkService.currentWifiSSID) - return NetworkService.currentWifiSSID; - } - if (status === "wifi" && NetworkService.currentWifiSSID) - return NetworkService.currentWifiSSID; - if (NetworkService.wifiEnabled) - return I18n.tr("Not connected", "network status"); - return I18n.tr("WiFi off", "network status"); - } - case "bluetooth": - { - if (!BluetoothService.available) - return I18n.tr("Bluetooth", "bluetooth status"); - if (!BluetoothService.adapter) - return I18n.tr("No adapter", "bluetooth status"); - if (!BluetoothService.adapter.enabled) - return I18n.tr("Disabled", "bluetooth status"); - return I18n.tr("Enabled", "bluetooth status"); - } - case "audioOutput": - return AudioService.sink?.description || I18n.tr("No output device", "audio status"); - case "audioInput": - return AudioService.source?.description || I18n.tr("No input device", "audio status"); - default: - return widgetDef?.text || I18n.tr("Unknown", "widget status"); - } - } - secondaryText: { - switch (widgetData.id || "") { - case "wifi": - { - if (NetworkService.wifiToggling) - return I18n.tr("Please wait...", "network status"); - - const status = NetworkService.networkStatus; - if (status === "ethernet") - return I18n.tr("Connected", "network status"); - if (status === "vpn") { - if (NetworkService.ethernetConnected) - return I18n.tr("Connected", "network status"); - if (NetworkService.wifiConnected) - return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : I18n.tr("Connected", "network status"); - } - if (status === "wifi") - return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : I18n.tr("Connected", "network status"); - if (NetworkService.wifiEnabled) - return I18n.tr("Select network", "network status"); - return ""; - } - case "bluetooth": - { - if (!BluetoothService.available) - return I18n.tr("No adapters", "bluetooth status"); - if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) - return I18n.tr("Off", "bluetooth status"); - const primaryDevice = (() => { - if (!BluetoothService.adapter || !BluetoothService.adapter.devices) - return null; - let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]; - for (let device of devices) { - if (device && device.connected) - return device; - } - return null; - })(); - if (primaryDevice) - return primaryDevice.name || primaryDevice.alias || primaryDevice.deviceName || I18n.tr("Connected Device", "bluetooth status"); - return I18n.tr("No devices", "bluetooth status"); - } - case "audioOutput": - { - if (!AudioService.sink) - return I18n.tr("Select device", "audio status"); - if (AudioService.sink.audio.muted) - return I18n.tr("Muted", "audio status"); - const volume = AudioService.sink.audio.volume; - if (typeof volume !== "number" || isNaN(volume)) - return "0%"; - return Math.round(volume * 100) + "%"; - } - case "audioInput": - { - if (!AudioService.source) - return I18n.tr("Select device", "audio status"); - if (AudioService.source.audio.muted) - return I18n.tr("Muted", "audio status"); - const volume = AudioService.source.audio.volume; - if (typeof volume !== "number" || isNaN(volume)) - return "0%"; - return Math.round(volume * 100) + "%"; - } - default: - return widgetDef?.description || ""; - } - } - isActive: { - switch (widgetData.id || "") { - case "wifi": - { - if (NetworkService.wifiToggling) - return false; - - const status = NetworkService.networkStatus; - if (status === "ethernet") - return true; - if (status === "vpn") - return NetworkService.ethernetConnected || NetworkService.wifiConnected; - if (status === "wifi") - return true; - return NetworkService.wifiEnabled; - } - case "bluetooth": - return !!(BluetoothService.available && BluetoothService.adapter && BluetoothService.adapter.enabled); - case "audioOutput": - return !!(AudioService.sink && !AudioService.sink.audio.muted); - case "audioInput": - return !!(AudioService.source && !AudioService.source.audio.muted); - default: - return false; - } - } - enabled: widgetDef?.enabled ?? true - onToggled: { - if (root.editMode) - return; - switch (widgetData.id || "") { - case "wifi": - { - if (NetworkService.networkStatus !== "ethernet" && !NetworkService.wifiToggling) { - NetworkService.toggleWifiRadio(); - } - break; - } - case "bluetooth": - { - if (BluetoothService.available && BluetoothService.adapter) { - BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled; - } - break; - } - case "audioOutput": - { - if (AudioService.sink && AudioService.sink.audio) { - AudioService.sink.audio.muted = !AudioService.sink.audio.muted; - } - break; - } - case "audioInput": - { - if (AudioService.source && AudioService.source.audio) { - AudioService.source.audio.muted = !AudioService.source.audio.muted; - } - break; - } - } - } - onExpandClicked: { - if (root.editMode) - return; - root.expandClicked(widgetData, widgetIndex); - } - onWheelEvent: function (wheelEvent) { - if (root.editMode) - return; - const id = widgetData.id || ""; - if (id === "audioOutput") { - if (!AudioService.sink || !AudioService.sink.audio) - return; - let delta = wheelEvent.angleDelta.y; - let maxVol = AudioService.sinkMaxVolume; - let currentVolume = AudioService.sink.audio.volume * 100; - let newVolume; - if (delta > 0) - newVolume = Math.min(maxVol, currentVolume + 5); - else - newVolume = Math.max(0, currentVolume - 5); - AudioService.sink.audio.muted = false; - AudioService.sink.audio.volume = newVolume / 100; - wheelEvent.accepted = true; - } else if (id === "audioInput") { - if (!AudioService.source || !AudioService.source.audio) - return; - let delta = wheelEvent.angleDelta.y; - let currentVolume = AudioService.source.audio.volume * 100; - let newVolume; - if (delta > 0) - newVolume = Math.min(100, currentVolume + 5); - else - newVolume = Math.max(0, currentVolume - 5); - AudioService.source.audio.muted = false; - AudioService.source.audio.volume = newVolume / 100; - wheelEvent.accepted = true; - } - } - } - } - - Component { - id: audioSliderComponent - Item { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 16 - - AudioSliderRow { - anchors.centerIn: parent - width: parent.width - height: 14 - property color sliderTrackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - } - } - } - - Component { - id: brightnessSliderComponent - Item { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 16 - - BrightnessSliderRow { - id: brightnessSliderRow - anchors.centerIn: parent - width: parent.width - height: 14 - deviceName: widgetData.deviceName || "" - instanceId: widgetData.instanceId || "" - screenName: root.screenName - parentScreen: root.parentScreen - property color sliderTrackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - onIconClicked: { - if (!root.editMode && DisplayService.devices && DisplayService.devices.length > 1) { - root.expandClicked(widgetData, widgetIndex); - } - } - } - } - } - - Component { - id: inputAudioSliderComponent - Item { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 16 - - InputAudioSliderRow { - anchors.centerIn: parent - width: parent.width - height: 14 - property color sliderTrackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - } - } - } - - Component { - id: batteryPillComponent - BatteryPill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 60 - - onExpandClicked: { - if (!root.editMode) { - root.expandClicked(widgetData, widgetIndex); - } - } - } - } - - Component { - id: smallBatteryComponent - SmallBatteryButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 48 - - onClicked: { - if (!root.editMode) { - root.expandClicked(widgetData, widgetIndex); - } - } - } - } - - Component { - id: toggleButtonComponent - ToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 60 - - iconName: { - switch (widgetData.id || "") { - case "nightMode": - return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"; - case "darkMode": - return "contrast"; - case "doNotDisturb": - return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"; - case "idleInhibitor": - return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"; - default: - return "help"; - } - } - - text: { - switch (widgetData.id || "") { - case "nightMode": - return I18n.tr("Night Mode"); - case "darkMode": - return I18n.tr("Dark Mode"); - case "doNotDisturb": - return I18n.tr("Do Not Disturb"); - case "idleInhibitor": - return SessionService.idleInhibited ? I18n.tr("Keeping Awake") : I18n.tr("Keep Awake"); - default: - return I18n.tr("Unknown", "widget status"); - } - } - - iconRotation: { - if (widgetData.id !== "darkMode") - return 0; - if (darkModeTransitionPending) { - return SessionData.isLightMode ? 180 : 0; - } - return SessionData.isLightMode ? 180 : 0; - } - - isActive: { - switch (widgetData.id || "") { - case "nightMode": - return DisplayService.nightModeEnabled || false; - case "darkMode": - return !SessionData.isLightMode; - case "doNotDisturb": - return SessionData.doNotDisturb || false; - case "idleInhibitor": - return SessionService.idleInhibited || false; - default: - return false; - } - } - - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - switch (widgetData.id || "") { - case "nightMode": - { - if (DisplayService.automationAvailable) - DisplayService.toggleNightMode(); - break; - } - case "darkMode": - { - const newMode = !SessionData.isLightMode; - Theme.screenTransition(); - Theme.setLightMode(newMode); - break; - } - case "doNotDisturb": - { - SessionData.setDoNotDisturb(!SessionData.doNotDisturb); - break; - } - case "idleInhibitor": - { - SessionService.toggleIdleInhibit(); - break; - } - } - } - } - } - - Component { - id: smallToggleComponent - SmallToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 48 - - iconName: { - switch (widgetData.id || "") { - case "nightMode": - return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"; - case "darkMode": - return "contrast"; - case "doNotDisturb": - return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"; - case "idleInhibitor": - return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"; - default: - return "help"; - } - } - - iconRotation: { - if (widgetData.id !== "darkMode") - return 0; - if (darkModeTransitionPending) { - return SessionData.isLightMode ? 180 : 0; - } - return SessionData.isLightMode ? 180 : 0; - } - - isActive: { - switch (widgetData.id || "") { - case "nightMode": - return DisplayService.nightModeEnabled || false; - case "darkMode": - return !SessionData.isLightMode; - case "doNotDisturb": - return SessionData.doNotDisturb || false; - case "idleInhibitor": - return SessionService.idleInhibited || false; - default: - return false; - } - } - - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - switch (widgetData.id || "") { - case "nightMode": - { - if (DisplayService.automationAvailable) - DisplayService.toggleNightMode(); - break; - } - case "darkMode": - { - const newMode = !SessionData.isLightMode; - Theme.screenTransition(); - Theme.setLightMode(newMode); - break; - } - case "doNotDisturb": - { - SessionData.setDoNotDisturb(!SessionData.doNotDisturb); - break; - } - case "idleInhibitor": - { - SessionService.toggleIdleInhibit(); - break; - } - } - } - } - } - - Component { - id: diskUsagePillComponent - DiskUsagePill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 60 - - mountPath: widgetData.mountPath || "/" - instanceId: widgetData.instanceId || "" - - onExpandClicked: { - if (!root.editMode) { - root.expandClicked(widgetData, widgetIndex); - } - } - } - } - - Component { - id: smallDiskUsageComponent - SmallDiskUsageButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 48 - - mountPath: widgetData.mountPath || "/" - instanceId: widgetData.instanceId || "" - - onClicked: { - if (!root.editMode) { - root.expandClicked(widgetData, widgetIndex); - } - } - } - } - - Component { - id: colorPickerPillComponent - ColorPickerPill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - width: parent.width - height: 60 - - colorPickerModal: root.colorPickerModal - } - } - - Component { - id: builtinPluginWidgetComponent - Loader { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property int widgetWidth: widgetData.width || 50 - width: parent.width - height: 60 - - property var builtinInstance: null - - Component.onCompleted: { - const id = widgetData.id || ""; - if (id === "builtin_vpn") { - if (root.model?.vpnLoader) { - root.model.vpnLoader.active = true; - } - builtinInstance = Qt.binding(() => root.model?.vpnBuiltinInstance); - } - if (id === "builtin_cups") { - if (root.model?.cupsLoader) { - root.model.cupsLoader.active = true; - } - builtinInstance = Qt.binding(() => root.model?.cupsBuiltinInstance); - } - } - - sourceComponent: { - if (!builtinInstance) - return null; - - const hasDetail = builtinInstance.ccDetailContent !== null; - - if (widgetWidth <= 25) { - return builtinSmallToggleComponent; - } else if (hasDetail) { - return builtinCompoundPillComponent; - } else { - return builtinToggleComponent; - } - } - } - } - - Component { - id: builtinCompoundPillComponent - CompoundPill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var builtinInstance: parent.builtinInstance - - iconName: builtinInstance?.ccWidgetIcon || "extension" - primaryText: builtinInstance?.ccWidgetPrimaryText || "Built-in" - secondaryText: builtinInstance?.ccWidgetSecondaryText || "" - isActive: builtinInstance?.ccWidgetIsActive || false - - onToggled: { - if (root.editMode) - return; - if (builtinInstance) { - builtinInstance.ccWidgetToggled(); - } - } - - onExpandClicked: { - if (root.editMode) - return; - if (builtinInstance) { - builtinInstance.ccWidgetExpanded(); - } - root.expandClicked(widgetData, widgetIndex); - } - } - } - - Component { - id: builtinToggleComponent - ToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var builtinInstance: parent.builtinInstance - - iconName: builtinInstance?.ccWidgetIcon || "extension" - text: builtinInstance?.ccWidgetPrimaryText || "Built-in" - isActive: builtinInstance?.ccWidgetIsActive || false - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - if (builtinInstance) { - builtinInstance.ccWidgetToggled(); - } - } - } - } - - Component { - id: builtinSmallToggleComponent - SmallToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var builtinInstance: parent.builtinInstance - - iconName: builtinInstance?.ccWidgetIcon || "extension" - isActive: builtinInstance?.ccWidgetIsActive || false - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - if (builtinInstance) { - builtinInstance.ccWidgetToggled(); - } - } - } - } - - Component { - id: pluginWidgetComponent - Loader { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property int widgetWidth: widgetData.width || 50 - width: parent.width - height: 60 - - property var pluginInstance: null - property string pluginId: widgetData.id?.replace("plugin_", "") || "" - - sourceComponent: { - if (!pluginInstance) - return null; - - const hasDetail = pluginInstance.ccDetailContent !== null; - - if (widgetWidth <= 25) { - return pluginSmallToggleComponent; - } else if (hasDetail) { - return pluginCompoundPillComponent; - } else { - return pluginToggleComponent; - } - } - - function tryCreatePluginInstance() { - const pluginComponent = PluginService.pluginWidgetComponents[pluginId]; - if (!pluginComponent) - return false; - try { - const instance = pluginComponent.createObject(null, { - "pluginId": pluginId, - "pluginService": PluginService, - "visible": false, - "width": 0, - "height": 0 - }); - if (instance) { - pluginInstance = instance; - return true; - } - } catch (e) { - console.warn("DragDropGrid: stale plugin component for", pluginId, "- reloading"); - PluginService.reloadPlugin(pluginId); - } - return false; - } - - Component.onCompleted: { - Qt.callLater(() => tryCreatePluginInstance()); - } - - Connections { - target: PluginService - function onPluginDataChanged(changedPluginId) { - if (changedPluginId === pluginId && pluginInstance) { - pluginInstance.loadPluginData(); - } - } - function onPluginLoaded(loadedPluginId) { - if (loadedPluginId !== pluginId || pluginInstance) - return; - Qt.callLater(() => tryCreatePluginInstance()); - } - } - - Component.onDestruction: { - if (pluginInstance) { - pluginInstance.destroy(); - } - } - } - } - - Component { - id: pluginCompoundPillComponent - CompoundPill { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var pluginInstance: parent.pluginInstance - - iconName: pluginInstance?.ccWidgetIcon || "extension" - primaryText: pluginInstance?.ccWidgetPrimaryText || "Plugin" - secondaryText: pluginInstance?.ccWidgetSecondaryText || "" - isActive: pluginInstance?.ccWidgetIsActive || false - - onToggled: { - if (root.editMode) - return; - if (pluginInstance) { - pluginInstance.ccWidgetToggled(); - } - } - - onExpandClicked: { - if (root.editMode) - return; - if (pluginInstance) { - pluginInstance.ccWidgetExpanded(); - } - root.expandClicked(widgetData, widgetIndex); - } - } - } - - Component { - id: pluginToggleComponent - ToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var pluginInstance: parent.pluginInstance - property var widgetDef: root.model?.getWidgetForId(widgetData.id || "") - - iconName: pluginInstance?.ccWidgetIcon || widgetDef?.icon || "extension" - text: pluginInstance?.ccWidgetPrimaryText || widgetDef?.text || "Plugin" - secondaryText: pluginInstance?.ccWidgetSecondaryText || "" - isActive: pluginInstance?.ccWidgetIsActive || false - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - if (pluginInstance) { - pluginInstance.ccWidgetToggled(); - } - } - } - } - - Component { - id: pluginSmallToggleComponent - SmallToggleButton { - property var widgetData: parent.widgetData || {} - property int widgetIndex: parent.widgetIndex || 0 - property var pluginInstance: parent.pluginInstance - property var widgetDef: root.model?.getWidgetForId(widgetData.id || "") - - iconName: pluginInstance?.ccWidgetIcon || widgetDef?.icon || "extension" - isActive: pluginInstance?.ccWidgetIsActive || false - enabled: !root.editMode - - onClicked: { - if (root.editMode) - return; - if (pluginInstance && pluginInstance.ccDetailContent) { - root.expandClicked(widgetData, widgetIndex); - } else if (pluginInstance) { - pluginInstance.ccWidgetToggled(); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropWidgetWrapper.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropWidgetWrapper.qml deleted file mode 100644 index 7cb0e2c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropWidgetWrapper.qml +++ /dev/null @@ -1,289 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property bool editMode: false - property var widgetData: null - property int widgetIndex: -1 - property bool isSlider: false - property Component widgetComponent: null - property real gridCellWidth: 100 - property real gridCellHeight: 60 - property int gridColumns: 4 - property var gridLayout: null - - z: dragArea.drag.active ? 10000 : 1 - - signal widgetMoved(int fromIndex, int toIndex) - signal removeWidget(int index) - signal toggleWidgetSize(int index) - - width: { - const widgetWidth = widgetData?.width || 50 - if (widgetWidth <= 25) return gridCellWidth - else if (widgetWidth <= 50) return gridCellWidth * 2 - else if (widgetWidth <= 75) return gridCellWidth * 3 - else return gridCellWidth * 4 - } - height: isSlider ? 16 : gridCellHeight - - Rectangle { - id: dragIndicator - anchors.fill: parent - color: "transparent" - border.color: Theme.primary - border.width: dragArea.drag.active ? 2 : 0 - radius: Theme.cornerRadius - opacity: dragArea.drag.active ? 0.8 : 1.0 - z: dragArea.drag.active ? 10000 : 1 - - Behavior on border.width { - NumberAnimation { duration: 150 } - } - Behavior on opacity { - NumberAnimation { duration: 150 } - } - } - - Loader { - id: widgetLoader - anchors.fill: parent - sourceComponent: widgetComponent - property var widgetData: root.widgetData - property int widgetIndex: root.widgetIndex - property int globalWidgetIndex: root.widgetIndex - property int widgetWidth: root.widgetData?.width || 50 - - - MouseArea { - id: editModeBlocker - anchors.fill: parent - enabled: root.editMode - acceptedButtons: Qt.AllButtons - onPressed: function(mouse) { mouse.accepted = true } - onWheel: function(wheel) { wheel.accepted = true } - z: 100 - } - } - - MouseArea { - id: dragArea - anchors.fill: parent - enabled: editMode - cursorShape: editMode ? Qt.OpenHandCursor : Qt.PointingHandCursor - drag.target: editMode ? root : null - drag.axis: Drag.XAndYAxis - drag.smoothed: true - - onPressed: function(mouse) { - if (editMode) { - cursorShape = Qt.ClosedHandCursor - if (root.gridLayout && root.gridLayout.moveToTop) { - root.gridLayout.moveToTop(root) - } - } - } - - onReleased: function(mouse) { - if (editMode) { - cursorShape = Qt.OpenHandCursor - root.snapToGrid() - } - } - } - - Drag.active: dragArea.drag.active - Drag.hotSpot.x: width / 2 - Drag.hotSpot.y: height / 2 - - function swapIndices(i, j) { - if (i === j) return; - const arr = SettingsData.controlCenterWidgets; - if (!arr || i < 0 || j < 0 || i >= arr.length || j >= arr.length) return; - - const copy = arr.slice(); - const tmp = copy[i]; - copy[i] = copy[j]; - copy[j] = tmp; - - SettingsData.set("controlCenterWidgets", copy); - } - - function snapToGrid() { - if (!editMode || !gridLayout) return - - const globalPos = root.mapToItem(gridLayout, 0, 0) - const cellWidth = gridLayout.width / gridColumns - const cellHeight = gridCellHeight + Theme.spacingS - - const centerX = globalPos.x + (root.width / 2) - const centerY = globalPos.y + (root.height / 2) - - let targetCol = Math.max(0, Math.floor(centerX / cellWidth)) - let targetRow = Math.max(0, Math.floor(centerY / cellHeight)) - - targetCol = Math.min(targetCol, gridColumns - 1) - - const newIndex = findBestInsertionIndex(targetRow, targetCol) - - if (newIndex !== widgetIndex && newIndex >= 0 && newIndex < (SettingsData.controlCenterWidgets?.length || 0)) { - swapIndices(widgetIndex, newIndex) - } - } - - function findBestInsertionIndex(targetRow, targetCol) { - const widgets = SettingsData.controlCenterWidgets || []; - const n = widgets.length; - if (!n || widgetIndex < 0 || widgetIndex >= n) return -1; - - function spanFor(width) { - const w = width ?? 50; - if (w <= 25) return 1; - if (w <= 50) return 2; - if (w <= 75) return 3; - return 4; - } - - const cols = gridColumns || 4; - - let row = 0, col = 0; - let draggedOrigKey = null; - - const pos = []; - - for (let i = 0; i < n; i++) { - const span = Math.min(spanFor(widgets[i].width), cols); - - if (col + span > cols) { - row++; - col = 0; - } - - const startCol = col; - const centerKey = row * cols + (startCol + (span - 1) / 2); - - if (i === widgetIndex) { - draggedOrigKey = centerKey; - } else { - pos.push({ index: i, row, startCol, span, centerKey }); - } - - col += span; - if (col >= cols) { - row++; - col = 0; - } - } - - if (pos.length === 0) return -1; - - const centerColCoord = targetCol + 0.5; - const targetKey = targetRow * cols + centerColCoord; - - for (let k = 0; k < pos.length; k++) { - const p = pos[k]; - if (p.row === targetRow && centerColCoord >= p.startCol && centerColCoord < (p.startCol + p.span)) { - return p.index; - } - } - - let lo = 0, hi = pos.length - 1; - if (targetKey <= pos[0].centerKey) return pos[0].index; - if (targetKey >= pos[hi].centerKey) return pos[hi].index; - - while (lo <= hi) { - const mid = (lo + hi) >> 1; - const mk = pos[mid].centerKey; - if (targetKey < mk) hi = mid - 1; - else if (targetKey > mk) lo = mid + 1; - else return pos[mid].index; - } - const movingUp = (draggedOrigKey != null) ? (targetKey < draggedOrigKey) : false; - return (movingUp ? pos[lo].index : pos[hi].index); - } - - Rectangle { - width: 16 - height: 16 - radius: 8 - color: Theme.error - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: -4 - visible: editMode - z: 10 - - DankIcon { - anchors.centerIn: parent - name: "close" - size: 12 - color: Theme.primaryText - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: removeWidget(widgetIndex) - } - } - - SizeControls { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.margins: -6 - visible: editMode - z: 10 - currentSize: root.widgetData?.width || 50 - isSlider: root.isSlider - widgetIndex: root.widgetIndex - onSizeChanged: (newSize) => { - var widgets = SettingsData.controlCenterWidgets.slice() - if (widgetIndex >= 0 && widgetIndex < widgets.length) { - widgets[widgetIndex].width = newSize - SettingsData.set("controlCenterWidgets", widgets) - } - } - } - - Rectangle { - id: dragHandle - width: 16 - height: 12 - radius: 2 - color: Theme.primary - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: 4 - visible: editMode - z: 15 - opacity: dragArea.drag.active ? 1.0 : 0.7 - - DankIcon { - anchors.centerIn: parent - name: "drag_indicator" - size: 10 - color: Theme.primaryText - } - - Behavior on opacity { - NumberAnimation { duration: 150 } - } - } - - Rectangle { - anchors.fill: parent - color: editMode ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius - border.color: "transparent" - border.width: 0 - z: -1 - - Behavior on color { - ColorAnimation { duration: Theme.shortDuration } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/EditControls.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/EditControls.qml deleted file mode 100644 index 50531aa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/EditControls.qml +++ /dev/null @@ -1,245 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets - -Row { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var availableWidgets: [] - property Item popoutContent: null - - signal addWidget(string widgetId) - signal resetToDefault - signal clearAll - - height: 48 - spacing: Theme.spacingS - - onAddWidget: addWidgetPopup.close() - - Popup { - id: addWidgetPopup - parent: popoutContent - x: parent ? Math.round((parent.width - width) / 2) : 0 - y: parent ? Math.round((parent.height - height) / 2) : 0 - width: 400 - height: 300 - modal: false - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - border.color: Theme.primarySelected - border.width: 0 - radius: Theme.cornerRadius - } - - contentItem: Item { - anchors.fill: parent - anchors.margins: Theme.spacingL - - Row { - id: headerRow - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - spacing: Theme.spacingM - - DankIcon { - name: "add_circle" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Typography { - text: I18n.tr("Add Widget") - style: Typography.Style.Subtitle - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankListView { - anchors.top: headerRow.bottom - anchors.topMargin: Theme.spacingM - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - spacing: Theme.spacingS - clip: true - model: root.availableWidgets - - delegate: Rectangle { - width: 400 - Theme.spacingL * 2 - height: 50 - radius: Theme.cornerRadius - color: widgetMouseArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: modelData.icon - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: 400 - Theme.spacingL * 2 - Theme.iconSize - Theme.spacingM * 3 - Theme.iconSize - - Typography { - text: modelData.text - style: Typography.Style.Body - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Typography { - text: modelData.description - style: Typography.Style.Caption - color: Theme.outline - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankIcon { - name: "add" - size: Theme.iconSize - 4 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: widgetMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.addWidget(modelData.id); - } - } - } - } - } - } - - Rectangle { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) - border.color: Theme.primary - border.width: 0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "add" - size: Theme.iconSize - 2 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Typography { - text: I18n.tr("Add Widget") - style: Typography.Style.Button - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: addWidgetPopup.open() - } - } - - Rectangle { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12) - border.color: Theme.warning - border.width: 0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "settings_backup_restore" - size: Theme.iconSize - 2 - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - Typography { - text: I18n.tr("Defaults") - style: Typography.Style.Button - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.resetToDefault() - } - } - - Rectangle { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) - border.color: Theme.error - border.width: 0 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "clear_all" - size: Theme.iconSize - 2 - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - Typography { - text: I18n.tr("Reset") - style: Typography.Style.Button - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.clearAll() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/HeaderPane.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/HeaderPane.qml deleted file mode 100644 index d36c5b6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/HeaderPane.qml +++ /dev/null @@ -1,118 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property bool editMode: false - - signal powerButtonClicked - signal lockRequested - signal editModeToggled - signal settingsButtonClicked - - Component.onCompleted: DgopService.addRef("system") - Component.onDestruction: DgopService.removeRef("system") - - implicitHeight: 70 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - spacing: Theme.spacingM - - DankCircularImage { - id: avatarContainer - - width: 60 - height: 60 - imageSource: { - if (PortalService.profileImage === "") - return ""; - - if (PortalService.profileImage.startsWith("/")) - return "file://" + PortalService.profileImage; - - return PortalService.profileImage; - } - fallbackIcon: "person" - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - Typography { - text: UserInfoService.fullName || UserInfoService.username || I18n.tr("User") - style: Typography.Style.Subtitle - color: Theme.surfaceText - } - - Typography { - text: DgopService.uptime || I18n.tr("Unknown") - style: Typography.Style.Caption - color: Theme.surfaceVariantText - } - } - } - - Row { - id: actionButtonsRow - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.rightMargin: Theme.spacingXS - spacing: Theme.spacingXS - - DankActionButton { - buttonSize: 36 - iconName: "lock" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - backgroundColor: "transparent" - onClicked: { - root.lockRequested(); - } - } - - DankActionButton { - buttonSize: 36 - iconName: "power_settings_new" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - backgroundColor: "transparent" - onClicked: root.powerButtonClicked() - } - - DankActionButton { - buttonSize: 36 - iconName: "settings" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - backgroundColor: "transparent" - onClicked: { - root.settingsButtonClicked(); - PopoutService.focusOrToggleSettings(); - } - } - - DankActionButton { - buttonSize: 36 - iconName: editMode ? "done" : "edit" - iconSize: Theme.iconSize - 4 - iconColor: editMode ? Theme.primary : Theme.surfaceText - backgroundColor: "transparent" - onClicked: root.editModeToggled() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/PowerButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/PowerButton.qml deleted file mode 100644 index 8ed7444..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/PowerButton.qml +++ /dev/null @@ -1,55 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string iconName: "" - property string text: "" - - signal pressed - - height: 34 - radius: Theme.cornerRadius - color: mouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5) - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: root.iconName - size: Theme.fontSizeSmall - color: mouseArea.containsMouse ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Typography { - text: root.text - style: Typography.Style.Button - color: mouseArea.containsMouse ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - ripple.trigger(mouse.x, mouse.y); - root.pressed(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/SizeControls.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/SizeControls.qml deleted file mode 100644 index aeae4ee..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/SizeControls.qml +++ /dev/null @@ -1,52 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets - -Row { - id: root - - property int currentSize: 50 - property bool isSlider: false - property int widgetIndex: -1 - - signal sizeChanged(int newSize) - - readonly property var availableSizes: isSlider ? [50, 75, 100] : [25, 50, 75, 100] - - spacing: 2 - - Repeater { - model: root.availableSizes - - Rectangle { - width: 16 - height: 16 - radius: 3 - color: modelData === root.currentSize ? Theme.primary : Theme.surfaceContainer - border.color: modelData === root.currentSize ? Theme.primary : Theme.outline - border.width: 1 - - StyledText { - anchors.centerIn: parent - text: modelData.toString() - font.pixelSize: 8 - font.weight: Font.Medium - color: modelData === root.currentSize ? Theme.primaryText : Theme.surfaceText - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - root.currentSize = modelData - root.sizeChanged(modelData) - } - } - - Behavior on color { - ColorAnimation { duration: Theme.shortDuration } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/Typography.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/Typography.qml deleted file mode 100644 index f3e554f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/Typography.qml +++ /dev/null @@ -1,46 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledText { - id: root - - enum Style { - Title, - Subtitle, - Body, - Caption, - Button - } - - property int style: Typography.Style.Body - - font.pixelSize: { - switch (style) { - case Typography.Style.Title: return Theme.fontSizeXLarge - case Typography.Style.Subtitle: return Theme.fontSizeLarge - case Typography.Style.Body: return Theme.fontSizeMedium - case Typography.Style.Caption: return Theme.fontSizeSmall - case Typography.Style.Button: return Theme.fontSizeSmall - default: return Theme.fontSizeMedium - } - } - - font.weight: { - switch (style) { - case Typography.Style.Title: return Font.Bold - case Typography.Style.Subtitle: return Font.Medium - case Typography.Style.Body: return Font.Normal - case Typography.Style.Caption: return Font.Normal - case Typography.Style.Button: return Font.Medium - default: return Font.Normal - } - } - - color: { - switch (style) { - case Typography.Style.Caption: return Theme.surfaceVariantText - default: return Theme.surfaceText - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/ControlCenterPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/ControlCenterPopout.qml deleted file mode 100644 index d8839aa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/ControlCenterPopout.qml +++ /dev/null @@ -1,272 +0,0 @@ -import QtQuick -import Quickshell.Wayland -import qs.Common -import qs.Modules.ControlCenter.Details -import qs.Services -import qs.Widgets -import qs.Modules.ControlCenter.Components -import qs.Modules.ControlCenter.Models -import "./utils/state.js" as StateUtils - -DankPopout { - id: root - - layerNamespace: "dms:control-center" - fullHeightSurface: true - - property string expandedSection: "" - property var triggerScreen: null - property bool editMode: false - property int expandedWidgetIndex: -1 - property var expandedWidgetData: null - property bool powerMenuOpen: powerMenuModalLoader?.item?.shouldBeVisible ?? false - - signal lockRequested - - function collapseAll() { - expandedSection = ""; - expandedWidgetIndex = -1; - expandedWidgetData = null; - } - - onEditModeChanged: { - if (editMode) { - collapseAll(); - } - } - - onVisibleChanged: { - if (!visible) { - collapseAll(); - } - } - - readonly property color _containerBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - function openWithSection(section) { - StateUtils.openWithSection(root, section); - } - - function toggleSection(section) { - StateUtils.toggleSection(root, section); - } - - popupWidth: 550 - popupHeight: { - const screenHeight = (triggerScreen?.height ?? 1080); - const maxHeight = screenHeight - 100; - const contentHeight = contentLoader.item && contentLoader.item.implicitHeight > 0 ? contentLoader.item.implicitHeight + 20 : 400; - return Math.min(maxHeight, contentHeight); - } - triggerWidth: 80 - positioning: "" - screen: triggerScreen - shouldBeVisible: false - - property bool credentialsPromptOpen: NetworkService.credentialsRequested - property bool wifiPasswordModalOpen: PopoutService.wifiPasswordModal?.visible ?? false - property bool polkitModalOpen: PopoutService.polkitAuthModal?.visible ?? false - property bool anyModalOpen: credentialsPromptOpen || wifiPasswordModalOpen || polkitModalOpen || powerMenuOpen - - backgroundInteractive: !anyModalOpen - - onCredentialsPromptOpenChanged: { - if (credentialsPromptOpen && shouldBeVisible) - close(); - } - - onPolkitModalOpenChanged: { - if (polkitModalOpen && shouldBeVisible) - close(); - } - - customKeyboardFocus: { - if (!shouldBeVisible) - return WlrKeyboardFocus.None; - if (anyModalOpen) - return WlrKeyboardFocus.None; - if (CompositorService.useHyprlandFocusGrab) - return WlrKeyboardFocus.OnDemand; - return WlrKeyboardFocus.Exclusive; - } - - onBackgroundClicked: close() - - onShouldBeVisibleChanged: { - if (shouldBeVisible) { - collapseAll(); - Qt.callLater(() => { - if (NetworkService.activeService) - NetworkService.activeService.autoRefreshEnabled = NetworkService.wifiEnabled; - }); - } else { - Qt.callLater(() => { - if (NetworkService.activeService) { - NetworkService.activeService.autoRefreshEnabled = false; - } - if (BluetoothService.adapter && BluetoothService.adapter.discovering) - BluetoothService.adapter.discovering = false; - editMode = false; - }); - } - } - - WidgetModel { - id: widgetModel - } - - content: Component { - Rectangle { - id: controlContent - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitHeight: mainColumn.implicitHeight + Theme.spacingM - property alias bluetoothCodecSelector: bluetoothCodecSelector - - color: "transparent" - clip: true - - Rectangle { - anchors.fill: parent - color: Qt.rgba(0, 0, 0, 0.6) - radius: parent.radius - visible: root.powerMenuOpen - z: 5000 - - Behavior on opacity { - NumberAnimation { - duration: 200 - easing.type: Easing.OutCubic - } - } - } - - Column { - id: mainColumn - width: parent.width - Theme.spacingL * 2 - x: Theme.spacingL - y: Theme.spacingL - spacing: Theme.spacingS - - HeaderPane { - id: headerPane - width: parent.width - editMode: root.editMode - onEditModeToggled: root.editMode = !root.editMode - onPowerButtonClicked: { - if (powerMenuModalLoader) { - powerMenuModalLoader.active = true; - if (powerMenuModalLoader.item) { - const bounds = Qt.rect(root.alignedX, root.alignedY, root.popupWidth, root.popupHeight); - powerMenuModalLoader.item.openFromControlCenter(bounds, root.screen); - } - } - } - onLockRequested: { - root.close(); - root.lockRequested(); - } - onSettingsButtonClicked: { - root.close(); - } - } - - DragDropGrid { - id: widgetGrid - width: parent.width - editMode: root.editMode - maxPopoutHeight: { - const screenHeight = (root.triggerScreen?.height ?? 1080); - return screenHeight - 100 - Theme.spacingL - headerPane.height - Theme.spacingS; - } - expandedSection: root.expandedSection - expandedWidgetIndex: root.expandedWidgetIndex - expandedWidgetData: root.expandedWidgetData - model: widgetModel - bluetoothCodecSelector: bluetoothCodecSelector - colorPickerModal: root.colorPickerModal - screenName: root.triggerScreen?.name || "" - screenModel: root.triggerScreen?.model || "" - parentScreen: root.triggerScreen - onExpandClicked: (widgetData, globalIndex) => { - root.expandedWidgetIndex = globalIndex; - root.expandedWidgetData = widgetData; - if (widgetData.id === "diskUsage") { - root.toggleSection("diskUsage_" + (widgetData.instanceId || "default")); - } else if (widgetData.id === "brightnessSlider") { - root.toggleSection("brightnessSlider_" + (widgetData.instanceId || "default")); - } else { - root.toggleSection(widgetData.id); - } - } - onRemoveWidget: index => widgetModel.removeWidget(index) - onMoveWidget: (fromIndex, toIndex) => widgetModel.moveWidget(fromIndex, toIndex) - onToggleWidgetSize: index => widgetModel.toggleWidgetSize(index) - onCollapseRequested: root.collapseAll() - } - - EditControls { - width: parent.width - visible: editMode - popoutContent: controlContent - availableWidgets: { - if (!editMode) - return []; - const existingIds = (SettingsData.controlCenterWidgets || []).map(w => w.id); - const allWidgets = widgetModel.baseWidgetDefinitions.concat(widgetModel.getPluginWidgets()); - return allWidgets.filter(w => w.allowMultiple || !existingIds.includes(w.id)); - } - onAddWidget: widgetId => widgetModel.addWidget(widgetId) - onResetToDefault: () => widgetModel.resetToDefault() - onClearAll: () => widgetModel.clearAll() - } - } - - BluetoothCodecSelector { - id: bluetoothCodecSelector - anchors.fill: parent - z: 10000 - } - } - } - - Component { - id: networkDetailComponent - NetworkDetail {} - } - - Component { - id: bluetoothDetailComponent - BluetoothDetail { - id: bluetoothDetail - onShowCodecSelector: function (device) { - if (contentLoader.item && contentLoader.item.bluetoothCodecSelector) { - contentLoader.item.bluetoothCodecSelector.show(device); - contentLoader.item.bluetoothCodecSelector.codecSelected.connect(function (deviceAddress, codecName) { - bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName); - }); - } - } - } - } - - Component { - id: audioOutputDetailComponent - AudioOutputDetail {} - } - - Component { - id: audioInputDetailComponent - AudioInputDetail {} - } - - Component { - id: batteryDetailComponent - BatteryDetail {} - } - - property var colorPickerModal: null - property var powerMenuModalLoader: null -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml deleted file mode 100644 index 8fc2d46..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml +++ /dev/null @@ -1,363 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Services.Pipewire -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property bool hasInputVolumeSliderInCC: { - const widgets = SettingsData.controlCenterWidgets || []; - return widgets.some(widget => widget.id === "inputVolumeSlider"); - } - - implicitHeight: headerRow.height + (hasInputVolumeSliderInCC ? 0 : volumeSlider.height) + audioContent.height + Theme.spacingM - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - height: 40 - - StyledText { - id: headerText - text: I18n.tr("Input Devices") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Item { - height: 1 - width: parent.width - headerText.width - settingsButton.width - } - - DankActionButton { - id: settingsButton - anchors.verticalCenter: parent.verticalCenter - iconName: "settings" - buttonSize: 28 - iconSize: 16 - iconColor: Theme.surfaceVariantText - onClicked: { - PopoutService.closeControlCenter(); - PopoutService.openSettingsWithTab("audio"); - } - } - } - - Row { - id: volumeSlider - anchors.left: parent.left - anchors.right: parent.right - anchors.top: headerRow.bottom - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingXS - height: 35 - spacing: 0 - visible: !hasInputVolumeSliderInCC - - Rectangle { - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: (Theme.iconSize + Theme.spacingS * 2) / 2 - color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankRipple { - id: iconRipple - cornerRadius: parent.radius - } - - MouseArea { - id: iconArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (AudioService.source && AudioService.source.audio) { - AudioService.source.audio.muted = !AudioService.source.audio.muted; - } - } - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!AudioService.source || !AudioService.source.audio) - return "mic_off"; - let muted = AudioService.source.audio.muted; - return muted ? "mic_off" : "mic"; - } - size: Theme.iconSize - color: AudioService.source && AudioService.source.audio && !AudioService.source.audio.muted && AudioService.source.audio.volume > 0 ? Theme.primary : Theme.surfaceText - } - } - - DankSlider { - readonly property real actualVolumePercent: AudioService.source && AudioService.source.audio ? Math.round(AudioService.source.audio.volume * 100) : 0 - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - (Theme.iconSize + Theme.spacingS * 2) - enabled: AudioService.source && AudioService.source.audio - minimum: 0 - maximum: 100 - value: AudioService.source && AudioService.source.audio ? Math.min(100, Math.round(AudioService.source.audio.volume * 100)) : 0 - showValue: true - unit: "%" - valueOverride: actualVolumePercent - thumbOutlineColor: Theme.surfaceVariant - - onSliderValueChanged: function (newValue) { - if (AudioService.source && AudioService.source.audio) { - AudioService.source.audio.volume = newValue / 100; - if (newValue > 0 && AudioService.source.audio.muted) { - AudioService.source.audio.muted = false; - } - } - } - } - } - - DankFlickable { - id: audioContent - anchors.top: hasInputVolumeSliderInCC ? headerRow.bottom : volumeSlider.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: hasInputVolumeSliderInCC ? Theme.spacingM : Theme.spacingS - contentHeight: audioColumn.height - clip: true - - property int maxPinnedInputs: 3 - - function normalizePinList(value) { - if (Array.isArray(value)) - return value.filter(v => v); - if (typeof value === "string" && value.length > 0) - return [value]; - return []; - } - - function getPinnedInputs() { - const pins = SettingsData.audioInputDevicePins || {}; - return normalizePinList(pins["preferredInput"]); - } - - Column { - id: audioColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: ScriptModel { - values: { - const hidden = SessionData.hiddenInputDeviceNames ?? []; - const nodes = Pipewire.nodes.values.filter(node => { - if (!node.audio || node.isSink || node.isStream) - return false; - return !hidden.includes(node.name); - }); - const pinnedList = audioContent.getPinnedInputs(); - - let sorted = [...nodes]; - sorted.sort((a, b) => { - // Pinned device first - const aPinnedIndex = pinnedList.indexOf(a.name); - const bPinnedIndex = pinnedList.indexOf(b.name); - if (aPinnedIndex !== -1 || bPinnedIndex !== -1) { - if (aPinnedIndex === -1) - return 1; - if (bPinnedIndex === -1) - return -1; - return aPinnedIndex - bPinnedIndex; - } - // Then active device - if (a === AudioService.source && b !== AudioService.source) - return -1; - if (b === AudioService.source && a !== AudioService.source) - return 1; - return 0; - }); - return sorted; - } - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: deviceMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.color: modelData === AudioService.source ? Theme.primary : Theme.outlineLight - border.width: modelData === AudioService.source ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: { - if (modelData.name.includes("bluez")) - return "headset"; - else if (modelData.name.includes("usb")) - return "headset"; - else - return "mic"; - } - size: Theme.iconSize - 4 - color: modelData === AudioService.source ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: { - const iconWidth = Theme.iconSize; - const pinButtonWidth = pinInputRow.width + Theme.spacingS * 4 + Theme.spacingM; - return parent.parent.width - iconWidth - parent.spacing - pinButtonWidth - Theme.spacingM * 2; - } - - StyledText { - text: AudioService.displayName(modelData) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === AudioService.source ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: modelData === AudioService.source ? I18n.tr("Active") : I18n.tr("Available") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - } - - Rectangle { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: pinInputRow.width + Theme.spacingS * 2 - height: 28 - radius: height / 2 - color: { - const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name); - return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05); - } - - Row { - id: pinInputRow - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: "push_pin" - size: 16 - color: { - const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name); - return isThisDevicePinned ? Theme.primary : Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name); - return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin"); - } - font.pixelSize: Theme.fontSizeSmall - color: { - const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name); - return isThisDevicePinned ? Theme.primary : Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: pinRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: { - const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {})); - let pinnedList = audioContent.normalizePinList(pins["preferredInput"]); - const pinIndex = pinnedList.indexOf(modelData.name); - - if (pinIndex !== -1) { - pinnedList.splice(pinIndex, 1); - } else { - pinnedList.unshift(modelData.name); - if (pinnedList.length > audioContent.maxPinnedInputs) - pinnedList = pinnedList.slice(0, audioContent.maxPinnedInputs); - } - - if (pinnedList.length > 0) - pins["preferredInput"] = pinnedList; - else - delete pins["preferredInput"]; - - SettingsData.set("audioInputDevicePins", pins); - } - } - } - - DankRipple { - id: deviceRipple - cornerRadius: parent.radius - } - - MouseArea { - id: deviceMouseArea - anchors.fill: parent - anchors.rightMargin: pinInputRow.width + Theme.spacingS * 4 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - let mapped = mapToItem(parent, mouse.x, mouse.y); - deviceRipple.trigger(mapped.x, mapped.y); - } - onClicked: { - if (modelData) { - Pipewire.preferredDefaultAudioSource = modelData; - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml deleted file mode 100644 index 7e86ae4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml +++ /dev/null @@ -1,544 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Services.Pipewire -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property bool hasVolumeSliderInCC: { - const widgets = SettingsData.controlCenterWidgets || []; - return widgets.some(widget => widget.id === "volumeSlider"); - } - - implicitHeight: headerRow.height + (!hasVolumeSliderInCC ? volumeSlider.height : 0) + audioContent.height + Theme.spacingM - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - height: 40 - - StyledText { - id: headerText - text: I18n.tr("Audio Devices") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Item { - height: 1 - width: parent.width - headerText.width - settingsButton.width - } - - DankActionButton { - id: settingsButton - anchors.verticalCenter: parent.verticalCenter - iconName: "settings" - buttonSize: 28 - iconSize: 16 - iconColor: Theme.surfaceVariantText - onClicked: { - PopoutService.closeControlCenter(); - PopoutService.openSettingsWithTab("audio"); - } - } - } - - Row { - id: volumeSlider - anchors.left: parent.left - anchors.right: parent.right - anchors.top: headerRow.bottom - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingXS - height: 35 - spacing: 0 - visible: !hasVolumeSliderInCC - - Rectangle { - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: (Theme.iconSize + Theme.spacingS * 2) / 2 - color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankRipple { - id: muteRipple - cornerRadius: parent.radius - } - - MouseArea { - id: iconArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => muteRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (AudioService.sink && AudioService.sink.audio) { - AudioService.sink.audio.muted = !AudioService.sink.audio.muted; - } - } - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!AudioService.sink || !AudioService.sink.audio) - return "volume_off"; - let muted = AudioService.sink.audio.muted; - let volume = AudioService.sink.audio.volume; - if (muted) - return "volume_off"; - if (volume === 0.0) - return "volume_mute"; - if (volume <= 0.33) - return "volume_down"; - if (volume <= 0.66) - return "volume_up"; - return "volume_up"; - } - size: Theme.iconSize - color: AudioService.sink && AudioService.sink.audio && !AudioService.sink.audio.muted && AudioService.sink.audio.volume > 0 ? Theme.primary : Theme.surfaceText - } - } - - DankSlider { - readonly property real actualVolumePercent: AudioService.sink && AudioService.sink.audio ? Math.round(AudioService.sink.audio.volume * 100) : 0 - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - (Theme.iconSize + Theme.spacingS * 2) - enabled: AudioService.sink && AudioService.sink.audio - minimum: 0 - maximum: AudioService.sinkMaxVolume - value: AudioService.sink && AudioService.sink.audio ? Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100)) : 0 - showValue: true - unit: "%" - valueOverride: actualVolumePercent - thumbOutlineColor: Theme.surfaceVariant - - onSliderValueChanged: function (newValue) { - if (AudioService.sink && AudioService.sink.audio) { - AudioService.sink.audio.volume = newValue / 100; - if (newValue > 0 && AudioService.sink.audio.muted) { - AudioService.sink.audio.muted = false; - } - AudioService.volumeChanged(); - } - } - } - } - - DankFlickable { - id: audioContent - anchors.top: volumeSlider.visible ? volumeSlider.bottom : headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: volumeSlider.visible ? Theme.spacingS : Theme.spacingM - contentHeight: audioColumn.height - clip: true - - property int maxPinnedOutputs: 3 - - function normalizePinList(value) { - if (Array.isArray(value)) - return value.filter(v => v); - if (typeof value === "string" && value.length > 0) - return [value]; - return []; - } - - function getPinnedOutputs() { - const pins = SettingsData.audioOutputDevicePins || {}; - return normalizePinList(pins["preferredOutput"]); - } - - Column { - id: audioColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: ScriptModel { - values: { - const hidden = SessionData.hiddenOutputDeviceNames ?? []; - const nodes = Pipewire.nodes.values.filter(node => { - if (!node.audio || !node.isSink || node.isStream) - return false; - return !hidden.includes(node.name); - }); - const pinnedList = audioContent.getPinnedOutputs(); - - let sorted = [...nodes]; - sorted.sort((a, b) => { - // Pinned device first - const aPinnedIndex = pinnedList.indexOf(a.name); - const bPinnedIndex = pinnedList.indexOf(b.name); - if (aPinnedIndex !== -1 || bPinnedIndex !== -1) { - if (aPinnedIndex === -1) - return 1; - if (bPinnedIndex === -1) - return -1; - return aPinnedIndex - bPinnedIndex; - } - // Then active device - if (a === AudioService.sink && b !== AudioService.sink) - return -1; - if (b === AudioService.sink && a !== AudioService.sink) - return 1; - return 0; - }); - return sorted; - } - } - - delegate: Rectangle { - id: outputDelegate - required property var modelData - required property int index - - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: deviceMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.color: modelData === AudioService.sink ? Theme.primary : Theme.outlineLight - border.width: modelData === AudioService.sink ? 2 : 1 - - DankRipple { - id: deviceRipple - cornerRadius: outputDelegate.radius - } - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: AudioService.sinkIcon(modelData) - size: Theme.iconSize - 4 - color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: { - const iconWidth = Theme.iconSize; - const pinButtonWidth = pinOutputRow.width + Theme.spacingS * 4 + Theme.spacingM; - return parent.parent.width - iconWidth - parent.spacing - pinButtonWidth - Theme.spacingM * 2; - } - - StyledText { - text: AudioService.displayName(modelData) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === AudioService.sink ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: modelData === AudioService.sink ? I18n.tr("Active") : I18n.tr("Available") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - } - - Rectangle { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: pinOutputRow.width + Theme.spacingS * 2 - height: 28 - radius: height / 2 - color: { - const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name); - return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05); - } - - Row { - id: pinOutputRow - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: "push_pin" - size: 16 - color: { - const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name); - return isThisDevicePinned ? Theme.primary : Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name); - return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin"); - } - font.pixelSize: Theme.fontSizeSmall - color: { - const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name); - return isThisDevicePinned ? Theme.primary : Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: pinRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: { - const pins = JSON.parse(JSON.stringify(SettingsData.audioOutputDevicePins || {})); - let pinnedList = audioContent.normalizePinList(pins["preferredOutput"]); - const pinIndex = pinnedList.indexOf(modelData.name); - - if (pinIndex !== -1) { - pinnedList.splice(pinIndex, 1); - } else { - pinnedList.unshift(modelData.name); - if (pinnedList.length > audioContent.maxPinnedOutputs) - pinnedList = pinnedList.slice(0, audioContent.maxPinnedOutputs); - } - - if (pinnedList.length > 0) - pins["preferredOutput"] = pinnedList; - else - delete pins["preferredOutput"]; - - SettingsData.set("audioOutputDevicePins", pins); - } - } - } - - MouseArea { - id: deviceMouseArea - anchors.fill: parent - anchors.rightMargin: pinOutputRow.width + Theme.spacingS * 4 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - let mapped = deviceMouseArea.mapToItem(outputDelegate, mouse.x, mouse.y); - deviceRipple.trigger(mapped.x, mapped.y); - } - onClicked: { - if (modelData) { - Pipewire.preferredDefaultAudioSink = modelData; - } - } - } - } - } - Row { - id: playbackHeaderRow - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - height: 28 - - StyledText { - id: playbackHeaderText - text: I18n.tr("Playback") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Repeater { - model: ScriptModel { - values: { - const nodes = Pipewire.nodes.values.filter(node => { - return node.audio && node.isSink && node.isStream; - }); - return nodes; - } - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: Theme.surfaceLight - border.color: modelData === AudioService.sink ? Theme.primary : Theme.outlineLight - border.width: modelData === AudioService.sink ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: "album" - size: Theme.iconSize - 4 - color: !modelData.audio.muted ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: { - const iconWidth = Theme.iconSize; - return parent.parent.width - iconWidth - parent.spacing - Theme.spacingM * 2; - } - - StyledText { - text: { - const modelDataMediaName = modelData && modelData.properties ? (modelData.properties["media.name"] || "") : ""; - const mediaName = AudioService.displayName(modelData) + ": " + modelDataMediaName; - const max = 35; - return mediaName.length > max ? mediaName.substring(0, max) + "..." : mediaName; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === AudioService.sink ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - wrapMode: Text.NoWrap - } - } - } - Rectangle { - anchors.right: parent.right - anchors.rightMargin: 120 - anchors.verticalCenter: parent.verticalCenter - width: appVolumeRow.width - height: 28 - radius: height / 2 - - Item { - id: appVolumeRow - property color sliderTrackColor: "transparent" - anchors.centerIn: parent - - height: 40 - width: parent.width - - Rectangle { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: Theme.cornerRadius - color: appIconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0) - - DankRipple { - id: appMuteRipple - cornerRadius: parent.radius - } - - MouseArea { - id: appIconArea - anchors.fill: parent - visible: modelData !== null - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => appMuteRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (modelData) { - SessionData.suppressOSDTemporarily(); - modelData.audio.muted = !modelData.audio.muted; - } - } - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!modelData) - return "volume_off"; - - let volume = modelData.audio.volume; - let muted = modelData.audio.muted; - - if (muted) - return "volume_off"; - if (volume === 0.0) - return "volume_mute"; - if (volume <= 0.33) - return "volume_down"; - if (volume <= 0.66) - return "volume_up"; - return "volume_up"; - } - size: Theme.iconSize - color: modelData && !modelData.audio.muted && modelData.audio.volume > 0 ? Theme.primary : Theme.surfaceText - } - } - - DankSlider { - readonly property real actualVolumePercent: modelData ? Math.round(modelData.audio.volume * 100) : 0 - - anchors.verticalCenter: parent.verticalCenter - width: 100 - enabled: modelData !== null - minimum: 0 - maximum: 100 - value: modelData ? Math.min(100, Math.round(modelData.audio.volume * 100)) : 0 - showValue: true - unit: "%" - valueOverride: actualVolumePercent - thumbOutlineColor: Theme.surfaceContainer - trackColor: appVolumeRow.sliderTrackColor.a > 0 ? appVolumeRow.sliderTrackColor : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - onSliderValueChanged: function (newValue) { - if (modelData) { - SessionData.suppressOSDTemporarily(); - modelData.audio.volume = newValue / 100.0; - if (newValue > 0 && modelData.audio.muted) { - modelData.audio.muted = false; - } - AudioService.playVolumeChangeSoundIfEnabled(); - } - } - } - } - PwObjectTracker { - objects: [modelData] - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BatteryDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BatteryDetail.qml deleted file mode 100644 index 1f0206a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BatteryDetail.qml +++ /dev/null @@ -1,267 +0,0 @@ -import QtQuick -import Quickshell.Services.UPower -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitHeight: contentColumn.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - function isActiveProfile(profile) { - if (typeof PowerProfiles === "undefined") { - return false; - } - return PowerProfiles.profile === profile; - } - - function setProfile(profile) { - if (typeof PowerProfiles === "undefined") { - ToastService.showError("power-profiles-daemon not available"); - return; - } - PowerProfiles.profile = profile; - if (PowerProfiles.profile !== profile) { - ToastService.showError("Failed to set power profile"); - } - } - - Column { - id: contentColumn - width: parent.width - Theme.spacingL * 2 - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - Row { - id: headerRow - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: BatteryService.getBatteryIcon() - size: Theme.iconSizeLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) - return Theme.error; - if (BatteryService.isCharging || BatteryService.isPluggedIn) - return Theme.primary; - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSizeLarge - Theme.spacingM - - Row { - spacing: Theme.spacingS - - StyledText { - text: BatteryService.batteryAvailable ? `${BatteryService.batteryLevel}%` : I18n.tr("Power") - font.pixelSize: Theme.fontSizeXLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - if (BatteryService.isCharging) { - return Theme.primary; - } - return Theme.surfaceText; - } - font.weight: Font.Bold - } - - StyledText { - text: BatteryService.batteryAvailable ? BatteryService.batteryStatus : I18n.tr("Management") - font.pixelSize: Theme.fontSizeLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - if (BatteryService.isCharging) { - return Theme.primary; - } - return Theme.surfaceText; - } - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: { - if (!BatteryService.batteryAvailable) - return I18n.tr("Power profile management available"); - const time = BatteryService.formatTimeRemaining(); - if (time !== "Unknown") { - return BatteryService.isCharging ? I18n.tr("Time until full: %1").arg(time) : I18n.tr("Time remaining: %1").arg(time); - } - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - visible: text.length > 0 - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: BatteryService.batteryAvailable - - StyledRect { - width: (parent.width - Theme.spacingM) / 2 - height: 64 - radius: Theme.cornerRadius - color: Theme.surfaceLight - border.color: Theme.outlineLight - border.width: 1 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Health") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: BatteryService.batteryHealth - font.pixelSize: Theme.fontSizeLarge - color: { - if (BatteryService.batteryHealth === "N/A") { - return Theme.surfaceText; - } - const healthNum = parseInt(BatteryService.batteryHealth); - return healthNum < 80 ? Theme.error : Theme.surfaceText; - } - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - StyledRect { - width: (parent.width - Theme.spacingM) / 2 - height: 64 - radius: Theme.cornerRadius - color: Theme.surfaceLight - border.color: Theme.outlineLight - border.width: 1 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Capacity") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: BatteryService.batteryCapacity > 0 ? `${BatteryService.batteryCapacity.toFixed(1)} Wh` : I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - DankButtonGroup { - property var profileModel: (typeof PowerProfiles !== "undefined") ? [PowerProfile.PowerSaver, PowerProfile.Balanced].concat(PowerProfiles.hasPerformanceProfile ? [PowerProfile.Performance] : []) : [PowerProfile.PowerSaver, PowerProfile.Balanced, PowerProfile.Performance] - property int currentProfileIndex: { - if (typeof PowerProfiles === "undefined") - return 1; - return profileModel.findIndex(profile => isActiveProfile(profile)); - } - - model: profileModel.map(profile => Theme.getPowerProfileLabel(profile)) - currentIndex: currentProfileIndex - selectionMode: "single" - anchors.horizontalCenter: parent.horizontalCenter - onSelectionChanged: (index, selected) => { - if (!selected) - return; - setProfile(profileModel[index]); - } - } - - StyledRect { - width: parent.width - height: degradationContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) - border.color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3) - border.width: 0 - visible: (typeof PowerProfiles !== "undefined") && PowerProfiles.degradationReason !== PerformanceDegradationReason.None - - Column { - id: degradationContent - width: parent.width - Theme.spacingL * 2 - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSize - Theme.spacingM - - StyledText { - text: I18n.tr("Power Profile Degradation") - font.pixelSize: Theme.fontSizeLarge - color: Theme.error - font.weight: Font.Medium - } - - StyledText { - text: (typeof PowerProfiles !== "undefined") ? PerformanceDegradationReason.toString(PowerProfiles.degradationReason) : "" - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.8) - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml deleted file mode 100644 index 0cad08c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml +++ /dev/null @@ -1,332 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var device: null - property bool modalVisible: false - property var parentItem - property var availableCodecs: [] - property string currentCodec: "" - property bool isLoading: false - - readonly property bool deviceValid: device !== null && device.connected && BluetoothService.isAudioDevice(device) - - signal codecSelected(string deviceAddress, string codecName) - - function show(bluetoothDevice) { - if (!bluetoothDevice?.connected) - return; - if (!BluetoothService.isAudioDevice(bluetoothDevice)) - return; - device = bluetoothDevice; - isLoading = true; - availableCodecs = []; - currentCodec = ""; - visible = true; - modalVisible = true; - queryCodecs(); - Qt.callLater(() => { - focusScope.forceActiveFocus(); - }); - } - - function hide() { - modalVisible = false; - Qt.callLater(() => { - visible = false; - device = null; - }); - } - - function queryCodecs() { - if (!deviceValid) { - hide(); - return; - } - - const capturedDevice = device; - const capturedAddress = device.address; - - BluetoothService.getAvailableCodecs(capturedDevice, function (codecs, current) { - if (!root.deviceValid || root.device?.address !== capturedAddress) - return; - availableCodecs = codecs; - currentCodec = current; - isLoading = false; - }); - } - - function selectCodec(profileName) { - if (!deviceValid || isLoading) - return; - - const capturedDevice = device; - const capturedAddress = device.address; - - const selectedCodec = availableCodecs.find(c => c.profile === profileName); - if (!selectedCodec) - return; - - BluetoothService.updateDeviceCodec(capturedAddress, selectedCodec.name); - codecSelected(capturedAddress, selectedCodec.name); - - isLoading = true; - BluetoothService.switchCodec(capturedDevice, profileName, function (success, message) { - if (!root.device || root.device.address !== capturedAddress) - return; - - isLoading = false; - if (success) { - ToastService.showToast(message, ToastService.levelInfo); - Qt.callLater(root.hide); - return; - } - ToastService.showToast(message, ToastService.levelError); - }); - } - - onDeviceValidChanged: { - if (modalVisible && !deviceValid) { - hide(); - } - } - - visible: false - anchors.fill: parent - z: 2000 - - MouseArea { - id: modalBlocker - anchors.fill: parent - visible: modalVisible - enabled: modalVisible - hoverEnabled: true - preventStealing: true - propagateComposedEvents: false - - onClicked: root.hide() - onWheel: wheel => { - wheel.accepted = true; - } - onPositionChanged: mouse => { - mouse.accepted = true; - } - } - - Rectangle { - id: modalBackground - anchors.fill: parent - color: Qt.rgba(0, 0, 0, 0.5) - opacity: modalVisible ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - - FocusScope { - id: focusScope - - anchors.fill: parent - focus: root.visible - enabled: root.visible - - Keys.onEscapePressed: { - root.hide(); - event.accepted = true; - } - } - - Rectangle { - id: modalContent - anchors.centerIn: parent - width: 320 - height: contentColumn.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - opacity: modalVisible ? 1 : 0 - scale: modalVisible ? 1 : 0.9 - - MouseArea { - anchors.fill: parent - hoverEnabled: true - preventStealing: true - propagateComposedEvents: false - onClicked: mouse => { - mouse.accepted = true; - } - onWheel: wheel => { - wheel.accepted = true; - } - onPositionChanged: mouse => { - mouse.accepted = true; - } - } - - Column { - id: contentColumn - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: device ? BluetoothService.getDeviceIcon(device) : "headset" - size: Theme.iconSize + 4 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: device ? (device.name || device.deviceName) : "" - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: I18n.tr("Audio Codec Selection") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05) - } - - StyledText { - text: isLoading ? I18n.tr("Loading codecs...") : I18n.tr("Current: %1").arg(currentCodec) - font.pixelSize: Theme.fontSizeSmall - color: isLoading ? Theme.primary : Theme.surfaceTextMedium - font.weight: Font.Medium - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: !isLoading - - Repeater { - model: availableCodecs - - Rectangle { - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: { - if (modelData.name === currentCodec) - return Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency); - else if (codecMouseArea.containsMouse) - return Theme.surfaceHover; - else - return "transparent"; - } - border.color: "transparent" - border.width: 0 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - Rectangle { - width: 6 - height: 6 - radius: 3 - color: modelData.qualityColor - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - color: modelData.name === currentCodec ? Theme.primary : Theme.surfaceText - font.weight: modelData.name === currentCodec ? Font.Medium : Font.Normal - } - - StyledText { - text: modelData.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - } - - DankIcon { - name: "check" - size: Theme.iconSize - 4 - color: Theme.primary - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: modelData.name === currentCodec - } - - DankRipple { - id: codecRipple - cornerRadius: parent.radius - } - - MouseArea { - id: codecMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: modelData.name !== currentCodec && !isLoading - onPressed: mouse => codecRipple.trigger(mouse.x, mouse.y) - onClicked: { - selectCodec(modelData.profile); - } - } - } - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml deleted file mode 100644 index 580ea9f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml +++ /dev/null @@ -1,743 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Bluetooth -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitHeight: { - if (height > 0) - return height; - if (!BluetoothService.adapter?.enabled) - return headerRow.height; - return headerRow.height + bluetoothContent.height + Theme.spacingM; - } - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - property var bluetoothCodecModalRef: null - property var devicesBeingPaired: new Set() - - signal showCodecSelector(var device) - - function isDeviceBeingPaired(deviceAddress) { - return devicesBeingPaired.has(deviceAddress); - } - - function handlePairDevice(device) { - if (!device) - return; - const deviceAddr = device.address; - const pairingSet = devicesBeingPaired; - - pairingSet.add(deviceAddr); - devicesBeingPairedChanged(); - - BluetoothService.pairDevice(device, function (response) { - pairingSet.delete(deviceAddr); - devicesBeingPairedChanged(); - - if (response.error) { - ToastService.showError(I18n.tr("Pairing failed"), response.error); - return; - } - if (!BluetoothService.enhancedPairingAvailable) { - ToastService.showSuccess(I18n.tr("Device paired")); - } - }); - } - - function updateDeviceCodecDisplay(deviceAddress, codecName) { - for (let i = 0; i < pairedRepeater.count; i++) { - const item = pairedRepeater.itemAt(i); - if (!item?.modelData) - continue; - if (item.modelData.address !== deviceAddress) - continue; - item.currentCodec = codecName; - break; - } - } - - function normalizePinList(value) { - if (Array.isArray(value)) - return value.filter(v => v); - if (typeof value === "string" && value.length > 0) - return [value]; - return []; - } - - function getPinnedDevices() { - const pins = SettingsData.bluetoothDevicePins || {}; - return normalizePinList(pins["preferredDevice"]); - } - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - height: 40 - - StyledText { - id: headerText - text: I18n.tr("Bluetooth Settings") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: Math.max(0, parent.width - headerText.implicitWidth - scanButton.width - Theme.spacingM) - height: parent.height - } - - Rectangle { - id: scanButton - - readonly property bool adapterEnabled: BluetoothService.adapter?.enabled ?? false - readonly property bool isDiscovering: BluetoothService.adapter?.discovering ?? false - - width: 100 - height: 36 - radius: 18 - color: scanMouseArea.containsMouse && adapterEnabled ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - border.color: adapterEnabled ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - border.width: 0 - visible: adapterEnabled - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: scanButton.isDiscovering ? "stop" : "bluetooth_searching" - size: 18 - color: scanButton.adapterEnabled ? Theme.primary : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: scanButton.isDiscovering ? I18n.tr("Scanning") : I18n.tr("Scan") - color: scanButton.adapterEnabled ? Theme.primary : Theme.surfaceVariantText - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: scanRipple - cornerRadius: scanButton.radius - } - - MouseArea { - id: scanMouseArea - anchors.fill: parent - hoverEnabled: true - enabled: scanButton.adapterEnabled - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onPressed: mouse => scanRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (!BluetoothService.adapter) - return; - BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering; - } - } - } - } - - DankFlickable { - id: bluetoothContent - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: BluetoothService.adapter?.enabled ?? false - contentHeight: bluetoothColumn.height - clip: true - - readonly property int maxPinnedDevices: 3 - - Column { - id: bluetoothColumn - width: parent.width - spacing: Theme.spacingS - - ScriptModel { - id: pairedDevicesModel - objectProp: "address" - values: { - if (!BluetoothService.adapter?.devices) - return []; - - const pinnedList = root.getPinnedDevices(); - const devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]; - - devices.sort((a, b) => { - const aPinnedIndex = pinnedList.indexOf(a.address); - const bPinnedIndex = pinnedList.indexOf(b.address); - - if (aPinnedIndex !== -1 || bPinnedIndex !== -1) { - if (aPinnedIndex === -1) - return 1; - if (bPinnedIndex === -1) - return -1; - return aPinnedIndex - bPinnedIndex; - } - - if (a.connected !== b.connected) - return a.connected ? -1 : 1; - - return (b.signalStrength || 0) - (a.signalStrength || 0); - }); - - return devices; - } - } - - Repeater { - id: pairedRepeater - model: pairedDevicesModel - - delegate: Rectangle { - id: pairedDelegate - required property var modelData - required property int index - - readonly property string currentCodec: BluetoothService.deviceCodecs[modelData.address] || "" - readonly property bool isConnecting: modelData.state === BluetoothDeviceState.Connecting - readonly property bool isConnected: modelData.connected - readonly property bool isPinned: root.getPinnedDevices().includes(modelData.address) - readonly property string deviceName: modelData.name || modelData.deviceName || I18n.tr("Unknown Device") - - width: parent.width - height: 50 - radius: Theme.cornerRadius - - Component.onCompleted: { - if (!isConnected) - return; - if (!BluetoothService.isAudioDevice(modelData)) - return; - BluetoothService.refreshDeviceCodec(modelData); - } - - color: { - if (isConnecting) - return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12); - if (deviceMouseArea.containsMouse) - return Theme.primaryHoverLight; - return Theme.surfaceLight; - } - - border.color: { - if (isConnecting) - return Theme.warning; - if (isConnected) - return Theme.primary; - return Theme.outlineLight; - } - border.width: (isConnecting || isConnected) ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: BluetoothService.getDeviceIcon(pairedDelegate.modelData) - size: Theme.iconSize - 4 - anchors.verticalCenter: parent.verticalCenter - color: { - if (pairedDelegate.isConnecting) - return Theme.warning; - if (pairedDelegate.isConnected) - return Theme.primary; - return Theme.surfaceText; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: 200 - - StyledText { - text: pairedDelegate.deviceName - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: pairedDelegate.isConnected ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: Theme.spacingXS - - StyledText { - text: { - if (pairedDelegate.isConnecting) - return I18n.tr("Connecting..."); - if (!pairedDelegate.isConnected) - return I18n.tr("Paired"); - if (!pairedDelegate.currentCodec) - return I18n.tr("Connected"); - return I18n.tr("Connected") + " • " + pairedDelegate.currentCodec; - } - font.pixelSize: Theme.fontSizeSmall - color: pairedDelegate.isConnecting ? Theme.warning : Theme.surfaceVariantText - } - - StyledText { - readonly property var btBattery: { - const name = pairedDelegate.deviceName; - return BatteryService.bluetoothDevices.find(dev => dev.name === name || dev.name.toLowerCase().includes(name.toLowerCase()) || name.toLowerCase().includes(dev.name.toLowerCase())); - } - text: { - if (pairedDelegate.modelData.batteryAvailable && pairedDelegate.modelData.battery > 0) - return "• " + Math.round(pairedDelegate.modelData.battery * 100) + "%"; - if (btBattery) - return "• " + btBattery.percentage + "%"; - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: text.length > 0 - } - - StyledText { - text: pairedDelegate.modelData.signalStrength > 0 ? "• " + pairedDelegate.modelData.signalStrength + "%" : "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: text.length > 0 - } - } - } - } - - Rectangle { - anchors.right: pairedOptionsButton.left - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: pinBluetoothRow.width + Theme.spacingS * 2 - height: 28 - radius: height / 2 - color: pairedDelegate.isPinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05) - - Row { - id: pinBluetoothRow - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: "push_pin" - size: 16 - color: pairedDelegate.isPinned ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: pairedDelegate.isPinned ? I18n.tr("Pinned") : I18n.tr("Pin") - font.pixelSize: Theme.fontSizeSmall - color: pairedDelegate.isPinned ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - const pins = JSON.parse(JSON.stringify(SettingsData.bluetoothDevicePins || {})); - let pinnedList = root.normalizePinList(pins["preferredDevice"]); - const pinIndex = pinnedList.indexOf(pairedDelegate.modelData.address); - - if (pinIndex !== -1) { - pinnedList.splice(pinIndex, 1); - } else { - pinnedList.unshift(pairedDelegate.modelData.address); - if (pinnedList.length > bluetoothContent.maxPinnedDevices) - pinnedList = pinnedList.slice(0, bluetoothContent.maxPinnedDevices); - } - - if (pinnedList.length > 0) { - pins["preferredDevice"] = pinnedList; - } else { - delete pins["preferredDevice"]; - } - - SettingsData.set("bluetoothDevicePins", pins); - } - } - } - - DankActionButton { - id: pairedOptionsButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "more_horiz" - buttonSize: 28 - onClicked: { - if (bluetoothContextMenu.visible) { - bluetoothContextMenu.close(); - return; - } - bluetoothContextMenu.currentDevice = pairedDelegate.modelData; - bluetoothContextMenu.popup(pairedOptionsButton, -bluetoothContextMenu.width + pairedOptionsButton.width, pairedOptionsButton.height + Theme.spacingXS); - } - } - - DankRipple { - id: deviceRipple - cornerRadius: pairedDelegate.radius - } - - MouseArea { - id: deviceMouseArea - anchors.fill: parent - anchors.rightMargin: pairedOptionsButton.width + Theme.spacingM + pinBluetoothRow.width + Theme.spacingS * 4 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - const pos = mapToItem(pairedDelegate, mouse.x, mouse.y); - deviceRipple.trigger(pos.x, pos.y); - } - onClicked: { - if (pairedDelegate.isConnected) { - pairedDelegate.modelData.disconnect(); - return; - } - BluetoothService.connectDeviceWithTrust(pairedDelegate.modelData); - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - visible: pairedRepeater.count > 0 && availableRepeater.count > 0 - } - - Item { - width: parent.width - height: 80 - visible: (BluetoothService.adapter?.discovering ?? false) && availableRepeater.count === 0 - - DankIcon { - anchors.centerIn: parent - name: "sync" - size: 24 - color: Qt.rgba(Theme.surfaceText.r || 0.8, Theme.surfaceText.g || 0.8, Theme.surfaceText.b || 0.8, 0.4) - - RotationAnimation on rotation { - running: parent.visible - loops: Animation.Infinite - from: 0 - to: 360 - duration: 1500 - } - } - } - - ScriptModel { - id: availableDevicesModel - objectProp: "address" - values: { - if (!BluetoothService.adapter?.discovering) - return []; - if (!Bluetooth.devices) - return []; - - const filtered = Bluetooth.devices.values.filter(dev => dev && !dev.paired && !dev.pairing && !dev.blocked && (dev.signalStrength === undefined || dev.signalStrength > 0)); - return BluetoothService.sortDevices(filtered); - } - } - - Repeater { - id: availableRepeater - model: availableDevicesModel - - delegate: Rectangle { - id: availableDelegate - required property var modelData - required property int index - - readonly property bool canConnect: BluetoothService.canConnect(modelData) - readonly property bool isBusy: BluetoothService.isDeviceBusy(modelData) || root.isDeviceBeingPaired(modelData.address) - readonly property bool isInteractive: canConnect && !isBusy - readonly property string deviceName: modelData.name || modelData.deviceName || I18n.tr("Unknown Device") - - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: availableMouseArea.containsMouse && isInteractive ? Theme.primaryHoverLight : Theme.surfaceLight - border.color: Theme.outlineLight - border.width: 1 - opacity: isInteractive ? 1 : 0.6 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: BluetoothService.getDeviceIcon(availableDelegate.modelData) - size: Theme.iconSize - 4 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: 200 - - StyledText { - text: availableDelegate.deviceName - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: Theme.spacingXS - - StyledText { - text: { - if (availableDelegate.modelData.pairing || availableDelegate.isBusy) - return I18n.tr("Pairing..."); - if (availableDelegate.modelData.blocked) - return I18n.tr("Blocked"); - return BluetoothService.getSignalStrength(availableDelegate.modelData); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: availableDelegate.modelData.signalStrength > 0 ? "• " + availableDelegate.modelData.signalStrength + "%" : "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: text.length > 0 && !availableDelegate.modelData.pairing && !availableDelegate.modelData.blocked - } - } - } - } - - StyledText { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - text: { - if (availableDelegate.isBusy) - return I18n.tr("Pairing..."); - if (!availableDelegate.canConnect) - return I18n.tr("Cannot pair"); - return I18n.tr("Pair"); - } - font.pixelSize: Theme.fontSizeSmall - color: availableDelegate.isInteractive ? Theme.primary : Theme.surfaceVariantText - font.weight: Font.Medium - } - - DankRipple { - id: availableRipple - cornerRadius: availableDelegate.radius - } - - MouseArea { - id: availableMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: availableDelegate.isInteractive ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: availableDelegate.isInteractive - onPressed: mouse => availableRipple.trigger(mouse.x, mouse.y) - onClicked: root.handlePairDevice(availableDelegate.modelData) - } - } - } - - Item { - width: parent.width - height: 60 - visible: !BluetoothService.adapter - - StyledText { - anchors.centerIn: parent - text: I18n.tr("No Bluetooth adapter found") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - } - } - } - - Menu { - id: bluetoothContextMenu - width: 150 - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent - - property var currentDevice: null - - readonly property bool hasDevice: currentDevice !== null - readonly property bool deviceConnected: currentDevice?.connected ?? false - readonly property bool showCodecOption: hasDevice && deviceConnected && BluetoothService.isAudioDevice(currentDevice) - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: 0 - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - MenuItem { - text: bluetoothContextMenu.deviceConnected ? I18n.tr("Disconnect") : I18n.tr("Connect") - height: 32 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (!bluetoothContextMenu.hasDevice) - return; - if (bluetoothContextMenu.deviceConnected) { - bluetoothContextMenu.currentDevice.disconnect(); - return; - } - BluetoothService.connectDeviceWithTrust(bluetoothContextMenu.currentDevice); - } - } - - MenuItem { - text: I18n.tr("Audio Codec") - height: bluetoothContextMenu.showCodecOption ? 32 : 0 - visible: bluetoothContextMenu.showCodecOption - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (!bluetoothContextMenu.hasDevice) - return; - if (!bluetoothContextMenu.currentDevice.connected) - return; - if (!BluetoothService.isAudioDevice(bluetoothContextMenu.currentDevice)) - return; - showCodecSelector(bluetoothContextMenu.currentDevice); - } - } - - MenuItem { - text: bluetoothContextMenu.currentDevice?.trusted ? I18n.tr("Untrust") : I18n.tr("Trust") - height: 32 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (!bluetoothContextMenu.hasDevice) - return; - bluetoothContextMenu.currentDevice.trusted = !bluetoothContextMenu.currentDevice.trusted; - } - } - - MenuItem { - text: I18n.tr("Forget Device") - height: 32 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (!bluetoothContextMenu.hasDevice) - return; - if (!BluetoothService.enhancedPairingAvailable) { - bluetoothContextMenu.currentDevice.forget(); - return; - } - - const devicePath = BluetoothService.getDevicePath(bluetoothContextMenu.currentDevice); - DMSService.bluetoothRemove(devicePath, response => { - if (!response.error) - return; - ToastService.showError(I18n.tr("Failed to remove device"), response.error); - }); - } - } - } - - Connections { - target: DMSService - - function onBluetoothPairingRequest(data) { - const modal = PopoutService.bluetoothPairingModal; - if (!modal) - return; - if (modal.token === data.token) - return; - modal.show(data); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BrightnessDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BrightnessDetail.qml deleted file mode 100644 index 0d42e62..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BrightnessDetail.qml +++ /dev/null @@ -1,498 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string initialDeviceName: "" - property string instanceId: "" - property string screenName: "" - property string screenModel: "" - - signal deviceNameChanged(string newDeviceName) - - property string currentDeviceName: "" - - function getScreenPinKey() { - if (!screenName) - return ""; - const screen = Quickshell.screens.find(s => s.name === screenName); - if (screen) { - return SettingsData.getScreenDisplayName(screen); - } - if (SettingsData.displayNameMode === "model" && screenModel && screenModel.length > 0) { - return screenModel; - } - return screenName; - } - - function resolveDeviceName() { - if (!DisplayService.brightnessAvailable || !DisplayService.devices || DisplayService.devices.length === 0) { - return ""; - } - - const pinKey = getScreenPinKey(); - if (pinKey.length > 0) { - const pins = SettingsData.brightnessDevicePins || {}; - const pinnedDevice = pins[pinKey]; - if (pinnedDevice && pinnedDevice.length > 0) { - const found = DisplayService.devices.find(dev => dev.name === pinnedDevice); - if (found) - return found.name; - } - } - - if (initialDeviceName && initialDeviceName.length > 0) { - const found = DisplayService.devices.find(dev => dev.name === initialDeviceName); - if (found) - return found.name; - } - - const currentDeviceNameFromService = DisplayService.currentDevice; - if (currentDeviceNameFromService) { - const found = DisplayService.devices.find(dev => dev.name === currentDeviceNameFromService); - if (found) - return found.name; - } - - const backlight = DisplayService.devices.find(d => d.class === "backlight"); - if (backlight) - return backlight.name; - - const ddc = DisplayService.devices.find(d => d.class === "ddc"); - if (ddc) - return ddc.name; - - return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : ""; - } - - Component.onCompleted: { - currentDeviceName = resolveDeviceName(); - } - - property bool isPinnedToScreen: { - const pinKey = getScreenPinKey(); - if (!pinKey || pinKey.length === 0) - return false; - const pins = SettingsData.brightnessDevicePins || {}; - return pins[pinKey] === currentDeviceName; - } - - function togglePinToScreen() { - const pinKey = getScreenPinKey(); - if (!pinKey || pinKey.length === 0 || !currentDeviceName || currentDeviceName.length === 0) - return; - const pins = JSON.parse(JSON.stringify(SettingsData.brightnessDevicePins || {})); - - if (isPinnedToScreen) { - delete pins[pinKey]; - } else { - pins[pinKey] = currentDeviceName; - } - - SettingsData.set("brightnessDevicePins", pins); - } - - implicitHeight: { - if (height > 0) { - return height; - } - return brightnessContent.height + Theme.spacingM; - } - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - DankFlickable { - id: brightnessContent - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - contentHeight: brightnessColumn.height - clip: true - - Column { - id: brightnessColumn - width: parent.width - spacing: Theme.spacingS - - Item { - width: parent.width - height: 100 - visible: !DisplayService.brightnessAvailable || !DisplayService.devices || DisplayService.devices.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - anchors.horizontalCenter: parent.horizontalCenter - name: DisplayService.brightnessAvailable ? "brightness_6" : "error" - size: 32 - color: DisplayService.brightnessAvailable ? Theme.primary : Theme.error - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: DisplayService.brightnessAvailable ? I18n.tr("No brightness devices available") : I18n.tr("Brightness control not available") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - } - } - } - - Rectangle { - width: parent.width - height: 40 - visible: screenName && screenName.length > 0 && DisplayService.devices && DisplayService.devices.length > 1 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - - Item { - anchors.fill: parent - anchors.margins: Theme.spacingM - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "monitor" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.getScreenPinKey() || I18n.tr("Unknown Monitor") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - width: pinRow.width + Theme.spacingS * 2 - height: 28 - radius: height / 2 - color: isPinnedToScreen ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05) - - Row { - id: pinRow - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: isPinnedToScreen ? "push_pin" : "push_pin" - size: 16 - color: isPinnedToScreen ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: isPinnedToScreen ? I18n.tr("Pinned") : I18n.tr("Pin") - font.pixelSize: Theme.fontSizeSmall - color: isPinnedToScreen ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: pinRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: root.togglePinToScreen() - } - } - } - } - - Repeater { - model: DisplayService.devices || [] - delegate: Rectangle { - required property var modelData - required property int index - - property real deviceBrightness: { - DisplayService.brightnessVersion; - return DisplayService.getDeviceBrightness(modelData.name); - } - - width: parent.width - height: 100 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - border.color: modelData.name === currentDeviceName ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - border.width: modelData.name === currentDeviceName ? 2 : 0 - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Item { - width: parent.width - height: Math.max(deviceIconColumn.height, deviceInfoColumn.height, exponentControls.height) - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Column { - id: deviceIconColumn - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - DankIcon { - name: { - const deviceClass = modelData.class || ""; - const deviceName = modelData.name || ""; - - if (deviceClass === "backlight" || deviceClass === "ddc") { - if (deviceBrightness <= 33) - return "brightness_low"; - if (deviceBrightness <= 66) - return "brightness_medium"; - return "brightness_high"; - } else if (deviceName.includes("kbd")) { - return "keyboard"; - } else { - return "lightbulb"; - } - } - size: Theme.iconSize - color: modelData.name === currentDeviceName ? Theme.primary : Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: Math.round(deviceBrightness) + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - id: deviceInfoColumn - anchors.verticalCenter: parent.verticalCenter - width: parent.parent.width - deviceIconColumn.width - exponentControls.width - Theme.spacingM * 3 - - StyledText { - text: { - const name = modelData.name || ""; - const deviceClass = modelData.class || ""; - if (deviceClass === "backlight") { - return name.replace("_", " ").replace(/\b\w/g, c => c.toUpperCase()); - } - return name; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData.name === currentDeviceName ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - const deviceClass = modelData.class || ""; - if (deviceClass === "backlight") - return I18n.tr("Backlight device"); - if (deviceClass === "ddc") - return I18n.tr("DDC/CI monitor"); - if (deviceClass === "leds") - return I18n.tr("LED device"); - return deviceClass; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Row { - id: exponentControls - width: 140 - height: 28 - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - visible: SessionData.getBrightnessExponential(modelData.name) - z: 1 - - StyledRect { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - opacity: SessionData.getBrightnessExponent(modelData.name) > 1.0 ? 1.0 : 0.4 - - DankIcon { - anchors.centerIn: parent - name: "remove" - size: 14 - color: Theme.surfaceText - } - - StateLayer { - stateColor: Theme.primary - cornerRadius: parent.radius - enabled: SessionData.getBrightnessExponent(modelData.name) > 1.0 - onClicked: { - const current = SessionData.getBrightnessExponent(modelData.name); - const newValue = Math.max(1.0, Math.round((current - 0.1) * 10) / 10); - SessionData.setBrightnessExponent(modelData.name, newValue); - } - } - } - - StyledRect { - width: 50 - height: 28 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - border.width: 0 - - StyledText { - anchors.centerIn: parent - text: SessionData.getBrightnessExponent(modelData.name).toFixed(1) - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primary - } - } - - StyledRect { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - opacity: SessionData.getBrightnessExponent(modelData.name) < 2.5 ? 1.0 : 0.4 - - DankIcon { - anchors.centerIn: parent - name: "add" - size: 14 - color: Theme.surfaceText - } - - StateLayer { - stateColor: Theme.primary - cornerRadius: parent.radius - enabled: SessionData.getBrightnessExponent(modelData.name) < 2.5 - onClicked: { - const current = SessionData.getBrightnessExponent(modelData.name); - const newValue = Math.min(2.5, Math.round((current + 0.1) * 10) / 10); - SessionData.setBrightnessExponent(modelData.name, newValue); - } - } - } - } - } - - Rectangle { - width: parent.width - height: 24 - radius: height / 2 - color: SessionData.getBrightnessExponential(modelData.name) ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05) - - Row { - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: "show_chart" - size: 14 - color: SessionData.getBrightnessExponential(modelData.name) ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: SessionData.getBrightnessExponential(modelData.name) ? I18n.tr("Exponential") : I18n.tr("Linear") - font.pixelSize: Theme.fontSizeSmall - color: SessionData.getBrightnessExponential(modelData.name) ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: expToggleRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => expToggleRipple.trigger(mouse.x, mouse.y) - onClicked: { - const currentState = SessionData.getBrightnessExponential(modelData.name); - SessionData.setBrightnessExponential(modelData.name, !currentState); - } - } - } - } - - DankRipple { - id: deviceRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - anchors.bottomMargin: 28 - anchors.rightMargin: SessionData.getBrightnessExponential(modelData.name) ? 145 : 0 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => deviceRipple.trigger(mouse.x, mouse.y) - onClicked: { - const pinKey = root.getScreenPinKey(); - if (pinKey.length > 0 && modelData.name !== currentDeviceName) { - const pins = JSON.parse(JSON.stringify(SettingsData.brightnessDevicePins || {})); - if (pins[pinKey]) { - delete pins[pinKey]; - SettingsData.set("brightnessDevicePins", pins); - } - } - currentDeviceName = modelData.name; - deviceNameChanged(modelData.name); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/DiskUsageDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/DiskUsageDetail.qml deleted file mode 100644 index 90fbf9d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/DiskUsageDetail.qml +++ /dev/null @@ -1,177 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string currentMountPath: "/" - property string instanceId: "" - - signal mountPathChanged(string newMountPath) - - implicitHeight: diskContent.height + Theme.spacingM - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - Component.onCompleted: { - DgopService.addRef(["diskmounts"]); - } - - Component.onDestruction: { - DgopService.removeRef(["diskmounts"]); - } - - DankFlickable { - id: diskContent - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - contentHeight: diskColumn.height - clip: true - - Column { - id: diskColumn - width: parent.width - spacing: Theme.spacingS - - Item { - width: parent.width - height: 100 - visible: !DgopService.dgopAvailable || !DgopService.diskMounts || DgopService.diskMounts.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - anchors.horizontalCenter: parent.horizontalCenter - name: DgopService.dgopAvailable ? "storage" : "error" - size: 32 - color: DgopService.dgopAvailable ? Theme.primary : Theme.error - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: DgopService.dgopAvailable ? I18n.tr("No disk data available") : I18n.tr("dgop not available") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - } - } - } - - Repeater { - model: DgopService.diskMounts || [] - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 80 - radius: Theme.cornerRadius - color: Theme.surfaceLight - border.color: modelData.mount === currentMountPath ? Theme.primary : Theme.outlineLight - border.width: modelData.mount === currentMountPath ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingM - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - DankIcon { - name: "storage" - size: Theme.iconSize - color: { - const percentStr = modelData.percent?.replace("%", "") || "0"; - const percent = parseFloat(percentStr) || 0; - if (percent > 90) - return Theme.error; - if (percent > 75) - return Theme.warning; - return modelData.mount === currentMountPath ? Theme.primary : Theme.surfaceText; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - const percentStr = modelData.percent?.replace("%", "") || "0"; - const percent = parseFloat(percentStr) || 0; - return percent.toFixed(0) + "%"; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.parent.width - parent.parent.anchors.leftMargin - parent.spacing - 50 - Theme.spacingM - - StyledText { - text: modelData.mount === "/" ? I18n.tr("Root Filesystem") : modelData.mount - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData.mount === currentMountPath ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: modelData.mount - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - visible: modelData.mount !== "/" - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: `${modelData.used || "?"} / ${modelData.size || "?"}` - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - DankRipple { - id: mountRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => mountRipple.trigger(mouse.x, mouse.y) - onClicked: { - currentMountPath = modelData.mount; - mountPathChanged(modelData.mount); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml deleted file mode 100644 index 5f1738a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml +++ /dev/null @@ -1,893 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modals - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitHeight: { - if (height > 0) - return height; - if (NetworkService.wifiToggling) - return headerRow.height + wifiToggleContent.height + Theme.spacingM; - if (NetworkService.wifiEnabled) - return headerRow.height + wifiContent.height + Theme.spacingM; - return headerRow.height + wifiOffContent.height + Theme.spacingM; - } - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - - Component.onCompleted: { - NetworkService.addRef(); - } - - Component.onDestruction: { - NetworkService.removeRef(); - } - - property bool hasEthernetAvailable: (NetworkService.ethernetDevices?.length ?? 0) > 0 - property bool hasWifiAvailable: (NetworkService.wifiDevices?.length ?? 0) > 0 - property bool hasBothConnectionTypes: hasEthernetAvailable && hasWifiAvailable - property int maxPinnedNetworks: 3 - - function normalizePinList(value) { - if (Array.isArray(value)) - return value.filter(v => v); - if (typeof value === "string" && value.length > 0) - return [value]; - return []; - } - - function getPinnedNetworks() { - const pins = SettingsData.wifiNetworkPins || {}; - return normalizePinList(pins["preferredWifi"]); - } - - property int currentPreferenceIndex: { - if (DMSService.apiVersion < 5) - return 1; - if (NetworkService.backend !== "networkmanager" || DMSService.apiVersion <= 10) - return 1; - if (!hasEthernetAvailable) - return 1; - if (!hasWifiAvailable) - return 0; - - const pref = NetworkService.userPreference; - switch (pref) { - case "ethernet": - return 0; - case "wifi": - return 1; - default: - return NetworkService.networkStatus === "ethernet" ? 0 : 1; - } - } - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - height: Math.max(headerLeft.implicitHeight, rightControls.implicitHeight) + Theme.spacingS * 2 - - StyledText { - id: headerLeft - text: I18n.tr("Network") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Item { - height: 1 - width: parent.width - headerLeft.width - rightControls.width - } - - Row { - id: rightControls - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankDropdown { - id: wifiDeviceDropdown - anchors.verticalCenter: parent.verticalCenter - visible: currentPreferenceIndex === 1 && (NetworkService.wifiDevices?.length ?? 0) > 1 - compactMode: true - dropdownWidth: 120 - popupWidth: 160 - alignPopupRight: true - - options: { - const devices = NetworkService.wifiDevices; - if (!devices || devices.length === 0) - return [I18n.tr("Auto")]; - return [I18n.tr("Auto")].concat(devices.map(d => d.name)); - } - - currentValue: NetworkService.wifiDeviceOverride || I18n.tr("Auto") - - onValueChanged: value => { - const deviceName = value === I18n.tr("Auto") ? "" : value; - NetworkService.setWifiDeviceOverride(deviceName); - } - } - - DankButtonGroup { - id: preferenceControls - anchors.verticalCenter: parent.verticalCenter - visible: hasBothConnectionTypes && NetworkService.backend === "networkmanager" && DMSService.apiVersion > 10 - buttonHeight: 28 - textSize: Theme.fontSizeSmall - - model: [I18n.tr("Ethernet"), I18n.tr("WiFi")] - currentIndex: currentPreferenceIndex - selectionMode: "single" - onSelectionChanged: (index, selected) => { - if (!selected) - return; - NetworkService.setNetworkPreference(index === 0 ? "ethernet" : "wifi"); - } - } - - DankActionButton { - anchors.verticalCenter: parent.verticalCenter - iconName: "settings" - buttonSize: 28 - iconSize: 16 - iconColor: Theme.surfaceVariantText - onClicked: { - PopoutService.closeControlCenter(); - PopoutService.openSettingsWithTab("network"); - } - } - } - } - - Item { - id: wifiToggleContent - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: currentPreferenceIndex === 1 && NetworkService.wifiToggling - height: visible ? wifiToggleColumn.implicitHeight + Theme.spacingM * 2 : 0 - - Column { - id: wifiToggleColumn - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - anchors.horizontalCenter: parent.horizontalCenter - name: "sync" - size: 32 - color: Theme.primary - - RotationAnimation on rotation { - running: NetworkService.wifiToggling - loops: Animation.Infinite - from: 0 - to: 360 - duration: 1000 - } - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: NetworkService.wifiEnabled ? I18n.tr("Disabling WiFi...") : I18n.tr("Enabling WiFi...") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - } - } - } - - Item { - id: wifiOffContent - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: currentPreferenceIndex === 1 && !NetworkService.wifiEnabled && !NetworkService.wifiToggling - height: visible ? wifiOffColumn.implicitHeight + Theme.spacingM * 2 : 0 - - Column { - id: wifiOffColumn - anchors.centerIn: parent - spacing: Theme.spacingL - width: parent.width - - DankIcon { - anchors.horizontalCenter: parent.horizontalCenter - name: "wifi_off" - size: 48 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: I18n.tr("WiFi is off") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - horizontalAlignment: Text.AlignHCenter - } - - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - width: enableWifiLabel.implicitWidth + Theme.spacingL * 2 - height: enableWifiLabel.implicitHeight + Theme.spacingM * 2 - radius: height / 2 - color: enableWifiButton.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) - border.width: 0 - border.color: Theme.primary - - StyledText { - id: enableWifiLabel - anchors.centerIn: parent - text: I18n.tr("Enable WiFi") - color: Theme.primary - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - } - - MouseArea { - id: enableWifiButton - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: NetworkService.toggleWifiRadio() - } - } - } - } - - ScriptModel { - id: wiredConnectionsModel - objectProp: "uuid" - values: { - const networks = NetworkService.wiredConnections; - if (!networks) - return []; - let sorted = [...networks]; - sorted.sort((a, b) => { - if (a.isActive && !b.isActive) - return -1; - if (!a.isActive && b.isActive) - return 1; - return a.id.localeCompare(b.id); - }); - return sorted; - } - } - - DankFlickable { - id: wiredContent - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: currentPreferenceIndex === 0 && NetworkService.backend === "networkmanager" && DMSService.apiVersion > 10 - contentHeight: wiredColumn.height - clip: true - - Column { - id: wiredColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: wiredConnectionsModel - - delegate: Rectangle { - id: wiredDelegate - required property var modelData - required property int index - - readonly property bool isActive: modelData.isActive - readonly property string configName: modelData.id || I18n.tr("Unknown Config") - - width: parent.width - height: wiredContentRow.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: wiredNetworkMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.color: isActive ? Theme.primary : Theme.outlineLight - border.width: isActive ? 2 : 1 - - Row { - id: wiredContentRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: "lan" - size: Theme.iconSize - 4 - color: wiredDelegate.isActive ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: 200 - - StyledText { - text: wiredDelegate.configName - font.pixelSize: Theme.fontSizeMedium - color: wiredDelegate.isActive ? Theme.primary : Theme.surfaceText - font.weight: wiredDelegate.isActive ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - } - } - } - - DankActionButton { - id: wiredOptionsButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "more_horiz" - buttonSize: 28 - onClicked: { - if (wiredNetworkContextMenu.visible) { - wiredNetworkContextMenu.close(); - return; - } - wiredNetworkContextMenu.currentID = modelData.id; - wiredNetworkContextMenu.currentUUID = modelData.uuid; - wiredNetworkContextMenu.currentConnected = wiredDelegate.isActive; - wiredNetworkContextMenu.popup(wiredOptionsButton, -wiredNetworkContextMenu.width + wiredOptionsButton.width, wiredOptionsButton.height + Theme.spacingXS); - } - } - - DankRipple { - id: wiredRipple - cornerRadius: parent.radius - } - - MouseArea { - id: wiredNetworkMouseArea - anchors.fill: parent - anchors.rightMargin: wiredOptionsButton.width + Theme.spacingS - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => wiredRipple.trigger(mouse.x, mouse.y) - onClicked: function (event) { - if (modelData.uuid !== NetworkService.ethernetConnectionUuid) - NetworkService.connectToSpecificWiredConfig(modelData.uuid); - event.accepted = true; - } - } - } - } - } - } - - Menu { - id: wiredNetworkContextMenu - width: 150 - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent - - property string currentID: "" - property string currentUUID: "" - property bool currentConnected: false - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: 0 - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - MenuItem { - text: I18n.tr("Activate") - height: !wiredNetworkContextMenu.currentConnected ? 32 : 0 - visible: !wiredNetworkContextMenu.currentConnected - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (!wiredNetworkContextMenu.currentConnected) - NetworkService.connectToSpecificWiredConfig(wiredNetworkContextMenu.currentUUID); - } - } - - MenuItem { - text: I18n.tr("Disconnect") - height: wiredNetworkContextMenu.currentConnected ? 32 : 0 - visible: wiredNetworkContextMenu.currentConnected - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - NetworkService.toggleNetworkConnection("ethernet"); - } - } - - MenuItem { - text: I18n.tr("Network Info") - height: wiredNetworkContextMenu.currentConnected ? 32 : 0 - visible: wiredNetworkContextMenu.currentConnected - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - const networkData = NetworkService.getWiredNetworkInfo(wiredNetworkContextMenu.currentUUID); - networkWiredInfoModalLoader.active = true; - networkWiredInfoModalLoader.item.showNetworkInfo(wiredNetworkContextMenu.currentID, networkData); - } - } - } - - ScriptModel { - id: wifiNetworksModel - objectProp: "ssid" - values: wifiContent.menuOpen ? wifiContent.frozenNetworks : wifiContent.sortedNetworks - } - - Item { - id: wifiScanningOverlay - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: currentPreferenceIndex === 1 && NetworkService.wifiEnabled && !NetworkService.wifiToggling && NetworkService.wifiInterface && (NetworkService.wifiNetworks?.length ?? 0) < 1 && NetworkService.isScanning - - DankIcon { - anchors.centerIn: parent - name: "refresh" - size: 48 - color: Qt.rgba(Theme.surfaceText.r || 0.8, Theme.surfaceText.g || 0.8, Theme.surfaceText.b || 0.8, 0.3) - - RotationAnimation on rotation { - running: wifiScanningOverlay.visible - loops: Animation.Infinite - from: 0 - to: 360 - duration: 1000 - } - } - } - - DankListView { - id: wifiContent - anchors.top: headerRow.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: Theme.spacingM - anchors.topMargin: Theme.spacingM - visible: currentPreferenceIndex === 1 && NetworkService.wifiEnabled && !NetworkService.wifiToggling && !wifiScanningOverlay.visible - clip: true - spacing: Theme.spacingS - model: wifiNetworksModel - - property var frozenNetworks: [] - property bool menuOpen: false - property var sortedNetworks: { - const ssid = NetworkService.currentWifiSSID; - const networks = NetworkService.wifiNetworks; - const pinnedList = root.getPinnedNetworks(); - - let sorted = [...networks]; - sorted.sort((a, b) => { - const aPinnedIndex = pinnedList.indexOf(a.ssid); - const bPinnedIndex = pinnedList.indexOf(b.ssid); - if (aPinnedIndex !== -1 || bPinnedIndex !== -1) { - if (aPinnedIndex === -1) - return 1; - if (bPinnedIndex === -1) - return -1; - return aPinnedIndex - bPinnedIndex; - } - if (a.ssid === ssid) - return -1; - if (b.ssid === ssid) - return 1; - return b.signal - a.signal; - }); - return sorted; - } - onSortedNetworksChanged: { - if (!menuOpen) - frozenNetworks = sortedNetworks; - } - onMenuOpenChanged: { - if (menuOpen) - frozenNetworks = sortedNetworks; - } - - delegate: Rectangle { - id: wifiDelegate - required property var modelData - required property int index - - readonly property bool isConnected: modelData.ssid === NetworkService.currentWifiSSID - readonly property bool isPinned: root.getPinnedNetworks().includes(modelData.ssid) - readonly property string networkName: modelData.ssid || I18n.tr("Unknown Network") - readonly property int signalStrength: modelData.signal || 0 - - width: wifiContent.width - height: wifiContentRow.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: networkMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.color: wifiDelegate.isConnected ? Theme.primary : Theme.outlineLight - border.width: wifiDelegate.isConnected ? 2 : 1 - - Row { - id: wifiContentRow - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: { - if (wifiDelegate.signalStrength >= 50) - return "wifi"; - if (wifiDelegate.signalStrength >= 25) - return "wifi_2_bar"; - return "wifi_1_bar"; - } - size: Theme.iconSize - 4 - color: wifiDelegate.isConnected ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: 200 - - StyledText { - text: wifiDelegate.networkName - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: wifiDelegate.isConnected ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - } - - Row { - spacing: Theme.spacingXS - - StyledText { - text: wifiDelegate.isConnected ? I18n.tr("Connected") + " \u2022" : (modelData.secured ? I18n.tr("Secured") + " \u2022" : I18n.tr("Open") + " \u2022") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: modelData.saved ? I18n.tr("Saved") : "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - visible: text.length > 0 - } - - StyledText { - text: (modelData.saved ? "\u2022 " : "") + wifiDelegate.signalStrength + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - DankActionButton { - id: optionsButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "more_horiz" - buttonSize: 28 - onClicked: { - if (networkContextMenu.visible) { - networkContextMenu.close(); - return; - } - wifiContent.menuOpen = true; - networkContextMenu.currentSSID = modelData.ssid; - networkContextMenu.currentSecured = modelData.secured; - networkContextMenu.currentConnected = wifiDelegate.isConnected; - networkContextMenu.currentSaved = modelData.saved; - networkContextMenu.currentSignal = modelData.signal; - networkContextMenu.currentAutoconnect = modelData.autoconnect || false; - networkContextMenu.popup(optionsButton, -networkContextMenu.width + optionsButton.width, optionsButton.height + Theme.spacingXS); - } - } - - Rectangle { - id: pinButton - anchors.right: parent.right - anchors.rightMargin: optionsButton.width + Theme.spacingM + Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: pinWifiRow.width + Theme.spacingS * 2 - height: pinWifiRow.implicitHeight + Theme.spacingXS * 2 - radius: height / 2 - color: wifiDelegate.isPinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05) - - Row { - id: pinWifiRow - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: "push_pin" - size: 16 - color: wifiDelegate.isPinned ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: wifiDelegate.isPinned ? I18n.tr("Pinned") : I18n.tr("Pin") - font.pixelSize: Theme.fontSizeSmall - color: wifiDelegate.isPinned ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankRipple { - id: pinRipple - cornerRadius: parent.radius - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: { - const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {})); - let pinnedList = root.normalizePinList(pins["preferredWifi"]); - const pinIndex = pinnedList.indexOf(modelData.ssid); - - if (pinIndex !== -1) { - pinnedList.splice(pinIndex, 1); - } else { - pinnedList.unshift(modelData.ssid); - if (pinnedList.length > root.maxPinnedNetworks) - pinnedList = pinnedList.slice(0, root.maxPinnedNetworks); - } - - if (pinnedList.length > 0) - pins["preferredWifi"] = pinnedList; - else - delete pins["preferredWifi"]; - - SettingsData.set("wifiNetworkPins", pins); - } - } - } - - DankActionButton { - id: qrCodeButton - visible: modelData.secured && modelData.saved - anchors.right: parent.right - anchors.rightMargin: optionsButton.width + pinWifiRow.width + 3 * Theme.spacingM + Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "qr_code" - buttonSize: 28 - onClicked: { - PopoutService.showWifiQRCodeModal(modelData.ssid); - } - } - - DankRipple { - id: wifiRipple - cornerRadius: parent.radius - } - - MouseArea { - id: networkMouseArea - anchors.fill: parent - anchors.rightMargin: optionsButton.width + pinWifiRow.width + (qrCodeButton.visible ? qrCodeButton.width : 0) + Theme.spacingS * 5 + Theme.spacingM - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => wifiRipple.trigger(mouse.x, mouse.y) - onClicked: function (event) { - if (wifiDelegate.isConnected) { - event.accepted = true; - return; - } - if (modelData.secured && !modelData.saved && DMSService.apiVersion < 7) { - PopoutService.showWifiPasswordModal(modelData.ssid); - } else { - NetworkService.connectToWifi(modelData.ssid); - } - event.accepted = true; - } - } - } - } - - Menu { - id: networkContextMenu - width: 150 - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent - - property string currentSSID: "" - property bool currentSecured: false - property bool currentConnected: false - property bool currentSaved: false - property int currentSignal: 0 - property bool currentAutoconnect: false - - readonly property bool showSavedOptions: currentSaved || currentConnected - - onClosed: { - wifiContent.menuOpen = false; - } - - background: Rectangle { - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: 0 - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - MenuItem { - text: networkContextMenu.currentConnected ? I18n.tr("Disconnect") : I18n.tr("Connect") - height: 32 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - if (networkContextMenu.currentConnected) { - NetworkService.disconnectWifi(); - return; - } - if (networkContextMenu.currentSecured && !networkContextMenu.currentSaved && DMSService.apiVersion < 7) { - PopoutService.showWifiPasswordModal(networkContextMenu.currentSSID); - return; - } - NetworkService.connectToWifi(networkContextMenu.currentSSID); - } - } - - MenuItem { - text: I18n.tr("Network Info") - height: 32 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - const networkData = NetworkService.getNetworkInfo(networkContextMenu.currentSSID); - networkInfoModalLoader.active = true; - networkInfoModalLoader.item.showNetworkInfo(networkContextMenu.currentSSID, networkData); - } - } - - MenuItem { - text: networkContextMenu.currentAutoconnect ? I18n.tr("Disable Autoconnect") : I18n.tr("Enable Autoconnect") - height: networkContextMenu.showSavedOptions && DMSService.apiVersion > 13 ? 32 : 0 - visible: networkContextMenu.showSavedOptions && DMSService.apiVersion > 13 - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - NetworkService.setWifiAutoconnect(networkContextMenu.currentSSID, !networkContextMenu.currentAutoconnect); - } - } - - MenuItem { - text: I18n.tr("Forget Network") - height: networkContextMenu.showSavedOptions ? 32 : 0 - visible: networkContextMenu.showSavedOptions - - contentItem: StyledText { - text: parent.text - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - leftPadding: Theme.spacingS - verticalAlignment: Text.AlignVCenter - } - - background: Rectangle { - color: parent.hovered ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.08) : "transparent" - radius: Theme.cornerRadius / 2 - } - - onTriggered: { - NetworkService.forgetWifiNetwork(networkContextMenu.currentSSID); - } - } - } - - Loader { - id: networkInfoModalLoader - active: false - sourceComponent: NetworkInfoModal {} - } - - Loader { - id: networkWiredInfoModalLoader - active: false - sourceComponent: NetworkWiredInfoModal {} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Models/WidgetModel.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Models/WidgetModel.qml deleted file mode 100644 index ac616ae..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Models/WidgetModel.qml +++ /dev/null @@ -1,283 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Modules.ControlCenter.BuiltinPlugins -import "../utils/widgets.js" as WidgetUtils - -QtObject { - id: root - - property var vpnBuiltinInstance: null - property var cupsBuiltinInstance: null - - property var vpnLoader: Loader { - active: false - sourceComponent: Component { - VpnWidget {} - } - - onItemChanged: { - root.vpnBuiltinInstance = item; - } - - Connections { - target: SettingsData - function onControlCenterWidgetsChanged() { - const widgets = SettingsData.controlCenterWidgets || []; - const hasVpnWidget = widgets.some(w => w.id === "builtin_vpn"); - if (!hasVpnWidget && vpnLoader.active) { - console.log("VpnWidget: No VPN widget in control center, deactivating loader"); - vpnLoader.active = false; - } - } - } - } - - property var cupsLoader: Loader { - active: false - sourceComponent: Component { - CupsWidget {} - } - - onItemChanged: { - root.cupsBuiltinInstance = item; - } - - onActiveChanged: { - if (!active) { - root.cupsBuiltinInstance = null; - } - } - - Connections { - target: SettingsData - function onControlCenterWidgetsChanged() { - const widgets = SettingsData.controlCenterWidgets || []; - const hasCupsWidget = widgets.some(w => w.id === "builtin_cups"); - if (!hasCupsWidget && cupsLoader.active) { - console.log("CupsWidget: No CUPS widget in control center, deactivating loader"); - cupsLoader.active = false; - } - } - } - } - - readonly property var coreWidgetDefinitions: [ - { - "id": "nightMode", - "text": I18n.tr("Night Mode"), - "description": I18n.tr("Blue light filter"), - "icon": "nightlight", - "type": "toggle", - "enabled": DisplayService.automationAvailable, - "warning": !DisplayService.automationAvailable ? I18n.tr("Requires night mode support") : undefined - }, - { - "id": "darkMode", - "text": I18n.tr("Dark Mode"), - "description": I18n.tr("System theme toggle"), - "icon": "contrast", - "type": "toggle", - "enabled": true - }, - { - "id": "doNotDisturb", - "text": I18n.tr("Do Not Disturb"), - "description": I18n.tr("Block notifications"), - "icon": "do_not_disturb_on", - "type": "toggle", - "enabled": true - }, - { - "id": "idleInhibitor", - "text": I18n.tr("Keep Awake"), - "description": I18n.tr("Prevent screen timeout"), - "icon": "motion_sensor_active", - "type": "toggle", - "enabled": true - }, - { - "id": "wifi", - "text": I18n.tr("Network"), - "description": I18n.tr("Wi-Fi and Ethernet connection"), - "icon": "wifi", - "type": "connection", - "enabled": NetworkService.wifiAvailable, - "warning": !NetworkService.wifiAvailable ? I18n.tr("Wi-Fi not available") : undefined - }, - { - "id": "bluetooth", - "text": I18n.tr("Bluetooth"), - "description": I18n.tr("Device connections"), - "icon": "bluetooth", - "type": "connection", - "enabled": BluetoothService.available, - "warning": !BluetoothService.available ? I18n.tr("Bluetooth not available") : undefined - }, - { - "id": "audioOutput", - "text": I18n.tr("Audio Output"), - "description": I18n.tr("Speaker settings"), - "icon": "volume_up", - "type": "connection", - "enabled": true - }, - { - "id": "audioInput", - "text": I18n.tr("Audio Input"), - "description": I18n.tr("Microphone settings"), - "icon": "mic", - "type": "connection", - "enabled": true - }, - { - "id": "volumeSlider", - "text": I18n.tr("Volume Slider"), - "description": I18n.tr("Audio volume control"), - "icon": "volume_up", - "type": "slider", - "enabled": true - }, - { - "id": "brightnessSlider", - "text": I18n.tr("Brightness Slider"), - "description": I18n.tr("Display brightness control"), - "icon": "brightness_6", - "type": "slider", - "enabled": DisplayService.brightnessAvailable, - "warning": !DisplayService.brightnessAvailable ? I18n.tr("Brightness control not available") : undefined, - "allowMultiple": true - }, - { - "id": "inputVolumeSlider", - "text": I18n.tr("Input Volume Slider"), - "description": I18n.tr("Microphone volume control"), - "icon": "mic", - "type": "slider", - "enabled": true - }, - { - "id": "battery", - "text": I18n.tr("Battery"), - "description": I18n.tr("Battery and power management"), - "icon": "battery_std", - "type": "action", - "enabled": true - }, - { - "id": "diskUsage", - "text": I18n.tr("Disk Usage"), - "description": I18n.tr("Filesystem usage monitoring"), - "icon": "storage", - "type": "action", - "enabled": DgopService.dgopAvailable, - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined, - "allowMultiple": true - }, - { - "id": "colorPicker", - "text": I18n.tr("Color Picker"), - "description": I18n.tr("Choose colors from palette"), - "icon": "palette", - "type": "action", - "enabled": true - }, - { - "id": "builtin_vpn", - "text": I18n.tr("VPN"), - "description": I18n.tr("VPN connections"), - "icon": "vpn_key", - "type": "builtin_plugin", - "enabled": DMSNetworkService.available, - "warning": !DMSNetworkService.available ? I18n.tr("VPN not available") : undefined, - "isBuiltinPlugin": true - }, - { - "id": "builtin_cups", - "text": I18n.tr("Printers"), - "description": I18n.tr("Print Server Management"), - "icon": "Print", - "type": "builtin_plugin", - "enabled": CupsService.available, - "warning": !CupsService.available ? I18n.tr("CUPS not available") : undefined, - "isBuiltinPlugin": true - } - ] - - function getPluginWidgets() { - const plugins = []; - const loadedPlugins = PluginService.getLoadedPlugins(); - - for (var i = 0; i < loadedPlugins.length; i++) { - const plugin = loadedPlugins[i]; - - if (plugin.type === "daemon") { - continue; - } - - const pluginComponent = PluginService.pluginWidgetComponents[plugin.id]; - if (!pluginComponent) - continue; - - let tempInstance; - try { - tempInstance = pluginComponent.createObject(null); - } catch (e) { - PluginService.reloadPlugin(plugin.id); - continue; - } - if (!tempInstance) - continue; - - const hasCCWidget = tempInstance.ccWidgetIcon && tempInstance.ccWidgetIcon.length > 0; - tempInstance.destroy(); - - if (!hasCCWidget) { - continue; - } - - plugins.push({ - "id": "plugin_" + plugin.id, - "pluginId": plugin.id, - "text": plugin.name || I18n.tr("Plugin"), - "description": plugin.description || "", - "icon": plugin.icon || "extension", - "type": "plugin", - "enabled": true, - "isPlugin": true - }); - } - - return plugins; - } - - readonly property var baseWidgetDefinitions: coreWidgetDefinitions - - function getWidgetForId(widgetId) { - return WidgetUtils.getWidgetForId(baseWidgetDefinitions, widgetId); - } - - function addWidget(widgetId) { - WidgetUtils.addWidget(widgetId); - } - - function removeWidget(index) { - WidgetUtils.removeWidget(index); - } - - function toggleWidgetSize(index) { - WidgetUtils.toggleWidgetSize(index); - } - - function moveWidget(fromIndex, toIndex) { - WidgetUtils.moveWidget(fromIndex, toIndex); - } - - function resetToDefault() { - WidgetUtils.resetToDefault(); - } - - function clearAll() { - WidgetUtils.clearAll(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/AudioSliderRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/AudioSliderRow.qml deleted file mode 100644 index 81d346d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/AudioSliderRow.qml +++ /dev/null @@ -1,103 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Row { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var defaultSink: AudioService.sink - property color sliderTrackColor: "transparent" - - height: 40 - spacing: 0 - - Rectangle { - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: (Theme.iconSize + Theme.spacingS * 2) / 2 - color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0) - - DankRipple { - id: iconRipple - cornerRadius: parent.radius - } - - MouseArea { - id: iconArea - anchors.fill: parent - visible: defaultSink !== null - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (defaultSink) { - SessionData.suppressOSDTemporarily(); - defaultSink.audio.muted = !defaultSink.audio.muted; - } - } - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!defaultSink) - return "volume_off"; - - let volume = defaultSink.audio.volume; - let muted = defaultSink.audio.muted; - - if (muted) - return "volume_off"; - if (volume === 0.0) - return "volume_mute"; - if (volume <= 0.33) - return "volume_down"; - if (volume <= 0.66) - return "volume_up"; - return "volume_up"; - } - size: Theme.iconSize - color: defaultSink && !defaultSink.audio.muted && defaultSink.audio.volume > 0 ? Theme.primary : Theme.surfaceText - } - } - - DankSlider { - id: volumeSlider - - readonly property real actualVolumePercent: defaultSink ? Math.round(defaultSink.audio.volume * 100) : 0 - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - (Theme.iconSize + Theme.spacingS * 2) - enabled: defaultSink !== null - minimum: 0 - maximum: AudioService.sinkMaxVolume - showValue: true - unit: "%" - valueOverride: actualVolumePercent - thumbOutlineColor: Theme.surfaceContainer - trackColor: root.sliderTrackColor.a > 0 ? root.sliderTrackColor : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - onSliderValueChanged: function (newValue) { - if (defaultSink) { - SessionData.suppressOSDTemporarily(); - defaultSink.audio.volume = newValue / 100.0; - if (newValue > 0 && defaultSink.audio.muted) { - defaultSink.audio.muted = false; - } - AudioService.playVolumeChangeSoundIfEnabled(); - } - } - } - - Binding { - target: volumeSlider - property: "value" - value: defaultSink ? Math.min(AudioService.sinkMaxVolume, Math.round(defaultSink.audio.volume * 100)) : 0 - when: !volumeSlider.isDragging - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BatteryPill.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BatteryPill.qml deleted file mode 100644 index c14c308..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BatteryPill.qml +++ /dev/null @@ -1,46 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Modules.ControlCenter.Widgets - -CompoundPill { - id: root - - iconName: BatteryService.getBatteryIcon() - - isActive: BatteryService.batteryAvailable && (BatteryService.isCharging || BatteryService.isPluggedIn) - - primaryText: { - if (!BatteryService.batteryAvailable) { - return I18n.tr("No battery"); - } - return I18n.tr("Battery"); - } - - secondaryText: { - if (!BatteryService.batteryAvailable) { - return I18n.tr("Not available"); - } - if (BatteryService.isCharging) { - return `${BatteryService.batteryLevel}% • ` + I18n.tr("Charging"); - } - if (BatteryService.isPluggedIn) { - return `${BatteryService.batteryLevel}% • ` + I18n.tr("Plugged in"); - } - return `${BatteryService.batteryLevel}%`; - } - - iconColor: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - if (BatteryService.isCharging || BatteryService.isPluggedIn) { - return Theme.primary; - } - return Theme.surfaceText; - } - - onToggled: { - expandClicked(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml deleted file mode 100644 index 037c08f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml +++ /dev/null @@ -1,194 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Row { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string deviceName: "" - property string instanceId: "" - property string screenName: "" - property var parentScreen: null - - signal iconClicked - - height: 40 - spacing: 0 - - DankTooltipV2 { - id: sharedTooltip - } - - property string targetDeviceName: { - if (!DisplayService.brightnessAvailable || !DisplayService.devices || DisplayService.devices.length === 0) { - return ""; - } - - if (screenName && screenName.length > 0) { - const pins = SettingsData.brightnessDevicePins || {}; - const pinnedDevice = pins[screenName]; - if (pinnedDevice && pinnedDevice.length > 0) { - const found = DisplayService.devices.find(dev => dev.name === pinnedDevice); - if (found) { - return found.name; - } - } - } - - if (deviceName && deviceName.length > 0) { - const found = DisplayService.devices.find(dev => dev.name === deviceName); - if (found) { - return found.name; - } - } - - const currentDeviceName = DisplayService.currentDevice; - if (currentDeviceName) { - const found = DisplayService.devices.find(dev => dev.name === currentDeviceName); - if (found) { - return found.name; - } - } - - const backlight = DisplayService.devices.find(d => d.class === "backlight"); - if (backlight) { - return backlight.name; - } - - const ddc = DisplayService.devices.find(d => d.class === "ddc"); - if (ddc) { - return ddc.name; - } - - return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : ""; - } - - property var targetDevice: { - if (!targetDeviceName || !DisplayService.devices) { - return null; - } - - return DisplayService.devices.find(dev => dev.name === targetDeviceName) || null; - } - - property real targetBrightness: { - DisplayService.brightnessVersion; - if (!targetDeviceName) { - return 0; - } - - return DisplayService.getDeviceBrightness(targetDeviceName); - } - - Rectangle { - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: (Theme.iconSize + Theme.spacingS * 2) / 2 - color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0) - - DankRipple { - id: iconRipple - cornerRadius: parent.radius - } - - MouseArea { - id: iconArea - anchors.fill: parent - hoverEnabled: true - cursorShape: DisplayService.devices && DisplayService.devices.length > 1 ? Qt.PointingHandCursor : Qt.ArrowCursor - - onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (DisplayService.devices && DisplayService.devices.length > 1) { - root.iconClicked(); - } - } - - onEntered: { - const tooltipText = targetDevice ? "bl device: " + targetDevice.name : "Backlight Control"; - sharedTooltip.show(tooltipText, iconArea, 0, 0, "bottom"); - } - - onExited: { - sharedTooltip.hide(); - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!DisplayService.brightnessAvailable || !targetDevice) { - return "brightness_low"; - } - - if (targetDevice.class === "backlight" || targetDevice.class === "ddc") { - const brightness = targetBrightness; - if (brightness <= 33) - return "brightness_low"; - if (brightness <= 66) - return "brightness_medium"; - return "brightness_high"; - } else if (targetDevice.name.includes("kbd")) { - return "keyboard"; - } else { - return "lightbulb"; - } - } - size: Theme.iconSize - color: DisplayService.brightnessAvailable && targetDevice && targetBrightness > 0 ? Theme.primary : Theme.surfaceText - } - } - } - - DankSlider { - id: brightnessSlider - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - (Theme.iconSize + Theme.spacingS * 2) - enabled: DisplayService.brightnessAvailable && targetDeviceName.length > 0 - minimum: { - if (!targetDevice) - return 1; - const isExponential = SessionData.getBrightnessExponential(targetDevice.id); - if (isExponential) { - return 1; - } - return (targetDevice.class === "backlight" || targetDevice.class === "ddc") ? 1 : 0; - } - maximum: { - if (!targetDevice) - return 100; - const isExponential = SessionData.getBrightnessExponential(targetDevice.id); - if (isExponential) { - return 100; - } - return targetDevice.displayMax || 100; - } - showValue: true - unit: { - if (!targetDevice) - return "%"; - const isExponential = SessionData.getBrightnessExponential(targetDevice.id); - if (isExponential) { - return "%"; - } - return targetDevice.class === "ddc" ? "" : "%"; - } - onSliderValueChanged: function (newValue) { - if (DisplayService.brightnessAvailable && targetDeviceName) { - DisplayService.setBrightness(newValue, targetDeviceName, true); - } - } - thumbOutlineColor: Theme.surfaceContainer - trackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - Binding on value { - value: root.targetBrightness - when: !brightnessSlider.isDragging - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ColorPickerPill.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ColorPickerPill.qml deleted file mode 100644 index a95410b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ColorPickerPill.qml +++ /dev/null @@ -1,29 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.ControlCenter.Widgets - -CompoundPill { - id: root - - property var colorPickerModal: null - - isActive: true - iconName: "palette" - iconColor: Theme.primary - primaryText: I18n.tr("Color Picker") - secondaryText: I18n.tr("Choose a color") - - onToggled: { - console.log("ColorPickerPill toggled, modal:", colorPickerModal); - if (colorPickerModal) { - colorPickerModal.show(); - } - } - - onExpandClicked: { - console.log("ColorPickerPill expandClicked, modal:", colorPickerModal); - if (colorPickerModal) { - colorPickerModal.show(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompactSlider.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompactSlider.qml deleted file mode 100644 index eeed4c4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompactSlider.qml +++ /dev/null @@ -1,71 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string iconName: "" - property color iconColor: Theme.surfaceText - property string labelText: "" - property real value: 0.0 - property real maximumValue: 1.0 - property real minimumValue: 0.0 - property bool enabled: true - - signal sliderValueChanged(real value) - - width: parent ? parent.width : 200 - height: 60 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - opacity: enabled ? 1.0 : 0.6 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - anchors.right: sliderContainer.left - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: root.iconName - size: Theme.iconSize - color: root.iconColor - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.labelText - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - id: sliderContainer - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.rightMargin: Theme.spacingM - width: 120 - height: parent.height - Theme.spacingS * 2 - - DankSlider { - anchors.centerIn: parent - width: parent.width - enabled: root.enabled - minimum: Math.round(root.minimumValue * 100) - maximum: Math.round(root.maximumValue * 100) - value: Math.round(root.value * 100) - onSliderValueChanged: root.sliderValueChanged(newValue / 100.0) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml deleted file mode 100644 index 9165ec4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml +++ /dev/null @@ -1,205 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string iconName: "" - property color iconColor: Theme.surfaceText - property string primaryText: "" - property string secondaryText: "" - property bool expanded: false - property bool isActive: false - property bool showExpandArea: true - - signal toggled - signal expandClicked - signal wheelEvent(var wheelEvent) - - width: parent ? parent.width : 220 - height: 60 - radius: Theme.cornerRadius - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - readonly property color _containerBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - color: { - const baseColor = bodyMouse.containsMouse ? Theme.primaryPressed : _containerBg; - return baseColor; - } - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.10) - border.width: 0 - antialiasing: true - - readonly property color _labelPrimary: Theme.surfaceText - readonly property color _labelSecondary: Theme.surfaceVariantText - readonly property color _tileBgActive: Theme.ccTileActiveBg - readonly property color _tileBgInactive: { - const transparency = Theme.popupTransparency; - const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1); - return Qt.rgba(surface.r, surface.g, surface.b, transparency); - } - readonly property color _tileRingActive: Theme.ccTileRing - readonly property color _tileRingInactive: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.18) - readonly property color _tileIconActive: Theme.ccTileActiveText - readonly property color _tileIconInactive: Theme.ccTileInactiveIcon - - property int _padH: Theme.spacingS - property int _tileSize: 48 - property int _tileRadius: Theme.cornerRadius - - Rectangle { - id: rightHoverOverlay - anchors.fill: parent - radius: root.radius - z: 0 - visible: false - color: hoverTint(_containerBg) - opacity: 0.08 - antialiasing: true - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - DankRipple { - id: bodyRipple - cornerRadius: root.radius - } - - Row { - id: row - anchors.fill: parent - anchors.leftMargin: _padH - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - Rectangle { - id: iconTile - z: 1 - width: _tileSize - height: _tileSize - anchors.verticalCenter: parent.verticalCenter - radius: _tileRadius - color: isActive ? _tileBgActive : _tileBgInactive - border.color: isActive ? _tileRingActive : "transparent" - border.width: isActive ? 1 : 0 - antialiasing: true - - Rectangle { - anchors.fill: parent - radius: _tileRadius - color: hoverTint(iconTile.color) - opacity: tileMouse.pressed ? 0.3 : (tileMouse.containsMouse ? 0.2 : 0.0) - visible: opacity > 0 - antialiasing: true - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - DankIcon { - anchors.centerIn: parent - name: iconName - size: Theme.iconSize - color: isActive ? _tileIconActive : _tileIconInactive - } - - DankRipple { - id: tileRipple - cornerRadius: _tileRadius - } - - MouseArea { - id: tileMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => tileRipple.trigger(mouse.x, mouse.y) - onClicked: root.toggled() - } - } - - Item { - id: body - width: row.width - iconTile.width - row.spacing - height: row.height - - Column { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - width: parent.width - text: root.primaryText - color: _labelPrimary - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - StyledText { - width: parent.width - text: root.secondaryText - color: _labelSecondary - font.pixelSize: Theme.fontSizeSmall - visible: text.length > 0 - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - - MouseArea { - id: bodyMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: { - rightHoverOverlay.visible = true; - rightHoverOverlay.opacity = 0.08; - } - onExited: { - rightHoverOverlay.opacity = 0.0; - rightHoverOverlay.visible = false; - } - onPressed: mouse => { - const pos = mapToItem(root, mouse.x, mouse.y); - bodyRipple.trigger(pos.x, pos.y); - rightHoverOverlay.opacity = 0.16; - } - onReleased: rightHoverOverlay.opacity = containsMouse ? 0.08 : 0.0 - onClicked: root.expandClicked() - onWheel: function (ev) { - root.wheelEvent(ev); - } - } - } - } - - focus: true - Keys.onPressed: function (ev) { - if (ev.key === Qt.Key_Space || ev.key === Qt.Key_Return) { - root.toggled(); - ev.accepted = true; - } else if (ev.key === Qt.Key_Right) { - root.expandClicked(); - ev.accepted = true; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DetailView.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DetailView.qml deleted file mode 100644 index 2d946f3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DetailView.qml +++ /dev/null @@ -1,23 +0,0 @@ -import QtQuick - -Rectangle { - id: root - - property string title: "" - property Component content: null - property bool isVisible: true - property int contentHeight: 300 - - width: parent ? parent.width : 400 - implicitHeight: isVisible ? contentHeight : 0 - height: implicitHeight - color: "transparent" - clip: true - - Loader { - id: contentLoader - anchors.fill: parent - sourceComponent: root.content - asynchronous: true - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DiskUsagePill.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DiskUsagePill.qml deleted file mode 100644 index 827df4e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/DiskUsagePill.qml +++ /dev/null @@ -1,76 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Modules.ControlCenter.Widgets - -CompoundPill { - id: root - - property string mountPath: "/" - property string instanceId: "" - - iconName: "storage" - - property var selectedMount: { - if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) { - return null; - } - - const targetMount = DgopService.diskMounts.find(mount => mount.mount === mountPath); - return targetMount || DgopService.diskMounts.find(mount => mount.mount === "/") || DgopService.diskMounts[0]; - } - - property real usagePercent: { - if (!selectedMount || !selectedMount.percent) { - return 0; - } - const percentStr = selectedMount.percent.replace("%", ""); - return parseFloat(percentStr) || 0; - } - - isActive: DgopService.dgopAvailable && selectedMount !== null - - primaryText: { - if (!DgopService.dgopAvailable) { - return I18n.tr("Disk Usage"); - } - if (!selectedMount) { - return I18n.tr("No disk data"); - } - return selectedMount.mount; - } - - secondaryText: { - if (!DgopService.dgopAvailable) { - return I18n.tr("dgop not available"); - } - if (!selectedMount) { - return I18n.tr("No disk data available"); - } - return `${selectedMount.used} / ${selectedMount.size} (${usagePercent.toFixed(0)}%)`; - } - - iconColor: { - if (!DgopService.dgopAvailable || !selectedMount) { - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5); - } - if (usagePercent > 90) { - return Theme.error; - } - if (usagePercent > 75) { - return Theme.warning; - } - return Theme.surfaceText; - } - - Component.onCompleted: { - DgopService.addRef(["diskmounts"]); - } - Component.onDestruction: { - DgopService.removeRef(["diskmounts"]); - } - - onToggled: { - expandClicked(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ErrorPill.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ErrorPill.qml deleted file mode 100644 index cece467..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ErrorPill.qml +++ /dev/null @@ -1,56 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string primaryMessage: "" - property string secondaryMessage: "" - - radius: Theme.cornerRadius - color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.1) - border.color: Theme.warning - border.width: 1 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - DankIcon { - name: "warning" - size: 16 - color: Theme.warning - anchors.top: parent.top - anchors.topMargin: 2 - } - - Column { - width: parent.width - 16 - parent.spacing - spacing: Theme.spacingXS - - StyledText { - width: parent.width - text: root.primaryMessage - font.pixelSize: Theme.fontSizeSmall - color: Theme.warning - font.weight: Font.Medium - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - StyledText { - width: parent.width - text: root.secondaryMessage - font.pixelSize: Theme.fontSizeSmall - color: Theme.warning - visible: text.length > 0 - horizontalAlignment: Text.AlignLeft - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/InputAudioSliderRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/InputAudioSliderRow.qml deleted file mode 100644 index 49ea30e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/InputAudioSliderRow.qml +++ /dev/null @@ -1,87 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Row { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var defaultSource: AudioService.source - property color sliderTrackColor: "transparent" - - height: 40 - spacing: 0 - - Rectangle { - width: Theme.iconSize + Theme.spacingS * 2 - height: Theme.iconSize + Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - radius: (Theme.iconSize + Theme.spacingS * 2) / 2 - color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0) - - DankRipple { - id: iconRipple - cornerRadius: parent.radius - } - - MouseArea { - id: iconArea - anchors.fill: parent - visible: defaultSource !== null - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (defaultSource) { - SessionData.suppressOSDTemporarily(); - defaultSource.audio.muted = !defaultSource.audio.muted; - } - } - } - - DankIcon { - anchors.centerIn: parent - name: { - if (!defaultSource) - return "mic_off"; - - let volume = defaultSource.audio.volume; - let muted = defaultSource.audio.muted; - - if (muted || volume === 0.0) - return "mic_off"; - return "mic"; - } - size: Theme.iconSize - color: defaultSource && !defaultSource.audio.muted && defaultSource.audio.volume > 0 ? Theme.primary : Theme.surfaceText - } - } - - DankSlider { - readonly property real actualVolumePercent: defaultSource ? Math.round(defaultSource.audio.volume * 100) : 0 - - anchors.verticalCenter: parent.verticalCenter - width: parent.width - (Theme.iconSize + Theme.spacingS * 2) - enabled: defaultSource !== null - minimum: 0 - maximum: 100 - value: defaultSource ? Math.min(100, Math.round(defaultSource.audio.volume * 100)) : 0 - showValue: true - unit: "%" - valueOverride: actualVolumePercent - thumbOutlineColor: Theme.surfaceContainer - trackColor: root.sliderTrackColor.a > 0 ? root.sliderTrackColor : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - onSliderValueChanged: function (newValue) { - if (defaultSource) { - SessionData.suppressOSDTemporarily(); - defaultSource.audio.volume = newValue / 100.0; - if (newValue > 0 && defaultSource.audio.muted) { - defaultSource.audio.muted = false; - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml deleted file mode 100644 index 02da286..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml +++ /dev/null @@ -1,113 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property bool isActive: BatteryService.batteryAvailable && (BatteryService.isCharging || BatteryService.isPluggedIn) - property bool enabled: BatteryService.batteryAvailable - - signal clicked - - width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48 - height: 48 - radius: { - if (Theme.cornerRadius === 0) - return 0; - return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4; - } - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - readonly property color _tileBgActive: Theme.ccTileActiveBg - readonly property color _tileBgInactive: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - readonly property color _tileRingActive: Theme.ccTileRing - readonly property color _tileIconActive: Theme.ccTileActiveText - readonly property color _tileIconInactive: Theme.ccTileInactiveIcon - - color: { - if (isActive) - return _tileBgActive; - const baseColor = mouseArea.containsMouse ? Theme.primaryPressed : _tileBgInactive; - return baseColor; - } - border.color: isActive ? _tileRingActive : "transparent" - border.width: isActive ? 1 : 0 - antialiasing: true - opacity: enabled ? 1.0 : 0.6 - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: hoverTint(root.color) - opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0) - visible: opacity > 0 - antialiasing: true - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - Row { - anchors.centerIn: parent - spacing: 4 - - DankIcon { - name: BatteryService.getBatteryIcon() - size: parent.parent.width * 0.25 - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - return isActive ? _tileIconActive : _tileIconInactive; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: BatteryService.batteryAvailable ? `${BatteryService.batteryLevel}%` : "" - font.pixelSize: parent.parent.width * 0.15 - font.weight: Font.Medium - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - return isActive ? _tileIconActive : _tileIconInactive; - } - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable - } - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: root.enabled - onPressed: mouse => ripple.trigger(mouse.x, mouse.y) - onClicked: root.clicked() - } - - Behavior on radius { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml deleted file mode 100644 index 30c4e36..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml +++ /dev/null @@ -1,129 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string mountPath: "/" - property string instanceId: "" - - property var selectedMount: { - if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) - return null; - const targetMount = DgopService.diskMounts.find(mount => mount.mount === mountPath); - return targetMount || DgopService.diskMounts.find(mount => mount.mount === "/") || DgopService.diskMounts[0]; - } - - property real usagePercent: { - if (!selectedMount?.percent) - return 0; - return parseFloat(selectedMount.percent.replace("%", "")) || 0; - } - - property bool enabled: DgopService.dgopAvailable - - signal clicked - - width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48 - height: 48 - radius: Theme.cornerRadius + 4 - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - readonly property color _tileBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - color: mouseArea.containsMouse ? Theme.primaryPressed : _tileBg - border.color: "transparent" - border.width: 0 - antialiasing: true - opacity: enabled ? 1.0 : 0.6 - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: hoverTint(root.color) - opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0) - visible: opacity > 0 - antialiasing: true - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "storage" - size: Theme.iconSizeSmall - color: { - if (root.usagePercent > 90) - return Theme.error; - if (root.usagePercent > 75) - return Theme.warning; - return Theme.ccTileInactiveIcon; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 0 - - StyledText { - text: root.selectedMount?.mount || root.mountPath - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideMiddle - width: Math.min(implicitWidth, root.width - Theme.iconSizeSmall - Theme.spacingM) - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: `${root.usagePercent.toFixed(0)}%` - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: { - if (root.usagePercent > 90) - return Theme.error; - if (root.usagePercent > 75) - return Theme.warning; - return Theme.ccTileInactiveIcon; - } - } - } - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: root.enabled - onPressed: mouse => ripple.trigger(mouse.x, mouse.y) - onClicked: root.clicked() - } - - Component.onCompleted: { - DgopService.addRef(["diskmounts"]); - } - Component.onDestruction: { - DgopService.removeRef(["diskmounts"]); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml deleted file mode 100644 index 7d86947..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml +++ /dev/null @@ -1,90 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - property string iconName: "" - property bool isActive: false - property bool enabled: true - property real iconRotation: 0 - - signal clicked - signal iconRotationCompleted - - width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48 - height: 48 - radius: { - if (Theme.cornerRadius === 0) - return 0; - return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4; - } - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - readonly property color _tileBgActive: Theme.ccTileActiveBg - readonly property color _tileBgInactive: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - readonly property color _tileRingActive: Theme.ccTileRing - readonly property color _tileIconActive: Theme.ccTileActiveText - readonly property color _tileIconInactive: Theme.ccTileInactiveIcon - - color: { - if (isActive) - return _tileBgActive; - const baseColor = mouseArea.containsMouse ? Theme.primaryPressed : _tileBgInactive; - return baseColor; - } - border.color: isActive ? _tileRingActive : "transparent" - border.width: isActive ? 1 : 0 - antialiasing: true - opacity: enabled ? 1.0 : 0.6 - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: hoverTint(root.color) - opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0) - visible: opacity > 0 - antialiasing: true - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - DankIcon { - anchors.centerIn: parent - name: iconName - size: Theme.iconSize - color: isActive ? _tileIconActive : _tileIconInactive - rotation: iconRotation - onRotationCompleted: root.iconRotationCompleted() - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: root.enabled - onPressed: mouse => ripple.trigger(mouse.x, mouse.y) - onClicked: root.clicked() - } - - Behavior on radius { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml deleted file mode 100644 index b8adda8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml +++ /dev/null @@ -1,134 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string iconName: "" - property string text: "" - property bool isActive: false - property bool enabled: true - property string secondaryText: "" - property real iconRotation: 0 - - signal clicked - signal iconRotationCompleted - - width: parent ? parent.width : 200 - height: 60 - radius: { - if (Theme.cornerRadius === 0) - return 0; - return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4; - } - - readonly property color _tileBgActive: Theme.ccTileActiveBg - readonly property color _tileBgInactive: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - readonly property color _tileRingActive: Theme.ccTileRing - - color: { - if (isActive) - return _tileBgActive; - const baseColor = mouseArea.containsMouse ? Theme.primaryPressed : _tileBgInactive; - return baseColor; - } - border.color: isActive ? _tileRingActive : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - opacity: enabled ? 1.0 : 0.6 - - function hoverTint(base) { - const factor = 1.2; - return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor); - } - - readonly property color _containerBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: mouseArea.containsMouse ? hoverTint(_containerBg) : Theme.withAlpha(_containerBg, 0) - opacity: mouseArea.containsMouse ? 0.08 : 0.0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - } - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingL + 2 - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: root.iconName - size: Theme.iconSize - color: isActive ? Theme.ccTileActiveText : Theme.ccTileInactiveIcon - anchors.verticalCenter: parent.verticalCenter - rotation: root.iconRotation - onRotationCompleted: root.iconRotationCompleted() - } - - Item { - width: parent.width - Theme.iconSize - parent.spacing - height: parent.height - - Column { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - width: parent.width - text: root.text - font.pixelSize: Theme.fontSizeMedium - color: isActive ? Theme.ccTileActiveText : Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - - StyledText { - width: parent.width - text: root.secondaryText - font.pixelSize: Theme.fontSizeSmall - color: isActive ? Theme.ccTileActiveText : Theme.surfaceVariantText - visible: text.length > 0 - elide: Text.ElideRight - wrapMode: Text.NoWrap - horizontalAlignment: Text.AlignLeft - } - } - } - } - - DankRipple { - id: ripple - cornerRadius: root.radius - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: root.enabled - onPressed: mouse => ripple.trigger(mouse.x, mouse.y) - onClicked: root.clicked() - } - - Behavior on radius { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/layout.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/layout.js deleted file mode 100644 index b8e5651..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/layout.js +++ /dev/null @@ -1,45 +0,0 @@ -function calculateRowsAndWidgets(controlCenterColumn, expandedSection, expandedWidgetIndex) { - var rows = [] - var currentRow = [] - var currentWidth = 0 - var expandedRow = -1 - - const widgets = SettingsData.controlCenterWidgets || [] - const baseWidth = controlCenterColumn.width - const spacing = Theme.spacingS - - for (var i = 0; i < widgets.length; i++) { - const widget = widgets[i] - const widgetWidth = widget.width || 50 - - var itemWidth - if (widgetWidth <= 25) { - itemWidth = (baseWidth - spacing * 3) / 4 - } else if (widgetWidth <= 50) { - itemWidth = (baseWidth - spacing) / 2 - } else if (widgetWidth <= 75) { - itemWidth = (baseWidth - spacing * 2) * 0.75 - } else { - itemWidth = baseWidth - } - - if (currentRow.length > 0 && (currentWidth + spacing + itemWidth > baseWidth)) { - rows.push([...currentRow]) - currentRow = [widget] - currentWidth = itemWidth - } else { - currentRow.push(widget) - currentWidth += (currentRow.length > 1 ? spacing : 0) + itemWidth - } - - if (expandedWidgetIndex === i) { - expandedRow = rows.length - } - } - - if (currentRow.length > 0) { - rows.push(currentRow) - } - - return { rows: rows, expandedRowIndex: expandedRow } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/state.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/state.js deleted file mode 100644 index a2d59a6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/state.js +++ /dev/null @@ -1,17 +0,0 @@ -function openWithSection(root, section) { - if (root.shouldBeVisible) { - root.close(); - } else { - root.expandedSection = section; - root.open(); - } -} - -function toggleSection(root, section) { - if (root.expandedSection === section) { - root.expandedSection = ""; - root.expandedWidgetIndex = -1; - } else { - root.expandedSection = section; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/widgets.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/widgets.js deleted file mode 100644 index 3e11d88..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/utils/widgets.js +++ /dev/null @@ -1,90 +0,0 @@ -function getWidgetForId(baseWidgetDefinitions, widgetId) { - return baseWidgetDefinitions.find(w => w.id === widgetId) -} - -function addWidget(widgetId) { - var widgets = SettingsData.controlCenterWidgets.slice() - var widget = { - "id": widgetId, - "enabled": true, - "width": 50 - } - - if (widgetId === "diskUsage") { - widget.instanceId = generateUniqueId() - widget.mountPath = "/" - } - - if (widgetId === "brightnessSlider") { - widget.instanceId = generateUniqueId() - widget.deviceName = "" - } - - widgets.push(widget) - SettingsData.set("controlCenterWidgets", widgets) -} - -function generateUniqueId() { - return Date.now().toString(36) + Math.random().toString(36).substr(2) -} - -function removeWidget(index) { - var widgets = SettingsData.controlCenterWidgets.slice() - if (index >= 0 && index < widgets.length) { - widgets.splice(index, 1) - SettingsData.set("controlCenterWidgets", widgets) - } -} - -function toggleWidgetSize(index) { - var widgets = SettingsData.controlCenterWidgets.slice() - if (index >= 0 && index < widgets.length) { - const currentWidth = widgets[index].width || 50 - const id = widgets[index].id || "" - - if (id === "wifi" || id === "bluetooth" || id === "audioOutput" || id === "audioInput") { - widgets[index].width = currentWidth <= 50 ? 100 : 50 - } else { - if (currentWidth <= 25) { - widgets[index].width = 50 - } else if (currentWidth <= 50) { - widgets[index].width = 100 - } else { - widgets[index].width = 25 - } - } - - SettingsData.set("controlCenterWidgets", widgets) - } -} - -function reorderWidgets(newOrder) { - SettingsData.set("controlCenterWidgets", newOrder) -} - -function moveWidget(fromIndex, toIndex) { - let widgets = [...(SettingsData.controlCenterWidgets || [])] - if (fromIndex >= 0 && fromIndex < widgets.length && toIndex >= 0 && toIndex < widgets.length) { - const movedWidget = widgets.splice(fromIndex, 1)[0] - widgets.splice(toIndex, 0, movedWidget) - SettingsData.set("controlCenterWidgets", widgets) - } -} - -function resetToDefault() { - const defaultWidgets = [ - {"id": "volumeSlider", "enabled": true, "width": 50}, - {"id": "brightnessSlider", "enabled": true, "width": 50}, - {"id": "wifi", "enabled": true, "width": 50}, - {"id": "bluetooth", "enabled": true, "width": 50}, - {"id": "audioOutput", "enabled": true, "width": 50}, - {"id": "audioInput", "enabled": true, "width": 50}, - {"id": "nightMode", "enabled": true, "width": 50}, - {"id": "darkMode", "enabled": true, "width": 50} - ] - SettingsData.set("controlCenterWidgets", defaultWidgets) -} - -function clearAll() { - SettingsData.set("controlCenterWidgets", []) -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/AxisContext.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/AxisContext.qml deleted file mode 100644 index 8a8fe97..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/AxisContext.qml +++ /dev/null @@ -1,57 +0,0 @@ -import QtQuick - -QtObject { - id: root - - property string edge: "top" - - readonly property string orientation: isVertical ? "vertical" : "horizontal" - readonly property bool isVertical: edge === "left" || edge === "right" - readonly property bool isHorizontal: !isVertical - - function primarySize(item) { - return isVertical ? item.height : item.width - } - - function crossSize(item) { - return isVertical ? item.width : item.height - } - - function setPrimaryPos(item, value) { - if (isVertical) { - item.y = value - } else { - item.x = value - } - } - - function getPrimaryPos(item) { - return isVertical ? item.y : item.x - } - - function primaryAnchor(anchors) { - return isVertical ? anchors.verticalCenter : anchors.horizontalCenter - } - - function crossAnchor(anchors) { - return isVertical ? anchors.horizontalCenter : anchors.verticalCenter - } - - function outerVisualEdge() { - if (edge === "bottom") return "bottom" - if (edge === "left") return "right" - if (edge === "right") return "left" - if (edge === "top") return "top" - return "bottom" - } - - signal axisEdgeChanged() - signal axisOrientationChanged() - signal changed() // Single coalesced signal - - onEdgeChanged: { - axisEdgeChanged() - axisOrientationChanged() - changed() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/BarCanvas.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/BarCanvas.qml deleted file mode 100644 index df3f17f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/BarCanvas.qml +++ /dev/null @@ -1,671 +0,0 @@ -import QtQuick -import QtQuick.Shapes -import qs.Common -import qs.Services - -Item { - id: root - - required property var barWindow - required property var axis - required property var barConfig - - anchors.fill: parent - - anchors.left: parent.left - anchors.top: parent.top - readonly property bool gothEnabled: (barConfig?.gothCornersEnabled ?? false) && !barWindow.hasMaximizedToplevel - anchors.leftMargin: -(gothEnabled && axis.isVertical && axis.edge === "right" ? barWindow._wingR : 0) - anchors.rightMargin: -(gothEnabled && axis.isVertical && axis.edge === "left" ? barWindow._wingR : 0) - anchors.topMargin: -(gothEnabled && !axis.isVertical && axis.edge === "bottom" ? barWindow._wingR : 0) - anchors.bottomMargin: -(gothEnabled && !axis.isVertical && axis.edge === "top" ? barWindow._wingR : 0) - - readonly property int barPos: barConfig?.position ?? 0 - readonly property bool isTop: barPos === SettingsData.Position.Top - readonly property bool isBottom: barPos === SettingsData.Position.Bottom - readonly property bool isLeft: barPos === SettingsData.Position.Left - readonly property bool isRight: barPos === SettingsData.Position.Right - - property real wing: gothEnabled ? barWindow._wingR : 0 - - Behavior on wing { - enabled: root.width > 0 && root.height > 0 - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - property real rt: { - if (barConfig?.squareCorners ?? false) - return 0; - if (barWindow.hasMaximizedToplevel) - return 0; - return Theme.cornerRadius; - } - - Behavior on rt { - enabled: root.width > 0 && root.height > 0 - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - // M3 elevation shadow — Level 2 baseline (navigation bar), with per-bar override support - readonly property bool hasPerBarOverride: (barConfig?.shadowIntensity ?? 0) > 0 - readonly property var elevLevel: Theme.elevationLevel2 - readonly property bool shadowEnabled: (Theme.elevationEnabled && (typeof SettingsData !== "undefined" ? (SettingsData.barElevationEnabled ?? true) : false)) || hasPerBarOverride - readonly property string autoBarShadowDirection: isTop ? "top" : (isBottom ? "bottom" : (isLeft ? "left" : (isRight ? "right" : "top"))) - readonly property string globalShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection - readonly property string perBarShadowDirectionMode: barConfig?.shadowDirectionMode ?? "inherit" - readonly property string perBarManualShadowDirection: { - switch (barConfig?.shadowDirection) { - case "top": - case "topLeft": - case "topRight": - case "bottom": - return barConfig.shadowDirection; - default: - return "top"; - } - } - readonly property string effectiveShadowDirection: { - if (!hasPerBarOverride) - return globalShadowDirection; - switch (perBarShadowDirectionMode) { - case "autoBar": - return autoBarShadowDirection; - case "manual": - return perBarManualShadowDirection === "autoBar" ? autoBarShadowDirection : perBarManualShadowDirection; - default: - return globalShadowDirection; - } - } - - // Per-bar override values (when barConfig.shadowIntensity > 0) - readonly property real overrideBlurPx: (barConfig?.shadowIntensity ?? 0) * 0.2 - readonly property real overrideOpacity: (barConfig?.shadowOpacity ?? 60) / 100 - readonly property string overrideColorMode: barConfig?.shadowColorMode ?? "default" - readonly property color overrideBaseColor: { - switch (overrideColorMode) { - case "surface": - return Theme.surface; - case "primary": - return Theme.primary; - case "secondary": - return Theme.secondary; - case "custom": - return barConfig?.shadowCustomColor ?? "#000000"; - default: - return "#000000"; - } - } - - // Resolved values — per-bar override wins if set, otherwise use global M3 elevation - readonly property real shadowBlurPx: hasPerBarOverride ? overrideBlurPx : (elevLevel.blurPx ?? 8) - readonly property color shadowColor: hasPerBarOverride ? Theme.withAlpha(overrideBaseColor, overrideOpacity) : Theme.elevationShadowColor(elevLevel) - readonly property real shadowOffsetMagnitude: hasPerBarOverride ? (overrideBlurPx * 0.5) : Theme.elevationOffsetMagnitude(elevLevel, 4, effectiveShadowDirection) - readonly property real shadowOffsetX: Theme.elevationOffsetXFor(hasPerBarOverride ? null : elevLevel, effectiveShadowDirection, shadowOffsetMagnitude) - readonly property real shadowOffsetY: Theme.elevationOffsetYFor(hasPerBarOverride ? null : elevLevel, effectiveShadowDirection, shadowOffsetMagnitude) - - readonly property string mainPath: generatePathForPosition(width, height) - readonly property string borderFullPath: generateBorderFullPath(width, height) - readonly property string borderEdgePath: generateBorderEdgePath(width, height) - property bool mainPathCorrectShape: false - property bool borderFullPathCorrectShape: false - property bool borderEdgePathCorrectShape: false - - onMainPathChanged: { - if (width > 0 && height > 0) { - root: mainPathCorrectShape = true; - } - } - onBorderFullPathChanged: { - if (width > 0 && height > 0) { - root: borderFullPathCorrectShape = true; - } - } - onBorderEdgePathChanged: { - if (width > 0 && height > 0) { - root: borderEdgePathCorrectShape = true; - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - z: -999 - onClicked: { - const activePopout = PopoutManager.getActivePopout(barWindow.screen); - if (activePopout) { - if (activePopout.dashVisible !== undefined) { - activePopout.dashVisible = false; - } else if (activePopout.notificationHistoryVisible !== undefined) { - activePopout.notificationHistoryVisible = false; - } else { - activePopout.close(); - } - } - TrayMenuManager.closeAllMenus(); - } - } - - ElevationShadow { - id: barShadow - visible: root.shadowEnabled && root.width > 0 && root.height > 0 - - // Size to the bar's rectangular body, excluding gothic wing extensions - x: root.isRight ? root.wing : 0 - y: root.isBottom ? root.wing : 0 - width: axis.isVertical ? (parent.width - root.wing) : parent.width - height: axis.isVertical ? parent.height : (parent.height - root.wing) - - shadowEnabled: root.shadowEnabled - level: root.hasPerBarOverride ? null : root.elevLevel - direction: root.effectiveShadowDirection - fallbackOffset: 4 - targetRadius: root.rt - targetColor: barWindow._bgColor - - shadowBlurPx: root.shadowBlurPx - shadowOffsetX: root.shadowOffsetX - shadowOffsetY: root.shadowOffsetY - shadowColor: root.shadowColor - blurMax: Theme.elevationBlurMax - } - - Loader { - id: barShape - anchors.fill: parent - active: mainPathCorrectShape - sourceComponent: Shape { - anchors.fill: parent - preferredRendererType: Shape.CurveRenderer - - ShapePath { - fillColor: barWindow._bgColor - strokeColor: "transparent" - strokeWidth: 0 - - PathSvg { - path: root.mainPath - } - } - } - } - - Loader { - id: barBorder - anchors.fill: parent - active: borderFullPathCorrectShape && borderEdgePathCorrectShape - - readonly property real _scale: CompositorService.getScreenScale(barWindow.screen) - readonly property real borderThickness: Math.ceil(Math.max(1, barConfig?.borderThickness ?? 1) * _scale) / _scale - readonly property real inset: borderThickness / 2 - readonly property string borderColorKey: barConfig?.borderColor || "surfaceText" - readonly property color baseColor: (borderColorKey === "surfaceText") ? Theme.surfaceText : (borderColorKey === "primary") ? Theme.primary : Theme.secondary - readonly property color borderColor: Theme.withAlpha(baseColor, barConfig?.borderOpacity ?? 1.0) - readonly property bool showFullBorder: (barConfig?.spacing ?? 4) > 0 - sourceComponent: Shape { - id: barBorderShape - anchors.fill: parent - preferredRendererType: Shape.CurveRenderer - visible: barConfig?.borderEnabled ?? false - - ShapePath { - fillColor: "transparent" - strokeColor: barBorder.borderColor - strokeWidth: barBorder.borderThickness - joinStyle: ShapePath.RoundJoin - capStyle: ShapePath.FlatCap - - PathSvg { - path: barBorder.showFullBorder ? root.borderFullPath : root.borderEdgePath - } - } - } - } - - function generatePathForPosition(w, h) { - if (isTop) - return generateTopPath(w, h); - if (isBottom) - return generateBottomPath(w, h); - if (isLeft) - return generateLeftPath(w, h); - if (isRight) - return generateRightPath(w, h); - return generateTopPath(w, h); - } - - function generateBorderPathForPosition() { - if (isTop) - return generateTopBorderPath(); - if (isBottom) - return generateBottomBorderPath(); - if (isLeft) - return generateLeftBorderPath(); - if (isRight) - return generateRightBorderPath(); - return generateTopBorderPath(); - } - - function generateTopPath(w, h) { - h = h - wing; - const r = wing; - const cr = rt; - - let d = `M ${cr} 0`; - d += ` L ${w - cr} 0`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w} ${cr}`; - if (r > 0) { - d += ` L ${w} ${h + r}`; - d += ` A ${r} ${r} 0 0 0 ${w - r} ${h}`; - d += ` L ${r} ${h}`; - d += ` A ${r} ${r} 0 0 0 0 ${h + r}`; - } else { - d += ` L ${w} ${h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w - cr} ${h}`; - d += ` L ${cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; - } - d += ` L 0 ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${cr} 0`; - d += " Z"; - return d; - } - - function generateBottomPath(w, h) { - const fullH = h; - h = h - wing; - const r = wing; - const cr = rt; - - let d = `M ${cr} ${fullH}`; - d += ` L ${w - cr} ${fullH}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${w} ${fullH - cr}`; - if (r > 0) { - d += ` L ${w} 0`; - d += ` A ${r} ${r} 0 0 1 ${w - r} ${r}`; - d += ` L ${r} ${r}`; - d += ` A ${r} ${r} 0 0 1 0 0`; - } else { - d += ` L ${w} ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${w - cr} 0`; - d += ` L ${cr} 0`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 0 ${cr}`; - } - d += ` L 0 ${fullH - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${cr} ${fullH}`; - d += " Z"; - return d; - } - - function generateLeftPath(w, h) { - w = w - wing; - const r = wing; - const cr = rt; - - let d = `M 0 ${cr}`; - d += ` L 0 ${h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${cr} ${h}`; - if (r > 0) { - d += ` L ${w + r} ${h}`; - d += ` A ${r} ${r} 0 0 1 ${w} ${h - r}`; - d += ` L ${w} ${r}`; - d += ` A ${r} ${r} 0 0 1 ${w + r} 0`; - } else { - d += ` L ${w - cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${w} ${h - cr}`; - d += ` L ${w} ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${w - cr} 0`; - } - d += ` L ${cr} 0`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 0 ${cr}`; - d += " Z"; - return d; - } - - function generateRightPath(w, h) { - const fullW = w; - w = w - wing; - const r = wing; - const cr = rt; - - let d = `M ${fullW} ${cr}`; - d += ` L ${fullW} ${h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${fullW - cr} ${h}`; - if (r > 0) { - d += ` L 0 ${h}`; - d += ` A ${r} ${r} 0 0 0 ${r} ${h - r}`; - d += ` L ${r} ${r}`; - d += ` A ${r} ${r} 0 0 0 0 0`; - } else { - d += ` L ${cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; - d += ` L 0 ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${cr} 0`; - } - d += ` L ${fullW - cr} 0`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${fullW} ${cr}`; - d += " Z"; - return d; - } - - function generateTopBorderPath() { - const w = barBorder.width; - const h = barBorder.height - wing; - const r = wing; - const cr = rt; - - let d = ""; - if (r > 0) { - d = `M ${w} ${h + r}`; - d += ` A ${r} ${r} 0 0 0 ${w - r} ${h}`; - d += ` L ${r} ${h}`; - d += ` A ${r} ${r} 0 0 0 0 ${h + r}`; - } else { - d = `M ${w} ${h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w - cr} ${h}`; - d += ` L ${cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; - } - return d; - } - - function generateBottomBorderPath() { - const w = barBorder.width; - const r = wing; - const cr = rt; - - let d = ""; - if (r > 0) { - d = `M ${w} 0`; - d += ` A ${r} ${r} 0 0 1 ${w - r} ${r}`; - d += ` L ${r} ${r}`; - d += ` A ${r} ${r} 0 0 1 0 0`; - } else { - d = `M ${w} ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w - cr} 0`; - d += ` L ${cr} 0`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 0 ${cr}`; - } - return d; - } - - function generateLeftBorderPath() { - const w = barBorder.width - wing; - const h = barBorder.height; - const r = wing; - const cr = rt; - - let d = ""; - if (r > 0) { - d = `M ${w + r} ${h}`; - d += ` A ${r} ${r} 0 0 1 ${w} ${h - r}`; - d += ` L ${w} ${r}`; - d += ` A ${r} ${r} 0 0 1 ${w + r} 0`; - } else { - d = `M ${w - cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w} ${h - cr}`; - d += ` L ${w} ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${w - cr} 0`; - } - return d; - } - - function generateRightBorderPath() { - const h = barBorder.height; - const r = wing; - const cr = rt; - - let d = ""; - if (r > 0) { - d = `M 0 ${h}`; - d += ` A ${r} ${r} 0 0 0 ${r} ${h - r}`; - d += ` L ${r} ${r}`; - d += ` A ${r} ${r} 0 0 0 0 0`; - } else { - d = `M ${cr} ${h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; - d += ` L 0 ${cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${cr} 0`; - } - return d; - } - - function generateBorderFullPath(fullW, fullH) { - const i = barBorder.inset; - const r = wing; - const cr = rt; - - if (isTop) { - const w = fullW - i * 2; - const h = fullH - wing - i * 2; - - let d = `M ${i + cr} ${i}`; - d += ` L ${i + w - cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + w} ${i + cr}`; - if (r > 0) { - d += ` L ${i + w} ${fullH - i}`; - d += ` A ${r} ${r} 0 0 0 ${i + w - r} ${i + h}`; - d += ` L ${i + r} ${i + h}`; - d += ` A ${r} ${r} 0 0 0 ${i} ${fullH - i}`; - } else { - d += ` L ${i + w} ${i + h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + w - cr} ${i + h}`; - d += ` L ${i + cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h - cr}`; - } - d += ` L ${i} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + cr} ${i}`; - d += " Z"; - return d; - } - - if (isBottom) { - const w = fullW - i * 2; - const h = fullH - wing - i * 2; - - let d = `M ${i + cr} ${fullH - i}`; - d += ` L ${i + w - cr} ${fullH - i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w} ${fullH - i - cr}`; - if (r > 0) { - d += ` L ${i + w} ${i}`; - d += ` A ${r} ${r} 0 0 1 ${i + w - r} ${i + r}`; - d += ` L ${i + r} ${i + r}`; - d += ` A ${r} ${r} 0 0 1 ${i} ${i}`; - } else { - d += ` L ${i + w} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w - cr} ${i}`; - d += ` L ${i + cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i} ${i + cr}`; - } - d += ` L ${i} ${fullH - i - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + cr} ${fullH - i}`; - d += " Z"; - return d; - } - - if (isLeft) { - const w = fullW - wing - i * 2; - const h = fullH - i * 2; - - let d = `M ${i} ${i + cr}`; - d += ` L ${i} ${i + h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + cr} ${i + h}`; - if (r > 0) { - d += ` L ${fullW - i} ${i + h}`; - d += ` A ${r} ${r} 0 0 1 ${i + w} ${i + h - r}`; - d += ` L ${i + w} ${i + r}`; - d += ` A ${r} ${r} 0 0 1 ${fullW - i} ${i}`; - } else { - d += ` L ${i + w - cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w} ${i + h - cr}`; - d += ` L ${i + w} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w - cr} ${i}`; - } - d += ` L ${i + cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i} ${i + cr}`; - d += " Z"; - return d; - } - - if (isRight) { - const w = fullW - wing - i * 2; - const h = fullH - i * 2; - - let d = `M ${fullW - i} ${i + cr}`; - d += ` L ${fullW - i} ${i + h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${fullW - i - cr} ${i + h}`; - if (r > 0) { - d += ` L ${i} ${i + h}`; - d += ` A ${r} ${r} 0 0 0 ${i + r} ${i + h - r}`; - d += ` L ${i + r} ${i + r}`; - d += ` A ${r} ${r} 0 0 0 ${i} ${i}`; - } else { - d += ` L ${wing + i + cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${wing + i} ${i + h - cr}`; - d += ` L ${wing + i} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${wing + i + cr} ${i}`; - } - d += ` L ${fullW - i - cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${fullW - i} ${i + cr}`; - d += " Z"; - return d; - } - - return ""; - } - - function generateBorderEdgePath(fullW, fullH) { - const i = barBorder.inset; - const r = wing; - const cr = rt; - - if (isTop) { - const w = fullW - i * 2; - const h = fullH - wing - i * 2; - - let d = ""; - if (r > 0) { - d = `M ${i + w} ${i + h + r}`; - d += ` A ${r} ${r} 0 0 0 ${i + w - r} ${i + h}`; - d += ` L ${i + r} ${i + h}`; - d += ` A ${r} ${r} 0 0 0 ${i} ${i + h + r}`; - } else { - d = `M ${i + w} ${i + h - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + w - cr} ${i + h}`; - d += ` L ${i + cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h - cr}`; - } - return d; - } - - if (isBottom) { - const w = fullW - i * 2; - - let d = ""; - if (r > 0) { - d = `M ${i + w} ${i}`; - d += ` A ${r} ${r} 0 0 1 ${i + w - r} ${i + r}`; - d += ` L ${i + r} ${i + r}`; - d += ` A ${r} ${r} 0 0 1 ${i} ${i}`; - } else { - d = `M ${i + w} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w - cr} ${i}`; - d += ` L ${i + cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i} ${i + cr}`; - } - return d; - } - - if (isLeft) { - const w = fullW - wing - i * 2; - const h = fullH - i * 2; - - let d = ""; - if (r > 0) { - d = `M ${i + w + r} ${i + h}`; - d += ` A ${r} ${r} 0 0 1 ${i + w} ${i + h - r}`; - d += ` L ${i + w} ${i + r}`; - d += ` A ${r} ${r} 0 0 1 ${i + w + r} ${i}`; - } else { - d = `M ${i + w - cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w} ${i + h - cr}`; - d += ` L ${i + w} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 0 ${i + w - cr} ${i}`; - } - return d; - } - - if (isRight) { - const h = fullH - i * 2; - - let d = ""; - if (r > 0) { - d = `M ${i} ${i + h}`; - d += ` A ${r} ${r} 0 0 0 ${i + r} ${i + h - r}`; - d += ` L ${i + r} ${i + r}`; - d += ` A ${r} ${r} 0 0 0 ${i} ${i}`; - } else { - d = `M ${i + cr} ${i + h}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h - cr}`; - d += ` L ${i} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + cr} ${i}`; - } - return d; - } - - return ""; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/CenterSection.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/CenterSection.qml deleted file mode 100644 index df86d4d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/CenterSection.qml +++ /dev/null @@ -1,387 +0,0 @@ -import QtQuick -import qs.Common - -Item { - id: root - - property var widgetsModel: null - property var components: null - property bool noBackground: false - required property var axis - property string section: "center" - property var parentScreen: null - property real widgetThickness: 30 - property real barThickness: 48 - property real barSpacing: 4 - property var barConfig: null - property var blurBarWindow: null - property bool overrideAxisLayout: false - property bool forceVerticalLayout: false - - readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false) - readonly property real widgetSpacing: { - const baseSpacing = noBackground ? 2 : Theme.spacingXS; - const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return baseSpacing + (outlineThickness * 2); - } - - property var centerWidgets: [] - property int totalWidgets: 0 - property real totalSize: 0 - - function updateLayout() { - if (SettingsData.centeringMode === "geometric") { - applyGeometricLayout(); - } else { - applyIndexLayout(); - } - } - - function applyGeometricLayout() { - if ((isVertical ? height : width) <= 0 || !visible) - return; - - centerWidgets = []; - totalWidgets = 0; - totalSize = 0; - - for (var i = 0; i < centerRepeater.count; i++) { - const loader = centerRepeater.itemAt(i); - if (loader && loader.active && loader.item) { - centerWidgets.push(loader.item); - totalWidgets++; - totalSize += isVertical ? loader.item.height : loader.item.width; - } - } - - if (totalWidgets === 0) - return; - - if (totalWidgets > 1) - totalSize += widgetSpacing * (totalWidgets - 1); - - positionWidgetsGeometric(); - } - - function positionWidgetsGeometric() { - const parentLength = isVertical ? height : width; - const parentCenter = parentLength / 2; - let currentPos = parentCenter - (totalSize / 2); - - centerWidgets.forEach(widget => { - if (isVertical) { - widget.anchors.verticalCenter = undefined; - widget.y = currentPos; - } else { - widget.anchors.horizontalCenter = undefined; - widget.x = currentPos; - } - const widgetSize = isVertical ? widget.height : widget.width; - currentPos += widgetSize + widgetSpacing; - }); - } - - function applyIndexLayout() { - if ((isVertical ? height : width) <= 0 || !visible) - return; - - centerWidgets = []; - totalWidgets = 0; - totalSize = 0; - - let configuredMiddleWidget = null; - let configuredLeftWidget = null; - let configuredRightWidget = null; - - const configuredWidgets = centerRepeater.count; - const isOddConfigured = configuredWidgets % 2 === 1; - const configuredMiddlePos = Math.floor(configuredWidgets / 2); - const configuredLeftPos = isOddConfigured ? -1 : ((configuredWidgets / 2) - 1); - const configuredRightPos = isOddConfigured ? -1 : (configuredWidgets / 2); - - for (var i = 0; i < centerRepeater.count; i++) { - const wrapper = centerRepeater.itemAt(i); - if (!wrapper) - continue; - - if (isOddConfigured && i === configuredMiddlePos && wrapper.active && wrapper.item) - configuredMiddleWidget = wrapper.item; - if (!isOddConfigured && i === configuredLeftPos && wrapper.active && wrapper.item) - configuredLeftWidget = wrapper.item; - if (!isOddConfigured && i === configuredRightPos && wrapper.active && wrapper.item) - configuredRightWidget = wrapper.item; - - if (wrapper.active && wrapper.item) { - centerWidgets.push(wrapper.item); - totalWidgets++; - totalSize += isVertical ? wrapper.item.height : wrapper.item.width; - } - } - - if (totalWidgets === 0) - return; - - if (totalWidgets > 1) - totalSize += widgetSpacing * (totalWidgets - 1); - - positionWidgetsByIndex(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget); - } - - function positionWidgetsByIndex(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget) { - const parentCenter = (isVertical ? height : width) / 2; - const isOddConfigured = configuredWidgets % 2 === 1; - - centerWidgets.forEach(widget => { - if (isVertical) - widget.anchors.verticalCenter = undefined; - else - widget.anchors.horizontalCenter = undefined; - }); - - if (isOddConfigured && configuredMiddleWidget) { - const middleWidget = configuredMiddleWidget; - const middleIndex = centerWidgets.indexOf(middleWidget); - const middleSize = isVertical ? middleWidget.height : middleWidget.width; - - if (isVertical) - middleWidget.y = parentCenter - (middleSize / 2); - else - middleWidget.x = parentCenter - (middleSize / 2); - - let currentPos = isVertical ? middleWidget.y : middleWidget.x; - for (var i = middleIndex - 1; i >= 0; i--) { - const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width; - currentPos -= (widgetSpacing + size); - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - } - - currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize; - for (var i = middleIndex + 1; i < totalWidgets; i++) { - currentPos += widgetSpacing; - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width; - } - return; - } - - if (totalWidgets === 1) { - const widget = centerWidgets[0]; - const size = isVertical ? widget.height : widget.width; - if (isVertical) - widget.y = parentCenter - (size / 2); - else - widget.x = parentCenter - (size / 2); - return; - } - - if (!configuredLeftWidget || !configuredRightWidget) { - if (totalWidgets % 2 === 1) { - const middleIndex = Math.floor(totalWidgets / 2); - const middleWidget = centerWidgets[middleIndex]; - - if (!middleWidget) - return; - - const middleSize = isVertical ? middleWidget.height : middleWidget.width; - - if (isVertical) - middleWidget.y = parentCenter - (middleSize / 2); - else - middleWidget.x = parentCenter - (middleSize / 2); - - let currentPos = isVertical ? middleWidget.y : middleWidget.x; - for (var i = middleIndex - 1; i >= 0; i--) { - const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width; - currentPos -= (widgetSpacing + size); - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - } - - currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize; - for (var i = middleIndex + 1; i < totalWidgets; i++) { - currentPos += widgetSpacing; - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width; - } - } else { - const leftIndex = (totalWidgets / 2) - 1; - const rightIndex = totalWidgets / 2; - const fallbackLeft = centerWidgets[leftIndex]; - const fallbackRight = centerWidgets[rightIndex]; - - if (!fallbackLeft || !fallbackRight) - return; - - const halfSpacing = widgetSpacing / 2; - const leftSize = isVertical ? fallbackLeft.height : fallbackLeft.width; - - if (isVertical) { - fallbackLeft.y = parentCenter - halfSpacing - leftSize; - fallbackRight.y = parentCenter + halfSpacing; - } else { - fallbackLeft.x = parentCenter - halfSpacing - leftSize; - fallbackRight.x = parentCenter + halfSpacing; - } - - let currentPos = isVertical ? fallbackLeft.y : fallbackLeft.x; - for (var i = leftIndex - 1; i >= 0; i--) { - const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width; - currentPos -= (widgetSpacing + size); - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - } - - currentPos = (isVertical ? fallbackRight.y + fallbackRight.height : fallbackRight.x + fallbackRight.width); - for (var i = rightIndex + 1; i < totalWidgets; i++) { - currentPos += widgetSpacing; - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width; - } - } - return; - } - - const leftWidget = configuredLeftWidget; - const rightWidget = configuredRightWidget; - const leftIndex = centerWidgets.indexOf(leftWidget); - const rightIndex = centerWidgets.indexOf(rightWidget); - const halfSpacing = widgetSpacing / 2; - const leftSize = isVertical ? leftWidget.height : leftWidget.width; - - if (isVertical) { - leftWidget.y = parentCenter - halfSpacing - leftSize; - rightWidget.y = parentCenter + halfSpacing; - } else { - leftWidget.x = parentCenter - halfSpacing - leftSize; - rightWidget.x = parentCenter + halfSpacing; - } - - let currentPos = isVertical ? leftWidget.y : leftWidget.x; - for (var i = leftIndex - 1; i >= 0; i--) { - const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width; - currentPos -= (widgetSpacing + size); - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - } - - currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width); - for (var i = rightIndex + 1; i < totalWidgets; i++) { - currentPos += widgetSpacing; - if (isVertical) - centerWidgets[i].y = currentPos; - else - centerWidgets[i].x = currentPos; - currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width; - } - } - - height: parent.height - width: parent.width - anchors.centerIn: parent - - implicitWidth: isVertical ? widgetThickness : totalSize - implicitHeight: isVertical ? totalSize : widgetThickness - - Timer { - id: layoutTimer - interval: 0 - repeat: false - onTriggered: root.updateLayout() - } - - Component.onCompleted: layoutTimer.restart() - - onWidthChanged: { - if (width > 0) - layoutTimer.restart(); - } - - onHeightChanged: { - if (height > 0) - layoutTimer.restart(); - } - - onVisibleChanged: { - if (visible && (isVertical ? height : width) > 0) - layoutTimer.restart(); - } - - Repeater { - id: centerRepeater - model: root.widgetsModel - - onCountChanged: layoutTimer.restart() - - Item { - property var itemData: modelData - readonly property real itemSpacing: root.widgetSpacing - - width: root.isVertical ? root.width : (widgetLoader.item ? widgetLoader.item.width : 0) - height: widgetLoader.item ? widgetLoader.item.height : 0 - - readonly property bool active: widgetLoader.active - readonly property var item: widgetLoader.item - - WidgetHost { - id: widgetLoader - - anchors.verticalCenter: !root.isVertical ? parent.verticalCenter : undefined - anchors.horizontalCenter: root.isVertical ? parent.horizontalCenter : undefined - - widgetId: itemData.widgetId - widgetData: itemData - spacerSize: itemData.size || 20 - components: root.components - isInColumn: root.isVertical - axis: root.axis - section: "center" - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - isFirst: index === 0 - isLast: index === centerRepeater.count - 1 - sectionSpacing: parent.itemSpacing - isLeftBarEdge: false - isRightBarEdge: false - isTopBarEdge: false - isBottomBarEdge: false - - onContentItemReady: contentItem => { - contentItem.widthChanged.connect(() => layoutTimer.restart()); - contentItem.heightChanged.connect(() => layoutTimer.restart()); - layoutTimer.restart(); - } - - onActiveChanged: layoutTimer.restart() - } - } - } - - Connections { - target: SettingsData - function onCenteringModeChanged() { - layoutTimer.restart(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBar.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBar.qml deleted file mode 100644 index 392bf9b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBar.qml +++ /dev/null @@ -1,182 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Hyprland -import Quickshell.I3 -import qs.Common -import qs.Services - -Item { - id: root - - required property var barConfig - - signal colorPickerRequested - signal barReady(var barConfig) - - property alias barVariants: barVariants - property var hyprlandOverviewLoader: null - property bool systemTrayMenuOpen: false - - property alias leftWidgetsModel: leftWidgetsModel - property alias centerWidgetsModel: centerWidgetsModel - property alias rightWidgetsModel: rightWidgetsModel - - property string _leftWidgetsJson: { - root.barConfig; - const leftWidgets = root.barConfig?.leftWidgets || []; - const mapped = leftWidgets.map((w, index) => { - if (typeof w === "string") { - return { - widgetId: w, - id: w + "_" + index, - enabled: true - }; - } else { - const obj = Object.assign({}, w); - obj.widgetId = w.id || w.widgetId; - obj.id = (w.id || w.widgetId) + "_" + index; - obj.enabled = w.enabled !== false; - return obj; - } - }); - return JSON.stringify(mapped); - } - - property string _centerWidgetsJson: { - root.barConfig; - const centerWidgets = root.barConfig?.centerWidgets || []; - const mapped = centerWidgets.map((w, index) => { - if (typeof w === "string") { - return { - widgetId: w, - id: w + "_" + index, - enabled: true - }; - } else { - const obj = Object.assign({}, w); - obj.widgetId = w.id || w.widgetId; - obj.id = (w.id || w.widgetId) + "_" + index; - obj.enabled = w.enabled !== false; - return obj; - } - }); - return JSON.stringify(mapped); - } - - property string _rightWidgetsJson: { - root.barConfig; - const rightWidgets = root.barConfig?.rightWidgets || []; - const mapped = rightWidgets.map((w, index) => { - if (typeof w === "string") { - return { - widgetId: w, - id: w + "_" + index, - enabled: true - }; - } else { - const obj = Object.assign({}, w); - obj.widgetId = w.id || w.widgetId; - obj.id = (w.id || w.widgetId) + "_" + index; - obj.enabled = w.enabled !== false; - return obj; - } - }); - return JSON.stringify(mapped); - } - - ScriptModel { - id: leftWidgetsModel - values: JSON.parse(root._leftWidgetsJson) - } - - ScriptModel { - id: centerWidgetsModel - values: JSON.parse(root._centerWidgetsJson) - } - - ScriptModel { - id: rightWidgetsModel - values: JSON.parse(root._rightWidgetsJson) - } - - function triggerControlCenterOnFocusedScreen() { - let focusedScreenName = ""; - if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) { - focusedScreenName = Hyprland.focusedWorkspace.monitor.name; - } else if (CompositorService.isNiri && NiriService.currentOutput) { - focusedScreenName = NiriService.currentOutput; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - focusedScreenName = focusedWs?.monitor?.name || ""; - } else if (CompositorService.isDwl && DwlService.activeOutput) { - focusedScreenName = DwlService.activeOutput; - } - - if (!focusedScreenName && barVariants.instances.length > 0) { - const firstBar = barVariants.instances[0]; - firstBar.triggerControlCenter(); - return true; - } - - for (var i = 0; i < barVariants.instances.length; i++) { - const barInstance = barVariants.instances[i]; - if (barInstance.modelData && barInstance.modelData.name === focusedScreenName) { - barInstance.triggerControlCenter(); - return true; - } - } - return false; - } - - function triggerWallpaperBrowserOnFocusedScreen() { - let focusedScreenName = ""; - if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) { - focusedScreenName = Hyprland.focusedWorkspace.monitor.name; - } else if (CompositorService.isNiri && NiriService.currentOutput) { - focusedScreenName = NiriService.currentOutput; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - focusedScreenName = focusedWs?.monitor?.name || ""; - } else if (CompositorService.isDwl && DwlService.activeOutput) { - focusedScreenName = DwlService.activeOutput; - } - - if (!focusedScreenName && barVariants.instances.length > 0) { - const firstBar = barVariants.instances[0]; - firstBar.triggerWallpaperBrowser(); - return true; - } - - for (var i = 0; i < barVariants.instances.length; i++) { - const barInstance = barVariants.instances[i]; - if (barInstance.modelData && barInstance.modelData.name === focusedScreenName) { - barInstance.triggerWallpaperBrowser(); - return true; - } - } - return false; - } - - Variants { - id: barVariants - model: { - const prefs = root.barConfig?.screenPreferences || ["all"]; - if (prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")) { - return Quickshell.screens; - } - const filtered = Quickshell.screens.filter(screen => SettingsData.isScreenInPreferences(screen, prefs)); - if (filtered.length === 0 && root.barConfig?.showOnLastDisplay && Quickshell.screens.length === 1) { - return Quickshell.screens; - } - return filtered; - } - - delegate: DankBarWindow { - rootWindow: root - barConfig: root.barConfig - leftWidgetsModel: root.leftWidgetsModel - centerWidgetsModel: root.centerWidgetsModel - rightWidgetsModel: root.rightWidgetsModel - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarContent.qml deleted file mode 100644 index 0c977bf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarContent.qml +++ /dev/null @@ -1,1459 +0,0 @@ -import QtQuick -import Quickshell.Hyprland -import Quickshell.I3 -import Quickshell.Services.SystemTray -import Quickshell.Wayland -import qs.Common -import qs.Modules.DankBar.Widgets -import qs.Services - -Item { - id: topBarContent - - required property var barWindow - required property var rootWindow - required property var barConfig - - readonly property var blurBarWindow: barWindow - - property var leftWidgetsModel - property var centerWidgetsModel - property var rightWidgetsModel - - readonly property real innerPadding: barConfig?.innerPadding ?? 4 - readonly property real outlineThickness: (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0 - - property alias hLeftSection: hLeftSection - property alias hCenterSection: hCenterSection - property alias hRightSection: hRightSection - property alias vLeftSection: vLeftSection - property alias vCenterSection: vCenterSection - property alias vRightSection: vRightSection - - anchors.fill: parent - anchors.leftMargin: Math.max(Theme.spacingXS, innerPadding * 0.8) - anchors.rightMargin: Math.max(Theme.spacingXS, innerPadding * 0.8) - anchors.topMargin: barWindow.isVertical ? (barWindow.hasAdjacentTopBar ? outlineThickness : Theme.spacingXS) : 0 - anchors.bottomMargin: barWindow.isVertical ? (barWindow.hasAdjacentBottomBar ? outlineThickness : Theme.spacingXS) : 0 - clip: false - - property int componentMapRevision: 0 - - function updateComponentMap() { - componentMapRevision++; - } - - readonly property var sortedToplevels: { - return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, barWindow.screenName); - } - - function getRealWorkspaces() { - if (CompositorService.isNiri) { - const fallbackWorkspaces = [ - { - "id": 1, - "idx": 0, - "name": "" - }, - { - "id": 2, - "idx": 1, - "name": "" - } - ]; - if (!barWindow.screenName || SettingsData.workspaceFollowFocus) { - const currentWorkspaces = NiriService.getCurrentOutputWorkspaces(); - return currentWorkspaces.length > 0 ? currentWorkspaces : fallbackWorkspaces; - } - const workspaces = NiriService.allWorkspaces.filter(ws => ws.output === barWindow.screenName); - return workspaces.length > 0 ? workspaces : fallbackWorkspaces; - } else if (CompositorService.isHyprland) { - const workspaces = Hyprland.workspaces?.values || []; - - if (!barWindow.screenName || SettingsData.workspaceFollowFocus) { - const sorted = workspaces.slice().sort((a, b) => a.id - b.id); - const filtered = sorted.filter(ws => ws.id > -1); - return filtered.length > 0 ? filtered : [ - { - "id": 1, - "name": "1" - } - ]; - } - - const monitorWorkspaces = workspaces.filter(ws => { - return ws.lastIpcObject && ws.lastIpcObject.monitor === barWindow.screenName && ws.id > -1; - }); - - if (monitorWorkspaces.length === 0) { - return [ - { - "id": 1, - "name": "1" - } - ]; - } - - return monitorWorkspaces.sort((a, b) => a.id - b.id); - } else if (CompositorService.isDwl) { - if (!DwlService.dwlAvailable) { - return [0]; - } - if (SettingsData.dwlShowAllTags) { - return Array.from({ - length: DwlService.tagCount - }, (_, i) => i); - } - return DwlService.getVisibleTags(barWindow.screenName); - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const workspaces = I3.workspaces?.values || []; - if (workspaces.length === 0) - return [ - { - "num": 1 - } - ]; - - if (!barWindow.screenName || SettingsData.workspaceFollowFocus) { - return workspaces.slice().sort((a, b) => a.num - b.num); - } - - const monitorWorkspaces = workspaces.filter(ws => ws.monitor?.name === barWindow.screenName); - return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.num - b.num) : [ - { - "num": 1 - } - ]; - } - return [1]; - } - - function getCurrentWorkspace() { - if (CompositorService.isNiri) { - if (!barWindow.screenName || SettingsData.workspaceFollowFocus) { - return NiriService.getCurrentWorkspaceNumber(); - } - const activeWs = NiriService.allWorkspaces.find(ws => ws.output === barWindow.screenName && ws.is_active); - return activeWs ? activeWs.idx : 1; - } else if (CompositorService.isHyprland) { - const monitors = Hyprland.monitors?.values || []; - const currentMonitor = monitors.find(monitor => monitor.name === barWindow.screenName); - return currentMonitor?.activeWorkspace?.id ?? 1; - } else if (CompositorService.isDwl) { - if (!DwlService.dwlAvailable) - return 0; - const outputState = DwlService.getOutputState(barWindow.screenName); - if (!outputState || !outputState.tags) - return 0; - const activeTags = DwlService.getActiveTags(barWindow.screenName); - return activeTags.length > 0 ? activeTags[0] : 0; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - if (!barWindow.screenName || SettingsData.workspaceFollowFocus) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - return focusedWs ? focusedWs.num : 1; - } - - const focusedWs = I3.workspaces?.values?.find(ws => ws.monitor?.name === barWindow.screenName && ws.focused === true); - return focusedWs ? focusedWs.num : 1; - } - return 1; - } - - function switchWorkspace(direction) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - if (CompositorService.isNiri) { - const currentWs = getCurrentWorkspace(); - const currentIndex = realWorkspaces.findIndex(ws => ws && ws.idx === currentWs); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex !== validIndex) { - const nextWorkspace = realWorkspaces[nextIndex]; - if (!nextWorkspace || nextWorkspace.idx === undefined) { - return; - } - NiriService.switchToWorkspace(nextWorkspace.idx); - } - } else if (CompositorService.isHyprland) { - const currentWs = getCurrentWorkspace(); - const currentIndex = realWorkspaces.findIndex(ws => ws.id === currentWs); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex !== validIndex) { - Hyprland.dispatch(`workspace ${realWorkspaces[nextIndex].id}`); - } - } else if (CompositorService.isDwl) { - const currentTag = getCurrentWorkspace(); - const currentIndex = realWorkspaces.findIndex(tag => tag === currentTag); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex !== validIndex) { - DwlService.switchToTag(barWindow.screenName, realWorkspaces[nextIndex]); - } - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const currentWs = getCurrentWorkspace(); - const currentIndex = realWorkspaces.findIndex(ws => ws.num === currentWs); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex !== validIndex) { - try { - I3.dispatch(`workspace number ${realWorkspaces[nextIndex].num}`); - } catch (_) {} - } - } - } - - function switchApp(deltaY) { - const windows = sortedToplevels; - if (windows.length < 2) { - return; - } - let currentIndex = -1; - for (let i = 0; i < windows.length; i++) { - if (windows[i].activated) { - currentIndex = i; - break; - } - } - let nextIndex; - if (deltaY < 0) { - if (currentIndex === -1) { - nextIndex = 0; - } else { - nextIndex = currentIndex + 1; - } - } else { - if (currentIndex === -1) { - nextIndex = windows.length - 1; - } else { - nextIndex = currentIndex - 1; - } - } - const nextWindow = windows[nextIndex]; - if (nextWindow) { - nextWindow.activate(); - } - } - - readonly property int availableWidth: width - readonly property int launcherButtonWidth: 40 - readonly property int workspaceSwitcherWidth: 120 - readonly property int focusedAppMaxWidth: 456 - readonly property int estimatedLeftSectionWidth: launcherButtonWidth + workspaceSwitcherWidth + focusedAppMaxWidth + (Theme.spacingXS * 2) - readonly property int rightSectionWidth: 200 - readonly property int clockWidth: 120 - readonly property int mediaMaxWidth: 280 - readonly property int weatherWidth: 80 - readonly property bool validLayout: availableWidth > 100 && estimatedLeftSectionWidth > 0 && rightSectionWidth > 0 - readonly property int clockLeftEdge: (availableWidth - clockWidth) / 2 - readonly property int clockRightEdge: clockLeftEdge + clockWidth - readonly property int leftSectionRightEdge: estimatedLeftSectionWidth - readonly property int mediaLeftEdge: clockLeftEdge - mediaMaxWidth - Theme.spacingS - readonly property int rightSectionLeftEdge: availableWidth - rightSectionWidth - readonly property int leftToClockGap: Math.max(0, clockLeftEdge - leftSectionRightEdge) - readonly property int leftToMediaGap: mediaMaxWidth > 0 ? Math.max(0, mediaLeftEdge - leftSectionRightEdge) : leftToClockGap - readonly property int mediaToClockGap: mediaMaxWidth > 0 ? Theme.spacingS : 0 - readonly property int clockToRightGap: validLayout ? Math.max(0, rightSectionLeftEdge - clockRightEdge) : 1000 - readonly property bool spacingTight: !barWindow.isVertical && validLayout && (leftToMediaGap < 150 || clockToRightGap < 100) - readonly property bool overlapping: !barWindow.isVertical && validLayout && (leftToMediaGap < 100 || clockToRightGap < 50) - - function getWidgetEnabled(enabled) { - return enabled !== false; - } - - function getWidgetSection(parentItem) { - let current = parentItem; - while (current) { - if (current.objectName === "leftSection") { - return "left"; - } - if (current.objectName === "centerSection") { - return "center"; - } - if (current.objectName === "rightSection") { - return "right"; - } - current = current.parent; - } - return "left"; - } - - readonly property var widgetVisibility: ({ - "cpuUsage": DgopService.dgopAvailable, - "memUsage": DgopService.dgopAvailable, - "cpuTemp": DgopService.dgopAvailable, - "gpuTemp": DgopService.dgopAvailable, - "network_speed_monitor": DgopService.dgopAvailable - }) - - function getWidgetVisible(widgetId) { - return widgetVisibility[widgetId] ?? true; - } - - readonly property var componentMap: { - componentMapRevision; - - let baseMap = { - "launcherButton": launcherButtonComponent, - "workspaceSwitcher": workspaceSwitcherComponent, - "focusedWindow": focusedWindowComponent, - "runningApps": runningAppsComponent, - "appsDock": appsDockComponent, - "clock": clockComponent, - "music": mediaComponent, - "weather": weatherComponent, - "systemTray": systemTrayComponent, - "privacyIndicator": privacyIndicatorComponent, - "clipboard": clipboardComponent, - "cpuUsage": cpuUsageComponent, - "memUsage": memUsageComponent, - "diskUsage": diskUsageComponent, - "cpuTemp": cpuTempComponent, - "gpuTemp": gpuTempComponent, - "notificationButton": notificationButtonComponent, - "battery": batteryComponent, - "layout": layoutComponent, - "controlCenterButton": controlCenterButtonComponent, - "capsLockIndicator": capsLockIndicatorComponent, - "idleInhibitor": idleInhibitorComponent, - "spacer": spacerComponent, - "separator": separatorComponent, - "network_speed_monitor": networkComponent, - "keyboard_layout_name": keyboardLayoutNameComponent, - "vpn": vpnComponent, - "notepadButton": notepadButtonComponent, - "colorPicker": colorPickerComponent, - "systemUpdate": systemUpdateComponent, - "powerMenuButton": powerMenuButtonComponent - }; - - let pluginMap = PluginService.getWidgetComponents(); - return Object.assign(baseMap, pluginMap); - } - - function getWidgetComponent(widgetId) { - return componentMap[widgetId] || null; - } - - readonly property var allComponents: ({ - "launcherButtonComponent": launcherButtonComponent, - "workspaceSwitcherComponent": workspaceSwitcherComponent, - "focusedWindowComponent": focusedWindowComponent, - "runningAppsComponent": runningAppsComponent, - "appsDockComponent": appsDockComponent, - "clockComponent": clockComponent, - "mediaComponent": mediaComponent, - "weatherComponent": weatherComponent, - "systemTrayComponent": systemTrayComponent, - "privacyIndicatorComponent": privacyIndicatorComponent, - "clipboardComponent": clipboardComponent, - "cpuUsageComponent": cpuUsageComponent, - "memUsageComponent": memUsageComponent, - "diskUsageComponent": diskUsageComponent, - "cpuTempComponent": cpuTempComponent, - "gpuTempComponent": gpuTempComponent, - "notificationButtonComponent": notificationButtonComponent, - "batteryComponent": batteryComponent, - "layoutComponent": layoutComponent, - "controlCenterButtonComponent": controlCenterButtonComponent, - "capsLockIndicatorComponent": capsLockIndicatorComponent, - "idleInhibitorComponent": idleInhibitorComponent, - "spacerComponent": spacerComponent, - "separatorComponent": separatorComponent, - "networkComponent": networkComponent, - "keyboardLayoutNameComponent": keyboardLayoutNameComponent, - "vpnComponent": vpnComponent, - "notepadButtonComponent": notepadButtonComponent, - "colorPickerComponent": colorPickerComponent, - "systemUpdateComponent": systemUpdateComponent, - "powerMenuButtonComponent": powerMenuButtonComponent - }) - - Item { - id: stackContainer - anchors.fill: parent - - Item { - id: horizontalStack - anchors.fill: parent - visible: !barWindow.axis.isVertical - - LeftSection { - id: hLeftSection - objectName: "leftSection" - overrideAxisLayout: true - forceVerticalLayout: false - anchors { - left: parent.left - verticalCenter: parent.verticalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.leftWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: hLeftSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: hLeftSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - - RightSection { - id: hRightSection - objectName: "rightSection" - overrideAxisLayout: true - forceVerticalLayout: false - anchors { - right: parent.right - verticalCenter: parent.verticalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.rightWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: hRightSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: hRightSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - - CenterSection { - id: hCenterSection - objectName: "centerSection" - overrideAxisLayout: true - forceVerticalLayout: false - anchors { - verticalCenter: parent.verticalCenter - horizontalCenter: parent.horizontalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.centerWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: hCenterSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: hCenterSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - } - - Item { - id: verticalStack - anchors.fill: parent - visible: barWindow.axis.isVertical - - LeftSection { - id: vLeftSection - objectName: "leftSection" - overrideAxisLayout: true - forceVerticalLayout: true - width: parent.width - anchors { - top: parent.top - horizontalCenter: parent.horizontalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.leftWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: vLeftSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: vLeftSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - - CenterSection { - id: vCenterSection - objectName: "centerSection" - overrideAxisLayout: true - forceVerticalLayout: true - width: parent.width - anchors { - verticalCenter: parent.verticalCenter - horizontalCenter: parent.horizontalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.centerWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: vCenterSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: vCenterSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - - RightSection { - id: vRightSection - objectName: "rightSection" - overrideAxisLayout: true - forceVerticalLayout: true - width: parent.width - height: implicitHeight - anchors { - bottom: parent.bottom - horizontalCenter: parent.horizontalCenter - } - axis: barWindow.axis - widgetsModel: topBarContent.rightWidgetsModel - components: topBarContent.allComponents - noBackground: barConfig?.noBackground ?? false - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - } - - Binding { - target: vRightSection - property: "barConfig" - value: topBarContent.barConfig - restoreMode: Binding.RestoreNone - } - Binding { - target: vRightSection - property: "blurBarWindow" - value: topBarContent.blurBarWindow - restoreMode: Binding.RestoreNone - } - } - } - - Component { - id: clipboardComponent - - ClipboardButton { - id: clipboardWidget - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) - parentScreen: barWindow.screen - popoutTarget: clipboardHistoryPopoutLoader.item ?? null - - function openClipboardPopout(initialTab) { - clipboardHistoryPopoutLoader.active = true; - if (!clipboardHistoryPopoutLoader.item) { - return; - } - const popout = clipboardHistoryPopoutLoader.item; - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (popout.setBarContext) { - popout.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (popout.setTriggerPosition) { - const globalPos = clipboardWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, clipboardWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - popout.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - if (initialTab) { - popout.activeTab = initialTab; - } - PopoutManager.requestPopout(popout, undefined, "clipboard"); - } - - onClipboardClicked: openClipboardPopout("recents") - - onShowSavedItemsRequested: openClipboardPopout("saved") - - onClearAllRequested: { - clipboardHistoryPopoutLoader.active = true; - const popout = clipboardHistoryPopoutLoader.item; - if (!popout?.confirmDialog) { - return; - } - const hasPinned = popout.pinnedCount > 0; - const message = hasPinned ? I18n.tr("This will delete all unpinned entries. %1 pinned entries will be kept.").arg(popout.pinnedCount) : I18n.tr("This will permanently delete all clipboard history."); - popout.confirmDialog.show(I18n.tr("Clear History?"), message, function () { - if (popout && typeof popout.clearAll === "function") { - popout.clearAll(); - } - }, function () {}); - } - } - } - - Component { - id: powerMenuButtonComponent - - PowerMenuButton { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) - parentScreen: barWindow.screen - onClicked: { - if (powerMenuModalLoader) { - powerMenuModalLoader.active = true; - if (powerMenuModalLoader.item) { - powerMenuModalLoader.item.openCentered(); - } - } - } - } - } - - Component { - id: launcherButtonComponent - - LauncherButton { - id: launcherButton - isActive: false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - section: topBarContent.getWidgetSection(parent) - popoutTarget: appDrawerLoader.item - parentScreen: barWindow.screen - hyprlandOverviewLoader: barWindow ? barWindow.hyprlandOverviewLoader : null - - function _preparePopout() { - appDrawerLoader.active = true; - if (!appDrawerLoader.item) - return false; - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (appDrawerLoader.item.setBarContext) - appDrawerLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - if (appDrawerLoader.item.setTriggerPosition) { - const globalPos = launcherButton.visualContent.mapToItem(null, 0, 0); - const currentScreen = barWindow.screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barWindow.effectiveBarThickness, launcherButton.visualWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - appDrawerLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, launcherButton.section, currentScreen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - return true; - } - - function openWithMode(mode) { - if (!_preparePopout()) - return; - appDrawerLoader.item.openWithMode(mode); - } - - function toggleWithMode(mode) { - if (!_preparePopout()) - return; - appDrawerLoader.item.toggleWithMode(mode); - } - - function openWithQuery(query) { - if (!_preparePopout()) - return; - appDrawerLoader.item.openWithQuery(query); - } - - function toggleWithQuery(query) { - if (!_preparePopout()) - return; - appDrawerLoader.item.toggleWithQuery(query); - } - - onClicked: { - if (!_preparePopout()) - return; - PopoutManager.requestPopout(appDrawerLoader.item, undefined, "appDrawer"); - } - } - } - - Component { - id: workspaceSwitcherComponent - - WorkspaceSwitcher { - axis: barWindow.axis - screenName: barWindow.screenName - widgetHeight: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - parentScreen: barWindow.screen - hyprlandOverviewLoader: barWindow ? barWindow.hyprlandOverviewLoader : null - } - } - - Component { - id: focusedWindowComponent - - FocusedApp { - axis: barWindow.axis - availableWidth: topBarContent.leftToMediaGap - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - barConfig: topBarContent.barConfig - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - parentScreen: barWindow.screen - } - } - - Component { - id: runningAppsComponent - - RunningApps { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - section: topBarContent.getWidgetSection(parent) - parentScreen: barWindow.screen - topBar: topBarContent - barConfig: topBarContent.barConfig - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - } - } - - Component { - id: appsDockComponent - - AppsDock { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - barSpacing: barConfig?.spacing ?? 4 - section: topBarContent.getWidgetSection(parent) - parentScreen: barWindow.screen - topBar: topBarContent - barConfig: topBarContent.barConfig - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - } - } - - Component { - id: clockComponent - - Clock { - axis: barWindow.axis - compactMode: topBarContent.overlapping - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: dankDashPopoutLoader.item ?? null - parentScreen: barWindow.screen - - Component.onCompleted: { - barWindow.clockButtonRef = this; - } - - Component.onDestruction: { - if (barWindow.clockButtonRef === this) { - barWindow.clockButtonRef = null; - } - } - - onClockClicked: { - dankDashPopoutLoader.active = true; - if (dankDashPopoutLoader.item) { - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (dankDashPopoutLoader.item.setBarContext) { - dankDashPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (dankDashPopoutLoader.item.setTriggerPosition) { - let triggerPos, triggerWidth; - if (section === "center") { - const centerSection = barWindow.isVertical ? (barWindow.axis?.edge === "left" ? vCenterSection : vCenterSection) : hCenterSection; - if (centerSection) { - if (barWindow.isVertical) { - const centerY = centerSection.height / 2; - const centerGlobalPos = centerSection.mapToItem(null, 0, centerY); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.height; - } else { - const centerGlobalPos = centerSection.mapToItem(null, 0, 0); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.width; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - const pos = SettingsData.getPopupTriggerPosition(triggerPos, barWindow.screen, barWindow.effectiveBarThickness, triggerWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen; - } - PopoutManager.requestPopout(dankDashPopoutLoader.item, 0, (effectiveBarConfig?.id ?? "default") + "-" + section + "-0"); - } - } - } - } - - Component { - id: mediaComponent - - Media { - axis: barWindow.axis - compactMode: topBarContent.spacingTight || topBarContent.overlapping - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: dankDashPopoutLoader.item ?? null - parentScreen: barWindow.screen - onClicked: { - dankDashPopoutLoader.active = true; - if (dankDashPopoutLoader.item) { - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (dankDashPopoutLoader.item.setBarContext) { - dankDashPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (dankDashPopoutLoader.item.setTriggerPosition) { - let triggerPos, triggerWidth; - if (section === "center") { - const centerSection = barWindow.isVertical ? (barWindow.axis?.edge === "left" ? vCenterSection : vCenterSection) : hCenterSection; - if (centerSection) { - if (barWindow.isVertical) { - const centerY = centerSection.height / 2; - const centerGlobalPos = centerSection.mapToItem(null, 0, centerY); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.height; - } else { - const centerGlobalPos = centerSection.mapToItem(null, 0, 0); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.width; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - const pos = SettingsData.getPopupTriggerPosition(triggerPos, barWindow.screen, barWindow.effectiveBarThickness, triggerWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen; - } - PopoutManager.requestPopout(dankDashPopoutLoader.item, 1, (effectiveBarConfig?.id ?? "default") + "-" + section + "-1"); - } - } - } - } - - Component { - id: weatherComponent - - Weather { - axis: barWindow.axis - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: dankDashPopoutLoader.item ?? null - parentScreen: barWindow.screen - onClicked: { - dankDashPopoutLoader.active = true; - if (dankDashPopoutLoader.item) { - const effectiveBarConfig = topBarContent.barConfig; - // Calculate barPosition from axis.edge - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (dankDashPopoutLoader.item.setBarContext) { - dankDashPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (dankDashPopoutLoader.item.setTriggerPosition) { - // For center section widgets, use center section bounds for DankDash centering - let triggerPos, triggerWidth; - if (section === "center") { - const centerSection = barWindow.isVertical ? (barWindow.axis?.edge === "left" ? vCenterSection : vCenterSection) : hCenterSection; - if (centerSection) { - // For vertical bars, use center Y of section; for horizontal, use left edge - if (barWindow.isVertical) { - const centerY = centerSection.height / 2; - const centerGlobalPos = centerSection.mapToItem(null, 0, centerY); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.height; - } else { - // For horizontal bars, use left edge (DankPopout will center it) - const centerGlobalPos = centerSection.mapToItem(null, 0, 0); - triggerPos = centerGlobalPos; - triggerWidth = centerSection.width; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - } else { - triggerPos = visualContent.mapToItem(null, 0, 0); - triggerWidth = visualWidth; - } - const pos = SettingsData.getPopupTriggerPosition(triggerPos, barWindow.screen, barWindow.effectiveBarThickness, triggerWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen; - } - PopoutManager.requestPopout(dankDashPopoutLoader.item, 3, (effectiveBarConfig?.id ?? "default") + "-" + section + "-3"); - } - } - } - } - - Component { - id: systemTrayComponent - - SystemTrayBar { - parentWindow: barWindow - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - barSpacing: barConfig?.spacing ?? 4 - barConfig: topBarContent.barConfig - widgetData: parent.widgetData - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - isAtBottom: barWindow.axis?.edge === "bottom" - visible: SettingsData.getFilteredScreens("systemTray").includes(barWindow.screen) && SystemTray.items.values.length > 0 - } - } - - Component { - id: privacyIndicatorComponent - - PrivacyIndicator { - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: cpuUsageComponent - - CpuMonitor { - id: cpuWidget - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: processListPopoutLoader.item ?? null - parentScreen: barWindow.screen - widgetData: parent.widgetData - onCpuClicked: { - processListPopoutLoader.active = true; - if (!processListPopoutLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (processListPopoutLoader.item.setBarContext) { - processListPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (processListPopoutLoader.item.setTriggerPosition) { - const globalPos = cpuWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, cpuWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - processListPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(processListPopoutLoader.item, undefined, "cpu"); - } - } - } - - Component { - id: memUsageComponent - - RamMonitor { - id: ramWidget - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: processListPopoutLoader.item ?? null - parentScreen: barWindow.screen - widgetData: parent.widgetData - onRamClicked: { - processListPopoutLoader.active = true; - if (!processListPopoutLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (processListPopoutLoader.item.setBarContext) { - processListPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (processListPopoutLoader.item.setTriggerPosition) { - const globalPos = ramWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, ramWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - processListPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(processListPopoutLoader.item, undefined, "memory"); - } - } - } - - Component { - id: diskUsageComponent - - DiskUsage { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - widgetData: parent.widgetData - parentScreen: barWindow.screen - barConfig: topBarContent.barConfig - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - } - } - - Component { - id: cpuTempComponent - - CpuTemperature { - id: cpuTempWidget - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: processListPopoutLoader.item ?? null - parentScreen: barWindow.screen - widgetData: parent.widgetData - onCpuTempClicked: { - processListPopoutLoader.active = true; - if (!processListPopoutLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (processListPopoutLoader.item.setBarContext) { - processListPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (processListPopoutLoader.item.setTriggerPosition) { - const globalPos = cpuTempWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, cpuTempWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - processListPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(processListPopoutLoader.item, undefined, "cpu_temp"); - } - } - } - - Component { - id: gpuTempComponent - - GpuTemperature { - id: gpuTempWidget - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: processListPopoutLoader.item ?? null - parentScreen: barWindow.screen - widgetData: parent.widgetData - onGpuTempClicked: { - processListPopoutLoader.active = true; - if (!processListPopoutLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (processListPopoutLoader.item.setBarContext) { - processListPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (processListPopoutLoader.item.setTriggerPosition) { - const globalPos = gpuTempWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, gpuTempWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - processListPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(processListPopoutLoader.item, undefined, "gpu_temp"); - } - } - } - - Component { - id: networkComponent - - NetworkMonitor {} - } - - Component { - id: notificationButtonComponent - - NotificationCenterButton { - id: notificationButton - hasUnread: barWindow.notificationCount > 0 - isActive: notificationCenterLoader.item ? notificationCenterLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: notificationCenterLoader.item ?? null - parentScreen: barWindow.screen - onClicked: { - notificationCenterLoader.active = true; - if (!notificationCenterLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (notificationCenterLoader.item.setBarContext) { - notificationCenterLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (notificationCenterLoader.item.setTriggerPosition) { - const globalPos = notificationButton.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, notificationButton.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - notificationCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(notificationCenterLoader.item, undefined, "notifications"); - } - } - } - - Component { - id: batteryComponent - - Battery { - id: batteryWidget - batteryPopupVisible: batteryPopoutLoader.item ? batteryPopoutLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - barSpacing: barConfig?.spacing ?? 4 - barConfig: topBarContent.barConfig - popoutTarget: batteryPopoutLoader.item ?? null - parentScreen: barWindow.screen - onToggleBatteryPopup: { - batteryPopoutLoader.active = true; - if (!batteryPopoutLoader.item) { - return; - } - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (batteryPopoutLoader.item.setBarContext) { - batteryPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (batteryPopoutLoader.item.setTriggerPosition) { - const globalPos = batteryWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, batteryWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - batteryPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(batteryPopoutLoader.item, undefined, "battery"); - } - } - } - - Component { - id: layoutComponent - - DWLLayout { - id: layoutWidget - layoutPopupVisible: layoutPopoutLoader.item ? layoutPopoutLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: layoutPopoutLoader.item ?? null - parentScreen: barWindow.screen - onToggleLayoutPopup: { - layoutPopoutLoader.active = true; - if (!layoutPopoutLoader.item) - return; - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - - if (layoutPopoutLoader.item.setTriggerPosition) { - const globalPos = layoutWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, layoutWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "center"; - layoutPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - - PopoutManager.requestPopout(layoutPopoutLoader.item, undefined, "layout"); - } - } - } - - Component { - id: vpnComponent - - Vpn { - id: vpnWidget - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - barSpacing: barConfig?.spacing ?? 4 - barConfig: topBarContent.barConfig - isAutoHideBar: topBarContent.barConfig?.autoHide ?? false - popoutTarget: vpnPopoutLoader.item ?? null - parentScreen: barWindow.screen - onToggleVpnPopup: { - vpnPopoutLoader.active = true; - if (!vpnPopoutLoader.item) - return; - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - - if (vpnPopoutLoader.item.setBarContext) { - vpnPopoutLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - - if (vpnPopoutLoader.item.setTriggerPosition) { - const globalPos = vpnWidget.mapToItem(null, 0, 0); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, vpnWidget.width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const widgetSection = topBarContent.getWidgetSection(parent) || "right"; - vpnPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, widgetSection, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - - PopoutManager.requestPopout(vpnPopoutLoader.item, undefined, "vpn"); - } - } - } - - Component { - id: controlCenterButtonComponent - - ControlCenterButton { - isActive: controlCenterLoader.item ? controlCenterLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: controlCenterLoader.item ?? null - parentScreen: barWindow.screen - screenName: barWindow.screen?.name || "" - screenModel: barWindow.screen?.model || "" - widgetData: parent.widgetData - - Component.onCompleted: { - barWindow.controlCenterButtonRef = this; - } - - Component.onDestruction: { - if (barWindow.controlCenterButtonRef === this) { - barWindow.controlCenterButtonRef = null; - } - } - - onClicked: { - controlCenterLoader.active = true; - if (!controlCenterLoader.item) { - return; - } - controlCenterLoader.item.triggerScreen = barWindow.screen; - if (controlCenterLoader.item.setTriggerPosition) { - const globalPos = mapToItem(null, 0, 0); - // Use topBarContent.barConfig directly - const effectiveBarConfig = topBarContent.barConfig; - // Calculate barPosition from axis.edge like Battery widget does - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, width, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - const section = topBarContent.getWidgetSection(parent) || "right"; - controlCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(controlCenterLoader.item, undefined, "controlCenter"); - if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) { - NetworkService.scanWifi(); - } - } - } - } - - Component { - id: capsLockIndicatorComponent - - CapsLockIndicator { - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: idleInhibitorComponent - - IdleInhibitor { - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: spacerComponent - - Item { - width: barWindow.isVertical ? barWindow.widgetThickness : (parent.spacerSize || 20) - height: barWindow.isVertical ? (parent.spacerSize || 20) : barWindow.widgetThickness - implicitWidth: width - implicitHeight: height - - Rectangle { - anchors.fill: parent - color: "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - border.width: 1 - radius: 2 - visible: false - - MouseArea { - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - cursorShape: Qt.ArrowCursor - onEntered: parent.visible = true - onExited: parent.visible = false - } - } - } - } - - Component { - id: separatorComponent - - Item { - width: barWindow.isVertical ? parent.barThickness : 1 - height: barWindow.isVertical ? 1 : parent.barThickness - implicitWidth: width - implicitHeight: height - - Rectangle { - width: barWindow.isVertical ? parent.width * 0.6 : 1 - height: barWindow.isVertical ? 1 : parent.height * 0.6 - anchors.centerIn: parent - color: Theme.outline - opacity: 0.3 - } - } - } - - Component { - id: keyboardLayoutNameComponent - - KeyboardLayoutName {} - } - - Component { - id: notepadButtonComponent - - NotepadButton { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: colorPickerComponent - - ColorPicker { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - onColorPickerRequested: { - barWindow.colorPickerRequested(); - } - } - } - - Component { - id: systemUpdateComponent - - SystemUpdate { - isActive: systemUpdateLoader.item ? systemUpdateLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: systemUpdateLoader.item ?? null - parentScreen: barWindow.screen - onClicked: { - systemUpdateLoader.active = true; - if (!systemUpdateLoader.item) - return; - const popout = systemUpdateLoader.item; - const effectiveBarConfig = topBarContent.barConfig; - const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1)); - if (popout.setBarContext) { - popout.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); - } - if (popout.setTriggerPosition) { - const globalPos = visualContent.mapToItem(null, 0, 0); - const currentScreen = parentScreen || Screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barWindow.effectiveBarThickness, visualWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); - popout.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); - } - PopoutManager.requestPopout(popout, undefined, "systemUpdate"); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarWindow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarWindow.qml deleted file mode 100644 index d8b0216..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/DankBarWindow.qml +++ /dev/null @@ -1,1058 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Services - -PanelWindow { - id: barWindow - - required property var rootWindow - required property var barConfig - property var modelData: item - property var hyprlandOverviewLoader: rootWindow ? rootWindow.hyprlandOverviewLoader : null - - property var leftWidgetsModel - property var centerWidgetsModel - property var rightWidgetsModel - - property var controlCenterButtonRef: null - property var clockButtonRef: null - - function triggerControlCenter() { - controlCenterLoader.active = true; - if (!controlCenterLoader.item) { - return; - } - - if (controlCenterButtonRef && controlCenterLoader.item.setTriggerPosition) { - const screenPos = controlCenterButtonRef.mapToItem(null, 0, 0); - const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(screenPos, barWindow.screen, barWindow.effectiveBarThickness, controlCenterButtonRef.width, barConfig?.spacing ?? 4, barPosition, barConfig); - const section = controlCenterButtonRef.section || "right"; - controlCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, barConfig?.spacing ?? 4, barConfig); - } else { - controlCenterLoader.item.triggerScreen = barWindow.screen; - } - - controlCenterLoader.item.toggle(); - if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) { - NetworkService.scanWifi(); - } - } - - function triggerWallpaperBrowser() { - dankDashPopoutLoader.active = true; - if (!dankDashPopoutLoader.item) { - return; - } - - let section = "center"; - if (clockButtonRef && clockButtonRef.visualContent && dankDashPopoutLoader.item.setTriggerPosition) { - // Calculate barPosition from axis.edge - const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1)); - section = clockButtonRef.section || "center"; - - let triggerPos, triggerWidth; - if (section === "center") { - const centerSection = barWindow.isVertical ? (barWindow.axis?.edge === "left" ? topBarContent.vCenterSection : topBarContent.vCenterSection) : topBarContent.hCenterSection; - if (centerSection) { - if (barWindow.isVertical) { - const centerY = centerSection.height / 2; - triggerPos = centerSection.mapToItem(null, 0, centerY); - triggerWidth = centerSection.height; - } else { - triggerPos = centerSection.mapToItem(null, 0, 0); - triggerWidth = centerSection.width; - } - } else { - triggerPos = clockButtonRef.visualContent.mapToItem(null, 0, 0); - triggerWidth = clockButtonRef.visualWidth; - } - } else { - triggerPos = clockButtonRef.visualContent.mapToItem(null, 0, 0); - triggerWidth = clockButtonRef.visualWidth; - } - - const pos = SettingsData.getPopupTriggerPosition(triggerPos, barWindow.screen, barWindow.effectiveBarThickness, triggerWidth, barConfig?.spacing ?? 4, barPosition, barConfig); - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, barConfig?.spacing ?? 4, barConfig); - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen; - } - - PopoutManager.requestPopout(dankDashPopoutLoader.item, 2, (barConfig?.id ?? "default") + "-" + section + "-2"); - } - - readonly property var dBarLayer: { - switch (Quickshell.env("DMS_DANKBAR_LAYER")) { - case "bottom": - return WlrLayer.Bottom; - case "overlay": - return WlrLayer.Overlay; - case "background": - return WlrLayer.background; - default: - return WlrLayer.Top; - } - } - - property var blurRegion: null - property var _blurWidgetItems: [] - - function registerBlurWidget(item) { - if (_blurWidgetItems.indexOf(item) >= 0) - return; - _blurWidgetItems = _blurWidgetItems.concat([item]); - _blurRebuildTimer.restart(); - } - - function unregisterBlurWidget(item) { - const idx = _blurWidgetItems.indexOf(item); - if (idx < 0) - return; - const arr = _blurWidgetItems.slice(); - arr.splice(idx, 1); - _blurWidgetItems = arr; - _blurRebuildTimer.restart(); - } - - Timer { - id: _blurRebuildTimer - interval: 1 - onTriggered: barBlur.rebuild() - } - - Item { - id: barBlur - visible: false - - readonly property bool barHasTransparency: barWindow._backgroundAlpha > 0 && barWindow._backgroundAlpha < 1 - - function rebuild() { - teardown(); - if (!BlurService.enabled || !BlurService.available) - return; - - const widgets = barWindow._blurWidgetItems.filter(w => w && w.visible && w.width > 0 && w.height > 0); - const hasBar = barHasTransparency; - if (!hasBar && widgets.length === 0) - return; - - const cr = Theme.cornerRadius; - let qml = 'import QtQuick; import Quickshell; Region {'; - for (let i = 0; i < widgets.length; i++) { - qml += ` property Item w${i}; Region { item: w${i}; radius: ${cr} }`; - } - qml += '}'; - - try { - const region = Qt.createQmlObject(qml, barWindow, "BarBlurRegion"); - - if (hasBar) { - region.x = Qt.binding(() => topBarMouseArea.x + barUnitInset.x + topBarSlide.x); - region.y = Qt.binding(() => topBarMouseArea.y + barUnitInset.y + topBarSlide.y); - region.width = Qt.binding(() => barUnitInset.width); - region.height = Qt.binding(() => barUnitInset.height); - region.radius = Qt.binding(() => barBackground.rt); - } - - for (let i = 0; i < widgets.length; i++) { - region[`w${i}`] = widgets[i]; - } - - barWindow.BackgroundEffect.blurRegion = region; - barWindow.blurRegion = region; - } catch (e) { - console.warn("BarBlur: Failed to create blur region:", e); - } - } - - function teardown() { - if (!barWindow.blurRegion) - return; - try { - barWindow.BackgroundEffect.blurRegion = null; - } catch (e) {} - barWindow.blurRegion.destroy(); - barWindow.blurRegion = null; - } - - onBarHasTransparencyChanged: _blurRebuildTimer.restart() - - Connections { - target: BlurService - function onEnabledChanged() { - barBlur.rebuild(); - } - } - - Connections { - target: topBarSlide - function onXChanged() { - if (barWindow.blurRegion) - barWindow.blurRegion.changed(); - } - function onYChanged() { - if (barWindow.blurRegion) - barWindow.blurRegion.changed(); - } - } - - Component.onCompleted: rebuild() - Component.onDestruction: teardown() - } - - WlrLayershell.layer: dBarLayer - WlrLayershell.namespace: "dms:bar" - - signal colorPickerRequested - - onColorPickerRequested: rootWindow.colorPickerRequested() - - property alias axis: axis - - AxisContext { - id: axis - edge: { - switch (barConfig?.position ?? 0) { - case SettingsData.Position.Top: - return "top"; - case SettingsData.Position.Bottom: - return "bottom"; - case SettingsData.Position.Left: - return "left"; - case SettingsData.Position.Right: - return "right"; - default: - return "top"; - } - } - } - - readonly property bool isVertical: axis.isVertical - - property bool gothCornersEnabled: barConfig?.gothCornersEnabled ?? false - property real wingtipsRadius: barConfig?.gothCornerRadiusOverride ? (barConfig?.gothCornerRadiusValue ?? 12) : Theme.cornerRadius - readonly property real _wingR: Math.max(0, wingtipsRadius) - readonly property color _surfaceContainer: Theme.surfaceContainer - readonly property string _barId: barConfig?.id ?? "default" - property real _backgroundAlpha: barConfig?.transparency ?? 1.0 - readonly property color _bgColor: Theme.withAlpha(_surfaceContainer, _backgroundAlpha) - - function _updateBackgroundAlpha() { - const live = SettingsData.barConfigs.find(c => c.id === _barId); - _backgroundAlpha = (live ?? barConfig)?.transparency ?? 1.0; - } - readonly property real _dpr: CompositorService.getScreenScale(barWindow.screen) - - // Shadow buffer: extra window space for shadow to render beyond bar bounds - readonly property bool _shadowActive: (Theme.elevationEnabled && (typeof SettingsData !== "undefined" ? (SettingsData.barElevationEnabled ?? true) : false)) || (barConfig?.shadowIntensity ?? 0) > 0 - readonly property real _shadowBuffer: { - if (!_shadowActive) - return 0; - const hasOverride = (barConfig?.shadowIntensity ?? 0) > 0; - if (hasOverride) { - const blur = (barConfig.shadowIntensity ?? 0) * 0.2; - const offset = blur * 0.5; - return Theme.snap(Math.max(16, blur + offset + 8), _dpr); - } - return Theme.snap(Theme.elevationRenderPadding(Theme.elevationLevel2, "top", 4, 8, 16), _dpr); - } - - property string screenName: modelData.name - - property bool hasMaximizedToplevel: false - property bool hasFullscreenToplevel: false - property bool shouldHideForWindows: false - - function _updateHasMaximizedToplevel() { - if (!(barConfig?.maximizeDetection ?? true)) { - hasMaximizedToplevel = false; - return; - } - if (!CompositorService.isHyprland && !CompositorService.isNiri) { - hasMaximizedToplevel = false; - return; - } - - const filtered = CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName); - for (let i = 0; i < filtered.length; i++) { - if (filtered[i]?.maximized) { - hasMaximizedToplevel = true; - return; - } - } - hasMaximizedToplevel = false; - } - - function _updateHasFullscreenToplevel() { - if (!CompositorService.isHyprland) { - hasFullscreenToplevel = false; - return; - } - - const filtered = CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName); - for (let i = 0; i < filtered.length; i++) { - if (filtered[i]?.fullscreen) { - // On niri, fullscreen windows in inactive columns should not hide the bar - if (CompositorService.isNiri && !filtered[i]?.activated) - continue; - hasFullscreenToplevel = true; - return; - } - } - hasFullscreenToplevel = false; - } - - function _updateShouldHideForWindows() { - if (!(barConfig?.showOnWindowsOpen ?? false)) { - shouldHideForWindows = false; - return; - } - if (!(barConfig?.autoHide ?? false)) { - shouldHideForWindows = false; - return; - } - if (!CompositorService.isNiri && !CompositorService.isHyprland) { - shouldHideForWindows = false; - return; - } - - if (CompositorService.isNiri) { - let currentWorkspaceId = null; - for (let i = 0; i < NiriService.allWorkspaces.length; i++) { - const ws = NiriService.allWorkspaces[i]; - if (ws.output === screenName && ws.is_active) { - currentWorkspaceId = ws.id; - break; - } - } - - if (currentWorkspaceId === null) { - shouldHideForWindows = false; - return; - } - - let hasTiled = false; - let hasFloatingTouchingBar = false; - const pos = barConfig?.position ?? 0; - const barThickness = barWindow.effectiveBarThickness + (barConfig?.spacing ?? 4); - - for (let i = 0; i < NiriService.windows.length; i++) { - const win = NiriService.windows[i]; - if (win.workspace_id !== currentWorkspaceId) - continue; - - if (!win.is_floating) { - hasTiled = true; - continue; - } - - const tilePos = win.layout?.tile_pos_in_workspace_view; - const winSize = win.layout?.window_size || win.layout?.tile_size; - if (!tilePos || !winSize) - continue; - - switch (pos) { - case SettingsData.Position.Top: - if (tilePos[1] < barThickness) - hasFloatingTouchingBar = true; - break; - case SettingsData.Position.Bottom: - const screenHeight = barWindow.screen?.height ?? 0; - if (tilePos[1] + winSize[1] > screenHeight - barThickness) - hasFloatingTouchingBar = true; - break; - case SettingsData.Position.Left: - if (tilePos[0] < barThickness) - hasFloatingTouchingBar = true; - break; - case SettingsData.Position.Right: - const screenWidth = barWindow.screen?.width ?? 0; - if (tilePos[0] + winSize[0] > screenWidth - barThickness) - hasFloatingTouchingBar = true; - break; - } - } - - shouldHideForWindows = hasTiled || hasFloatingTouchingBar; - return; - } - - const filtered = CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName); - shouldHideForWindows = filtered.length > 0; - } - - property real effectiveSpacing: hasMaximizedToplevel ? 0 : (barConfig?.spacing ?? 4) - - Behavior on effectiveSpacing { - enabled: barWindow.visible - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - readonly property int notificationCount: NotificationService.notifications.length - readonly property real effectiveBarThickness: Theme.snap(Math.max(barWindow.widgetThickness + (barConfig?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))), _dpr) - readonly property real widgetThickness: Theme.snap(Math.max(20, 26 + (barConfig?.innerPadding ?? 4) * 0.6), _dpr) - - readonly property bool hasAdjacentTopBar: { - if (barConfig?.autoHide ?? false) - return false; - if (!isVertical) - return false; - return SettingsData.barConfigs.some(bc => { - if (!bc.enabled || bc.id === barConfig?.id) - return false; - if (bc.autoHide) - return false; - if (!(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Top && bc.position !== 0) - return false; - const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all"); - if (!onThisScreen) - return false; - if (bc.showOnLastDisplay && screenName !== barWindow.screenName) - return false; - return true; - }); - } - - readonly property bool hasAdjacentBottomBar: { - if (barConfig?.autoHide ?? false) - return false; - if (!isVertical) - return false; - const result = SettingsData.barConfigs.some(bc => { - if (!bc.enabled || bc.id === barConfig?.id) - return false; - if (bc.autoHide) - return false; - if (!(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Bottom && bc.position !== 1) - return false; - const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all"); - if (!onThisScreen) - return false; - if (bc.showOnLastDisplay && screenName !== barWindow.screenName) - return false; - return true; - }); - return result; - } - - readonly property bool hasAdjacentLeftBar: { - if (barConfig?.autoHide ?? false) - return false; - if (isVertical) - return false; - const result = SettingsData.barConfigs.some(bc => { - if (!bc.enabled || bc.id === barConfig?.id) - return false; - if (bc.autoHide) - return false; - if (!(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Left && bc.position !== 2) - return false; - const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all"); - if (!onThisScreen) - return false; - if (bc.showOnLastDisplay && screenName !== barWindow.screenName) - return false; - return true; - }); - return result; - } - - readonly property bool hasAdjacentRightBar: { - if (barConfig?.autoHide ?? false) - return false; - if (isVertical) - return false; - const result = SettingsData.barConfigs.some(bc => { - if (!bc.enabled || bc.id === barConfig?.id) - return false; - if (bc.autoHide) - return false; - if (!(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Right && bc.position !== 3) - return false; - const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all"); - if (!onThisScreen) - return false; - if (bc.showOnLastDisplay && screenName !== barWindow.screenName) - return false; - return true; - }); - return result; - } - - screen: modelData - implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + effectiveSpacing + ((barConfig?.gothCornersEnabled ?? false) && !hasMaximizedToplevel ? _wingR : 0), _dpr) + _shadowBuffer : 0 - implicitWidth: isVertical ? Theme.px(effectiveBarThickness + effectiveSpacing + ((barConfig?.gothCornersEnabled ?? false) && !hasMaximizedToplevel ? _wingR : 0), _dpr) + _shadowBuffer : 0 - color: "transparent" - - property var nativeInhibitor: null - - Component.onCompleted: { - if (SettingsData.forceStatusBarLayoutRefresh) { - SettingsData.forceStatusBarLayoutRefresh.connect(() => { - Qt.callLater(() => { - stackContainer.visible = false; - Qt.callLater(() => { - stackContainer.visible = true; - }); - }); - }); - } - - updateGpuTempConfig(); - _updateBackgroundAlpha(); - _updateHasMaximizedToplevel(); - _updateShouldHideForWindows(); - - inhibitorInitTimer.start(); - } - - Timer { - id: inhibitorInitTimer - interval: 300 - repeat: false - onTriggered: { - if (SessionService.nativeInhibitorAvailable) { - createNativeInhibitor(); - } - } - } - - Connections { - target: PluginService - function onPluginLoaded(pluginId) { - console.info("DankBar: Plugin loaded:", pluginId); - SettingsData.widgetDataChanged(); - } - function onPluginUnloaded(pluginId) { - console.info("DankBar: Plugin unloaded:", pluginId); - SettingsData.widgetDataChanged(); - } - } - - function updateGpuTempConfig() { - const leftWidgets = barConfig?.leftWidgets || []; - const centerWidgets = barConfig?.centerWidgets || []; - const rightWidgets = barConfig?.rightWidgets || []; - const allWidgets = [...leftWidgets, ...centerWidgets, ...rightWidgets]; - - const hasGpuTempWidget = allWidgets.some(widget => { - const widgetId = typeof widget === "string" ? widget : widget.id; - const widgetEnabled = typeof widget === "string" ? true : (widget.enabled !== false); - return widgetId === "gpuTemp" && widgetEnabled; - }); - - DgopService.gpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled || SessionData.nonNvidiaGpuTempEnabled; - DgopService.nvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled; - DgopService.nonNvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nonNvidiaGpuTempEnabled; - } - - function createNativeInhibitor() { - if (!SessionService.nativeInhibitorAvailable) { - return; - } - - try { - const qmlString = ` - import QtQuick - import Quickshell.Wayland - - IdleInhibitor { - enabled: false - } - `; - - nativeInhibitor = Qt.createQmlObject(qmlString, barWindow, "DankBar.NativeInhibitor"); - nativeInhibitor.window = barWindow; - nativeInhibitor.enabled = Qt.binding(() => SessionService.idleInhibited); - nativeInhibitor.enabledChanged.connect(function () { - if (SessionService.idleInhibited !== nativeInhibitor.enabled) { - SessionService.idleInhibited = nativeInhibitor.enabled; - SessionService.inhibitorChanged(); - } - }); - } catch (e) { - nativeInhibitor = null; - } - } - - Connections { - function onBarConfigChanged() { - barWindow.updateGpuTempConfig(); - barWindow._updateBackgroundAlpha(); - barWindow._updateHasMaximizedToplevel(); - barWindow._updateShouldHideForWindows(); - } - - target: rootWindow - } - - Connections { - target: SettingsData - function onBarConfigsChanged() { - barWindow._updateBackgroundAlpha(); - } - } - - Connections { - target: CompositorService - function onToplevelsChanged() { - barWindow._updateHasMaximizedToplevel(); - barWindow._updateHasFullscreenToplevel(); - barWindow._updateShouldHideForWindows(); - } - } - - Connections { - target: NiriService - function onAllWorkspacesChanged() { - barWindow._updateHasMaximizedToplevel(); - barWindow._updateHasFullscreenToplevel(); - barWindow._updateShouldHideForWindows(); - } - } - - Connections { - function onNvidiaGpuTempEnabledChanged() { - barWindow.updateGpuTempConfig(); - } - - function onNonNvidiaGpuTempEnabledChanged() { - barWindow.updateGpuTempConfig(); - } - - target: SessionData - } - - readonly property int barPos: barConfig?.position ?? 0 - - anchors.top: !isVertical ? (barPos === SettingsData.Position.Top) : true - anchors.bottom: !isVertical ? (barPos === SettingsData.Position.Bottom) : true - anchors.left: !isVertical ? true : (barPos === SettingsData.Position.Left) - anchors.right: !isVertical ? true : (barPos === SettingsData.Position.Right) - - exclusiveZone: (!(barConfig?.visible ?? true) || topBarCore.autoHide) ? -1 : (barWindow.effectiveBarThickness + effectiveSpacing + (barConfig?.bottomGap ?? 0)) - - Item { - id: inputMask - - readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + barWindow.effectiveSpacing, barWindow._dpr) - - readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false) - readonly property bool effectiveVisible: (barConfig?.visible ?? true) || inOverviewWithShow - readonly property bool showing: effectiveVisible && (topBarCore.reveal || inOverviewWithShow || !topBarCore.autoHide) - - readonly property int maskThickness: showing ? barThickness : 1 - - x: { - if (!axis.isVertical) { - return 0; - } else { - switch (barPos) { - case SettingsData.Position.Left: - return 0; - case SettingsData.Position.Right: - return parent.width - maskThickness; - default: - return 0; - } - } - } - y: { - if (axis.isVertical) { - return 0; - } else { - switch (barPos) { - case SettingsData.Position.Top: - return 0; - case SettingsData.Position.Bottom: - return parent.height - maskThickness; - default: - return 0; - } - } - } - width: axis.isVertical ? maskThickness : parent.width - height: axis.isVertical ? parent.height : maskThickness - } - - readonly property bool clickThroughEnabled: barConfig?.clickThrough ?? false - - readonly property var _leftSection: topBarContent ? (barWindow.isVertical ? topBarContent.vLeftSection : topBarContent.hLeftSection) : null - readonly property var _centerSection: topBarContent ? (barWindow.isVertical ? topBarContent.vCenterSection : topBarContent.hCenterSection) : null - readonly property var _rightSection: topBarContent ? (barWindow.isVertical ? topBarContent.vRightSection : topBarContent.hRightSection) : null - readonly property real _revealProgress: topBarSlide.x + topBarSlide.y - - function sectionRect(section, isCenter, _dep) { - if (!section) - return { - "x": 0, - "y": 0, - "w": 0, - "h": 0 - }; - - const pos = section.mapToItem(barWindow.contentItem, 0, 0); - const implW = section.implicitWidth || 0; - const implH = section.implicitHeight || 0; - - const offsetX = isCenter && !barWindow.isVertical ? (section.width - implW) / 2 : 0; - const offsetY = !barWindow.isVertical ? (section.height - implH) / 2 : (isCenter ? (section.height - implH) / 2 : 0); - - const edgePad = 2; - return { - "x": pos.x + offsetX - edgePad, - "y": pos.y + offsetY - edgePad, - "w": implW + edgePad * 2, - "h": implH + edgePad * 2 - }; - } - - mask: Region { - item: clickThroughEnabled ? null : inputMask - - Region { - readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._leftSection, false, barWindow._revealProgress) : { - "x": 0, - "y": 0, - "w": 0, - "h": 0 - } - x: r.x - y: r.y - width: r.w - height: r.h - } - - Region { - readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._centerSection, true, barWindow._revealProgress) : { - "x": 0, - "y": 0, - "w": 0, - "h": 0 - } - x: r.x - y: r.y - width: r.w - height: r.h - } - - Region { - readonly property var r: barWindow.clickThroughEnabled ? barWindow.sectionRect(barWindow._rightSection, false, barWindow._revealProgress) : { - "x": 0, - "y": 0, - "w": 0, - "h": 0 - } - x: r.x - y: r.y - width: r.w - height: r.h - } - - Region { - readonly property bool active: barWindow.clickThroughEnabled && !inputMask.showing - x: active ? inputMask.x : 0 - y: active ? inputMask.y : 0 - width: active ? inputMask.width : 0 - height: active ? inputMask.height : 0 - } - } - - Item { - id: topBarCore - anchors.fill: parent - layer.enabled: false - - property bool autoHide: barConfig?.autoHide ?? false - property bool revealSticky: false - - Timer { - id: revealHold - interval: barWindow.clickThroughEnabled ? Math.max((barConfig?.autoHideDelay ?? 250) * 6, 1500) : (barConfig?.autoHideDelay ?? 250) - repeat: false - onTriggered: { - if (!topBarMouseArea.containsMouse && !topBarCore.hasActivePopout) { - topBarCore.revealSticky = false; - } - } - } - - property bool reveal: { - const inOverviewWithShow = CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false); - if (inOverviewWithShow) - return true; - - if (barWindow.hasFullscreenToplevel) - return false; - - const showOnWindowsSetting = barConfig?.showOnWindowsOpen ?? false; - if (showOnWindowsSetting && autoHide && (CompositorService.isNiri || CompositorService.isHyprland)) { - if (barWindow.shouldHideForWindows) - return topBarMouseArea.containsMouse || hasActivePopout || revealSticky; - return true; - } - - if (CompositorService.isNiri && NiriService.inOverview) - return topBarMouseArea.containsMouse || hasActivePopout || revealSticky; - - return (barConfig?.visible ?? true) && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky); - } - - property bool hasActivePopout: false - - onHasActivePopoutChanged: evaluateReveal() - - function updateActivePopoutState() { - if (!barWindow.screen) - return; - const screenName = barWindow.screen.name; - const activePopout = PopoutManager.currentPopoutsByScreen[screenName]; - const activeTrayMenu = TrayMenuManager.activeTrayMenus[screenName]; - const trayOpen = rootWindow.systemTrayMenuOpen; - - const hasVisiblePopout = activePopout && activePopout.shouldBeVisible; - topBarCore.hasActivePopout = !!(hasVisiblePopout || activeTrayMenu || trayOpen); - } - - Connections { - target: PopoutManager - function onPopoutChanged() { - topBarCore.updateActivePopoutState(); - } - } - - Connections { - target: TrayMenuManager - function onActiveTrayMenusChanged() { - topBarCore.updateActivePopoutState(); - } - } - - Connections { - function onBarConfigChanged() { - topBarCore.autoHide = barConfig?.autoHide ?? false; - } - - target: rootWindow - } - - function evaluateReveal() { - if (!autoHide) - return; - - if (topBarMouseArea.containsMouse || hasActivePopout) { - revealSticky = true; - revealHold.stop(); - return; - } - - revealHold.restart(); - } - - Connections { - target: topBarMouseArea - function onContainsMouseChanged() { - topBarCore.evaluateReveal(); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - topBarCore.evaluateReveal(); - } - } - - MouseArea { - id: topBarMouseArea - y: !barWindow.isVertical ? (barPos === SettingsData.Position.Bottom ? parent.height - height : 0) : 0 - x: barWindow.isVertical ? (barPos === SettingsData.Position.Right ? parent.width - width : 0) : 0 - height: !barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + barWindow.effectiveSpacing, barWindow._dpr) : undefined - width: barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + barWindow.effectiveSpacing, barWindow._dpr) : undefined - anchors { - left: !barWindow.isVertical ? parent.left : (barPos === SettingsData.Position.Left ? parent.left : undefined) - right: !barWindow.isVertical ? parent.right : (barPos === SettingsData.Position.Right ? parent.right : undefined) - top: barWindow.isVertical ? parent.top : undefined - bottom: barWindow.isVertical ? parent.bottom : undefined - } - readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false) - hoverEnabled: (barConfig?.autoHide ?? false) && !inOverview && !topBarCore.hasActivePopout - acceptedButtons: Qt.NoButton - enabled: (barConfig?.autoHide ?? false) && !inOverview - - Item { - id: topBarContainer - anchors.fill: parent - - transform: Translate { - id: topBarSlide - x: barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (barPos === SettingsData.Position.Right ? barWindow.implicitWidth : -barWindow.implicitWidth), barWindow._dpr) : 0 - y: !barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (barPos === SettingsData.Position.Bottom ? barWindow.implicitHeight : -barWindow.implicitHeight), barWindow._dpr) : 0 - - Behavior on x { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on y { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - } - - Item { - id: barUnitInset - property int spacingPx: Theme.px(barWindow.effectiveSpacing, barWindow._dpr) - anchors.fill: parent - anchors.leftMargin: !barWindow.isVertical ? spacingPx : (axis.edge === "left" ? spacingPx : 0) - anchors.rightMargin: !barWindow.isVertical ? spacingPx : (axis.edge === "right" ? spacingPx : 0) - anchors.topMargin: barWindow.isVertical ? (barWindow.hasAdjacentTopBar ? 0 : spacingPx) : (axis.outerVisualEdge() === "bottom" ? 0 : spacingPx) - anchors.bottomMargin: barWindow.isVertical ? (barWindow.hasAdjacentBottomBar ? 0 : spacingPx) : (axis.outerVisualEdge() === "bottom" ? spacingPx : 0) - - BarCanvas { - id: barBackground - barWindow: barWindow - axis: axis - barConfig: barWindow.barConfig - } - - MouseArea { - id: scrollArea - anchors.fill: parent - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - z: -1 - - property real touchpadAccumulatorY: 0 - property real touchpadAccumulatorX: 0 - property real mouseAccumulatorY: 0 - property real mouseAccumulatorX: 0 - property bool actionInProgress: false - - Timer { - id: cooldownTimer - interval: 100 - onTriggered: parent.actionInProgress = false - } - - function handleScrollAction(behavior, direction) { - switch (behavior) { - case "workspace": - topBarContent.switchWorkspace(direction); - return true; - case "column": - if (!CompositorService.isNiri) - return false; - if (direction > 0) - NiriService.moveColumnRight(); - else - NiriService.moveColumnLeft(); - return true; - default: - return false; - } - } - - onWheel: wheel => { - if (!(barConfig?.scrollEnabled ?? true) || actionInProgress) { - wheel.accepted = false; - return; - } - - const deltaY = wheel.angleDelta.y; - const deltaX = wheel.angleDelta.x; - const isTouchpadY = wheel.pixelDelta && wheel.pixelDelta.y !== 0; - const isTouchpadX = wheel.pixelDelta && wheel.pixelDelta.x !== 0; - const xBehavior = barConfig?.scrollXBehavior ?? "column"; - const yBehavior = barConfig?.scrollYBehavior ?? "workspace"; - const reverse = SettingsData.reverseScrolling ? -1 : 1; - - if (CompositorService.isNiri && xBehavior !== "none" && Math.abs(deltaX) > Math.abs(deltaY)) { - if (isTouchpadX) { - touchpadAccumulatorX += deltaX; - if (Math.abs(touchpadAccumulatorX) >= 500) { - const direction = touchpadAccumulatorX * reverse < 0 ? 1 : -1; - if (handleScrollAction(xBehavior, direction)) { - actionInProgress = true; - cooldownTimer.restart(); - } - touchpadAccumulatorX = 0; - } - } else { - mouseAccumulatorX += deltaX; - if (Math.abs(mouseAccumulatorX) >= 120) { - const direction = mouseAccumulatorX * reverse < 0 ? 1 : -1; - if (handleScrollAction(xBehavior, direction)) { - actionInProgress = true; - cooldownTimer.restart(); - } - mouseAccumulatorX = 0; - } - } - wheel.accepted = false; - return; - } - - if (yBehavior === "none") { - wheel.accepted = false; - return; - } - - if (isTouchpadY) { - touchpadAccumulatorY += deltaY; - if (Math.abs(touchpadAccumulatorY) >= 500) { - const direction = touchpadAccumulatorY * reverse < 0 ? 1 : -1; - if (handleScrollAction(yBehavior, direction)) { - actionInProgress = true; - cooldownTimer.restart(); - } - touchpadAccumulatorY = 0; - } - } else { - mouseAccumulatorY += deltaY; - if (Math.abs(mouseAccumulatorY) >= 120) { - const direction = mouseAccumulatorY * reverse < 0 ? 1 : -1; - if (handleScrollAction(yBehavior, direction)) { - actionInProgress = true; - cooldownTimer.restart(); - } - mouseAccumulatorY = 0; - } - } - - wheel.accepted = false; - } - } - - DankBarContent { - id: topBarContent - barWindow: barWindow - rootWindow: barWindow.rootWindow - barConfig: barWindow.barConfig - leftWidgetsModel: barWindow.leftWidgetsModel - centerWidgetsModel: barWindow.centerWidgetsModel - rightWidgetsModel: barWindow.rightWidgetsModel - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/LeftSection.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/LeftSection.qml deleted file mode 100644 index d7219db..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/LeftSection.qml +++ /dev/null @@ -1,119 +0,0 @@ -import QtQuick -import qs.Common - -Item { - id: root - - property var widgetsModel: null - property var components: null - property bool noBackground: false - required property var axis - property var parentScreen: null - property real widgetThickness: 30 - property real barThickness: 48 - property real barSpacing: 4 - property var barConfig: null - property var blurBarWindow: null - property bool overrideAxisLayout: false - property bool forceVerticalLayout: false - - readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false) - - implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0 - implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0 - - Loader { - id: layoutLoader - anchors.fill: parent - sourceComponent: root.isVertical ? columnComp : rowComp - } - - Component { - id: rowComp - Row { - readonly property real widgetSpacing: { - const baseSpacing = noBackground ? 2 : Theme.spacingXS; - const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return baseSpacing + (outlineThickness * 2); - } - spacing: widgetSpacing - Repeater { - id: rowRepeater - model: root.widgetsModel - Item { - readonly property real rowSpacing: parent.widgetSpacing - property var itemData: modelData - width: widgetLoader.item ? widgetLoader.item.width : 0 - height: widgetLoader.item ? widgetLoader.item.height : 0 - WidgetHost { - id: widgetLoader - anchors.verticalCenter: parent.verticalCenter - widgetId: itemData.widgetId - widgetData: itemData - spacerSize: itemData.size || 20 - components: root.components - isInColumn: false - axis: root.axis - section: "left" - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - isFirst: index === 0 - isLast: index === rowRepeater.count - 1 - sectionSpacing: parent.rowSpacing - isLeftBarEdge: true - isRightBarEdge: false - } - } - } - } - } - - Component { - id: columnComp - Column { - width: parent.width - readonly property real widgetSpacing: { - const baseSpacing = noBackground ? 2 : Theme.spacingXS; - const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return baseSpacing + (outlineThickness * 2); - } - spacing: widgetSpacing - Repeater { - id: columnRepeater - model: root.widgetsModel - Item { - width: parent.width - readonly property real columnSpacing: parent.widgetSpacing - property var itemData: modelData - height: widgetLoader.item ? widgetLoader.item.height : 0 - WidgetHost { - id: widgetLoader - anchors.horizontalCenter: parent.horizontalCenter - widgetId: itemData.widgetId - widgetData: itemData - spacerSize: itemData.size || 20 - components: root.components - isInColumn: true - axis: root.axis - section: "left" - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - isFirst: index === 0 - isLast: index === columnRepeater.count - 1 - sectionSpacing: parent.columnSpacing - isTopBarEdge: true - isBottomBarEdge: false - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml deleted file mode 100644 index f0cb9d8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/BatteryPopout.qml +++ /dev/null @@ -1,633 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Services.UPower -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:battery" - - property var triggerScreen: null - - function isActiveProfile(profile) { - if (typeof PowerProfiles === "undefined") { - return false; - } - - return PowerProfiles.profile === profile; - } - - function setProfile(profile) { - if (typeof PowerProfiles === "undefined") { - ToastService.showError(I18n.tr("power-profiles-daemon not available")); - return; - } - PowerProfiles.profile = profile; - if (PowerProfiles.profile !== profile) { - ToastService.showError(I18n.tr("Failed to set power profile")); - } - } - - popupWidth: 400 - popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 0 - triggerWidth: 70 - positioning: "" - screen: triggerScreen - - onBackgroundClicked: close() - - content: Component { - Rectangle { - id: batteryContent - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitHeight: contentColumn.implicitHeight + Theme.spacingL * 2 - color: "transparent" - focus: true - Component.onCompleted: { - if (root.shouldBeVisible) { - forceActiveFocus(); - } - } - Keys.onPressed: function (event) { - if (event.key === Qt.Key_Escape) { - root.close(); - event.accepted = true; - } - } - - Connections { - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) { - Qt.callLater(function () { - batteryContent.forceActiveFocus(); - }); - } - } - - target: root - } - - Column { - id: contentColumn - - width: parent.width - Theme.spacingL * 2 - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - Row { - width: parent.width - height: 48 - spacing: Theme.spacingM - - DankIcon { - name: { - if (!BatteryService.batteryAvailable) - return "power"; - - if (!BatteryService.isCharging && BatteryService.isPluggedIn) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - return "battery_charging_20"; - } - if (BatteryService.isCharging) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - return "battery_charging_20"; - } else { - if (BatteryService.batteryLevel >= 95) { - return "battery_full"; - } - if (BatteryService.batteryLevel >= 85) { - return "battery_6_bar"; - } - if (BatteryService.batteryLevel >= 70) { - return "battery_5_bar"; - } - if (BatteryService.batteryLevel >= 55) { - return "battery_4_bar"; - } - if (BatteryService.batteryLevel >= 40) { - return "battery_3_bar"; - } - if (BatteryService.batteryLevel >= 25) { - return "battery_2_bar"; - } - return "battery_1_bar"; - } - } - size: Theme.iconSizeLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) - return Theme.error; - if (BatteryService.isCharging || BatteryService.isPluggedIn) - return Theme.primary; - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - Column { - id: headerInfoColumn - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSizeLarge - 32 - Theme.spacingM * 2 - readonly property string timeInfoText: { - if (!BatteryService.batteryAvailable) - return I18n.tr("Power profile management available"); - const time = BatteryService.formatTimeRemaining(); - if (time !== "Unknown") { - return BatteryService.isCharging ? I18n.tr("Time until full: %1").arg(time) : I18n.tr("Time remaining: %1").arg(time); - } - return ""; - } - readonly property bool showPowerRate: BatteryService.batteryAvailable && Math.abs(BatteryService.changeRate) > 0.05 - readonly property bool isOnAC: BatteryService.batteryAvailable && (BatteryService.isCharging || BatteryService.isPluggedIn) - readonly property bool isDischarging: BatteryService.batteryAvailable && !BatteryService.isCharging && !BatteryService.isPluggedIn - - Row { - spacing: Theme.spacingS - - StyledText { - text: BatteryService.batteryAvailable ? `${BatteryService.batteryLevel}%` : I18n.tr("Power") - font.pixelSize: Theme.fontSizeXLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - if (BatteryService.isCharging) { - return Theme.primary; - } - return Theme.surfaceText; - } - font.weight: Font.Bold - } - - StyledText { - text: BatteryService.batteryStatus - font.pixelSize: Theme.fontSizeLarge - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - if (BatteryService.isCharging) { - return Theme.primary; - } - return Theme.surfaceText; - } - font.weight: Font.Medium - visible: BatteryService.batteryAvailable - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: headerInfoColumn.timeInfoText.length > 0 - - StyledText { - id: powerRateText - text: `${headerInfoColumn.isOnAC ? "+" : (headerInfoColumn.isDischarging ? "-" : "")}${Math.abs(BatteryService.changeRate).toFixed(1)}W` - font.pixelSize: Theme.fontSizeSmall - color: { - if (headerInfoColumn.isOnAC) { - return Theme.primary; - } - if (headerInfoColumn.isDischarging) { - return Theme.warning; - } - return Theme.surfaceTextMedium; - } - font.weight: Font.Medium - visible: headerInfoColumn.showPowerRate - } - - StyledText { - text: headerInfoColumn.timeInfoText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - elide: Text.ElideRight - width: parent.width - (powerRateText.visible ? (powerRateText.implicitWidth + parent.spacing) : 0) - } - } - } - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: closeBatteryArea.containsMouse ? Theme.errorHover : "transparent" - anchors.top: parent.top - - DankIcon { - anchors.centerIn: parent - name: "close" - size: Theme.iconSize - 4 - color: closeBatteryArea.containsMouse ? Theme.error : Theme.surfaceText - } - - MouseArea { - id: closeBatteryArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - root.close(); - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: BatteryService.batteryAvailable - - StyledRect { - width: (parent.width - Theme.spacingM) / 2 - height: 64 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Health") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: BatteryService.batteryHealth - font.pixelSize: Theme.fontSizeLarge - color: { - if (BatteryService.batteryHealth === "N/A") { - return Theme.surfaceText; - } - const healthNum = parseInt(BatteryService.batteryHealth); - return healthNum < 80 ? Theme.error : Theme.surfaceText; - } - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - StyledRect { - width: (parent.width - Theme.spacingM) / 2 - height: 64 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Capacity") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: BatteryService.batteryCapacity > 0 ? `${BatteryService.batteryCapacity.toFixed(1)} Wh` : I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - // Individual battery details for multiple batteries - Column { - width: parent.width - spacing: Theme.spacingS - visible: !BatteryService.usePreferred && BatteryService.batteries.length > 1 - - StyledText { - text: I18n.tr("Individual Batteries") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - } - - Repeater { - model: ScriptModel { - values: BatteryService.batteries - } - - delegate: StyledRect { - required property var modelData - required property int index - - width: parent.width - height: batteryColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - border.width: 0 - - Column { - id: batteryColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - // Top row: name and percentage - Row { - width: parent.width - spacing: Theme.spacingM - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - percentText.width - chargingIcon.width - Theme.spacingM * 2 - - StyledText { - text: modelData.model || I18n.tr("Battery %1").arg(index + 1) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - width: parent.width - } - - StyledText { - text: modelData.nativePath - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - elide: Text.ElideMiddle - width: parent.width - } - } - - Item { - width: 1 - height: parent.height - } - - StyledText { - id: percentText - text: `${Math.round(100 * modelData.percentage)}%` - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Bold - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - id: chargingIcon - name: modelData.state === UPowerDeviceState.Charging ? "bolt" : "" - size: Theme.iconSizeSmall - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - visible: modelData.state === UPowerDeviceState.Charging - } - } - - // Bottom row: Health, Capacity and Time - Flow { - width: parent.width - spacing: Theme.spacingS - - StyledRect { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - Column { - anchors.centerIn: parent - spacing: 2 - - StyledText { - text: I18n.tr("Health") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (!modelData.healthSupported || modelData.healthPercentage <= 0) - return "N/A"; - return `${Math.round(modelData.healthPercentage)}%`; - } - font.pixelSize: Theme.fontSizeSmall - color: { - if (!modelData.healthSupported || modelData.healthPercentage <= 0) - return Theme.surfaceText; - return modelData.healthPercentage < 80 ? Theme.error : Theme.surfaceText; - } - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - StyledRect { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - Column { - anchors.centerIn: parent - spacing: 2 - - StyledText { - text: I18n.tr("Capacity") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: modelData.energyCapacity > 0 ? `${modelData.energyCapacity.toFixed(1)}` : "N/A" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - StyledRect { - width: (parent.width - Theme.spacingS * 2) / 3 - height: 48 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.width: 0 - - Column { - anchors.centerIn: parent - spacing: 2 - - StyledText { - text: modelData.state === UPowerDeviceState.Charging ? I18n.tr("To Full") : modelData.state === UPowerDeviceState.Discharging ? I18n.tr("Left") : "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - const time = modelData.state === UPowerDeviceState.Charging ? modelData.timeToFull : modelData.state === UPowerDeviceState.Discharging && BatteryService.changeRate > 0 ? (3600 * modelData.energy) / BatteryService.changeRate : 0; - - if (!time || time <= 0 || time > 86400) - return "N/A"; - - const hours = Math.floor(time / 3600); - const minutes = Math.floor((time % 3600) / 60); - return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Bold - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - } - } - } - } - - Item { - width: parent.width - height: profileButtonGroup.height * profileButtonGroup.scale - - DankButtonGroup { - id: profileButtonGroup - - property var profileModel: (typeof PowerProfiles !== "undefined") ? [PowerProfile.PowerSaver, PowerProfile.Balanced].concat(PowerProfiles.hasPerformanceProfile ? [PowerProfile.Performance] : []) : [PowerProfile.PowerSaver, PowerProfile.Balanced, PowerProfile.Performance] - property int currentProfileIndex: { - if (typeof PowerProfiles === "undefined") - return 1; - return profileModel.findIndex(profile => root.isActiveProfile(profile)); - } - - scale: Math.min(1, parent.width / implicitWidth) - transformOrigin: Item.Center - anchors.horizontalCenter: parent.horizontalCenter - model: profileModel.map(profile => Theme.getPowerProfileLabel(profile)) - currentIndex: currentProfileIndex - selectionMode: "single" - onSelectionChanged: (index, selected) => { - if (!selected) - return; - root.setProfile(profileModel[index]); - } - } - } - - StyledRect { - width: parent.width - height: degradationContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) - border.color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3) - border.width: 0 - visible: (typeof PowerProfiles !== "undefined") && PowerProfiles.degradationReason !== PerformanceDegradationReason.None - - Column { - id: degradationContent - width: parent.width - Theme.spacingL * 2 - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSize - Theme.spacingM - - StyledText { - text: I18n.tr("Power Profile Degradation") - font.pixelSize: Theme.fontSizeLarge - color: Theme.error - font.weight: Font.Medium - } - - StyledText { - text: (typeof PowerProfiles !== "undefined") ? PerformanceDegradationReason.toString(PowerProfiles.degradationReason) : "" - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.8) - wrapMode: Text.WordWrap - width: parent.width - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/DWLLayoutPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/DWLLayoutPopout.qml deleted file mode 100644 index 9daed8d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/DWLLayoutPopout.qml +++ /dev/null @@ -1,302 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:layout" - - property var triggerScreen: null - - function setTriggerPosition(x, y, width, section, screen, barPosition, barThickness, barSpacing, barConfig) { - triggerX = x; - triggerY = y; - triggerWidth = width; - triggerSection = section; - triggerScreen = screen; - root.screen = screen; - - storedBarThickness = barThickness !== undefined ? barThickness : (Theme.barHeight - 4); - storedBarSpacing = barSpacing !== undefined ? barSpacing : 4; - storedBarConfig = barConfig; - - const pos = barPosition !== undefined ? barPosition : 0; - const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : 0) : 0; - - setBarContext(pos, bottomGap); - - updateOutputState(); - } - - onScreenChanged: updateOutputState() - - function updateOutputState() { - if (screen && DwlService.dwlAvailable) { - outputState = DwlService.getOutputState(screen.name); - } else { - outputState = null; - } - } - - property var outputState: null - property string currentLayoutSymbol: outputState?.layoutSymbol || "" - - readonly property var layoutNames: ({ - "CT": I18n.tr("Center Tiling"), - "G": I18n.tr("Grid"), - "K": I18n.tr("Deck"), - "M": I18n.tr("Monocle"), - "RT": I18n.tr("Right Tiling"), - "S": I18n.tr("Scrolling"), - "T": I18n.tr("Tiling"), - "VG": I18n.tr("Vertical Grid"), - "VK": I18n.tr("Vertical Deck"), - "VS": I18n.tr("Vertical Scrolling"), - "VT": I18n.tr("Vertical Tiling") - }) - - readonly property var layoutIcons: ({ - "CT": "view_compact", - "G": "grid_view", - "K": "layers", - "M": "fullscreen", - "RT": "view_sidebar", - "S": "view_carousel", - "T": "view_quilt", - "VG": "grid_on", - "VK": "view_day", - "VS": "scrollable_header", - "VT": "clarify" - }) - - function getLayoutName(symbol) { - return layoutNames[symbol] || symbol; - } - - function getLayoutIcon(symbol) { - return layoutIcons[symbol] || "view_quilt"; - } - - Connections { - target: DwlService - function onStateChanged() { - updateOutputState(); - } - } - - onShouldBeVisibleChanged: { - if (shouldBeVisible) { - updateOutputState(); - } - } - - Component.onCompleted: { - updateOutputState(); - } - - popupWidth: 300 - popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 550 - triggerWidth: 70 - positioning: "" - screen: triggerScreen - shouldBeVisible: false - - onBackgroundClicked: close() - - content: Component { - Rectangle { - id: layoutContent - - implicitHeight: contentColumn.implicitHeight + Theme.spacingL * 2 - color: "transparent" - focus: true - - Component.onCompleted: { - if (root.shouldBeVisible) { - forceActiveFocus(); - } - } - - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - root.close(); - event.accepted = true; - } - } - - Connections { - target: root - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) { - Qt.callLater(() => { - layoutContent.forceActiveFocus(); - }); - } - } - } - - Column { - id: contentColumn - - width: parent.width - Theme.spacingL * 2 - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - height: 40 - spacing: Theme.spacingM - - DankIcon { - name: "view_quilt" - size: Theme.iconSizeLarge - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSizeLarge - 32 - Theme.spacingM * 2 - - StyledText { - text: I18n.tr("Layout") - font.pixelSize: Theme.fontSizeXLarge - color: Theme.surfaceText - font.weight: Font.Bold - } - - StyledText { - text: root.currentLayoutSymbol - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: closeLayoutArea.containsMouse ? Theme.errorHover : "transparent" - anchors.top: parent.top - - DankIcon { - anchors.centerIn: parent - name: "close" - size: Theme.iconSize - 4 - color: closeLayoutArea.containsMouse ? Theme.error : Theme.surfaceText - } - - MouseArea { - id: closeLayoutArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - root.close(); - } - } - } - } - - StyledText { - text: I18n.tr("Available Layouts") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - font.weight: Font.Medium - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: DwlService.layouts - - delegate: Rectangle { - required property string modelData - required property int index - - property bool isActive: modelData === root.currentLayoutSymbol - - width: parent.width - height: 40 - radius: Theme.cornerRadius - color: layoutArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: root.getLayoutIcon(modelData) - size: 20 - color: parent.parent.isActive ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: root.getLayoutName(modelData) - font.pixelSize: Theme.fontSizeSmall - color: parent.parent.parent.isActive ? Theme.primary : Theme.surfaceText - font.weight: parent.parent.parent.isActive ? Font.Medium : Font.Normal - } - - StyledText { - text: modelData - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - } - } - } - - MouseArea { - id: layoutArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - if (!root.triggerScreen) { - return; - } - if (!DwlService.dwlAvailable) { - return; - } - - DwlService.setLayout(root.triggerScreen.name, index); - root.close(); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - - StyledText { - text: I18n.tr("Right-click bar widget to cycle") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/VpnPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/VpnPopout.qml deleted file mode 100644 index 064f578..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Popouts/VpnPopout.qml +++ /dev/null @@ -1,87 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:vpn" - - Ref { - service: DMSNetworkService - } - - property bool wasVisible: false - property var triggerScreen: null - - popupWidth: 380 - popupHeight: Math.min((screen ? screen.height : Screen.height) - 100, contentLoader.item ? contentLoader.item.implicitHeight : 320) - triggerWidth: 70 - screen: triggerScreen - shouldBeVisible: false - - onShouldBeVisibleChanged: { - if (shouldBeVisible && !wasVisible) { - DMSNetworkService.getState(); - } - wasVisible = shouldBeVisible; - } - - onBackgroundClicked: close() - - content: Component { - Rectangle { - id: content - - implicitHeight: contentColumn.height + Theme.spacingL * 2 - color: "transparent" - focus: true - - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - root.close(); - event.accepted = true; - } - } - - Column { - id: contentColumn - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - RowLayout { - width: parent.width - height: 32 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("VPN Connections") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - Layout.fillWidth: true - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.close() - } - } - - VpnDetailContent { - width: parent.width - listHeight: 200 - parentPopout: root - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/RightSection.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/RightSection.qml deleted file mode 100644 index 58844bc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/RightSection.qml +++ /dev/null @@ -1,121 +0,0 @@ -import QtQuick -import qs.Common - -Item { - id: root - - property var widgetsModel: null - property var components: null - property bool noBackground: false - required property var axis - property var parentScreen: null - property real widgetThickness: 30 - property real barThickness: 48 - property real barSpacing: 4 - property var barConfig: null - property var blurBarWindow: null - property bool overrideAxisLayout: false - property bool forceVerticalLayout: false - - readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false) - - implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0 - implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0 - - Loader { - id: layoutLoader - width: parent.width - height: parent.height - sourceComponent: root.isVertical ? columnComp : rowComp - } - - Component { - id: rowComp - Row { - readonly property real widgetSpacing: { - const baseSpacing = noBackground ? 2 : Theme.spacingXS; - const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return baseSpacing + (outlineThickness * 2); - } - spacing: widgetSpacing - anchors.right: parent ? parent.right : undefined - Repeater { - id: rowRepeater - model: root.widgetsModel - Item { - readonly property real rowSpacing: parent.widgetSpacing - property var itemData: modelData - width: widgetLoader.item ? widgetLoader.item.width : 0 - height: widgetLoader.item ? widgetLoader.item.height : 0 - WidgetHost { - id: widgetLoader - anchors.verticalCenter: parent.verticalCenter - widgetId: itemData.widgetId - widgetData: itemData - spacerSize: itemData.size || 20 - components: root.components - isInColumn: false - axis: root.axis - section: "right" - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - isFirst: index === 0 - isLast: index === rowRepeater.count - 1 - sectionSpacing: parent.rowSpacing - isLeftBarEdge: false - isRightBarEdge: true - } - } - } - } - } - - Component { - id: columnComp - Column { - width: parent.width - readonly property real widgetSpacing: { - const baseSpacing = noBackground ? 2 : Theme.spacingXS; - const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return baseSpacing + (outlineThickness * 2); - } - spacing: widgetSpacing - Repeater { - id: columnRepeater - model: root.widgetsModel - Item { - width: parent.width - readonly property real columnSpacing: parent.widgetSpacing - property var itemData: modelData - height: widgetLoader.item ? widgetLoader.item.height : 0 - WidgetHost { - id: widgetLoader - anchors.horizontalCenter: parent.horizontalCenter - widgetId: itemData.widgetId - widgetData: itemData - spacerSize: itemData.size || 20 - components: root.components - isInColumn: true - axis: root.axis - section: "right" - parentScreen: root.parentScreen - widgetThickness: root.widgetThickness - barThickness: root.barThickness - barSpacing: root.barSpacing - barConfig: root.barConfig - blurBarWindow: root.blurBarWindow - isFirst: index === 0 - isLast: index === columnRepeater.count - 1 - sectionSpacing: parent.columnSpacing - isTopBarEdge: false - isBottomBarEdge: true - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/WidgetHost.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/WidgetHost.qml deleted file mode 100644 index 01d1c73..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/WidgetHost.qml +++ /dev/null @@ -1,290 +0,0 @@ -import QtQuick -import qs.Services - -Loader { - id: root - - property string widgetId: "" - property var widgetData: null - property int spacerSize: 20 - property var components: null - property bool isInColumn: false - property var axis: null - property string section: "center" - property var parentScreen: null - property real widgetThickness: 30 - property real barThickness: 48 - property real barSpacing: 4 - property var barConfig: null - property var blurBarWindow: null - property bool isFirst: false - property bool isLast: false - property real sectionSpacing: 0 - property bool isLeftBarEdge: false - property bool isRightBarEdge: false - property bool isTopBarEdge: false - property bool isBottomBarEdge: false - property string _registeredScreenName: "" - - asynchronous: false - - readonly property bool orientationMatches: (axis?.isVertical ?? false) === isInColumn - - readonly property bool widgetEnabled: widgetData?.enabled !== false - - active: orientationMatches && getWidgetVisible(widgetId, DgopService.dgopAvailable) && (widgetId !== "music" || MprisController.activePlayer !== null) - sourceComponent: getWidgetComponent(widgetId, components) - - signal contentItemReady(var item) - - Binding { - target: root.item - when: root.item && !root.widgetEnabled - property: "visible" - value: false - restoreMode: Binding.RestoreBinding - } - - Binding { - target: root.item - when: root.item && "parentScreen" in root.item - property: "parentScreen" - value: root.parentScreen - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "section" in root.item - property: "section" - value: root.section - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "widgetThickness" in root.item - property: "widgetThickness" - value: root.widgetThickness - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "barThickness" in root.item - property: "barThickness" - value: root.barThickness - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "barSpacing" in root.item - property: "barSpacing" - value: root.barSpacing - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "barConfig" in root.item - property: "barConfig" - value: root.barConfig - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "blurBarWindow" in root.item - property: "blurBarWindow" - value: root.blurBarWindow - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "axis" in root.item - property: "axis" - value: root.axis - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "widgetData" in root.item - property: "widgetData" - value: root.widgetData - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isFirst" in root.item - property: "isFirst" - value: root.isFirst - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isLast" in root.item - property: "isLast" - value: root.isLast - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "sectionSpacing" in root.item - property: "sectionSpacing" - value: root.sectionSpacing - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isLeftBarEdge" in root.item - property: "isLeftBarEdge" - value: root.isLeftBarEdge - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isRightBarEdge" in root.item - property: "isRightBarEdge" - value: root.isRightBarEdge - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isTopBarEdge" in root.item - property: "isTopBarEdge" - value: root.isTopBarEdge - restoreMode: Binding.RestoreNone - } - - Binding { - target: root.item - when: root.item && "isBottomBarEdge" in root.item - property: "isBottomBarEdge" - value: root.isBottomBarEdge - restoreMode: Binding.RestoreNone - } - - onLoaded: { - if (!item) - return; - - contentItemReady(item); - - if (axis && "isVertical" in item) { - try { - item.isVertical = axis.isVertical; - } catch (e) {} - } - - if (item.pluginService !== undefined) { - var parts = widgetId.split(":"); - var pluginId = parts[0]; - var variantId = parts.length > 1 ? parts[1] : null; - - if (item.pluginId !== undefined) - item.pluginId = pluginId; - if (item.variantId !== undefined) - item.variantId = variantId; - if (item.variantData !== undefined && variantId) - item.variantData = PluginService.getPluginVariantData(pluginId, variantId); - item.pluginService = PluginService; - } - - if (item.popoutService !== undefined) - item.popoutService = PopoutService; - - registerWidgetIfEligible(); - } - - Component.onDestruction: { - unregisterWidget(); - } - - function registerWidgetIfEligible() { - if (!item || !widgetId || !parentScreen?.name) - return; - - const hasPopout = item.popoutTarget !== undefined || typeof item.triggerPopout === "function" || typeof item.clicked === "function"; - if (!hasPopout) - return; - - _registeredScreenName = parentScreen.name; - BarWidgetService.registerWidget(widgetId, _registeredScreenName, item); - } - - function unregisterWidget() { - if (!widgetId || !_registeredScreenName) - return; - - BarWidgetService.unregisterWidget(widgetId, _registeredScreenName); - _registeredScreenName = ""; - } - - function getWidgetComponent(widgetId, components) { - const componentMap = { - "launcherButton": components.launcherButtonComponent, - "workspaceSwitcher": components.workspaceSwitcherComponent, - "focusedWindow": components.focusedWindowComponent, - "runningApps": components.runningAppsComponent, - "clock": components.clockComponent, - "music": components.mediaComponent, - "weather": components.weatherComponent, - "systemTray": components.systemTrayComponent, - "privacyIndicator": components.privacyIndicatorComponent, - "clipboard": components.clipboardComponent, - "cpuUsage": components.cpuUsageComponent, - "memUsage": components.memUsageComponent, - "diskUsage": components.diskUsageComponent, - "cpuTemp": components.cpuTempComponent, - "gpuTemp": components.gpuTempComponent, - "notificationButton": components.notificationButtonComponent, - "battery": components.batteryComponent, - "controlCenterButton": components.controlCenterButtonComponent, - "capsLockIndicator": components.capsLockIndicatorComponent, - "idleInhibitor": components.idleInhibitorComponent, - "spacer": components.spacerComponent, - "separator": components.separatorComponent, - "network_speed_monitor": components.networkComponent, - "keyboard_layout_name": components.keyboardLayoutNameComponent, - "vpn": components.vpnComponent, - "notepadButton": components.notepadButtonComponent, - "colorPicker": components.colorPickerComponent, - "systemUpdate": components.systemUpdateComponent, - "layout": components.layoutComponent, - "powerMenuButton": components.powerMenuButtonComponent, - "appsDock": components.appsDockComponent - }; - - if (componentMap[widgetId]) { - return componentMap[widgetId]; - } - - var parts = widgetId.split(":"); - var pluginId = parts[0]; - - let pluginMap = PluginService.getWidgetComponents(); - return pluginMap[pluginId] || null; - } - - function getWidgetVisible(widgetId, dgopAvailable) { - const widgetVisibility = { - "cpuUsage": dgopAvailable, - "memUsage": dgopAvailable, - "cpuTemp": dgopAvailable, - "gpuTemp": dgopAvailable, - "network_speed_monitor": dgopAvailable, - "layout": CompositorService.isDwl && DwlService.dwlAvailable - }; - - return widgetVisibility[widgetId] ?? true; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDock.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDock.qml deleted file mode 100644 index 294102d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDock.qml +++ /dev/null @@ -1,1011 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Widgets -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - enableBackgroundHover: false - enableCursor: false - section: "left" - - property var widgetData: null - property var hoveredItem: null - property var topBar: null - property bool isAutoHideBar: false - property Item windowRoot: (Window.window ? Window.window.contentItem : null) - - property int draggedIndex: -1 - property int dropTargetIndex: -1 - property bool suppressShiftAnimation: false - property int pinnedAppCount: 0 - - property int maxVisibleApps: widgetData?.barMaxVisibleApps !== undefined ? widgetData.barMaxVisibleApps : SettingsData.barMaxVisibleApps - property int maxVisibleRunningApps: widgetData?.barMaxVisibleRunningApps !== undefined ? widgetData.barMaxVisibleRunningApps : SettingsData.barMaxVisibleRunningApps - property bool showOverflowBadge: widgetData?.barShowOverflowBadge !== undefined ? widgetData.barShowOverflowBadge : SettingsData.barShowOverflowBadge - property bool overflowExpanded: false - property int overflowItemCount: 0 - - onMaxVisibleAppsChanged: updateModel() - onMaxVisibleRunningAppsChanged: updateModel() - - readonly property real effectiveBarThickness: { - if (barThickness > 0 && barSpacing > 0) { - return barThickness + barSpacing; - } - const innerPadding = barConfig?.innerPadding ?? 4; - const spacing = barConfig?.spacing ?? 4; - return Math.max(26 + innerPadding * 0.6, Theme.barHeight - 4 - (8 - innerPadding)) + spacing; - } - - readonly property var barBounds: { - if (!parentScreen || !barConfig) { - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - const barPosition = axis.edge === "left" ? 2 : (axis.edge === "right" ? 3 : (axis.edge === "top" ? 0 : 1)); - return SettingsData.getBarBounds(parentScreen, effectiveBarThickness, barPosition, barConfig); - } - - readonly property real barY: barBounds.y - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - return effectiveBarThickness; - } - - return 0; - } - - // --- Dock Logic Helpers --- - function movePinnedApp(fromDockIndex, toDockIndex) { - if (fromDockIndex === toDockIndex) - return; - - const currentPinned = [...(SessionData.barPinnedApps || [])]; - if (fromDockIndex < 0 || fromDockIndex >= currentPinned.length || toDockIndex < 0 || toDockIndex >= currentPinned.length) { - return; - } - - const movedApp = currentPinned.splice(fromDockIndex, 1)[0]; - currentPinned.splice(toDockIndex, 0, movedApp); - - SessionData.setBarPinnedApps(currentPinned); - } - - property int _desktopEntriesUpdateTrigger: 0 - property int _toplevelsUpdateTrigger: 0 - property int _appIdSubstitutionsTrigger: 0 - - Connections { - target: CompositorService - function onToplevelsChanged() { - _toplevelsUpdateTrigger++; - updateModel(); - } - } - - Connections { - target: DesktopEntries - function onApplicationsChanged() { - _desktopEntriesUpdateTrigger++; - } - } - - Connections { - target: SettingsData - function onAppIdSubstitutionsChanged() { - _appIdSubstitutionsTrigger++; - updateModel(); - } - function onRunningAppsCurrentWorkspaceChanged() { - updateModel(); - } - function onBarMaxVisibleAppsChanged() { - updateModel(); - } - function onBarMaxVisibleRunningAppsChanged() { - updateModel(); - } - } - - Connections { - target: SessionData - function onBarPinnedAppsChanged() { - root.suppressShiftAnimation = true; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - updateModel(); - Qt.callLater(() => { - root.suppressShiftAnimation = false; - }); - } - } - - property var dockItems: [] - - function isOnScreen(toplevel, screenName) { - if (!toplevel.screens) - return false; - for (let i = 0; i < toplevel.screens.length; i++) { - if (toplevel.screens[i]?.name === screenName) - return true; - } - return false; - } - - function getCoreAppData(appId) { - if (typeof AppSearchService === "undefined") - return null; - const coreApps = AppSearchService.coreApps || []; - for (let i = 0; i < coreApps.length; i++) { - if (coreApps[i].builtInPluginId === appId) - return coreApps[i]; - } - return null; - } - - function getCoreAppDataByTitle(windowTitle) { - if (typeof AppSearchService === "undefined" || !windowTitle) - return null; - const coreApps = AppSearchService.coreApps || []; - for (let i = 0; i < coreApps.length; i++) { - if (coreApps[i].name === windowTitle) - return coreApps[i]; - } - return null; - } - - function createSeparator(key) { - return { - uniqueKey: key, - type: "separator", - appId: "__SEPARATOR__", - toplevel: null, - isPinned: false, - isRunning: false, - isInOverflow: false - }; - } - - function markAsOverflow(item) { - return { - uniqueKey: item.uniqueKey, - type: item.type, - appId: item.appId, - toplevel: item.toplevel, - isPinned: item.isPinned, - isRunning: item.isRunning, - windowCount: item.windowCount, - allWindows: item.allWindows, - isCoreApp: item.isCoreApp, - coreAppData: item.coreAppData, - isInOverflow: true - }; - } - - function markAsVisible(item) { - return { - uniqueKey: item.uniqueKey, - type: item.type, - appId: item.appId, - toplevel: item.toplevel, - isPinned: item.isPinned, - isRunning: item.isRunning, - windowCount: item.windowCount, - allWindows: item.allWindows, - isCoreApp: item.isCoreApp, - coreAppData: item.coreAppData, - isInOverflow: false - }; - } - - function buildBaseItems() { - const items = []; - const pinnedApps = [...(SessionData.barPinnedApps || [])]; - _toplevelsUpdateTrigger; - const allToplevels = CompositorService.sortedToplevels; - - let sortedToplevels = allToplevels; - if (SettingsData.runningAppsCurrentWorkspace && parentScreen) { - sortedToplevels = CompositorService.filterCurrentWorkspace(allToplevels, parentScreen.name) || []; - } - - const appGroups = new Map(); - - pinnedApps.forEach(rawAppId => { - const appId = Paths.moddedAppId(rawAppId); - const coreAppData = getCoreAppData(appId); - appGroups.set(appId, { - appId: appId, - isPinned: true, - windows: [], - isCoreApp: coreAppData !== null, - coreAppData: coreAppData - }); - }); - - sortedToplevels.forEach((toplevel, index) => { - const rawAppId = toplevel.appId || "unknown"; - let appId = Paths.moddedAppId(rawAppId); - - let coreAppData = null; - if (rawAppId === "org.quickshell" || rawAppId === "com.danklinux.dms") { - coreAppData = getCoreAppDataByTitle(toplevel.title); - if (coreAppData) { - appId = coreAppData.builtInPluginId; - } - } - - if (!appGroups.has(appId)) { - appGroups.set(appId, { - appId: appId, - isPinned: false, - windows: [], - isCoreApp: coreAppData !== null, - coreAppData: coreAppData - }); - } - - appGroups.get(appId).windows.push({ - toplevel: toplevel, - index: index, - windowTitle: toplevel.title - }); - }); - - const pinnedGroups = []; - const unpinnedGroups = []; - - Array.from(appGroups.entries()).forEach(([appId, group]) => { - const firstWindow = group.windows.length > 0 ? group.windows[0] : null; - - const item = { - uniqueKey: "grouped_" + appId, - type: "grouped", - appId: appId, - toplevel: firstWindow ? firstWindow.toplevel : null, - isPinned: group.isPinned, - isRunning: group.windows.length > 0, - windowCount: group.windows.length, - allWindows: group.windows, - isCoreApp: group.isCoreApp || false, - coreAppData: group.coreAppData || null, - isInOverflow: false - }; - - if (group.isPinned) { - pinnedGroups.push(item); - } else { - unpinnedGroups.push(item); - } - }); - - pinnedGroups.forEach(item => items.push(item)); - - if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) { - items.push(createSeparator("separator_grouped")); - } - - unpinnedGroups.forEach(item => items.push(item)); - - root.pinnedAppCount = pinnedGroups.length; - return { - items, - pinnedCount: pinnedGroups.length, - runningCount: unpinnedGroups.length - }; - } - - function applyOverflow(baseResult) { - const { - items - } = baseResult; - const maxPinned = root.maxVisibleApps; - const maxRunning = root.maxVisibleRunningApps; - - const pinnedItems = items.filter(i => i.type === "grouped" && i.isPinned); - const runningItems = items.filter(i => i.type === "grouped" && i.isRunning && !i.isPinned); - - const pinnedOverflow = maxPinned > 0 && pinnedItems.length > maxPinned; - const runningOverflow = maxRunning > 0 && runningItems.length > maxRunning; - - if (!pinnedOverflow && !runningOverflow) { - root.overflowItemCount = 0; - return items.map(i => markAsVisible(i)); - } - - const visiblePinnedKeys = new Set(pinnedOverflow ? pinnedItems.slice(0, maxPinned).map(i => i.uniqueKey) : pinnedItems.map(i => i.uniqueKey)); - const visibleRunningKeys = new Set(runningOverflow ? runningItems.slice(0, maxRunning).map(i => i.uniqueKey) : runningItems.map(i => i.uniqueKey)); - - const overflowPinnedCount = pinnedOverflow ? pinnedItems.length - maxPinned : 0; - const overflowRunningCount = runningOverflow ? runningItems.length - maxRunning : 0; - const totalOverflow = overflowPinnedCount + overflowRunningCount; - root.overflowItemCount = totalOverflow; - - const finalItems = []; - let addedSeparator = false; - - for (let i = 0; i < items.length; i++) { - const item = items[i]; - switch (item.type) { - case "separator": - break; - case "grouped": - if (item.isPinned) { - if (visiblePinnedKeys.has(item.uniqueKey)) { - finalItems.push(markAsVisible(item)); - } else { - finalItems.push(markAsOverflow(item)); - } - } else if (item.isRunning) { - if (!addedSeparator && finalItems.length > 0) { - finalItems.push(createSeparator("separator_overflow")); - addedSeparator = true; - } - if (visibleRunningKeys.has(item.uniqueKey)) { - finalItems.push(markAsVisible(item)); - } else { - finalItems.push(markAsOverflow(item)); - } - } - break; - default: - finalItems.push(item); - break; - } - } - - if (totalOverflow > 0) { - const toggleIndex = finalItems.findIndex(i => i.type === "separator"); - const insertPos = toggleIndex >= 0 ? toggleIndex : finalItems.length; - finalItems.splice(insertPos, 0, { - uniqueKey: "overflow_toggle", - type: "overflow-toggle", - appId: "__OVERFLOW_TOGGLE__", - toplevel: null, - isPinned: false, - isRunning: false, - isInOverflow: false, - overflowCount: totalOverflow - }); - } - - return finalItems; - } - - function updateModel() { - const baseResult = buildBaseItems(); - dockItems = applyOverflow(baseResult); - } - - Component.onCompleted: updateModel() - - visible: dockItems.length > 0 - readonly property real iconCellSize: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) + 6 - - content: Component { - Item { - implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0 - implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0 - - Loader { - id: layoutLoader - anchors.centerIn: parent - sourceComponent: root.isVerticalOrientation ? columnLayout : rowLayout - } - } - } - - Component { - id: rowLayout - Row { - spacing: Theme.spacingXS - - Repeater { - id: repeater - model: ScriptModel { - values: root.dockItems - objectProp: "uniqueKey" - } - - delegate: dockDelegate - } - } - } - - Component { - id: columnLayout - Column { - spacing: Theme.spacingXS - - Repeater { - model: ScriptModel { - values: root.dockItems - objectProp: "uniqueKey" - } - delegate: dockDelegate - } - } - } - - Loader { - id: tooltipLoader - active: false - sourceComponent: DankTooltip {} - } - - Component { - id: dockDelegate - Item { - id: delegateItem - property bool isSeparator: modelData.type === "separator" - readonly property bool isOverflowToggle: modelData.type === "overflow-toggle" - readonly property bool isInOverflow: modelData.isInOverflow === true - - readonly property real visualSize: isSeparator ? 8 : ((widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? root.iconCellSize : (root.iconCellSize + Theme.spacingXS + 120)) - readonly property real visualWidth: root.isVerticalOrientation ? root.barThickness : visualSize - readonly property real visualHeight: root.isVerticalOrientation ? visualSize : root.barThickness - - visible: !isInOverflow || root.overflowExpanded - opacity: (isInOverflow && !root.overflowExpanded) ? 0 : 1 - scale: (isInOverflow && !root.overflowExpanded) ? 0.8 : 1 - - width: (isInOverflow && !root.overflowExpanded) ? 0 : visualWidth - height: (isInOverflow && !root.overflowExpanded) ? 0 : visualHeight - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - z: (dragHandler.dragging) ? 100 : 0 - - // --- Drag and Drop Shift Animation Logic --- - property real shiftOffset: { - if (root.draggedIndex < 0 || !modelData.isPinned || isSeparator) - return 0; - if (index === root.draggedIndex) - return 0; - - const dragIdx = root.draggedIndex; - const dropIdx = root.dropTargetIndex; - const myIdx = index; - const shiftAmount = visualSize + Theme.spacingXS; - - if (dropIdx < 0) - return 0; - if (dragIdx < dropIdx && myIdx > dragIdx && myIdx <= dropIdx) - return -shiftAmount; - if (dragIdx > dropIdx && myIdx >= dropIdx && myIdx < dragIdx) - return shiftAmount; - return 0; - } - - transform: Translate { - x: root.isVerticalOrientation ? 0 : delegateItem.shiftOffset - y: root.isVerticalOrientation ? delegateItem.shiftOffset : 0 - - Behavior on x { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - Behavior on y { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - Rectangle { - visible: isSeparator - width: root.isVerticalOrientation ? root.barThickness * 0.6 : 2 - height: root.isVerticalOrientation ? 2 : root.barThickness * 0.6 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - radius: 1 - anchors.centerIn: parent - } - - AppsDockOverflowButton { - visible: isOverflowToggle - anchors.centerIn: parent - width: delegateItem.visualWidth - height: delegateItem.visualHeight - iconSize: 24 - overflowCount: modelData.overflowCount || 0 - overflowExpanded: root.overflowExpanded - isVertical: root.isVerticalOrientation - showBadge: root.showOverflowBadge - z: 10 - onClicked: { - console.log("Overflow button clicked! Current state:", root.overflowExpanded); - root.overflowExpanded = !root.overflowExpanded; - console.log("New state:", root.overflowExpanded); - } - } - - Item { - id: appItem - visible: !isSeparator && !isOverflowToggle - anchors.fill: parent - - property bool isFocused: { - if (modelData.type === "grouped") { - return modelData.allWindows.some(w => w.toplevel && w.toplevel.activated); - } - return modelData.toplevel ? modelData.toplevel.activated : false; - } - - property var appId: modelData.appId - property int windowCount: modelData.windowCount || (modelData.isRunning ? 1 : 0) - property string windowTitle: { - if (modelData.type === "grouped") { - const active = modelData.allWindows.find(w => w.toplevel && w.toplevel.activated); - if (active) - return active.windowTitle || "(Unnamed)"; - if (modelData.allWindows.length > 0) - return modelData.allWindows[0].windowTitle || "(Unnamed)"; - return ""; - } - return modelData.toplevel ? (modelData.toplevel.title || "(Unnamed)") : ""; - } - - property string tooltipText: { - root._desktopEntriesUpdateTrigger; - const desktopEntry = appId ? DesktopEntries.heuristicLookup(appId) : null; - const appName = appId ? Paths.getAppName(appId, desktopEntry) : "Unknown"; - - if (modelData.type === "grouped" && windowCount > 1) { - return appName + " (" + windowCount + " windows)"; - } - return appName + (windowTitle ? " • " + windowTitle : ""); - } - - readonly property bool enlargeEnabled: (widgetData?.appsDockEnlargeOnHover !== undefined ? widgetData.appsDockEnlargeOnHover : SettingsData.appsDockEnlargeOnHover) - readonly property real enlargeScale: enlargeEnabled && mouseArea.containsMouse ? (widgetData?.appsDockEnlargePercentage !== undefined ? widgetData.appsDockEnlargePercentage : SettingsData.appsDockEnlargePercentage) / 100.0 : 1.0 - readonly property real baseIconSizeMultiplier: (widgetData?.appsDockIconSizePercentage !== undefined ? widgetData.appsDockIconSizePercentage : SettingsData.appsDockIconSizePercentage) / 100.0 - readonly property real effectiveIconSize: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) * baseIconSizeMultiplier - - readonly property color activeOverlayColor: { - switch (SettingsData.appsDockActiveColorMode) { - case "secondary": - return Theme.secondary; - case "primaryContainer": - return Theme.primaryContainer; - case "error": - return Theme.error; - case "success": - return Theme.success; - default: - return Theme.primary; - } - } - - transform: Translate { - x: (dragHandler.dragging && !root.isVerticalOrientation) ? dragHandler.dragAxisOffset : 0 - y: (dragHandler.dragging && root.isVerticalOrientation) ? dragHandler.dragAxisOffset : 0 - } - - Rectangle { - id: visualContent - width: root.isVerticalOrientation ? root.iconCellSize : delegateItem.visualSize - height: root.isVerticalOrientation ? delegateItem.visualSize : root.iconCellSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: { - const colorizeEnabled = (widgetData?.appsDockColorizeActive !== undefined ? widgetData.appsDockColorizeActive : SettingsData.appsDockColorizeActive); - - if (appItem.isFocused && colorizeEnabled) { - return mouseArea.containsMouse ? Theme.withAlpha(Qt.lighter(appItem.activeOverlayColor, 1.3), 0.4) : Theme.withAlpha(appItem.activeOverlayColor, 0.3); - } - return mouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent"; - } - - border.width: dragHandler.dragging ? 2 : 0 - border.color: Theme.primary - opacity: dragHandler.dragging ? 0.8 : 1.0 - - AppIconRenderer { - id: coreIcon - readonly property bool isCompact: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - anchors.left: (root.isVerticalOrientation || isCompact) ? undefined : parent.left - anchors.leftMargin: (root.isVerticalOrientation || isCompact) ? 0 : Theme.spacingXS - anchors.top: (root.isVerticalOrientation && !isCompact) ? parent.top : undefined - anchors.topMargin: (root.isVerticalOrientation && !isCompact) ? Theme.spacingXS : 0 - anchors.centerIn: (root.isVerticalOrientation || isCompact) ? parent : undefined - - iconSize: appItem.effectiveIconSize - materialIconSizeAdjustment: 0 - iconValue: { - if (!modelData || !modelData.isCoreApp || !modelData.coreAppData) - return ""; - const appId = modelData.coreAppData.id || modelData.coreAppData.builtInPluginId; - if ((appId === "dms_settings" || appId === "dms_notepad" || appId === "dms_sysmon") && modelData.coreAppData.cornerIcon) { - return "material:" + modelData.coreAppData.cornerIcon; - } - return modelData.coreAppData.icon || ""; - } - colorOverride: Theme.widgetIconColor - fallbackText: "?" - visible: iconValue !== "" - z: 2 - - transformOrigin: Item.Center - scale: appItem.enlargeScale - Behavior on scale { - NumberAnimation { - duration: 120 - easing.type: Easing.OutCubic - } - } - } - - IconImage { - id: iconImg - readonly property bool isCompact: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - anchors.left: (root.isVerticalOrientation || isCompact) ? undefined : parent.left - anchors.leftMargin: (root.isVerticalOrientation || isCompact) ? 0 : Theme.spacingXS - anchors.top: (root.isVerticalOrientation && !isCompact) ? parent.top : undefined - anchors.topMargin: (root.isVerticalOrientation && !isCompact) ? Theme.spacingXS : 0 - anchors.centerIn: (root.isVerticalOrientation || isCompact) ? parent : undefined - - width: appItem.effectiveIconSize - height: appItem.effectiveIconSize - source: { - root._desktopEntriesUpdateTrigger; - root._appIdSubstitutionsTrigger; - if (!appItem.appId) - return ""; - if (modelData.isCoreApp) - return ""; - const desktopEntry = DesktopEntries.heuristicLookup(appItem.appId); - return Paths.getAppIcon(appItem.appId, desktopEntry); - } - smooth: true - mipmap: true - asynchronous: true - visible: status === Image.Ready && !coreIcon.visible - layer.enabled: appItem.appId === "org.quickshell" || appItem.appId === "com.danklinux.dms" - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - z: 2 - - transformOrigin: Item.Center - scale: appItem.enlargeScale - Behavior on scale { - NumberAnimation { - duration: 120 - easing.type: Easing.OutCubic - } - } - } - - DankIcon { - readonly property bool isCompact: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - anchors.left: (root.isVerticalOrientation || isCompact) ? undefined : parent.left - anchors.leftMargin: (root.isVerticalOrientation || isCompact) ? 0 : Theme.spacingXS - anchors.top: (root.isVerticalOrientation && !isCompact) ? parent.top : undefined - anchors.topMargin: (root.isVerticalOrientation && !isCompact) ? Theme.spacingXS : 0 - anchors.centerIn: (root.isVerticalOrientation || isCompact) ? parent : undefined - - size: appItem.effectiveIconSize - name: "sports_esports" - color: Theme.widgetTextColor - visible: !iconImg.visible && !coreIcon.visible && Paths.isSteamApp(appItem.appId) - - transformOrigin: Item.Center - scale: appItem.enlargeScale - Behavior on scale { - NumberAnimation { - duration: 120 - easing.type: Easing.OutCubic - } - } - } - - Text { - anchors.centerIn: parent - visible: !iconImg.visible && !coreIcon.visible && !Paths.isSteamApp(appItem.appId) - text: { - root._desktopEntriesUpdateTrigger; - if (!appItem.appId) - return "?"; - const desktopEntry = DesktopEntries.heuristicLookup(appItem.appId); - const appName = Paths.getAppName(appItem.appId, desktopEntry); - return appName.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - - transformOrigin: Item.Center - scale: appItem.enlargeScale - Behavior on scale { - NumberAnimation { - duration: 120 - easing.type: Easing.OutCubic - } - } - } - - Rectangle { - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.rightMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? -2 : 2 - anchors.bottomMargin: -2 - width: 14 - height: 14 - radius: 7 - color: Theme.primary - visible: modelData.type === "grouped" && appItem.windowCount > 1 && (widgetData?.barShowOverflowBadge !== undefined ? widgetData.barShowOverflowBadge : SettingsData.barShowOverflowBadge) - z: 10 - - StyledText { - anchors.centerIn: parent - text: appItem.windowCount > 9 ? "9+" : appItem.windowCount - font.pixelSize: 9 - color: Theme.surface - } - } - - StyledText { - visible: !root.isVerticalOrientation && !(widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - anchors.left: iconImg.right - anchors.leftMargin: Theme.spacingXS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: appItem.windowTitle || appItem.appId - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - elide: Text.ElideRight - maximumLineCount: 1 - } - - Rectangle { - visible: modelData.isRunning && !(widgetData?.appsDockHideIndicators !== undefined ? widgetData.appsDockHideIndicators : SettingsData.appsDockHideIndicators) - width: root.isVerticalOrientation ? 2 : 20 - height: root.isVerticalOrientation ? 20 : 2 - radius: 1 - color: appItem.isFocused ? Theme.primary : Theme.surfaceText - opacity: appItem.isFocused ? 1 : 0.5 - - anchors.bottom: root.isVerticalOrientation ? undefined : parent.bottom - anchors.right: root.isVerticalOrientation ? parent.right : undefined - anchors.horizontalCenter: root.isVerticalOrientation ? undefined : parent.horizontalCenter - anchors.verticalCenter: root.isVerticalOrientation ? parent.verticalCenter : undefined - - anchors.margins: 0 - z: 5 - } - } - } - - // Handler for Drag Logic - Item { - id: dragHandler - anchors.fill: parent - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - property bool longPressing: false - - Timer { - id: longPressTimer - interval: 500 - repeat: false - onTriggered: { - if (modelData.isPinned) { - dragHandler.longPressing = true; - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: dragHandler.longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - - onPressed: mouse => { - if (mouse.button === Qt.LeftButton && modelData.isPinned) { - dragHandler.dragStartPos = Qt.point(mouse.x, mouse.y); - longPressTimer.start(); - } - } - - onReleased: mouse => { - longPressTimer.stop(); - const wasDragging = dragHandler.dragging; - const didReorder = wasDragging && root.dropTargetIndex >= 0 && root.dropTargetIndex !== root.draggedIndex; - - if (didReorder) { - root.movePinnedApp(root.draggedIndex, root.dropTargetIndex); - } - - dragHandler.longPressing = false; - dragHandler.dragging = false; - dragHandler.dragAxisOffset = 0; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - if (modelData.type === "grouped") { - if (modelData.windowCount === 0) { - if (modelData.isCoreApp && modelData.coreAppData) { - AppSearchService.executeCoreApp(modelData.coreAppData); - } else { - const moddedId = Paths.moddedAppId(modelData.appId); - const desktopEntry = DesktopEntries.heuristicLookup(moddedId); - if (desktopEntry) - SessionService.launchDesktopEntry(desktopEntry); - } - } else if (modelData.windowCount === 1) { - if (modelData.allWindows[0].toplevel) - modelData.allWindows[0].toplevel.activate(); - } else { - let currentIndex = -1; - for (var i = 0; i < modelData.allWindows.length; i++) { - if (modelData.allWindows[i].toplevel.activated) { - currentIndex = i; - break; - } - } - const nextIndex = (currentIndex + 1) % modelData.allWindows.length; - modelData.allWindows[nextIndex].toplevel.activate(); - } - } - } - - onPositionChanged: mouse => { - if (dragHandler.longPressing && !dragHandler.dragging) { - const distance = Math.sqrt(Math.pow(mouse.x - dragHandler.dragStartPos.x, 2) + Math.pow(mouse.y - dragHandler.dragStartPos.y, 2)); - if (distance > 5) { - dragHandler.dragging = true; - root.draggedIndex = index; - root.dropTargetIndex = index; - } - } - - if (!dragHandler.dragging) - return; - - const axisOffset = root.isVerticalOrientation ? (mouse.y - dragHandler.dragStartPos.y) : (mouse.x - dragHandler.dragStartPos.x); - dragHandler.dragAxisOffset = axisOffset; - - const itemSize = (root.isVerticalOrientation ? delegateItem.height : delegateItem.width) + Theme.spacingXS; - const slotOffset = Math.round(axisOffset / itemSize); - const newTargetIndex = Math.max(0, Math.min(root.pinnedAppCount - 1, index + slotOffset)); - - if (newTargetIndex !== root.dropTargetIndex) { - root.dropTargetIndex = newTargetIndex; - } - } - - onEntered: { - root.hoveredItem = delegateItem; - if (isSeparator || isOverflowToggle) - return; - - tooltipLoader.active = true; - if (tooltipLoader.item) { - if (root.isVerticalOrientation) { - const globalPos = delegateItem.mapToGlobal(0, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const isLeft = root.axis?.edge === "left"; - const tooltipX = isLeft ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - const screenRelativeY = globalPos.y - screenY + root.minTooltipY; - tooltipLoader.item.show(appItem.tooltipText, screenX + tooltipX, screenRelativeY, root.parentScreen, isLeft, !isLeft); - } else { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height); - const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height; - const isBottom = root.axis?.edge === "bottom"; - const tooltipY = isBottom ? (screenHeight - root.barThickness - root.barSpacing - Theme.spacingXS - 35) : (root.barThickness + root.barSpacing + Theme.spacingXS); - tooltipLoader.item.show(appItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false); - } - } - } - onExited: { - if (root.hoveredItem === delegateItem) { - root.hoveredItem = null; - if (tooltipLoader.item) - tooltipLoader.item.hide(); - tooltipLoader.active = false; - } - } - - onClicked: mouse => { - if (mouse.button === Qt.RightButton) { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - contextMenuLoader.active = true; - - if (contextMenuLoader.item) { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const isBarVertical = root.axis?.isVertical ?? false; - const barEdge = root.axis?.edge ?? "top"; - - let x = globalPos.x - screenX; - let y = globalPos.y - screenY; - - switch (barEdge) { - case "bottom": - y = (root.parentScreen ? root.parentScreen.height : Screen.height) - root.barThickness - root.barSpacing; - break; - case "top": - y = root.barThickness + root.barSpacing; - break; - case "left": - x = root.barThickness + root.barSpacing; - break; - case "right": - x = (root.parentScreen ? root.parentScreen.width : Screen.width) - root.barThickness - root.barSpacing; - break; - } - - const shouldHidePin = modelData.appId === "org.quickshell" || modelData.appId === "com.danklinux.dms"; - const moddedId = Paths.moddedAppId(modelData.appId); - const desktopEntry = moddedId ? DesktopEntries.heuristicLookup(moddedId) : null; - - contextMenuLoader.item.showAt(x, y, isBarVertical, barEdge, modelData, shouldHidePin, desktopEntry, root.parentScreen); - } - } - } - } - } - } - } - - Loader { - id: contextMenuLoader - active: false - source: "AppsDockContextMenu.qml" - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml deleted file mode 100644 index 46c4f69..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockContextMenu.qml +++ /dev/null @@ -1,486 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Common -import qs.Services -import qs.Widgets - -PanelWindow { - id: root - - WlrLayershell.namespace: "dms:dock-context-menu" - - property var appData: null - property var anchorItem: null - property int margin: 10 - property bool hidePin: false - property var desktopEntry: null - property bool isDmsWindow: appData?.appId === "org.quickshell" || appData?.appId === "com.danklinux.dms" - - property bool isVertical: false - property string edge: "top" - property point anchorPos: Qt.point(0, 0) - - function showAt(x, y, vertical, barEdge, data, hidePinOption, entry, targetScreen) { - if (targetScreen) { - root.screen = targetScreen; - } - - anchorPos = Qt.point(x, y); - isVertical = vertical ?? false; - edge = barEdge ?? "top"; - - appData = data; - hidePin = hidePinOption || false; - desktopEntry = entry || null; - - visible = true; - - if (targetScreen) { - TrayMenuManager.registerMenu(targetScreen.name, root); - } - } - - function close() { - visible = false; - - if (root.screen) { - TrayMenuManager.unregisterMenu(root.screen.name); - } - } - - screen: null - visible: false - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - anchors { - top: true - left: true - right: true - bottom: true - } - - Component.onDestruction: { - if (root.screen) { - TrayMenuManager.unregisterMenu(root.screen.name); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - root.close(); - } - } - - Rectangle { - id: menuContainer - - x: { - if (root.isVertical) { - if (root.edge === "left") { - return Math.min(root.width - width - 10, root.anchorPos.x); - } else { - return Math.max(10, root.anchorPos.x - width); - } - } else { - const left = 10; - const right = root.width - width - 10; - const want = root.anchorPos.x - width / 2; - return Math.max(left, Math.min(right, want)); - } - } - y: { - if (root.isVertical) { - const top = 10; - const bottom = root.height - height - 10; - const want = root.anchorPos.y - height / 2; - return Math.max(top, Math.min(bottom, want)); - } else { - if (root.edge === "top") { - return Math.min(root.height - height - 10, root.anchorPos.y); - } else { - return Math.max(10, root.anchorPos.y - height); - } - } - } - - width: Math.min(400, Math.max(180, menuColumn.implicitWidth + Theme.spacingS * 2)) - height: Math.max(60, menuColumn.implicitHeight + Theme.spacingS * 2) - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 1 - - opacity: root.visible ? 1 : 0 - visible: opacity > 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: -1 - } - - Column { - id: menuColumn - width: parent.width - Theme.spacingS * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - spacing: 1 - - // Window list for grouped apps - Repeater { - model: { - if (!root.appData || root.appData.type !== "grouped") - return []; - - const toplevels = []; - const allToplevels = ToplevelManager.toplevels.values; - for (let i = 0; i < allToplevels.length; i++) { - const toplevel = allToplevels[i]; - if (toplevel.appId === root.appData.appId) { - toplevels.push(toplevel); - } - } - return toplevels; - } - - Rectangle { - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: windowArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: closeButton.left - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - text: (modelData && modelData.title) ? modelData.title : I18n.tr("(Unnamed)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - Rectangle { - id: closeButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: 20 - height: 20 - radius: 10 - color: closeMouseArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.2) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "close" - size: 12 - color: closeMouseArea.containsMouse ? Theme.error : Theme.surfaceText - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData && modelData.close) { - modelData.close(); - } - root.close(); - } - } - } - - DankRipple { - id: windowRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: windowArea - anchors.fill: parent - anchors.rightMargin: 24 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => windowRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (modelData && modelData.activate) { - modelData.activate(); - } - root.close(); - } - } - } - } - - Rectangle { - visible: { - if (!root.appData) - return false; - if (root.appData.type !== "grouped") - return false; - return root.appData.windowCount > 0; - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Repeater { - model: root.desktopEntry && root.desktopEntry.actions ? root.desktopEntry.actions : [] - - Rectangle { - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: actionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Item { - anchors.verticalCenter: parent.verticalCenter - width: 16 - height: 16 - visible: modelData.icon && modelData.icon !== "" - - IconImage { - anchors.fill: parent - source: modelData.icon ? Paths.resolveIconPath(modelData.icon) : "" - smooth: true - asynchronous: true - visible: status === Image.Ready - } - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: modelData.name || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - - DankRipple { - id: actionRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: actionArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => actionRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (modelData) { - SessionService.launchDesktopAction(root.desktopEntry, modelData); - } - root.close(); - } - } - } - } - - Rectangle { - visible: { - if (!root.desktopEntry?.actions || root.desktopEntry.actions.length === 0) { - return false; - } - return !root.hidePin || (!root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand); - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Rectangle { - visible: !root.hidePin - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: pinArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: root.appData && root.appData.isPinned ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - DankRipple { - id: pinRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: pinArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (!root.appData) { - return; - } - if (root.appData.isPinned) { - SessionData.removeBarPinnedApp(root.appData.appId); - } else { - SessionData.addBarPinnedApp(root.appData.appId); - } - root.close(); - } - } - } - - Rectangle { - visible: { - const hasNvidia = !root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand; - const hasWindow = root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0)); - const hasPinOption = !root.hidePin; - const hasContentAbove = hasPinOption || hasNvidia; - return hasContentAbove && hasWindow; - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Rectangle { - visible: !root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: nvidiaArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Launch on dGPU") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - DankRipple { - id: nvidiaRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: nvidiaArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => nvidiaRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (root.desktopEntry) { - SessionService.launchDesktopEntry(root.desktopEntry, true); - } - root.close(); - } - } - } - - Rectangle { - visible: root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0)) - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: closeArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: { - if (root.appData && root.appData.type === "grouped") { - return I18n.tr("Close All Windows"); - } - return I18n.tr("Close Window"); - } - font.pixelSize: Theme.fontSizeSmall - color: closeArea.containsMouse ? Theme.error : Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - DankRipple { - id: closeRipple - rippleColor: Theme.error - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: closeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => closeRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (root.appData?.type === "window") { - root.appData?.toplevel?.close(); - } else if (root.appData?.type === "grouped") { - root.appData?.allWindows?.forEach(window => window.toplevel?.close()); - } - root.close(); - } - } - } - } - } - - MouseArea { - anchors.fill: parent - z: -1 - onClicked: root.close() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockOverflowButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockOverflowButton.qml deleted file mode 100644 index 82c78d0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AppsDockOverflowButton.qml +++ /dev/null @@ -1,76 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Item { - id: root - - property real iconSize: 24 - property int overflowCount: 0 - property bool overflowExpanded: false - property bool isVertical: false - property bool showBadge: true - - signal clicked - - Rectangle { - id: buttonBackground - anchors.centerIn: parent - width: root.iconSize - height: root.iconSize - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, mouseArea.containsMouse ? 0.2 : 0.1) - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - DankIcon { - id: arrowIcon - anchors.centerIn: parent - size: root.iconSize * 0.6 - name: "expand_more" - color: Theme.widgetIconColor - rotation: isVertical ? (overflowExpanded ? 180 : 0) : (overflowExpanded ? 90 : -90) - - Behavior on rotation { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - } - } - - Rectangle { - visible: overflowCount > 0 && !overflowExpanded && root.showBadge - anchors.right: buttonBackground.right - anchors.top: buttonBackground.top - anchors.rightMargin: -4 - anchors.topMargin: -4 - width: Math.max(18, badgeText.width + 8) - height: 18 - radius: 9 - color: Theme.primary - z: 10 - - StyledText { - id: badgeText - anchors.centerIn: parent - text: `+${overflowCount}` - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: Theme.onPrimary - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AudioVisualization.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AudioVisualization.qml deleted file mode 100644 index 52ace33..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/AudioVisualization.qml +++ /dev/null @@ -1,94 +0,0 @@ -import QtQuick -import Quickshell.Services.Mpris -import qs.Common -import qs.Services - -Item { - id: root - - readonly property MprisPlayer activePlayer: MprisController.activePlayer - readonly property bool hasActiveMedia: activePlayer !== null - readonly property bool isPlaying: hasActiveMedia && activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing - - width: 20 - height: Theme.iconSize - - Loader { - active: isPlaying - - sourceComponent: Component { - Ref { - service: CavaService - } - } - } - - readonly property real maxBarHeight: Theme.iconSize - 2 - readonly property real minBarHeight: 3 - readonly property real heightRange: maxBarHeight - minBarHeight - property var barHeights: [minBarHeight, minBarHeight, minBarHeight, minBarHeight, minBarHeight, minBarHeight] - - Timer { - id: fallbackTimer - - running: !CavaService.cavaAvailable && isPlaying - interval: 500 - repeat: true - onTriggered: { - CavaService.values = [Math.random() * 20 + 5, Math.random() * 25 + 8, Math.random() * 22 + 6, Math.random() * 20 + 5, Math.random() * 22 + 6, Math.random() * 25 + 8]; - } - } - - Connections { - target: CavaService - function onValuesChanged() { - if (!root.isPlaying) { - root.barHeights = [root.minBarHeight, root.minBarHeight, root.minBarHeight, root.minBarHeight, root.minBarHeight, root.minBarHeight]; - return; - } - - const newHeights = []; - for (let i = 0; i < 6; i++) { - if (CavaService.values.length <= i) { - newHeights.push(root.minBarHeight); - continue; - } - - const rawLevel = CavaService.values[i]; - if (rawLevel <= 0) { - newHeights.push(root.minBarHeight); - } else if (rawLevel >= 100) { - newHeights.push(root.maxBarHeight); - } else { - newHeights.push(root.minBarHeight + Math.sqrt(rawLevel * 0.01) * root.heightRange); - } - } - root.barHeights = newHeights; - } - } - - Row { - anchors.centerIn: parent - spacing: 1.5 - - Repeater { - model: 6 - - Rectangle { - width: 2 - height: root.barHeights[index] - radius: 1.5 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - - Behavior on height { - enabled: root.isPlaying && !CavaService.cavaAvailable - NumberAnimation { - duration: 100 - easing.type: Easing.Linear - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Battery.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Battery.qml deleted file mode 100644 index 51d4b54..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Battery.qml +++ /dev/null @@ -1,165 +0,0 @@ -import QtQuick -import Quickshell.Services.UPower -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: battery - - property bool batteryPopupVisible: false - property var popoutTarget: null - - property real touchpadAccumulator: 0 - - readonly property int barPosition: { - switch (axis?.edge) { - case "top": - return 0; - case "bottom": - return 1; - case "left": - return 2; - case "right": - return 3; - default: - return 0; - } - } - - signal toggleBatteryPopup - - visible: true - - content: Component { - Item { - implicitWidth: battery.isVerticalOrientation ? (battery.widgetThickness - battery.horizontalPadding * 2) : batteryContent.implicitWidth - implicitHeight: battery.isVerticalOrientation ? batteryColumn.implicitHeight : (battery.widgetThickness - battery.horizontalPadding * 2) - - Column { - id: batteryColumn - visible: battery.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: BatteryService.getBatteryIcon() - size: Theme.barIconSize(battery.barThickness, undefined, battery.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (!BatteryService.batteryAvailable) { - return Theme.widgetIconColor; - } - - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - - if (BatteryService.isCharging || BatteryService.isPluggedIn) { - return Theme.primary; - } - - return Theme.widgetIconColor; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: BatteryService.batteryLevel.toString() - font.pixelSize: Theme.barTextSize(battery.barThickness, battery.barConfig?.fontScale, battery.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - visible: BatteryService.batteryAvailable - } - } - - Row { - id: batteryContent - visible: !battery.isVerticalOrientation - anchors.centerIn: parent - spacing: (barConfig?.noBackground ?? false) ? 1 : 2 - - DankIcon { - name: BatteryService.getBatteryIcon() - size: Theme.barIconSize(battery.barThickness, -4, battery.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (!BatteryService.batteryAvailable) { - return Theme.widgetIconColor; - } - - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - - if (BatteryService.isCharging || BatteryService.isPluggedIn) { - return Theme.primary; - } - - return Theme.widgetIconColor; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: `${BatteryService.batteryLevel}%` - font.pixelSize: Theme.barTextSize(battery.barThickness, battery.barConfig?.fontScale, battery.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable - } - } - } - } - - MouseArea { - x: -battery.leftMargin - y: -battery.topMargin - width: battery.width + battery.leftMargin + battery.rightMargin - height: battery.height + battery.topMargin + battery.bottomMargin - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - battery.triggerRipple(this, mouse.x, mouse.y); - toggleBatteryPopup(); - } - onWheel: wheel => { - var delta = wheel.angleDelta.y; - if (delta === 0) - return; - - // Check if this is a touchpad - if (delta !== 120 && delta !== -120) { - touchpadAccumulator += delta; - console.info("Acc: "+touchpadAccumulator); - if (Math.abs(touchpadAccumulator) < 500) - return; - delta = touchpadAccumulator; - touchpadAccumulator = 0; - } - console.info("Trigger! Delta: "+delta) - - // This is after the other delta checks so it only shows on valid Y scroll - if (typeof PowerProfiles === "undefined") { - ToastService.showError("power-profiles-daemon not available"); - return; - } - - // Get list of profiles, and current index - const profiles = [PowerProfile.PowerSaver, PowerProfile.Balanced].concat(PowerProfiles.hasPerformanceProfile ? [PowerProfile.Performance] : []); - var index = profiles.findIndex(profile => PowerProfiles.profile === profile); - - // Step once based on mouse wheel direction - if (delta > 0) index += 1; - else index -= 1; - - // Already at end of list, can't go further - if (index < 0 || index >= profiles.length) return; - - // Set new profile - PowerProfiles.profile = profiles[index]; - if (PowerProfiles.profile !== profiles[index]) { - ToastService.showError("Failed to set power profile"); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CapsLockIndicator.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CapsLockIndicator.qml deleted file mode 100644 index ada41dd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CapsLockIndicator.qml +++ /dev/null @@ -1,62 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - opacity: DMSService.capsLockState ? 1 : 0 - - states: [ - State { - name: "hidden_horizontal" - when: !DMSService.capsLockState && !isVerticalOrientation - PropertyChanges { - target: root - width: 0 - } - }, - State { - name: "hidden_vertical" - when: !DMSService.capsLockState && isVerticalOrientation - PropertyChanges { - target: root - height: 0 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "width,height" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - anchors.centerIn: parent - name: "shift_lock" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.primary - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml deleted file mode 100644 index e970662..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ClipboardButton.qml +++ /dev/null @@ -1,314 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - property bool isAutoHideBar: false - - signal clipboardClicked - signal showSavedItemsRequested - signal clearAllRequested - - readonly property real minTooltipY: { - if (!parentScreen || !(axis?.isVertical ?? false)) { - return 0; - } - if (isAutoHideBar) { - return 0; - } - if (parentScreen.y > 0) { - return barThickness + barSpacing; - } - return 0; - } - - function clamp(value, minValue, maxValue) { - return Math.max(minValue, Math.min(maxValue, value)); - } - - function openContextMenu() { - const screen = root.parentScreen || Screen; - const screenX = screen.x || 0; - const screenY = screen.y || 0; - const isVertical = root.axis?.isVertical ?? false; - const edge = root.axis?.edge ?? "top"; - const gap = Math.max(Theme.spacingXS, root.barSpacing ?? Theme.spacingXS); - - const globalPos = root.mapToGlobal(root.width / 2, root.height / 2); - const relativeX = globalPos.x - screenX; - const relativeY = globalPos.y - screenY; - - let anchorX = relativeX; - let anchorY = relativeY; - - if (isVertical) { - anchorX = edge === "left" ? (root.barThickness + root.barSpacing + gap) : (screen.width - (root.barThickness + root.barSpacing + gap)); - anchorY = relativeY + root.minTooltipY; - } else { - anchorX = relativeX; - anchorY = edge === "bottom" ? (screen.height - (root.barThickness + root.barSpacing + gap)) : (root.barThickness + root.barSpacing + gap); - } - - contextMenuWindow.showAt(anchorX, anchorY, isVertical, edge, screen); - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton - cursorShape: Qt.PointingHandCursor - onPressed: mouse => root.triggerRipple(this, mouse.x, mouse.y) - onClicked: function (mouse) { - switch (mouse.button) { - case Qt.RightButton: - openContextMenu(); - break; - case Qt.LeftButton: - clipboardClicked(); - break; - } - } - } - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - anchors.centerIn: parent - name: "content_paste" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetIconColor - } - } - } - - PanelWindow { - id: contextMenuWindow - - WindowBlur { - targetWindow: contextMenuWindow - blurX: menuContainer.x - blurY: menuContainer.y - blurWidth: contextMenuWindow.visible ? menuContainer.width : 0 - blurHeight: contextMenuWindow.visible ? menuContainer.height : 0 - blurRadius: Theme.cornerRadius - } - - WlrLayershell.namespace: "dms:clipboard-context-menu" - - property bool isVertical: false - property string edge: "top" - property point anchorPos: Qt.point(0, 0) - - function showAt(x, y, vertical, barEdge, targetScreen) { - if (targetScreen) { - contextMenuWindow.screen = targetScreen; - } - - anchorPos = Qt.point(x, y); - isVertical = vertical ?? false; - edge = barEdge ?? "top"; - - visible = true; - - if (contextMenuWindow.screen) { - TrayMenuManager.registerMenu(contextMenuWindow.screen.name, contextMenuWindow); - } - } - - function closeMenu() { - visible = false; - - if (contextMenuWindow.screen) { - TrayMenuManager.unregisterMenu(contextMenuWindow.screen.name); - } - } - - screen: null - visible: false - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - anchors { - top: true - left: true - right: true - bottom: true - } - - Component.onDestruction: { - if (contextMenuWindow.screen) { - TrayMenuManager.unregisterMenu(contextMenuWindow.screen.name); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - contextMenuWindow.closeMenu(); - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: contextMenuWindow.closeMenu() - } - - Rectangle { - id: menuContainer - - x: { - if (contextMenuWindow.isVertical) { - if (contextMenuWindow.edge === "left") { - return Math.min(contextMenuWindow.width - width - 10, contextMenuWindow.anchorPos.x); - } - return Math.max(10, contextMenuWindow.anchorPos.x - width); - } - const left = 10; - const right = contextMenuWindow.width - width - 10; - const want = contextMenuWindow.anchorPos.x - width / 2; - return Math.max(left, Math.min(right, want)); - } - y: { - if (contextMenuWindow.isVertical) { - const top = 10; - const bottom = contextMenuWindow.height - height - 10; - const want = contextMenuWindow.anchorPos.y - height / 2; - return Math.max(top, Math.min(bottom, want)); - } - if (contextMenuWindow.edge === "top") { - return Math.min(contextMenuWindow.height - height - 10, contextMenuWindow.anchorPos.y); - } - return Math.max(10, contextMenuWindow.anchorPos.y - height); - } - - width: Math.min(240, Math.max(170, menuColumn.implicitWidth + Theme.spacingS * 2)) - height: Math.max(64, menuColumn.implicitHeight + Theme.spacingS * 2) - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: BlurService.enabled ? BlurService.borderWidth : 1 - - opacity: contextMenuWindow.visible ? 1 : 0 - visible: opacity > 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: -1 - } - - Column { - id: menuColumn - width: parent.width - Theme.spacingS * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - spacing: 1 - - Rectangle { - id: clearAllItem - width: parent.width - height: 30 - radius: Theme.cornerRadius - color: clearAllArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "delete_sweep" - size: 16 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Clear All") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - - MouseArea { - id: clearAllArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - contextMenuWindow.closeMenu(); - root.clearAllRequested(); - } - } - } - - Rectangle { - id: savedItemsItem - width: parent.width - height: 30 - radius: Theme.cornerRadius - color: savedItemsArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "push_pin" - size: 16 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Show Saved Items") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - - MouseArea { - id: savedItemsArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - contextMenuWindow.closeMenu(); - root.showSavedItemsRequested(); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Clock.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Clock.qml deleted file mode 100644 index c49221e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Clock.qml +++ /dev/null @@ -1,331 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Modules.Plugins -import qs.Widgets - -BasePill { - id: root - - property var widgetData: null - property bool compactMode: false - signal clockClicked - - onClicked: clockClicked() - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : clockRow.implicitWidth - implicitHeight: root.isVerticalOrientation ? clockColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - readonly property bool compact: widgetData?.clockCompactMode !== undefined ? widgetData.clockCompactMode : SettingsData.clockCompactMode - - Column { - id: clockColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 0 - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: { - const hours = systemClock?.date?.getHours(); - if (SettingsData.use24HourClock) - return String(hours).padStart(2, '0').charAt(0); - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; - return String(display).padStart(2, '0').charAt(0); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - - StyledText { - text: { - const hours = systemClock?.date?.getHours(); - if (SettingsData.use24HourClock) - return String(hours).padStart(2, '0').charAt(1); - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; - return String(display).padStart(2, '0').charAt(1); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - } - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0) - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - - StyledText { - text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1) - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - } - - Row { - visible: SettingsData.showSeconds - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(0) - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - - StyledText { - text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(1) - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - } - - Item { - width: parent.width - height: Theme.spacingM - anchors.horizontalCenter: parent.horizontalCenter - visible: !compact - - Rectangle { - width: parent.width * 0.6 - height: 1 - color: Theme.outlineButton - anchors.centerIn: parent - } - } - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - visible: !compact - - StyledText { - text: { - const locale = I18n.locale(); - const dateFormatShort = locale.dateFormat(Locale.ShortFormat); - const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M'); - const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0'); - return value.charAt(0); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.primary - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - - StyledText { - text: { - const locale = I18n.locale(); - const dateFormatShort = locale.dateFormat(Locale.ShortFormat); - const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M'); - const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0'); - return value.charAt(1); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.primary - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - } - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - visible: !compact - - StyledText { - text: { - const locale = I18n.locale(); - const dateFormatShort = locale.dateFormat(Locale.ShortFormat); - const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M'); - const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0'); - return value.charAt(0); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.primary - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - - StyledText { - text: { - const locale = I18n.locale(); - const dateFormatShort = locale.dateFormat(Locale.ShortFormat); - const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M'); - const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0'); - return value.charAt(1); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.primary - width: Math.round(font.pixelSize * 0.6) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignBottom - } - } - } - - Row { - id: clockRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingS - - property real fontSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - property real digitWidth: fontSize * 0.6 - - property string hoursStr: { - const hours = systemClock?.date?.getHours() ?? 0; - if (SettingsData.use24HourClock) - return String(hours).padStart(2, '0'); - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; - if (SettingsData.padHours12Hour) - return String(display).padStart(2, '0'); - return String(display); - } - property string minutesStr: String(systemClock?.date?.getMinutes() ?? 0).padStart(2, '0') - property string secondsStr: String(systemClock?.date?.getSeconds() ?? 0).padStart(2, '0') - property string ampmStr: { - if (SettingsData.use24HourClock) - return ""; - const hours = systemClock?.date?.getHours() ?? 0; - return hours >= 12 ? " PM" : " AM"; - } - - Row { - spacing: 0 - anchors.verticalCenter: parent.verticalCenter - - StyledText { - visible: clockRow.hoursStr.length > 1 - text: clockRow.hoursStr.charAt(0) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: clockRow.hoursStr.length > 1 ? clockRow.hoursStr.charAt(1) : clockRow.hoursStr.charAt(0) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: ":" - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - } - - StyledText { - text: clockRow.minutesStr.charAt(0) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: clockRow.minutesStr.charAt(1) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - visible: SettingsData.showSeconds - text: ":" - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - } - - StyledText { - visible: SettingsData.showSeconds - text: clockRow.secondsStr.charAt(0) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - visible: SettingsData.showSeconds - text: clockRow.secondsStr.charAt(1) - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - width: clockRow.digitWidth - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - visible: !SettingsData.use24HourClock - text: clockRow.ampmStr - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - } - } - - StyledText { - id: middleDot - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.outlineButton - anchors.verticalCenter: parent.verticalCenter - visible: !compact - } - - StyledText { - id: dateText - text: { - if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0) { - return systemClock?.date?.toLocaleDateString(I18n.locale(), SettingsData.clockDateFormat); - } - return systemClock?.date?.toLocaleDateString(I18n.locale(), "ddd d"); - } - font.pixelSize: clockRow.fontSize - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - visible: !compact - } - } - - SystemClock { - id: systemClock - precision: SettingsData.showSeconds ? SystemClock.Seconds : SystemClock.Minutes - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ColorPicker.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ColorPicker.qml deleted file mode 100644 index d3330cd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ColorPicker.qml +++ /dev/null @@ -1,37 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - - signal colorPickerRequested - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - anchors.centerIn: parent - name: "palette" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: root.isActive ? Theme.primary : Theme.surfaceText - } - } - } - - MouseArea { - z: 1 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - root.colorPickerRequested(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml deleted file mode 100644 index 5413d20..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml +++ /dev/null @@ -1,830 +0,0 @@ -pragma ComponentBehavior: Bound -import QtQuick -import Quickshell -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - property var popoutTarget: null - property var widgetData: null - property string screenName: "" - property string screenModel: "" - property bool showNetworkIcon: widgetData?.showNetworkIcon !== undefined ? widgetData.showNetworkIcon : SettingsData.controlCenterShowNetworkIcon - property bool showBluetoothIcon: widgetData?.showBluetoothIcon !== undefined ? widgetData.showBluetoothIcon : SettingsData.controlCenterShowBluetoothIcon - property bool showAudioIcon: widgetData?.showAudioIcon !== undefined ? widgetData.showAudioIcon : SettingsData.controlCenterShowAudioIcon - property bool showAudioPercent: widgetData?.showAudioPercent !== undefined ? widgetData.showAudioPercent : SettingsData.controlCenterShowAudioPercent - property bool showVpnIcon: widgetData?.showVpnIcon !== undefined ? widgetData.showVpnIcon : SettingsData.controlCenterShowVpnIcon - property bool showBrightnessIcon: widgetData?.showBrightnessIcon !== undefined ? widgetData.showBrightnessIcon : SettingsData.controlCenterShowBrightnessIcon - property bool showBrightnessPercent: widgetData?.showBrightnessPercent !== undefined ? widgetData.showBrightnessPercent : SettingsData.controlCenterShowBrightnessPercent - property bool showMicIcon: widgetData?.showMicIcon !== undefined ? widgetData.showMicIcon : SettingsData.controlCenterShowMicIcon - property bool showMicPercent: widgetData?.showMicPercent !== undefined ? widgetData.showMicPercent : SettingsData.controlCenterShowMicPercent - property bool showBatteryIcon: widgetData?.showBatteryIcon !== undefined ? widgetData.showBatteryIcon : SettingsData.controlCenterShowBatteryIcon - property bool showPrinterIcon: widgetData?.showPrinterIcon !== undefined ? widgetData.showPrinterIcon : SettingsData.controlCenterShowPrinterIcon - property bool showScreenSharingIcon: widgetData?.showScreenSharingIcon !== undefined ? widgetData.showScreenSharingIcon : SettingsData.controlCenterShowScreenSharingIcon - property real touchpadThreshold: 100 - property real micAccumulator: 0 - property real volumeAccumulator: 0 - property real brightnessAccumulator: 0 - readonly property real vIconSize: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - property var _hRow: null - property var _vCol: null - property var _hAudio: null - property var _hBrightness: null - property var _hMic: null - property var _vAudio: null - property var _vBrightness: null - property var _vMic: null - property var _interactionDelegates: [] - readonly property var defaultControlCenterGroupOrder: ["network", "vpn", "bluetooth", "audio", "microphone", "brightness", "battery", "printer", "screenSharing"] - readonly property var effectiveControlCenterGroupOrder: getEffectiveControlCenterGroupOrder() - readonly property var controlCenterRenderModel: getControlCenterRenderModel() - - onIsVerticalOrientationChanged: root.clearInteractionRefs() - - onWheel: function (wheelEvent) { - const delta = wheelEvent.angleDelta.y; - if (delta === 0) - return; - - root.refreshInteractionRefs(); - - const rootX = wheelEvent.x - root.leftMargin; - const rootY = wheelEvent.y - root.topMargin; - - if (root.isVerticalOrientation && _vCol) { - const pos = root.mapToItem(_vCol, rootX, rootY); - if (_vBrightness?.visible && pos.y >= _vBrightness.y && pos.y < _vBrightness.y + _vBrightness.height) { - root.handleBrightnessWheel(delta); - } else if (_vMic?.visible && pos.y >= _vMic.y && pos.y < _vMic.y + _vMic.height) { - root.handleMicWheel(delta); - } else { - root.handleVolumeWheel(delta); - } - } else if (_hRow) { - const pos = root.mapToItem(_hRow, rootX, rootY); - if (_hBrightness?.visible && pos.x >= _hBrightness.x && pos.x < _hBrightness.x + _hBrightness.width) { - root.handleBrightnessWheel(delta); - } else if (_hMic?.visible && pos.x >= _hMic.x && pos.x < _hMic.x + _hMic.width) { - root.handleMicWheel(delta); - } else { - root.handleVolumeWheel(delta); - } - } else { - root.handleVolumeWheel(delta); - } - wheelEvent.accepted = true; - } - - onRightClicked: function (rootX, rootY) { - root.refreshInteractionRefs(); - - if (root.isVerticalOrientation && _vCol) { - const pos = root.mapToItem(_vCol, rootX, rootY); - if (_vAudio?.visible && pos.y >= _vAudio.y && pos.y < _vAudio.y + _vAudio.height) { - AudioService.toggleMute(); - return; - } - if (_vMic?.visible && pos.y >= _vMic.y && pos.y < _vMic.y + _vMic.height) { - AudioService.toggleMicMute(); - return; - } - } else if (_hRow) { - const pos = root.mapToItem(_hRow, rootX, rootY); - if (_hAudio?.visible && pos.x >= _hAudio.x && pos.x < _hAudio.x + _hAudio.width) { - AudioService.toggleMute(); - return; - } - if (_hMic?.visible && pos.x >= _hMic.x && pos.x < _hMic.x + _hMic.width) { - AudioService.toggleMicMute(); - return; - } - } - } - - Loader { - active: root.showPrinterIcon - sourceComponent: Component { - Ref { - service: CupsService - } - } - } - - function getNetworkIconName() { - if (NetworkService.wifiToggling) - return "sync"; - switch (NetworkService.networkStatus) { - case "ethernet": - return "lan"; - case "vpn": - return NetworkService.ethernetConnected ? "lan" : NetworkService.wifiSignalIcon; - default: - return NetworkService.wifiSignalIcon; - } - } - - function getNetworkIconColor() { - if (NetworkService.wifiToggling) - return Theme.primary; - return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.surfaceText; - } - - function getVolumeIconName() { - if (!AudioService.sink?.audio) - return "volume_up"; - if (AudioService.sink.audio.muted) - return "volume_off"; - if (AudioService.sink.audio.volume === 0) - return "volume_mute"; - if (AudioService.sink.audio.volume * 100 < 33) - return "volume_down"; - return "volume_up"; - } - - function getMicIconName() { - if (!AudioService.source?.audio) - return "mic"; - if (AudioService.source.audio.muted || AudioService.source.audio.volume === 0) - return "mic_off"; - return "mic"; - } - - function getMicIconColor() { - if (!AudioService.source?.audio) - return Theme.surfaceText; - if (AudioService.source.audio.muted || AudioService.source.audio.volume === 0) - return Theme.surfaceText; - return Theme.widgetIconColor; - } - - function getBrightnessIconName() { - const deviceName = getPinnedBrightnessDevice(); - if (!deviceName) - return "brightness_medium"; - const level = DisplayService.getDeviceBrightness(deviceName); - if (level <= 33) - return "brightness_low"; - if (level <= 66) - return "brightness_medium"; - return "brightness_high"; - } - - function getScreenPinKey() { - if (!root.screenName) - return ""; - const screen = Quickshell.screens.find(s => s.name === root.screenName); - if (screen) { - return SettingsData.getScreenDisplayName(screen); - } - if (SettingsData.displayNameMode === "model" && root.screenModel && root.screenModel.length > 0) { - return root.screenModel; - } - return root.screenName; - } - - function getPinnedBrightnessDevice() { - const pinKey = getScreenPinKey(); - if (!pinKey) - return ""; - const pins = SettingsData.brightnessDevicePins || {}; - return pins[pinKey] || ""; - } - - function hasPinnedBrightnessDevice() { - return getPinnedBrightnessDevice().length > 0; - } - - function handleVolumeWheel(delta) { - if (!AudioService.sink?.audio) - return; - - var step = 5; - const isMouseWheel = Math.abs(delta) >= 120 && (Math.abs(delta) % 120) === 0; - if (!isMouseWheel) { - step = 1; - volumeAccumulator += delta; - if (Math.abs(volumeAccumulator) < touchpadThreshold) - return; - - delta = volumeAccumulator; - volumeAccumulator = 0; - } - - const maxVol = AudioService.sinkMaxVolume; - const currentVolume = AudioService.sink.audio.volume * 100; - const newVolume = delta > 0 ? Math.min(maxVol, currentVolume + step) : Math.max(0, currentVolume - step); - AudioService.sink.audio.muted = false; - AudioService.sink.audio.volume = newVolume / 100; - AudioService.playVolumeChangeSoundIfEnabled(); - } - - function handleMicWheel(delta) { - if (!AudioService.source?.audio) - return; - - var step = 5; - const isMouseWheel = Math.abs(delta) >= 120 && (Math.abs(delta) % 120) === 0; - if (!isMouseWheel) { - step = 1; - micAccumulator += delta; - if (Math.abs(micAccumulator) < touchpadThreshold) - return; - - delta = micAccumulator; - micAccumulator = 0; - } - - const currentVolume = AudioService.source.audio.volume * 100; - const newVolume = delta > 0 ? Math.min(100, currentVolume + step) : Math.max(0, currentVolume - step); - AudioService.source.audio.muted = false; - AudioService.source.audio.volume = newVolume / 100; - } - - function handleBrightnessWheel(delta) { - const deviceName = getPinnedBrightnessDevice(); - if (!deviceName) { - return; - } - - var step = 5; - const isMouseWheel = Math.abs(delta) >= 120 && (Math.abs(delta) % 120) === 0; - if (!isMouseWheel) { - step = 1; - brightnessAccumulator += delta; - if (Math.abs(brightnessAccumulator) < touchpadThreshold) - return; - - delta = brightnessAccumulator; - brightnessAccumulator = 0; - } - - const currentBrightness = DisplayService.getDeviceBrightness(deviceName); - const newBrightness = delta > 0 ? Math.min(100, currentBrightness + step) : Math.max(1, currentBrightness - step); - DisplayService.setBrightness(newBrightness, deviceName); - } - - function getBrightness() { - const deviceName = getPinnedBrightnessDevice(); - if (!deviceName) { - return; - } - return DisplayService.getDeviceBrightness(deviceName) / 100; - } - - function getBatteryIconColor() { - if (!BatteryService.batteryAvailable) - return Theme.widgetIconColor; - if (BatteryService.isLowBattery && !BatteryService.isCharging) - return Theme.error; - if (BatteryService.isCharging || BatteryService.isPluggedIn) - return Theme.primary; - return Theme.widgetIconColor; - } - - function hasPrintJobs() { - return CupsService.getTotalJobsNum() > 0; - } - - function getControlCenterIconSize() { - return Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale); - } - - function getEffectiveControlCenterGroupOrder() { - const knownIds = root.defaultControlCenterGroupOrder; - const savedOrder = root.widgetData?.controlCenterGroupOrder; - const result = []; - const seen = {}; - - if (savedOrder && typeof savedOrder.length === "number") { - for (let i = 0; i < savedOrder.length; ++i) { - const groupId = savedOrder[i]; - if (knownIds.indexOf(groupId) === -1 || seen[groupId]) - continue; - - seen[groupId] = true; - result.push(groupId); - } - } - - for (let i = 0; i < knownIds.length; ++i) { - const groupId = knownIds[i]; - if (seen[groupId]) - continue; - - seen[groupId] = true; - result.push(groupId); - } - - return result; - } - - function isGroupVisible(groupId) { - switch (groupId) { - case "screenSharing": - return root.showScreenSharingIcon && NiriService.hasCasts; - case "network": - return root.showNetworkIcon && NetworkService.networkAvailable; - case "vpn": - return root.showVpnIcon && NetworkService.vpnAvailable && NetworkService.vpnConnected; - case "bluetooth": - return root.showBluetoothIcon && BluetoothService.available && BluetoothService.enabled; - case "audio": - return root.showAudioIcon; - case "microphone": - return root.showMicIcon; - case "brightness": - return root.showBrightnessIcon && DisplayService.brightnessAvailable && root.hasPinnedBrightnessDevice(); - case "battery": - return root.showBatteryIcon && BatteryService.batteryAvailable; - case "printer": - return root.showPrinterIcon && CupsService.cupsAvailable && root.hasPrintJobs(); - default: - return false; - } - } - - function isCompositeGroup(groupId) { - return groupId === "audio" || groupId === "microphone" || groupId === "brightness"; - } - - function getControlCenterRenderModel() { - return root.effectiveControlCenterGroupOrder.map(groupId => ({ - "id": groupId, - "visible": root.isGroupVisible(groupId), - "composite": root.isCompositeGroup(groupId) - })); - } - - function clearInteractionRefs() { - root._hAudio = null; - root._hBrightness = null; - root._hMic = null; - root._vAudio = null; - root._vBrightness = null; - root._vMic = null; - } - - function registerInteractionDelegate(isVertical, item) { - if (!item) - return; - - for (let i = 0; i < root._interactionDelegates.length; ++i) { - const entry = root._interactionDelegates[i]; - if (entry && entry.item === item) { - entry.isVertical = isVertical; - return; - } - } - - root._interactionDelegates = root._interactionDelegates.concat([ - { - "isVertical": isVertical, - "item": item - } - ]); - } - - function unregisterInteractionDelegate(item) { - if (!item) - return; - - root._interactionDelegates = root._interactionDelegates.filter(entry => entry && entry.item !== item); - } - - function refreshInteractionRefs() { - root.clearInteractionRefs(); - - for (let i = 0; i < root._interactionDelegates.length; ++i) { - const entry = root._interactionDelegates[i]; - const item = entry?.item; - if (!item || !item.visible) - continue; - - const groupId = item.interactionGroupId; - if (entry.isVertical) { - if (groupId === "audio") - root._vAudio = item; - else if (groupId === "microphone") - root._vMic = item; - else if (groupId === "brightness") - root._vBrightness = item; - } else { - if (groupId === "audio") - root._hAudio = item; - else if (groupId === "microphone") - root._hMic = item; - else if (groupId === "brightness") - root._hBrightness = item; - } - } - } - - function hasNoVisibleIcons() { - return !root.controlCenterRenderModel.some(entry => entry.visible); - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : controlIndicators.implicitWidth - implicitHeight: root.isVerticalOrientation ? controlColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - Component.onCompleted: { - root._hRow = controlIndicators; - root._vCol = controlColumn; - root.clearInteractionRefs(); - } - - Column { - id: controlColumn - visible: root.isVerticalOrientation - width: parent.width - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXS - - Repeater { - model: root.controlCenterRenderModel - Item { - id: verticalGroupItem - required property var modelData - required property int index - property string interactionGroupId: modelData.id - - width: parent.width - height: { - switch (modelData.id) { - case "audio": - return root.vIconSize + (audioPercentV.visible ? audioPercentV.implicitHeight + 2 : 0); - case "microphone": - return root.vIconSize + (micPercentV.visible ? micPercentV.implicitHeight + 2 : 0); - case "brightness": - return root.vIconSize + (brightnessPercentV.visible ? brightnessPercentV.implicitHeight + 2 : 0); - default: - return root.vIconSize; - } - } - visible: modelData.visible - - Component.onCompleted: { - root.registerInteractionDelegate(true, verticalGroupItem); - root.refreshInteractionRefs(); - } - Component.onDestruction: { - if (root) { - root.unregisterInteractionDelegate(verticalGroupItem); - root.refreshInteractionRefs(); - } - } - onVisibleChanged: root.refreshInteractionRefs() - onInteractionGroupIdChanged: { - root.refreshInteractionRefs(); - } - - DankIcon { - anchors.centerIn: parent - visible: !verticalGroupItem.modelData.composite - name: { - switch (verticalGroupItem.modelData.id) { - case "screenSharing": - return "screen_record"; - case "network": - return root.getNetworkIconName(); - case "vpn": - return "vpn_lock"; - case "bluetooth": - return "bluetooth"; - case "battery": - return Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable); - case "printer": - return "print"; - default: - return "settings"; - } - } - size: root.vIconSize - color: { - switch (verticalGroupItem.modelData.id) { - case "screenSharing": - return NiriService.hasActiveCast ? Theme.primary : Theme.surfaceText; - case "network": - return root.getNetworkIconColor(); - case "vpn": - return NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText; - case "bluetooth": - return BluetoothService.connected ? Theme.primary : Theme.surfaceText; - case "battery": - return root.getBatteryIconColor(); - case "printer": - return Theme.primary; - default: - return Theme.widgetIconColor; - } - } - } - - DankIcon { - id: audioIconV - visible: verticalGroupItem.modelData.id === "audio" - name: root.getVolumeIconName() - size: root.vIconSize - color: Theme.widgetIconColor - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - } - - NumericText { - id: audioPercentV - visible: verticalGroupItem.modelData.id === "audio" && root.showAudioPercent && isFinite(AudioService.sink?.audio?.volume) - text: Math.round((AudioService.sink?.audio?.volume ?? 0) * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: audioIconV.bottom - anchors.topMargin: 2 - } - - DankIcon { - id: micIconV - visible: verticalGroupItem.modelData.id === "microphone" - name: root.getMicIconName() - size: root.vIconSize - color: root.getMicIconColor() - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - } - - NumericText { - id: micPercentV - visible: verticalGroupItem.modelData.id === "microphone" && root.showMicPercent && isFinite(AudioService.source?.audio?.volume) - text: Math.round((AudioService.source?.audio?.volume ?? 0) * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: micIconV.bottom - anchors.topMargin: 2 - } - - DankIcon { - id: brightnessIconV - visible: verticalGroupItem.modelData.id === "brightness" - name: root.getBrightnessIconName() - size: root.vIconSize - color: Theme.widgetIconColor - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - } - - NumericText { - id: brightnessPercentV - visible: verticalGroupItem.modelData.id === "brightness" && root.showBrightnessPercent && isFinite(getBrightness()) - text: Math.round(getBrightness() * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: brightnessIconV.bottom - anchors.topMargin: 2 - } - } - } - - Item { - width: parent.width - height: root.vIconSize - visible: root.hasNoVisibleIcons() - - DankIcon { - name: "settings" - size: root.vIconSize - color: root.isActive ? Theme.primary : Theme.widgetIconColor - anchors.centerIn: parent - } - } - } - - Row { - id: controlIndicators - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - Repeater { - model: root.controlCenterRenderModel - - Item { - id: horizontalGroupItem - required property var modelData - required property int index - property string interactionGroupId: modelData.id - - width: { - switch (modelData.id) { - case "audio": - return audioGroup.width; - case "microphone": - return micGroup.width; - case "brightness": - return brightnessGroup.width; - default: - return root.getControlCenterIconSize(); - } - } - implicitWidth: width - height: root.widgetThickness - root.horizontalPadding * 2 - visible: modelData.visible - - Component.onCompleted: { - root.registerInteractionDelegate(false, horizontalGroupItem); - root.refreshInteractionRefs(); - } - Component.onDestruction: { - if (root) { - root.unregisterInteractionDelegate(horizontalGroupItem); - root.refreshInteractionRefs(); - } - } - onVisibleChanged: root.refreshInteractionRefs() - onInteractionGroupIdChanged: { - root.refreshInteractionRefs(); - } - - DankIcon { - id: iconOnlyItem - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - visible: !horizontalGroupItem.modelData.composite - name: { - switch (horizontalGroupItem.modelData.id) { - case "screenSharing": - return "screen_record"; - case "network": - return root.getNetworkIconName(); - case "vpn": - return "vpn_lock"; - case "bluetooth": - return "bluetooth"; - case "battery": - return Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable); - case "printer": - return "print"; - default: - return "settings"; - } - } - size: root.getControlCenterIconSize() - color: { - switch (horizontalGroupItem.modelData.id) { - case "screenSharing": - return NiriService.hasActiveCast ? Theme.primary : Theme.surfaceText; - case "network": - return root.getNetworkIconColor(); - case "vpn": - return NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText; - case "bluetooth": - return BluetoothService.connected ? Theme.primary : Theme.surfaceText; - case "battery": - return root.getBatteryIconColor(); - case "printer": - return Theme.primary; - default: - return Theme.widgetIconColor; - } - } - } - - Rectangle { - id: audioGroup - width: audioContent.implicitWidth + 2 - implicitWidth: width - height: parent.height - color: "transparent" - anchors.verticalCenter: parent.verticalCenter - visible: horizontalGroupItem.modelData.id === "audio" - - Row { - id: audioContent - anchors.left: parent.left - anchors.leftMargin: 1 - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - DankIcon { - id: audioIcon - name: root.getVolumeIconName() - size: root.getControlCenterIconSize() - color: Theme.widgetIconColor - anchors.verticalCenter: parent.verticalCenter - } - - NumericText { - id: audioPercent - visible: root.showAudioPercent && isFinite(AudioService.sink?.audio?.volume) - text: Math.round((AudioService.sink?.audio?.volume ?? 0) * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - width: visible ? implicitWidth : 0 - } - } - } - - Rectangle { - id: micGroup - width: micContent.implicitWidth + 2 - implicitWidth: width - height: parent.height - color: "transparent" - anchors.verticalCenter: parent.verticalCenter - visible: horizontalGroupItem.modelData.id === "microphone" - - Row { - id: micContent - anchors.left: parent.left - anchors.leftMargin: 1 - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - DankIcon { - id: micIcon - name: root.getMicIconName() - size: root.getControlCenterIconSize() - color: root.getMicIconColor() - anchors.verticalCenter: parent.verticalCenter - } - - NumericText { - id: micPercent - visible: root.showMicPercent && isFinite(AudioService.source?.audio?.volume) - text: Math.round((AudioService.source?.audio?.volume ?? 0) * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - width: visible ? implicitWidth : 0 - } - } - } - - Rectangle { - id: brightnessGroup - width: brightnessContent.implicitWidth + 2 - implicitWidth: width - height: parent.height - color: "transparent" - anchors.verticalCenter: parent.verticalCenter - visible: horizontalGroupItem.modelData.id === "brightness" - - Row { - id: brightnessContent - anchors.left: parent.left - anchors.leftMargin: 1 - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - DankIcon { - id: brightnessIcon - name: root.getBrightnessIconName() - size: root.getControlCenterIconSize() - color: Theme.widgetIconColor - anchors.verticalCenter: parent.verticalCenter - } - - NumericText { - id: brightnessPercent - visible: root.showBrightnessPercent && isFinite(getBrightness()) - text: Math.round(getBrightness() * 100) + "%" - reserveText: "100%" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - width: visible ? implicitWidth : 0 - } - } - } - } - } - - DankIcon { - name: "settings" - size: root.getControlCenterIconSize() - color: root.isActive ? Theme.primary : Theme.widgetIconColor - anchors.verticalCenter: parent.verticalCenter - visible: root.hasNoVisibleIcons() - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.NoButton - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuMonitor.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuMonitor.qml deleted file mode 100644 index 212f9b5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuMonitor.qml +++ /dev/null @@ -1,146 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool showPercentage: true - property bool showIcon: true - property var toggleProcessList - property var popoutTarget: null - property var widgetData: null - property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true - - signal cpuClicked - - Component.onCompleted: { - DgopService.addRef(["cpu"]); - } - Component.onDestruction: { - DgopService.removeRef(["cpu"]); - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuContent.implicitWidth - implicitHeight: root.isVerticalOrientation ? cpuColumn.implicitHeight : cpuContent.implicitHeight - - Column { - id: cpuColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "memory" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.cpuUsage > 80) { - return Theme.tempDanger; - } - - if (DgopService.cpuUsage > 60) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (DgopService.cpuUsage === undefined || DgopService.cpuUsage === null || DgopService.cpuUsage === 0) { - return "--"; - } - - return DgopService.cpuUsage.toFixed(0); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: cpuContent - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - id: cpuIcon - name: "memory" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.cpuUsage > 80) { - return Theme.tempDanger; - } - - if (DgopService.cpuUsage > 60) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.verticalCenter: parent.verticalCenter - } - - Item { - id: textBox - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: root.minimumWidth ? Math.max(cpuBaseline.width, cpuCurrent.width) : cpuCurrent.width - implicitHeight: cpuText.implicitHeight - - width: implicitWidth - height: implicitHeight - - StyledTextMetrics { - id: cpuBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: "100%" - } - - StyledTextMetrics { - id: cpuCurrent - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: cpuText.text - } - - StyledText { - id: cpuText - text: { - const v = DgopService.cpuUsage; - if (v === undefined || v === null || v === 0) { - return "--%"; - } - return v.toFixed(0) + "%"; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - - anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - elide: Text.ElideNone - } - } - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - DgopService.setSortBy("cpu"); - cpuClicked(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuTemperature.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuTemperature.qml deleted file mode 100644 index 4066387..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/CpuTemperature.qml +++ /dev/null @@ -1,140 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool showPercentage: true - property bool showIcon: true - property var toggleProcessList - property var popoutTarget: null - property var widgetData: null - property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true - - signal cpuTempClicked - - Component.onCompleted: { - DgopService.addRef(["cpu"]); - } - Component.onDestruction: { - DgopService.removeRef(["cpu"]); - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuTempRow.implicitWidth - implicitHeight: root.isVerticalOrientation ? cpuTempColumn.implicitHeight : cpuTempRow.implicitHeight - - Column { - id: cpuTempColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "device_thermostat" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.cpuTemperature > 85) { - return Theme.tempDanger; - } - - if (DgopService.cpuTemperature > 69) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (DgopService.cpuTemperature === undefined || DgopService.cpuTemperature === null || DgopService.cpuTemperature < 0) { - return "--"; - } - - return Math.round(DgopService.cpuTemperature).toString(); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: cpuTempRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - id: cpuTempIcon - name: "device_thermostat" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.cpuTemperature > 85) { - return Theme.tempDanger; - } - - if (DgopService.cpuTemperature > 69) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.verticalCenter: parent.verticalCenter - } - - Item { - id: textBox - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: root.minimumWidth ? Math.max(tempBaseline.width, cpuTempText.paintedWidth) : cpuTempText.paintedWidth - implicitHeight: cpuTempText.implicitHeight - - width: implicitWidth - height: implicitHeight - - StyledTextMetrics { - id: tempBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: "88°" - } - - StyledText { - id: cpuTempText - text: { - if (DgopService.cpuTemperature === undefined || DgopService.cpuTemperature === null || DgopService.cpuTemperature < 0) { - return "--°"; - } - - return Math.round(DgopService.cpuTemperature) + "°"; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - - anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - elide: Text.ElideNone - } - } - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - DgopService.setSortBy("cpu"); - cpuTempClicked(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DWLLayout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DWLLayout.qml deleted file mode 100644 index f810cb6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DWLLayout.qml +++ /dev/null @@ -1,110 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: layout - - property bool layoutPopupVisible: false - property var popoutTarget: null - - signal toggleLayoutPopup() - - visible: CompositorService.isDwl && DwlService.dwlAvailable - - property var outputState: parentScreen ? DwlService.getOutputState(parentScreen.name) : null - property string currentLayoutSymbol: outputState?.layoutSymbol || "" - property int currentLayoutIndex: outputState?.layout || 0 - - readonly property var layoutIcons: ({ - "CT": "view_compact", - "G": "grid_view", - "K": "layers", - "M": "fullscreen", - "RT": "view_sidebar", - "S": "view_carousel", - "T": "view_quilt", - "VG": "grid_on", - "VK": "view_day", - "VS": "scrollable_header", - "VT": "clarify" - }) - - function getLayoutIcon(symbol) { - return layoutIcons[symbol] || "view_quilt" - } - - Connections { - target: DwlService - function onStateChanged() { - outputState = parentScreen ? DwlService.getOutputState(parentScreen.name) : null - } - } - - content: Component { - Item { - implicitWidth: layout.isVerticalOrientation ? (layout.widgetThickness - layout.horizontalPadding * 2) : layoutContent.implicitWidth - implicitHeight: layout.isVerticalOrientation ? layoutColumn.implicitHeight : (layout.widgetThickness - layout.horizontalPadding * 2) - - Column { - id: layoutColumn - visible: layout.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: layout.getLayoutIcon(layout.currentLayoutSymbol) - size: Theme.barIconSize(layout.barThickness, undefined, layout.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: layout.currentLayoutSymbol - font.pixelSize: Theme.barTextSize(layout.barThickness, layout.barConfig?.fontScale, layout.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: layoutContent - visible: !layout.isVerticalOrientation - anchors.centerIn: parent - spacing: (barConfig?.noBackground ?? false) ? 1 : 2 - - DankIcon { - name: layout.getLayoutIcon(layout.currentLayoutSymbol) - size: Theme.barIconSize(layout.barThickness, -4, layout.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: layout.currentLayoutSymbol - font.pixelSize: Theme.barTextSize(layout.barThickness, layout.barConfig?.fontScale, layout.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - - onClicked: { - toggleLayoutPopup() - } - - onRightClicked: { - if (!parentScreen || !DwlService.dwlAvailable || DwlService.layouts.length === 0) { - return - } - - const currentIndex = layout.currentLayoutIndex - const nextIndex = (currentIndex + 1) % DwlService.layouts.length - - DwlService.setLayout(parentScreen.name, nextIndex) - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DiskUsage.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DiskUsage.qml deleted file mode 100644 index d6e6d1b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/DiskUsage.qml +++ /dev/null @@ -1,255 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property var widgetData: null - property string mountPath: (widgetData && widgetData.mountPath !== undefined) ? widgetData.mountPath : "/" - property int diskUsageMode: (widgetData && widgetData.diskUsageMode !== undefined) ? widgetData.diskUsageMode : 0 - property bool isHovered: mouseArea.containsMouse - property bool isAutoHideBar: false - - property var selectedMount: { - if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) { - return null; - } - - const currentMountPath = root.mountPath || "/"; - - for (let i = 0; i < DgopService.diskMounts.length; i++) { - if (DgopService.diskMounts[i].mount === currentMountPath) { - return DgopService.diskMounts[i]; - } - } - - for (let i = 0; i < DgopService.diskMounts.length; i++) { - if (DgopService.diskMounts[i].mount === "/") { - return DgopService.diskMounts[i]; - } - } - - return DgopService.diskMounts[0] || null; - } - - property real diskUsagePercent: { - if (!selectedMount || !selectedMount.percent) { - return 0; - } - const percentStr = selectedMount.percent.replace("%", ""); - return parseFloat(percentStr) || 0; - } - - Component.onCompleted: { - DgopService.addRef(["diskmounts"]); - } - Component.onDestruction: { - DgopService.removeRef(["diskmounts"]); - } - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - const spacing = barConfig?.spacing ?? 4; - const offset = barThickness + spacing; - return offset; - } - - return 0; - } - - Connections { - function onWidgetDataChanged() { - root.mountPath = Qt.binding(() => { - return (root.widgetData && root.widgetData.mountPath !== undefined) ? root.widgetData.mountPath : "/"; - }); - - root.selectedMount = Qt.binding(() => { - if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) { - return null; - } - - const currentMountPath = root.mountPath || "/"; - - for (let i = 0; i < DgopService.diskMounts.length; i++) { - if (DgopService.diskMounts[i].mount === currentMountPath) { - return DgopService.diskMounts[i]; - } - } - - for (let i = 0; i < DgopService.diskMounts.length; i++) { - if (DgopService.diskMounts[i].mount === "/") { - return DgopService.diskMounts[i]; - } - } - - return DgopService.diskMounts[0] || null; - }); - } - - target: SettingsData - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : diskContent.implicitWidth - implicitHeight: root.isVerticalOrientation ? diskColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - Column { - id: diskColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "storage" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (root.diskUsagePercent > 90) { - return Theme.tempDanger; - } - if (root.diskUsagePercent > 75) { - return Theme.tempWarning; - } - return Theme.surfaceText; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) { - return "--"; - } - if (!root.selectedMount) return "--"; - switch (root.diskUsageMode) { - case 1: return root.selectedMount.size || "--"; - case 2: return root.selectedMount.avail || "--"; - case 3: return (root.selectedMount.avail || "--") + " / " + (root.selectedMount.size || "--"); - default: return root.diskUsagePercent.toFixed(0); - } - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: diskContent - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: 3 - - DankIcon { - name: "storage" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (root.diskUsagePercent > 90) { - return Theme.tempDanger; - } - if (root.diskUsagePercent > 75) { - return Theme.tempWarning; - } - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - if (!root.selectedMount) { - return "--"; - } - return root.selectedMount.mount; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignLeft - elide: Text.ElideNone - } - - StyledText { - text: { - if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) { - return "--%"; - } - if (!root.selectedMount) return "--%"; - switch (root.diskUsageMode) { - case 1: return root.selectedMount.size || "--"; - case 2: return root.selectedMount.avail || "--"; - case 3: return (root.selectedMount.avail || "--") + " / " + (root.selectedMount.size || "--"); - default: return root.diskUsagePercent.toFixed(0) + "%"; - } - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignLeft - elide: Text.ElideNone - - StyledTextMetrics { - id: diskBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: { - switch (root.diskUsageMode) { - case 3: return "888.8G / 888.8G"; - case 1: - case 2: return "888.8G"; - default: return "100%"; - } - } - } - - width: Math.max(diskBaseline.width, paintedWidth) - } - } - } - } - - Loader { - id: tooltipLoader - active: false - sourceComponent: DankTooltip {} - } - - MouseArea { - id: mouseArea - z: 1 - anchors.fill: parent - hoverEnabled: root.isVerticalOrientation - onEntered: { - if (root.isVerticalOrientation && root.selectedMount) { - tooltipLoader.active = true; - if (tooltipLoader.item) { - const globalPos = mapToGlobal(width / 2, height / 2); - const currentScreen = root.parentScreen || Screen; - const screenX = currentScreen ? currentScreen.x : 0; - const screenY = currentScreen ? currentScreen.y : 0; - const relativeY = globalPos.y - screenY; - const adjustedY = relativeY + root.minTooltipY; - const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (currentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - const isLeft = root.axis?.edge === "left"; - tooltipLoader.item.show(root.selectedMount.mount, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft); - } - } - } - onExited: { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/FocusedApp.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/FocusedApp.qml deleted file mode 100644 index a4ad4d2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/FocusedApp.qml +++ /dev/null @@ -1,317 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Wayland -import Quickshell.Widgets -import Quickshell.Hyprland -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property var widgetData: null - property bool compactMode: widgetData?.focusedWindowCompactMode !== undefined ? widgetData.focusedWindowCompactMode : SettingsData.focusedWindowCompactMode - property int availableWidth: 400 - readonly property int maxNormalWidth: 456 - readonly property int maxCompactWidth: 288 - property Toplevel activeWindow: null - property var activeDesktopEntry: null - property bool isHovered: mouseArea.containsMouse - property bool isAutoHideBar: false - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - return barThickness + (barSpacing || 4); - } - - return 0; - } - - function updateActiveWindow() { - const active = ToplevelManager.activeToplevel; - - if (!active) { - // Only clear if our tracked window is no longer alive - if (activeWindow) { - const alive = ToplevelManager.toplevels?.values; - if (alive && !Array.from(alive).some(t => t === activeWindow)) - activeWindow = null; - } - return; - } - - if (!parentScreen || CompositorService.filterCurrentDisplay([active], parentScreen?.name)?.length > 0) { - activeWindow = active; - } - // else: active window is on a different screen so keep the previous value - } - - Component.onCompleted: { - updateActiveWindow(); - updateDesktopEntry(); - } - - Connections { - target: ToplevelManager - function onActiveToplevelChanged() { - root.updateActiveWindow(); - } - } - - Connections { - target: CompositorService - function onToplevelsChanged() { - root.updateActiveWindow(); - } - } - - Connections { - target: DesktopEntries - function onApplicationsChanged() { - root.updateDesktopEntry(); - } - } - - Connections { - target: root - function onActiveWindowChanged() { - root.updateDesktopEntry(); - } - } - - Connections { - target: SettingsData - function onAppIdSubstitutionsChanged() { - root.updateDesktopEntry(); - } - } - - function updateDesktopEntry() { - if (activeWindow && activeWindow.appId) { - const moddedId = Paths.moddedAppId(activeWindow.appId); - activeDesktopEntry = DesktopEntries.heuristicLookup(moddedId); - } else { - activeDesktopEntry = null; - } - } - readonly property bool hasWindowsOnCurrentWorkspace: { - if (CompositorService.isNiri) { - let currentWorkspaceId = null; - for (var i = 0; i < NiriService.allWorkspaces.length; i++) { - const ws = NiriService.allWorkspaces[i]; - if (ws.is_focused) { - currentWorkspaceId = ws.id; - break; - } - } - - if (!currentWorkspaceId) { - return false; - } - - const workspaceWindows = NiriService.windows.filter(w => w.workspace_id === currentWorkspaceId); - return workspaceWindows.length > 0 && activeWindow && (activeWindow.title || activeWindow.appId); - } - - if (CompositorService.isHyprland) { - if (!Hyprland.focusedWorkspace || !activeWindow || !(activeWindow.title || activeWindow.appId)) { - return false; - } - - try { - if (!Hyprland.toplevels) - return false; - const hyprlandToplevels = Array.from(Hyprland.toplevels.values); - const activeHyprToplevel = hyprlandToplevels.find(t => t?.wayland === activeWindow); - - if (!activeHyprToplevel || !activeHyprToplevel.workspace) { - return false; - } - - return activeHyprToplevel.workspace.id === Hyprland.focusedWorkspace.id; - } catch (e) { - return false; - } - } - - return activeWindow && (activeWindow.title || activeWindow.appId); - } - - width: hasWindowsOnCurrentWorkspace ? (isVerticalOrientation ? barThickness : visualWidth) : 0 - height: hasWindowsOnCurrentWorkspace ? (isVerticalOrientation ? visualHeight : barThickness) : 0 - visible: hasWindowsOnCurrentWorkspace - - content: Component { - Item { - implicitWidth: { - if (!root.hasWindowsOnCurrentWorkspace) - return 0; - if (root.isVerticalOrientation) - return root.widgetThickness - root.horizontalPadding * 2; - const baseWidth = contentRow.implicitWidth; - return compactMode ? Math.min(baseWidth, maxCompactWidth - root.horizontalPadding * 2) : Math.min(baseWidth, maxNormalWidth - root.horizontalPadding * 2); - } - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - clip: false - - IconImage { - id: appIcon - anchors.centerIn: parent - width: 18 - height: 18 - visible: root.isVerticalOrientation && activeWindow && status === Image.Ready - source: { - if (!activeWindow || !activeWindow.appId) - return ""; - return Paths.getAppIcon(activeWindow.appId, activeDesktopEntry); - } - smooth: true - mipmap: true - asynchronous: true - layer.enabled: activeWindow && (activeWindow.appId === "org.quickshell" || activeWindow.appId === "com.danklinux.dms") - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } - - DankIcon { - anchors.centerIn: parent - size: 18 - name: "sports_esports" - color: Theme.widgetTextColor - visible: root.isVerticalOrientation && activeWindow && activeWindow.appId && appIcon.status !== Image.Ready && Paths.isSteamApp(activeWindow.appId) - } - - Text { - anchors.centerIn: parent - visible: root.isVerticalOrientation && activeWindow && activeWindow.appId && appIcon.status !== Image.Ready && !Paths.isSteamApp(activeWindow.appId) - text: { - if (!activeWindow || !activeWindow.appId) - return "?"; - const appName = Paths.getAppName(activeWindow.appId, activeDesktopEntry); - return appName.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - Row { - id: contentRow - anchors.centerIn: parent - spacing: Theme.spacingS - visible: !root.isVerticalOrientation - - StyledText { - id: appText - text: { - if (!activeWindow || !activeWindow.appId) - return ""; - return Paths.getAppName(activeWindow.appId, activeDesktopEntry); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - maximumLineCount: 1 - width: Math.min(implicitWidth, compactMode ? 80 : 180) - visible: !compactMode && text.length > 0 - } - - StyledText { - text: "•" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.outlineButton - anchors.verticalCenter: parent.verticalCenter - visible: !compactMode && appText.text && titleText.text - } - - StyledText { - id: titleText - text: { - const title = activeWindow && activeWindow.title ? activeWindow.title : ""; - const appName = appText.text; - - if (compactMode) { - if (!title || title === appName) - return title || appName; - if (title.endsWith(appName)) - return title.substring(0, title.length - appName.length).replace(/ (-|—) $/, "") || appName; - return title; - } - - if (!title || !appName) - return title; - - if (title.endsWith(appName)) - return title.substring(0, title.length - appName.length).replace(/ (-|—) $/, ""); - - return title; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - maximumLineCount: 1 - width: Math.min(implicitWidth, compactMode ? 280 : 250) - visible: text.length > 0 - } - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: root.isVerticalOrientation - acceptedButtons: Qt.NoButton - onEntered: { - if (root.isVerticalOrientation && activeWindow && activeWindow.appId && root.parentScreen) { - tooltipLoader.active = true; - if (tooltipLoader.item) { - const globalPos = mapToGlobal(width / 2, height / 2); - const currentScreen = root.parentScreen; - const screenX = currentScreen ? currentScreen.x : 0; - const screenY = currentScreen ? currentScreen.y : 0; - const relativeY = globalPos.y - screenY; - // Add minTooltipY offset to account for top bar - const adjustedY = relativeY + root.minTooltipY; - const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS); - - const appName = Paths.getAppName(activeWindow.appId, activeDesktopEntry); - const title = activeWindow.title || ""; - const tooltipText = appName + (title ? " • " + title : ""); - - const isLeft = root.axis?.edge === "left"; - tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft); - } - } - } - onExited: { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - } - } - - Loader { - id: tooltipLoader - active: false - sourceComponent: DankTooltip {} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/GpuTemperature.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/GpuTemperature.qml deleted file mode 100644 index cf07f3e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/GpuTemperature.qml +++ /dev/null @@ -1,224 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool showPercentage: true - property bool showIcon: true - property var toggleProcessList - property var popoutTarget: null - property var widgetData: null - property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0 - property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true - - signal gpuTempClicked - - property real displayTemp: { - if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) { - return 0; - } - - if (selectedGpuIndex >= 0 && selectedGpuIndex < DgopService.availableGpus.length) { - return DgopService.availableGpus[selectedGpuIndex].temperature || 0; - } - - return 0; - } - - function updateWidgetPciId(pciId) { - const sections = ["left", "center", "right"]; - const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default"); - if (!defaultBar) - return; - for (let s = 0; s < sections.length; s++) { - const sectionId = sections[s]; - let widgets = []; - if (sectionId === "left") { - widgets = (defaultBar.leftWidgets || []).slice(); - } else if (sectionId === "center") { - widgets = (defaultBar.centerWidgets || []).slice(); - } else if (sectionId === "right") { - widgets = (defaultBar.rightWidgets || []).slice(); - } - for (let i = 0; i < widgets.length; i++) { - const widget = widgets[i]; - if (typeof widget === "object" && widget.id === "gpuTemp" && (!widget.pciId || widget.pciId === "")) { - widgets[i] = { - "id": widget.id, - "enabled": widget.enabled !== undefined ? widget.enabled : true, - "selectedGpuIndex": 0, - "pciId": pciId - }; - if (sectionId === "left") { - SettingsData.setDankBarLeftWidgets(widgets); - } else if (sectionId === "center") { - SettingsData.setDankBarCenterWidgets(widgets); - } else if (sectionId === "right") { - SettingsData.setDankBarRightWidgets(widgets); - } - return; - } - } - } - } - - Component.onCompleted: { - DgopService.addRef(["gpu"]); - if (widgetData && widgetData.pciId) { - DgopService.addGpuPciId(widgetData.pciId); - } else { - autoSaveTimer.running = true; - } - } - Component.onDestruction: { - DgopService.removeRef(["gpu"]); - if (widgetData && widgetData.pciId) { - DgopService.removeGpuPciId(widgetData.pciId); - } - } - - Connections { - function onWidgetDataChanged() { - root.selectedGpuIndex = Qt.binding(() => { - return (root.widgetData && root.widgetData.selectedGpuIndex !== undefined) ? root.widgetData.selectedGpuIndex : 0; - }); - } - - target: SettingsData - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : gpuTempRow.implicitWidth - implicitHeight: root.isVerticalOrientation ? gpuTempColumn.implicitHeight : gpuTempRow.implicitHeight - - Column { - id: gpuTempColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "auto_awesome_mosaic" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (root.displayTemp > 80) { - return Theme.tempDanger; - } - - if (root.displayTemp > 65) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) { - return "--"; - } - - return Math.round(root.displayTemp).toString(); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: gpuTempRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - id: gpuTempIcon - name: "auto_awesome_mosaic" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (root.displayTemp > 80) { - return Theme.tempDanger; - } - - if (root.displayTemp > 65) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.verticalCenter: parent.verticalCenter - } - - Item { - id: textBox - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: root.minimumWidth ? Math.max(gpuTempBaseline.width, gpuTempText.paintedWidth) : gpuTempText.paintedWidth - implicitHeight: gpuTempText.implicitHeight - - width: implicitWidth - height: implicitHeight - - StyledTextMetrics { - id: gpuTempBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: "88°" - } - - StyledText { - id: gpuTempText - text: { - if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) { - return "--°"; - } - - return Math.round(root.displayTemp) + "°"; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - - anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - elide: Text.ElideNone - } - } - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - DgopService.setSortBy("cpu"); - gpuTempClicked(); - } - } - - Timer { - id: autoSaveTimer - - interval: 100 - running: false - onTriggered: { - if (DgopService.availableGpus && DgopService.availableGpus.length > 0) { - const firstGpu = DgopService.availableGpus[0]; - if (firstGpu && firstGpu.pciId) { - updateWidgetPciId(firstGpu.pciId); - DgopService.addGpuPciId(firstGpu.pciId); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/IdleInhibitor.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/IdleInhibitor.qml deleted file mode 100644 index a8e5993..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/IdleInhibitor.qml +++ /dev/null @@ -1,36 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - anchors.centerIn: parent - name: SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - } - } - } - - MouseArea { - z: 1 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - } - onClicked: { - SessionService.toggleIdleInhibit(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/KeyboardLayoutName.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/KeyboardLayoutName.qml deleted file mode 100644 index 8b49a7d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/KeyboardLayoutName.qml +++ /dev/null @@ -1,268 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Hyprland -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property var widgetData: null - property bool compactMode: widgetData?.keyboardLayoutNameCompactMode !== undefined ? widgetData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode - readonly property var langCodes: ({ - "afrikaans": "af", - "albanian": "sq", - "amharic": "am", - "arabic": "ar", - "armenian": "hy", - "azerbaijani": "az", - "basque": "eu", - "belarusian": "be", - "bengali": "bn", - "bosnian": "bs", - "bulgarian": "bg", - "burmese": "my", - "catalan": "ca", - "chinese": "zh", - "croatian": "hr", - "czech": "cs", - "danish": "da", - "dutch": "nl", - "english": "en", - "esperanto": "eo", - "estonian": "et", - "filipino": "fil", - "finnish": "fi", - "french": "fr", - "galician": "gl", - "georgian": "ka", - "german": "de", - "greek": "el", - "gujarati": "gu", - "hausa": "ha", - "hebrew": "he", - "hindi": "hi", - "hungarian": "hu", - "icelandic": "is", - "igbo": "ig", - "indonesian": "id", - "irish": "ga", - "italian": "it", - "japanese": "ja", - "javanese": "jv", - "kannada": "kn", - "kazakh": "kk", - "khmer": "km", - "korean": "ko", - "kurdish": "ku", - "kyrgyz": "ky", - "lao": "lo", - "latvian": "lv", - "lithuanian": "lt", - "luxembourgish": "lb", - "macedonian": "mk", - "malay": "ms", - "malayalam": "ml", - "maltese": "mt", - "maori": "mi", - "marathi": "mr", - "mongolian": "mn", - "nepali": "ne", - "norwegian": "no", - "pashto": "ps", - "persian": "fa", - "iranian": "fa", - "farsi": "fa", - "polish": "pl", - "portuguese": "pt", - "punjabi": "pa", - "romanian": "ro", - "russian": "ru", - "serbian": "sr", - "sindhi": "sd", - "sinhala": "si", - "slovak": "sk", - "slovenian": "sl", - "somali": "so", - "spanish": "es", - "swahili": "sw", - "swedish": "sv", - "tajik": "tg", - "tamil": "ta", - "tatar": "tt", - "telugu": "te", - "thai": "th", - "tibetan": "bo", - "turkish": "tr", - "turkmen": "tk", - "ukrainian": "uk", - "urdu": "ur", - "uyghur": "ug", - "uzbek": "uz", - "vietnamese": "vi", - "welsh": "cy", - "yiddish": "yi", - "yoruba": "yo", - "zulu": "zu" - }) - readonly property var validVariants: ["US", "UK", "GB", "AZERTY", "QWERTY", "Dvorak", "Colemak", "Mac", "Intl", "International"] - property string currentLayout: { - if (CompositorService.isNiri) { - return NiriService.getCurrentKeyboardLayoutName(); - } else if (CompositorService.isDwl) { - return DwlService.currentKeyboardLayout; - } - return ""; - } - property string hyprlandKeyboard: "" - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : contentRow.implicitWidth - implicitHeight: root.isVerticalOrientation ? contentColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - Column { - id: contentColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "keyboard" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (!root.currentLayout) - return ""; - const lang = root.currentLayout.split(" ")[0].toLowerCase(); - const code = root.langCodes[lang] || lang.substring(0, 2); - return code.toUpperCase(); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: contentRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingS - - StyledText { - text: { - if (!root.currentLayout) - return ""; - if (root.compactMode && !CompositorService.isHyprland) { - const match = root.currentLayout.match(/^(\S+)(?:.*\(([^)]+)\))?/); - if (match) { - const lang = match[1].toLowerCase(); - const code = root.langCodes[lang] || lang.substring(0, 2); - if (match[2]) { - const variant = match[2].trim(); - const isValid = root.validVariants.some(v => variant.toUpperCase().includes(v.toUpperCase())) || variant.length <= 3; - if (isValid) - return code + "-" + variant; - } - return code.toUpperCase(); - } - return root.currentLayout.substring(0, 2).toUpperCase(); - } - return root.currentLayout; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - - MouseArea { - z: 1 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - } - onClicked: { - if (CompositorService.isNiri) { - NiriService.cycleKeyboardLayout(); - } else if (CompositorService.isHyprland) { - Quickshell.execDetached(["hyprctl", "switchxkblayout", root.hyprlandKeyboard, "next"]); - } else if (CompositorService.isDwl) { - Quickshell.execDetached(["mmsg", "-d", "switch_keyboard_layout"]); - } - } - } - - Connections { - target: CompositorService.isHyprland ? Hyprland : null - enabled: CompositorService.isHyprland - - function onRawEvent(event) { - if (event.name === "activelayout") { - updateLayout(); - } - } - } - - Component.onCompleted: { - if (CompositorService.isHyprland) { - updateLayout(); - } - } - - function updateLayout() { - if (CompositorService.isHyprland) { - Proc.runCommand(null, ["hyprctl", "-j", "devices"], (output, exitCode) => { - if (exitCode !== 0) { - root.currentLayout = "Unknown"; - return; - } - try { - const data = JSON.parse(output); - const mainKeyboard = data.keyboards.find(kb => kb.main === true); - root.hyprlandKeyboard = mainKeyboard.name; - - if (mainKeyboard) { - const layout = mainKeyboard.layout; - const variant = mainKeyboard.variant; - const index = mainKeyboard.active_layout_index; - - if (root.compactMode && layout && index !== undefined) { - const layouts = mainKeyboard.layout.split(","); - const variants = mainKeyboard.variant.split(","); - const index = mainKeyboard.active_layout_index; - - if (layouts[index] && variants[index] !== undefined) { - if (variants[index] === "") { - root.currentLayout = layouts[index]; - } else { - root.currentLayout = layouts[index] + "-" + variants[index]; - } - } else { - root.currentLayout = layouts[index]; - } - } else if (mainKeyboard && mainKeyboard.active_keymap) { - root.currentLayout = mainKeyboard.active_keymap; - } else { - root.currentLayout = "Unknown"; - } - } else { - root.currentLayout = "Unknown"; - } - } catch (e) { - root.currentLayout = "Unknown"; - } - }); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/LauncherButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/LauncherButton.qml deleted file mode 100644 index 81e6457..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/LauncherButton.qml +++ /dev/null @@ -1,123 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell.Widgets -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - property var hyprlandOverviewLoader: null - - content: Component { - Item { - implicitWidth: root.widgetThickness - root.horizontalPadding * 2 - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - visible: SettingsData.launcherLogoMode === "apps" - anchors.centerIn: parent - name: "apps" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetIconColor - } - - SystemLogo { - visible: SettingsData.launcherLogoMode === "os" - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - colorOverride: Theme.effectiveLogoColor - brightnessOverride: SettingsData.launcherLogoBrightness - contrastOverride: SettingsData.launcherLogoContrast - } - - IconImage { - visible: SettingsData.launcherLogoMode === "dank" - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - smooth: true - mipmap: true - asynchronous: true - source: "file://" + Theme.shellDir + "/assets/danklogo.svg" - layer.enabled: Theme.effectiveLogoColor !== "" - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.effectiveLogoColor - } - } - - IconImage { - visible: SettingsData.launcherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle || CompositorService.isLabwc) - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - smooth: true - asynchronous: true - source: { - if (CompositorService.isNiri) { - return "file://" + Theme.shellDir + "/assets/niri.svg"; - } else if (CompositorService.isHyprland) { - return "file://" + Theme.shellDir + "/assets/hyprland.svg"; - } else if (CompositorService.isDwl) { - return "file://" + Theme.shellDir + "/assets/mango.png"; - } else if (CompositorService.isSway) { - return "file://" + Theme.shellDir + "/assets/sway.svg"; - } else if (CompositorService.isScroll) { - return "file://" + Theme.shellDir + "/assets/sway.svg"; - } else if (CompositorService.isMiracle) { - return "file://" + Theme.shellDir + "/assets/miraclewm.svg"; - } else if (CompositorService.isLabwc) { - return "file://" + Theme.shellDir + "/assets/labwc.png"; - } - return ""; - } - layer.enabled: Theme.effectiveLogoColor !== "" - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.effectiveLogoColor - brightness: { - SettingsData.launcherLogoBrightness; - } - contrast: { - SettingsData.launcherLogoContrast; - } - } - } - - IconImage { - visible: SettingsData.launcherLogoMode === "custom" && SettingsData.launcherLogoCustomPath !== "" - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - smooth: true - asynchronous: true - source: SettingsData.launcherLogoCustomPath ? "file://" + SettingsData.launcherLogoCustomPath.replace("file://", "") : "" - layer.enabled: Theme.effectiveLogoColor !== "" - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.effectiveLogoColor - brightness: SettingsData.launcherLogoBrightness - contrast: SettingsData.launcherLogoContrast - } - } - } - } - - onRightClicked: { - if (CompositorService.isNiri) { - NiriService.toggleOverview(); - } else if (root.hyprlandOverviewLoader?.item) { - root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Media.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Media.qml deleted file mode 100644 index 6007427..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Media.qml +++ /dev/null @@ -1,502 +0,0 @@ -import QtQuick -import Quickshell.Services.Mpris -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - readonly property MprisPlayer activePlayer: MprisController.activePlayer - readonly property bool playerAvailable: activePlayer !== null - readonly property bool __isChromeBrowser: { - if (!activePlayer?.identity) - return false; - const id = activePlayer.identity.toLowerCase(); - return id.includes("chrome") || id.includes("chromium"); - } - readonly property bool usePlayerVolume: activePlayer && activePlayer.volumeSupported && !__isChromeBrowser - property bool compactMode: false - property var widgetData: null - readonly property bool adaptiveWidthEnabled: SettingsData.mediaAdaptiveWidthEnabled - readonly property int maxTextWidth: { - const size = widgetData?.mediaSize !== undefined ? widgetData.mediaSize : SettingsData.mediaSize; - switch (size) { - case 0: - return 0; - case 2: - return 180; - case 3: - return 240; - default: - return 120; - } - } - readonly property int currentContentWidth: { - if (isVerticalOrientation) { - return widgetThickness - horizontalPadding * 2; - } - return 0; - } - readonly property int currentContentHeight: { - if (!isVerticalOrientation) { - return widgetThickness - horizontalPadding * 2; - } - const audioVizHeight = 20; - const playButtonHeight = 24; - return audioVizHeight + Theme.spacingXS + playButtonHeight; - } - - property real scrollAccumulatorY: 0 - property real touchpadThreshold: 100 - - onWheel: function (wheelEvent) { - if (SettingsData.audioScrollMode === "nothing") - return; - - if (SettingsData.audioScrollMode === "volume") { - if (!usePlayerVolume) - return; - - wheelEvent.accepted = true; - - const deltaY = wheelEvent.angleDelta.y; - const isMouseWheelY = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0; - - const currentVolume = activePlayer.volume * 100; - - let newVolume = currentVolume; - if (isMouseWheelY) { - if (deltaY > 0) { - newVolume = Math.min(100, currentVolume + SettingsData.audioWheelScrollAmount); - } else if (deltaY < 0) { - newVolume = Math.max(0, currentVolume - SettingsData.audioWheelScrollAmount); - } - } else { - scrollAccumulatorY += deltaY; - if (Math.abs(scrollAccumulatorY) >= touchpadThreshold) { - if (scrollAccumulatorY > 0) { - newVolume = Math.min(100, currentVolume + 1); - } else { - newVolume = Math.max(0, currentVolume - 1); - } - scrollAccumulatorY = 0; - } - } - - activePlayer.volume = newVolume / 100; - } else if (SettingsData.audioScrollMode === "song") { - if (!activePlayer) - return; - - wheelEvent.accepted = true; - - const deltaY = wheelEvent.angleDelta.y; - const isMouseWheelY = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0; - - if (isMouseWheelY) { - if (deltaY > 0) { - MprisController.previousOrRewind(); - } else { - activePlayer.next(); - } - } else { - scrollAccumulatorY += deltaY; - if (Math.abs(scrollAccumulatorY) >= touchpadThreshold) { - if (scrollAccumulatorY > 0) { - MprisController.previousOrRewind(); - } else { - activePlayer.next(); - } - scrollAccumulatorY = 0; - } - } - } - } - - content: Component { - Item { - id: contentRoot - readonly property real measuredTextWidth: { - if (!root.playerAvailable || root.maxTextWidth <= 0 || !textContainer.visible) - return 0; - // Preserve the fixed-width text slot even if metadata is briefly empty. - if (!root.adaptiveWidthEnabled) - return root.maxTextWidth; - if (textContainer.displayText.length === 0) - return 0; - const rawWidth = mediaText.contentWidth; - if (!isFinite(rawWidth) || rawWidth <= 0) - return 0; - return Math.min(root.maxTextWidth, Math.ceil(rawWidth)); - } - readonly property int horizontalContentWidth: { - const controlsWidth = 20 + Theme.spacingXS + 24 + Theme.spacingXS + 20; - const audioVizWidth = 20; - const baseWidth = audioVizWidth + Theme.spacingXS + controlsWidth; - return baseWidth + (measuredTextWidth > 0 ? measuredTextWidth + Theme.spacingXS : 0); - } - - implicitWidth: root.playerAvailable ? (root.isVerticalOrientation ? root.currentContentWidth : horizontalContentWidth) : 0 - implicitHeight: root.playerAvailable ? root.currentContentHeight : 0 - opacity: root.playerAvailable ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on implicitWidth { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - - Behavior on implicitHeight { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Column { - id: verticalLayout - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - Item { - width: 20 - height: 20 - anchors.horizontalCenter: parent.horizontalCenter - - AudioVisualization { - anchors.fill: parent - visible: CavaService.cavaAvailable && SettingsData.audioVisualizerEnabled - } - - DankIcon { - anchors.fill: parent - name: "music_note" - size: 20 - color: Theme.primary - visible: !CavaService.cavaAvailable || !SettingsData.audioVisualizerEnabled - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - } - onClicked: { - if (root.popoutTarget && root.popoutTarget.setTriggerPosition) { - const globalPos = parent.mapToItem(null, 0, 0); - const currentScreen = root.parentScreen || Screen; - const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, parent.width, root.barSpacing, barPosition, root.barConfig); - root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen, barPosition, root.barThickness, root.barSpacing, root.barConfig); - } - root.clicked(); - } - } - } - - Rectangle { - width: 24 - height: 24 - radius: 12 - anchors.horizontalCenter: parent.horizontalCenter - color: activePlayer && activePlayer.playbackState === 1 ? Theme.primary : Theme.primaryHover - visible: root.playerAvailable - opacity: activePlayer ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: activePlayer && activePlayer.playbackState === 1 ? "pause" : "play_arrow" - size: 14 - color: activePlayer && activePlayer.playbackState === 1 ? Theme.background : Theme.primary - } - - MouseArea { - anchors.fill: parent - enabled: root.playerAvailable - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton - onClicked: mouse => { - if (!activePlayer) - return; - if (mouse.button === Qt.LeftButton) { - activePlayer.togglePlaying(); - } else if (mouse.button === Qt.MiddleButton) { - MprisController.previousOrRewind(); - } else if (mouse.button === Qt.RightButton) { - activePlayer.next(); - } - } - } - } - } - - Row { - id: mediaRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - Row { - id: mediaInfo - spacing: Theme.spacingXS - - Item { - width: 20 - height: 20 - anchors.verticalCenter: parent.verticalCenter - - AudioVisualization { - anchors.fill: parent - visible: CavaService.cavaAvailable && SettingsData.audioVisualizerEnabled - } - - DankIcon { - anchors.fill: parent - name: "music_note" - size: 20 - color: Theme.primary - visible: !CavaService.cavaAvailable || !SettingsData.audioVisualizerEnabled - } - } - - Rectangle { - id: textContainer - readonly property string cachedIdentity: activePlayer ? (activePlayer.identity || "") : "" - readonly property string lowerIdentity: cachedIdentity.toLowerCase() - readonly property bool isWebMedia: lowerIdentity.includes("firefox") || lowerIdentity.includes("chrome") || lowerIdentity.includes("chromium") || lowerIdentity.includes("edge") || lowerIdentity.includes("safari") - - property string displayText: { - if (!activePlayer || !activePlayer.trackTitle) { - return ""; - } - - const title = isWebMedia ? activePlayer.trackTitle : (activePlayer.trackTitle || "Unknown Track"); - const subtitle = isWebMedia ? (activePlayer.trackArtist || cachedIdentity) : (activePlayer.trackArtist || ""); - return subtitle.length > 0 ? title + " • " + subtitle : title; - } - - anchors.verticalCenter: parent.verticalCenter - width: contentRoot.measuredTextWidth - height: root.widgetThickness - visible: { - const size = widgetData?.mediaSize !== undefined ? widgetData.mediaSize : SettingsData.mediaSize; - return size > 0; - } - clip: true - color: "transparent" - - Behavior on width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - - Item { - id: textClip - anchors.fill: parent - clip: true - - StyledText { - id: mediaText - property bool needsScrolling: implicitWidth > textContainer.width && SettingsData.scrollTitleEnabled - property real scrollOffset: 0 - property real textShift: 0 - - anchors.verticalCenter: parent.verticalCenter - text: textContainer.displayText - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - wrapMode: Text.NoWrap - x: (needsScrolling ? -scrollOffset : 0) + textShift - opacity: 1 - - onTextChanged: { - scrollOffset = 0; - textShift = 0; - scrollAnimation.restart(); - textChangeAnimation.restart(); - } - - SequentialAnimation { - id: scrollAnimation - running: mediaText.needsScrolling && textContainer.visible - loops: Animation.Infinite - - PauseAnimation { - duration: 2000 - } - - NumberAnimation { - target: mediaText - property: "scrollOffset" - from: 0 - to: mediaText.implicitWidth - textContainer.width + 5 - duration: Math.max(1000, (mediaText.implicitWidth - textContainer.width + 5) * 60) - easing.type: Easing.Linear - } - - PauseAnimation { - duration: 2000 - } - - NumberAnimation { - target: mediaText - property: "scrollOffset" - to: 0 - duration: Math.max(1000, (mediaText.implicitWidth - textContainer.width + 5) * 60) - easing.type: Easing.Linear - } - } - - SequentialAnimation { - id: textChangeAnimation - - ParallelAnimation { - NumberAnimation { - target: mediaText - property: "opacity" - from: 0.7 - to: 1 - duration: Theme.shortDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - - NumberAnimation { - target: mediaText - property: "textShift" - from: 4 - to: 0 - duration: Theme.shortDuration - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - } - } - } - - MouseArea { - anchors.fill: parent - enabled: root.playerAvailable - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - if (root.popoutTarget && root.popoutTarget.setTriggerPosition) { - const globalPos = mapToItem(null, 0, 0); - const currentScreen = root.parentScreen || Screen; - const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, root.width, root.barSpacing, barPosition, root.barConfig); - root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen, barPosition, root.barThickness, root.barSpacing, root.barConfig); - } - root.clicked(); - } - } - } - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.verticalCenter: parent.verticalCenter - color: prevArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - visible: root.playerAvailable - opacity: (activePlayer && activePlayer.canGoPrevious) ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: "skip_previous" - size: 12 - color: Theme.widgetTextColor - } - - MouseArea { - id: prevArea - anchors.fill: parent - enabled: root.playerAvailable - cursorShape: Qt.PointingHandCursor - onClicked: MprisController.previousOrRewind() - } - } - - Rectangle { - width: 24 - height: 24 - radius: 12 - anchors.verticalCenter: parent.verticalCenter - color: activePlayer && activePlayer.playbackState === 1 ? Theme.primary : Theme.primaryHover - visible: root.playerAvailable - opacity: activePlayer ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: activePlayer && activePlayer.playbackState === 1 ? "pause" : "play_arrow" - size: 14 - color: activePlayer && activePlayer.playbackState === 1 ? Theme.background : Theme.primary - } - - MouseArea { - anchors.fill: parent - enabled: root.playerAvailable - cursorShape: Qt.PointingHandCursor - onClicked: { - if (activePlayer) { - activePlayer.togglePlaying(); - } - } - } - } - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.verticalCenter: parent.verticalCenter - color: nextArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - visible: playerAvailable - opacity: (activePlayer && activePlayer.canGoNext) ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: "skip_next" - size: 12 - color: Theme.widgetTextColor - } - - MouseArea { - id: nextArea - anchors.fill: parent - enabled: root.playerAvailable - cursorShape: Qt.PointingHandCursor - onClicked: { - if (activePlayer) { - activePlayer.next(); - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml deleted file mode 100644 index b7d8436..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml +++ /dev/null @@ -1,147 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Modules.Plugins -import qs.Modules.ProcessList -import qs.Services -import qs.Widgets - -BasePill { - id: root - - function formatNetworkSpeed(bytesPerSec) { - if (bytesPerSec < 1024) { - return bytesPerSec.toFixed(0) + " B/s" - } else if (bytesPerSec < 1024 * 1024) { - return (bytesPerSec / 1024).toFixed(1) + " KB/s" - } else if (bytesPerSec < 1024 * 1024 * 1024) { - return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s" - } else { - return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(1) + " GB/s" - } - } - - Component.onCompleted: { - DgopService.addRef(["network"]) - } - Component.onDestruction: { - DgopService.removeRef(["network"]) - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : contentRow.implicitWidth - implicitHeight: root.isVerticalOrientation ? contentColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - Column { - id: contentColumn - anchors.centerIn: parent - spacing: 2 - visible: root.isVerticalOrientation - - DankIcon { - name: "network_check" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - const rate = DgopService.networkRxRate - if (rate < 1024) return rate.toFixed(0) - if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K" - return (rate / (1024 * 1024)).toFixed(0) + "M" - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.info - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - const rate = DgopService.networkTxRate - if (rate < 1024) return rate.toFixed(0) - if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K" - return (rate / (1024 * 1024)).toFixed(0) + "M" - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.error - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: contentRow - anchors.centerIn: parent - spacing: Theme.spacingS - visible: !root.isVerticalOrientation - - DankIcon { - name: "network_check" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - - Row { - anchors.verticalCenter: parent.verticalCenter - spacing: 4 - - StyledText { - text: "↓" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.info - } - - StyledText { - text: DgopService.networkRxRate > 0 ? root.formatNetworkSpeed(DgopService.networkRxRate) : "0 B/s" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignLeft - elide: Text.ElideNone - wrapMode: Text.NoWrap - - StyledTextMetrics { - id: rxBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: "88.8 MB/s" - } - - width: Math.max(rxBaseline.width, paintedWidth) - } - } - - Row { - anchors.verticalCenter: parent.verticalCenter - spacing: 4 - - StyledText { - text: "↑" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.error - } - - StyledText { - text: DgopService.networkTxRate > 0 ? root.formatNetworkSpeed(DgopService.networkTxRate) : "0 B/s" - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignLeft - elide: Text.ElideNone - wrapMode: Text.NoWrap - - StyledTextMetrics { - id: txBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: "88.8 MB/s" - } - - width: Math.max(txBaseline.width, paintedWidth) - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotepadButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotepadButton.qml deleted file mode 100644 index 08f5e6b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotepadButton.qml +++ /dev/null @@ -1,367 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import Quickshell.Hyprland -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - readonly property string focusedScreenName: (CompositorService.isHyprland && typeof Hyprland !== "undefined" && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor ? (Hyprland.focusedWorkspace.monitor.name || "") : CompositorService.isNiri && typeof NiriService !== "undefined" && NiriService.currentOutput ? NiriService.currentOutput : "") - - function resolveNotepadInstance() { - if (typeof notepadSlideoutVariants === "undefined" || !notepadSlideoutVariants || !notepadSlideoutVariants.instances) { - return null; - } - - const targetScreen = focusedScreenName; - if (targetScreen) { - for (var i = 0; i < notepadSlideoutVariants.instances.length; i++) { - var slideout = notepadSlideoutVariants.instances[i]; - if (slideout.modelData && slideout.modelData.name === targetScreen) { - return slideout; - } - } - } - - return notepadSlideoutVariants.instances.length > 0 ? notepadSlideoutVariants.instances[0] : null; - } - - readonly property var notepadInstance: resolveNotepadInstance() - readonly property bool isActive: notepadInstance?.isVisible ?? false - property bool isAutoHideBar: false - - readonly property real minTooltipY: { - if (!parentScreen || !(axis?.isVertical ?? false)) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - return barThickness + barSpacing; - } - - return 0; - } - - readonly property var savedTabEntries: { - const result = []; - const tabs = NotepadStorageService.tabs || []; - for (let i = 0; i < tabs.length; i++) { - const tab = tabs[i]; - if (tab && !tab.isTemporary) { - result.push({ - index: i, - tab: tab - }); - } - } - return result.slice(0, 5); - } - - function openTabByIndex(tabIndex) { - if (tabIndex < 0) - return; - if (root.notepadInstance && typeof root.notepadInstance.show === "function") { - root.notepadInstance.show(); - } - Qt.callLater(() => { - NotepadStorageService.switchToTab(tabIndex); - }); - } - - function openNewNote() { - if (root.notepadInstance && typeof root.notepadInstance.show === "function") { - root.notepadInstance.show(); - } - Qt.callLater(() => { - NotepadStorageService.createNewTab(); - }); - } - - function openContextMenu() { - const screen = root.parentScreen || Screen; - const screenX = screen.x || 0; - const screenY = screen.y || 0; - const isVertical = root.axis?.isVertical ?? false; - const edge = root.axis?.edge ?? "top"; - const gap = Math.max(Theme.spacingXS, root.barSpacing ?? Theme.spacingXS); - - const globalPos = root.mapToGlobal(root.width / 2, root.height / 2); - const relativeX = globalPos.x - screenX; - const relativeY = globalPos.y - screenY; - - let anchorX = relativeX; - let anchorY = relativeY; - - if (isVertical) { - anchorX = edge === "left" ? (root.barThickness + root.barSpacing + gap) : (screen.width - (root.barThickness + root.barSpacing + gap)); - anchorY = relativeY + root.minTooltipY; - } else { - anchorX = relativeX; - anchorY = edge === "bottom" ? (screen.height - (root.barThickness + root.barSpacing + gap)) : (root.barThickness + root.barSpacing + gap); - } - - contextMenuWindow.showAt(anchorX, anchorY, isVertical, edge, screen); - } - - content: Component { - Item { - implicitWidth: notepadIcon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: notepadIcon - - anchors.centerIn: parent - name: "assignment" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: root.isActive ? Theme.primary : Theme.surfaceText - } - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - } - onClicked: function (mouse) { - if (mouse.button === Qt.RightButton) { - openContextMenu(); - return; - } - const inst = root.notepadInstance; - if (inst) { - inst.toggle(); - } - } - } - - PanelWindow { - id: contextMenuWindow - - WlrLayershell.namespace: "dms:notepad-context-menu" - - property bool isVertical: false - property string edge: "top" - property point anchorPos: Qt.point(0, 0) - - function showAt(x, y, vertical, barEdge, targetScreen) { - if (targetScreen) { - contextMenuWindow.screen = targetScreen; - } - - anchorPos = Qt.point(x, y); - isVertical = vertical ?? false; - edge = barEdge ?? "top"; - - visible = true; - - if (contextMenuWindow.screen) { - TrayMenuManager.registerMenu(contextMenuWindow.screen.name, contextMenuWindow); - } - } - - function closeMenu() { - visible = false; - - if (contextMenuWindow.screen) { - TrayMenuManager.unregisterMenu(contextMenuWindow.screen.name); - } - } - - screen: null - visible: false - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - anchors { - top: true - left: true - right: true - bottom: true - } - - Component.onDestruction: { - if (contextMenuWindow.screen) { - TrayMenuManager.unregisterMenu(contextMenuWindow.screen.name); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - contextMenuWindow.closeMenu(); - } - } - - MouseArea { - anchors.fill: parent - z: 0 - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: contextMenuWindow.closeMenu() - } - - Rectangle { - id: menuContainer - z: 1 - - x: { - if (contextMenuWindow.isVertical) { - if (contextMenuWindow.edge === "left") { - return Math.min(contextMenuWindow.width - width - 10, contextMenuWindow.anchorPos.x); - } - return Math.max(10, contextMenuWindow.anchorPos.x - width); - } - const left = 10; - const right = contextMenuWindow.width - width - 10; - const want = contextMenuWindow.anchorPos.x - width / 2; - return Math.max(left, Math.min(right, want)); - } - y: { - if (contextMenuWindow.isVertical) { - const top = 10; - const bottom = contextMenuWindow.height - height - 10; - const want = contextMenuWindow.anchorPos.y - height / 2; - return Math.max(top, Math.min(bottom, want)); - } - if (contextMenuWindow.edge === "top") { - return Math.min(contextMenuWindow.height - height - 10, contextMenuWindow.anchorPos.y); - } - return Math.max(10, contextMenuWindow.anchorPos.y - height); - } - - width: Math.min(260, Math.max(180, menuColumn.implicitWidth + Theme.spacingS * 2)) - height: Math.max(60, menuColumn.implicitHeight + Theme.spacingS * 2) - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 1 - - opacity: contextMenuWindow.visible ? 1 : 0 - visible: opacity > 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: -1 - } - - Column { - id: menuColumn - width: parent.width - Theme.spacingS * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - spacing: 1 - - Repeater { - model: root.savedTabEntries - - Rectangle { - required property var modelData - - width: parent.width - height: 30 - radius: Theme.cornerRadius - color: tabArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "description" - size: 16 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: modelData.tab?.title || I18n.tr("Saved Note") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - elide: Text.ElideRight - maximumLineCount: 1 - } - } - - MouseArea { - id: tabArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - contextMenuWindow.closeMenu(); - root.openTabByIndex(modelData.index); - } - } - } - } - - Rectangle { - width: parent.width - height: 30 - radius: Theme.cornerRadius - color: newNoteArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "add" - size: 16 - color: Theme.surfaceText - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Open a new note") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - - MouseArea { - id: newNoteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - contextMenuWindow.closeMenu(); - root.openNewNote(); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotificationCenterButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotificationCenterButton.qml deleted file mode 100644 index d7bcc1e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/NotificationCenterButton.qml +++ /dev/null @@ -1,40 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Widgets - -BasePill { - id: root - - property bool hasUnread: false - property bool isActive: false - - content: Component { - Item { - implicitWidth: notifIcon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: notifIcon - anchors.centerIn: parent - name: SessionData.doNotDisturb ? "notifications_off" : "notifications" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: SessionData.doNotDisturb ? Theme.primary : (root.isActive ? Theme.primary : Theme.widgetIconColor) - } - - Rectangle { - width: 6 - height: 6 - radius: 3 - color: Theme.error - anchors.right: notifIcon.right - anchors.top: notifIcon.top - visible: root.hasUnread - } - } - } - - onRightClicked: { - SessionData.setDoNotDisturb(!SessionData.doNotDisturb); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PowerMenuButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PowerMenuButton.qml deleted file mode 100644 index da9caee..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PowerMenuButton.qml +++ /dev/null @@ -1,25 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - anchors.centerIn: parent - name: "power_settings_new" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetIconColor - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PrivacyIndicator.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PrivacyIndicator.qml deleted file mode 100644 index a09aa55..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/PrivacyIndicator.qml +++ /dev/null @@ -1,247 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - section: "right" - - property bool showMicIcon: SettingsData.privacyShowMicIcon - property bool showCameraIcon: SettingsData.privacyShowCameraIcon - property bool showScreenSharingIcon: SettingsData.privacyShowScreenShareIcon - - readonly property bool hasActivePrivacy: showMicIcon || showCameraIcon || showScreenSharingIcon || PrivacyService.anyPrivacyActive - readonly property int activeCount: (showMicIcon ? 1 : PrivacyService.microphoneActive) + (showCameraIcon ? 1 : PrivacyService.cameraActive) + (showScreenSharingIcon ? 1 : PrivacyService.screensharingActive) - readonly property real contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0 - readonly property real contentHeight: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0 - - opacity: hasActivePrivacy ? 1 : 0 - - states: [ - State { - name: "hidden_horizontal" - when: !hasActivePrivacy && !isVerticalOrientation - PropertyChanges { - target: root - width: 0 - } - }, - State { - name: "hidden_vertical" - when: !hasActivePrivacy && isVerticalOrientation - PropertyChanges { - target: root - height: 0 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "width,height" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - content: Component { - Item { - implicitWidth: root.hasActivePrivacy ? root.contentWidth : 0 - implicitHeight: root.hasActivePrivacy ? root.contentHeight : 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - visible: root.isVerticalOrientation && root.hasActivePrivacy - - Item { - width: 18 - height: 18 - visible: root.showMicIcon || PrivacyService.microphoneActive - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - name: { - const sourceAudio = AudioService.source?.audio; - const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0; - if (muted) - return "mic_off"; - return "mic"; - } - size: Theme.iconSizeSmall - color: PrivacyService.microphoneActive ? Theme.error : Theme.surfaceText - filled: PrivacyService.microphoneActive - anchors.centerIn: parent - } - } - - Item { - width: 18 - height: 18 - visible: root.showCameraIcon || PrivacyService.cameraActive - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - name: "camera_video" - size: Theme.iconSizeSmall - color: PrivacyService.cameraActive ? Theme.error : Theme.surfaceText - filled: PrivacyService.cameraActive - anchors.centerIn: parent - } - - Rectangle { - width: 6 - height: 6 - radius: 3 - color: Theme.error - anchors.right: parent.right - anchors.top: parent.top - anchors.rightMargin: -2 - anchors.topMargin: -1 - visible: PrivacyService.cameraActive - } - } - - Item { - width: 18 - height: 18 - visible: root.showScreenSharingIcon || PrivacyService.screensharingActive - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - name: "screen_share" - size: Theme.iconSizeSmall - color: PrivacyService.screensharingActive ? Theme.warning : Theme.surfaceText - filled: PrivacyService.screensharingActive - anchors.centerIn: parent - } - } - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - visible: !root.isVerticalOrientation && root.hasActivePrivacy - - Item { - width: 18 - height: 18 - visible: root.showMicIcon || PrivacyService.microphoneActive - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: { - const sourceAudio = AudioService.source?.audio; - const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0; - if (muted) - return "mic_off"; - return "mic"; - } - size: Theme.iconSizeSmall - color: PrivacyService.microphoneActive ? Theme.error : Theme.surfaceText - filled: PrivacyService.microphoneActive - anchors.centerIn: parent - } - } - - Item { - width: 18 - height: 18 - visible: root.showCameraIcon || PrivacyService.cameraActive - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: "camera_video" - size: Theme.iconSizeSmall - color: PrivacyService.cameraActive ? Theme.error : Theme.surfaceText - filled: PrivacyService.cameraActive - anchors.centerIn: parent - } - - Rectangle { - width: 6 - height: 6 - radius: 3 - color: Theme.error - anchors.right: parent.right - anchors.top: parent.top - anchors.rightMargin: -2 - anchors.topMargin: -1 - visible: PrivacyService.cameraActive - } - } - - Item { - width: 18 - height: 18 - visible: root.showScreenSharingIcon || PrivacyService.screensharingActive - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: "screen_share" - size: Theme.iconSizeSmall - color: PrivacyService.screensharingActive ? Theme.warning : Theme.surfaceText - filled: PrivacyService.screensharingActive - anchors.centerIn: parent - } - } - } - } - } - - Rectangle { - id: tooltip - width: tooltipText.contentWidth + Theme.spacingM * 2 - height: tooltipText.contentHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - border.color: Theme.outlineMedium - border.width: 1 - visible: false - opacity: root.isMouseHovered && hasActivePrivacy ? 1 : 0 - z: 100 - x: (parent.width - width) / 2 - y: -height - Theme.spacingXS - - StyledText { - id: tooltipText - anchors.centerIn: parent - text: PrivacyService.getPrivacySummary() - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - } - - Rectangle { - width: 8 - height: 8 - color: parent.color - border.color: parent.border.color - border.width: parent.border.width - rotation: 45 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.bottom - anchors.topMargin: -4 - } - - Behavior on opacity { - enabled: hasActivePrivacy && root.visible - - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RamMonitor.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RamMonitor.qml deleted file mode 100644 index f5d6de5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RamMonitor.qml +++ /dev/null @@ -1,175 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool showPercentage: true - property bool showIcon: true - property var toggleProcessList - property var popoutTarget: null - property var widgetData: null - property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true - property bool showSwap: (widgetData && widgetData.showSwap !== undefined) ? widgetData.showSwap : false - property bool showInGb: (widgetData && widgetData.showInGb !== undefined) ? widgetData.showInGb : false - readonly property real swapUsage: DgopService.totalSwapKB > 0 ? (DgopService.usedSwapKB / DgopService.totalSwapKB) * 100 : 0 - - signal ramClicked - - Component.onCompleted: { - DgopService.addRef(["memory"]); - } - Component.onDestruction: { - DgopService.removeRef(["memory"]); - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : ramContent.implicitWidth - implicitHeight: root.isVerticalOrientation ? ramColumn.implicitHeight : ramContent.implicitHeight - - Column { - id: ramColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: "developer_board" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.memoryUsage > 90) { - return Theme.tempDanger; - } - - if (DgopService.memoryUsage > 75) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) { - return "--"; - } - - if (root.showInGb) { - return (DgopService.usedMemoryMB / 1024).toFixed(1); - } - - return DgopService.memoryUsage.toFixed(0); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - visible: root.showSwap && DgopService.totalSwapKB > 0 - text: root.swapUsage.toFixed(0) - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: ramContent - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - id: ramIcon - name: "developer_board" - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (DgopService.memoryUsage > 90) { - return Theme.tempDanger; - } - - if (DgopService.memoryUsage > 75) { - return Theme.tempWarning; - } - - return Theme.widgetIconColor; - } - anchors.verticalCenter: parent.verticalCenter - } - - Item { - id: textBox - anchors.verticalCenter: parent.verticalCenter - - implicitWidth: root.minimumWidth ? Math.max(ramBaseline.width, ramText.paintedWidth) : ramText.paintedWidth - implicitHeight: ramText.implicitHeight - - width: implicitWidth - height: implicitHeight - - StyledTextMetrics { - id: ramBaseline - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - text: { - let baseText = root.showInGb ? "88.8 GB" : "88%"; - if (!root.showSwap) { - return baseText; - } - if (root.swapUsage < 10) { - return baseText + " · 0%"; - } - return baseText + " · 88%"; - } - } - - StyledText { - id: ramText - text: { - if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) { - return root.showInGb ? "-- GB" : "--%"; - } - - let ramText = ""; - if (root.showInGb) { - ramText = (DgopService.usedMemoryMB / 1024).toFixed(1) + " GB"; - } else { - ramText = DgopService.memoryUsage.toFixed(0) + "%"; - } - - if (root.showSwap && DgopService.totalSwapKB > 0) { - return ramText + " · " + root.swapUsage.toFixed(0) + "%"; - } - return ramText; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - - anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - elide: Text.ElideNone - wrapMode: Text.NoWrap - } - } - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - DgopService.setSortBy("memory"); - ramClicked(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RunningApps.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RunningApps.qml deleted file mode 100644 index ae58802..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/RunningApps.qml +++ /dev/null @@ -1,902 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Effects -import Quickshell -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - enableBackgroundHover: false - enableCursor: false - section: "left" - - property var widgetData: null - property var hoveredItem: null - property var topBar: null - property bool isAutoHideBar: false - property Item windowRoot: (Window.window ? Window.window.contentItem : null) - - readonly property real effectiveBarThickness: { - if (barThickness > 0 && barSpacing > 0) { - return barThickness + barSpacing; - } - const innerPadding = barConfig?.innerPadding ?? 4; - const spacing = barConfig?.spacing ?? 4; - return Math.max(26 + innerPadding * 0.6, Theme.barHeight - 4 - (8 - innerPadding)) + spacing; - } - - readonly property var barBounds: { - if (!parentScreen || !barConfig) { - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - const barPosition = axis.edge === "left" ? 2 : (axis.edge === "right" ? 3 : (axis.edge === "top" ? 0 : 1)); - return SettingsData.getBarBounds(parentScreen, effectiveBarThickness, barPosition, barConfig); - } - - readonly property real barY: barBounds.y - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - return effectiveBarThickness; - } - - return 0; - } - - property int _desktopEntriesUpdateTrigger: 0 - property int _toplevelsUpdateTrigger: 0 - property int _appIdSubstitutionsTrigger: 0 - - readonly property bool _currentWorkspace: widgetData?.runningAppsCurrentWorkspace !== undefined ? widgetData.runningAppsCurrentWorkspace : SettingsData.runningAppsCurrentWorkspace - readonly property bool _currentMonitor: widgetData?.runningAppsCurrentMonitor !== undefined ? widgetData.runningAppsCurrentMonitor : SettingsData.runningAppsCurrentMonitor - readonly property bool _groupByApp: widgetData?.runningAppsGroupByApp !== undefined ? widgetData.runningAppsGroupByApp : SettingsData.runningAppsGroupByApp - - readonly property var sortedToplevels: { - _toplevelsUpdateTrigger; - let toplevels = CompositorService.sortedToplevels; - if (!toplevels || toplevels.length === 0) - return []; - - if (_currentWorkspace) - toplevels = CompositorService.filterCurrentWorkspace(toplevels, parentScreen?.name) || []; - if (_currentMonitor) - toplevels = CompositorService.filterCurrentDisplay(toplevels, parentScreen?.name) || []; - return toplevels; - } - - Connections { - target: CompositorService - function onToplevelsChanged() { - _toplevelsUpdateTrigger++; - } - } - - Connections { - target: DesktopEntries - function onApplicationsChanged() { - _desktopEntriesUpdateTrigger++; - } - } - - Connections { - target: SettingsData - function onAppIdSubstitutionsChanged() { - _appIdSubstitutionsTrigger++; - } - } - readonly property var groupedWindows: { - if (!_groupByApp) { - return []; - } - try { - if (!sortedToplevels || sortedToplevels.length === 0) { - return []; - } - const appGroups = new Map(); - sortedToplevels.forEach((toplevel, index) => { - if (!toplevel) - return; - const appId = toplevel?.appId || "unknown"; - if (!appGroups.has(appId)) { - appGroups.set(appId, { - "appId": appId, - "windows": [] - }); - } - appGroups.get(appId).windows.push({ - "toplevel": toplevel, - "windowId": index, - "windowTitle": toplevel?.title || "(Unnamed)" - }); - }); - return Array.from(appGroups.values()); - } catch (e) { - return []; - } - } - readonly property int windowCount: _groupByApp ? (groupedWindows?.length || 0) : (sortedToplevels?.length || 0) - readonly property real iconCellSize: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) + 6 - - readonly property string focusedAppId: { - if (!sortedToplevels || sortedToplevels.length === 0) - return ""; - for (let i = 0; i < sortedToplevels.length; i++) { - if (sortedToplevels[i].activated) - return sortedToplevels[i].appId || ""; - } - return ""; - } - - visible: windowCount > 0 - - property real scrollAccumulator: 0 - property real touchpadThreshold: 500 - - onWheel: function (wheelEvent) { - wheelEvent.accepted = true; - const deltaY = wheelEvent.angleDelta.y; - const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0; - - const windows = root.sortedToplevels; - if (windows.length < 2) - return; - - if (isMouseWheel) { - let currentIndex = -1; - for (var i = 0; i < windows.length; i++) { - if (windows[i].activated) { - currentIndex = i; - break; - } - } - - let nextIndex; - if (deltaY < 0) { - nextIndex = currentIndex === -1 ? 0 : Math.min(currentIndex + 1, windows.length - 1); - } else { - nextIndex = currentIndex === -1 ? windows.length - 1 : Math.max(currentIndex - 1, 0); - } - - const nextWindow = windows[nextIndex]; - if (nextWindow) - nextWindow.activate(); - } else { - scrollAccumulator += deltaY; - - if (Math.abs(scrollAccumulator) >= touchpadThreshold) { - let currentIndex = -1; - for (var i = 0; i < windows.length; i++) { - if (windows[i].activated) { - currentIndex = i; - break; - } - } - - let nextIndex; - if (scrollAccumulator < 0) { - nextIndex = currentIndex === -1 ? 0 : Math.min(currentIndex + 1, windows.length - 1); - } else { - nextIndex = currentIndex === -1 ? windows.length - 1 : Math.max(currentIndex - 1, 0); - } - - const nextWindow = windows[nextIndex]; - if (nextWindow) - nextWindow.activate(); - - scrollAccumulator = 0; - } - } - } - - content: Component { - Item { - implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0 - implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0 - - Loader { - id: layoutLoader - anchors.centerIn: parent - sourceComponent: root.isVerticalOrientation ? columnLayout : rowLayout - } - } - } - - Component { - id: rowLayout - Row { - spacing: Theme.spacingXS - - Repeater { - id: windowRepeater - model: ScriptModel { - values: _groupByApp ? groupedWindows : sortedToplevels - objectProp: _groupByApp ? "appId" : "address" - } - - delegate: Item { - id: delegateItem - - property bool isGrouped: root._groupByApp - property var groupData: isGrouped ? modelData : null - property var toplevelData: isGrouped ? (modelData.windows.length > 0 ? modelData.windows[0].toplevel : null) : modelData - property bool isFocused: isGrouped ? (root.focusedAppId === appId) : (toplevelData ? toplevelData.activated : false) - property string appId: isGrouped ? modelData.appId : (modelData.appId || "") - readonly property string effectiveAppId: { - root._appIdSubstitutionsTrigger; - return Paths.moddedAppId(appId); - } - property string windowTitle: toplevelData ? (toplevelData.title || "(Unnamed)") : "(Unnamed)" - property var toplevelObject: toplevelData - property int windowCount: isGrouped ? modelData.windows.length : 1 - property string tooltipText: { - root._desktopEntriesUpdateTrigger; - const desktopEntry = effectiveAppId ? DesktopEntries.heuristicLookup(effectiveAppId) : null; - const appName = effectiveAppId ? Paths.getAppName(effectiveAppId, desktopEntry) : "Unknown"; - - if (isGrouped && windowCount > 1) { - return appName + " (" + windowCount + " windows)"; - } - return appName + (windowTitle ? " • " + windowTitle : ""); - } - readonly property real visualWidth: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? root.iconCellSize : (root.iconCellSize + Theme.spacingXS + 120) - - width: visualWidth - height: root.barThickness - - Rectangle { - id: visualContent - width: delegateItem.visualWidth - height: root.iconCellSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: { - if (isFocused) { - return mouseArea.containsMouse ? Theme.primarySelected : Theme.withAlpha(Theme.primary, 0.45); - } - return mouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent"; - } - - // App icon - IconImage { - id: iconImg - anchors.left: parent.left - anchors.leftMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? Math.round((parent.width - Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)) / 2) : Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: { - root._desktopEntriesUpdateTrigger; - root._appIdSubstitutionsTrigger; - if (!effectiveAppId) - return ""; - const desktopEntry = DesktopEntries.heuristicLookup(effectiveAppId); - return Paths.getAppIcon(effectiveAppId, desktopEntry); - } - smooth: true - mipmap: true - asynchronous: true - visible: status === Image.Ready - layer.enabled: appId === "org.quickshell" || appId === "com.danklinux.dms" - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } - - DankIcon { - anchors.left: parent.left - anchors.leftMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? Math.round((parent.width - Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)) / 2) : Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - name: "sports_esports" - color: Theme.widgetTextColor - visible: !iconImg.visible && Paths.isSteamApp(effectiveAppId) - } - - Text { - anchors.centerIn: parent - visible: !iconImg.visible && !Paths.isSteamApp(effectiveAppId) - text: { - root._desktopEntriesUpdateTrigger; - if (!effectiveAppId) - return "?"; - const desktopEntry = DesktopEntries.heuristicLookup(effectiveAppId); - const appName = Paths.getAppName(effectiveAppId, desktopEntry); - return appName.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - Rectangle { - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.rightMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? -2 : 2 - anchors.bottomMargin: -2 - width: 14 - height: 14 - radius: 7 - color: Theme.primary - visible: isGrouped && windowCount > 1 - z: 10 - - StyledText { - anchors.centerIn: parent - text: windowCount > 9 ? "9+" : windowCount - font.pixelSize: 9 - color: Theme.surface - } - } - - StyledText { - anchors.left: iconImg.right - anchors.leftMargin: Theme.spacingXS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - visible: !(widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - text: windowTitle - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - elide: Text.ElideRight - maximumLineCount: 1 - } - - DankRipple { - id: itemRipple - cornerRadius: Theme.cornerRadius - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onPressed: mouse => { - const pos = mapToItem(visualContent, mouse.x, mouse.y); - itemRipple.trigger(pos.x, pos.y); - } - onClicked: mouse => { - if (mouse.button === Qt.LeftButton) { - if (isGrouped && windowCount > 1) { - let currentIndex = -1; - for (var i = 0; i < groupData.windows.length; i++) { - if (groupData.windows[i].toplevel.activated) { - currentIndex = i; - break; - } - } - const nextIndex = (currentIndex + 1) % groupData.windows.length; - groupData.windows[nextIndex].toplevel.activate(); - } else if (toplevelObject) { - toplevelObject.activate(); - } - } else if (mouse.button === Qt.RightButton) { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - - windowContextMenuLoader.active = true; - if (windowContextMenuLoader.item) { - windowContextMenuLoader.item.currentWindow = toplevelObject; - // Pass bar context - windowContextMenuLoader.item.triggerBarConfig = root.barConfig; - windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1)); - windowContextMenuLoader.item.triggerBarThickness = root.barThickness; - windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing; - if (root.isVerticalOrientation) { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const relativeY = globalPos.y - screenY; - // Add minTooltipY offset to account for top bar - const adjustedY = relativeY + root.minTooltipY; - const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge); - } else { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const relativeX = globalPos.x - screenX; - const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height; - const isBottom = root.axis?.edge === "bottom"; - const yPos = isBottom ? (screenHeight - root.barThickness - root.barSpacing - 32 - Theme.spacingXS) : (root.barThickness + root.barSpacing + Theme.spacingXS); - windowContextMenuLoader.item.showAt(relativeX, yPos, false, root.axis?.edge); - } - } - } else if (mouse.button === Qt.MiddleButton) { - if (toplevelObject) { - if (typeof toplevelObject.close === "function") { - toplevelObject.close(); - } - } - } - } - onEntered: { - root.hoveredItem = delegateItem; - tooltipLoader.active = true; - if (tooltipLoader.item) { - if (root.isVerticalOrientation) { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const relativeY = globalPos.y - screenY; - const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - const isLeft = root.axis?.edge === "left"; - const adjustedY = relativeY + root.minTooltipY; - const finalX = screenX + tooltipX; - tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft); - } else { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height); - const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height; - const isBottom = root.axis?.edge === "bottom"; - const tooltipY = isBottom ? (screenHeight - root.barThickness - root.barSpacing - Theme.spacingXS - 35) : (root.barThickness + root.barSpacing + Theme.spacingXS); - tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false); - } - } - } - onExited: { - if (root.hoveredItem === delegateItem) { - root.hoveredItem = null; - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - - tooltipLoader.active = false; - } - } - } - } - } - } - } - - Component { - id: columnLayout - Column { - spacing: Theme.spacingXS - - Repeater { - id: windowRepeater - model: ScriptModel { - values: _groupByApp ? groupedWindows : sortedToplevels - objectProp: _groupByApp ? "appId" : "address" - } - - delegate: Item { - id: delegateItem - - property bool isGrouped: root._groupByApp - property var groupData: isGrouped ? modelData : null - property var toplevelData: isGrouped ? (modelData.windows.length > 0 ? modelData.windows[0].toplevel : null) : modelData - property bool isFocused: isGrouped ? (root.focusedAppId === appId) : (toplevelData ? toplevelData.activated : false) - property string appId: isGrouped ? modelData.appId : (modelData.appId || "") - readonly property string effectiveAppId: { - root._appIdSubstitutionsTrigger; - return Paths.moddedAppId(appId); - } - property string windowTitle: toplevelData ? (toplevelData.title || "(Unnamed)") : "(Unnamed)" - property var toplevelObject: toplevelData - property int windowCount: isGrouped ? modelData.windows.length : 1 - property string tooltipText: { - root._desktopEntriesUpdateTrigger; - const desktopEntry = effectiveAppId ? DesktopEntries.heuristicLookup(effectiveAppId) : null; - const appName = effectiveAppId ? Paths.getAppName(effectiveAppId, desktopEntry) : "Unknown"; - - if (isGrouped && windowCount > 1) { - return appName + " (" + windowCount + " windows)"; - } - return appName + (windowTitle ? " • " + windowTitle : ""); - } - readonly property real visualWidth: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? root.iconCellSize : (root.iconCellSize + Theme.spacingXS + 120) - - width: root.barThickness - height: root.iconCellSize - - Rectangle { - id: visualContent - width: delegateItem.visualWidth - height: root.iconCellSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: { - if (isFocused) { - return mouseArea.containsMouse ? Theme.primarySelected : Theme.withAlpha(Theme.primary, 0.45); - } - return mouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent"; - } - - IconImage { - id: iconImg - anchors.left: parent.left - anchors.leftMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? Math.round((parent.width - Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)) / 2) : Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: { - root._desktopEntriesUpdateTrigger; - root._appIdSubstitutionsTrigger; - if (!effectiveAppId) - return ""; - const desktopEntry = DesktopEntries.heuristicLookup(effectiveAppId); - return Paths.getAppIcon(effectiveAppId, desktopEntry); - } - smooth: true - mipmap: true - asynchronous: true - visible: status === Image.Ready - layer.enabled: appId === "org.quickshell" || appId === "com.danklinux.dms" - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } - - DankIcon { - anchors.left: parent.left - anchors.leftMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? Math.round((parent.width - Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)) / 2) : Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - name: "sports_esports" - color: Theme.widgetTextColor - visible: !iconImg.visible && Paths.isSteamApp(effectiveAppId) - } - - Text { - anchors.centerIn: parent - visible: !iconImg.visible && !Paths.isSteamApp(effectiveAppId) - text: { - root._desktopEntriesUpdateTrigger; - if (!effectiveAppId) - return "?"; - const desktopEntry = DesktopEntries.heuristicLookup(effectiveAppId); - const appName = Paths.getAppName(effectiveAppId, desktopEntry); - return appName.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - Rectangle { - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.rightMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? -2 : 2 - anchors.bottomMargin: -2 - width: 14 - height: 14 - radius: 7 - color: Theme.primary - visible: isGrouped && windowCount > 1 - z: 10 - - StyledText { - anchors.centerIn: parent - text: windowCount > 9 ? "9+" : windowCount - font.pixelSize: 9 - color: Theme.surface - } - } - - StyledText { - anchors.left: iconImg.right - anchors.leftMargin: Theme.spacingXS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - visible: !(widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) - text: windowTitle - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - elide: Text.ElideRight - maximumLineCount: 1 - } - - DankRipple { - id: itemRipple - cornerRadius: Theme.cornerRadius - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - onPressed: mouse => { - const pos = mapToItem(visualContent, mouse.x, mouse.y); - itemRipple.trigger(pos.x, pos.y); - } - onClicked: mouse => { - if (mouse.button === Qt.LeftButton) { - if (isGrouped && windowCount > 1) { - let currentIndex = -1; - for (var i = 0; i < groupData.windows.length; i++) { - if (groupData.windows[i].toplevel.activated) { - currentIndex = i; - break; - } - } - const nextIndex = (currentIndex + 1) % groupData.windows.length; - groupData.windows[nextIndex].toplevel.activate(); - } else if (toplevelObject) { - toplevelObject.activate(); - } - } else if (mouse.button === Qt.RightButton) { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - - windowContextMenuLoader.active = true; - if (windowContextMenuLoader.item) { - windowContextMenuLoader.item.currentWindow = toplevelObject; - // Pass bar context - windowContextMenuLoader.item.triggerBarConfig = root.barConfig; - windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1)); - windowContextMenuLoader.item.triggerBarThickness = root.barThickness; - windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing; - if (root.isVerticalOrientation) { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const relativeY = globalPos.y - screenY; - // Add minTooltipY offset to account for top bar - const adjustedY = relativeY + root.minTooltipY; - const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge); - } else { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const relativeX = globalPos.x - screenX; - const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height; - const isBottom = root.axis?.edge === "bottom"; - const yPos = isBottom ? (screenHeight - root.barThickness - root.barSpacing - 32 - Theme.spacingXS) : (root.barThickness + root.barSpacing + Theme.spacingXS); - windowContextMenuLoader.item.showAt(relativeX, yPos, false, root.axis?.edge); - } - } - } - } - onEntered: { - root.hoveredItem = delegateItem; - tooltipLoader.active = true; - if (tooltipLoader.item) { - if (root.isVerticalOrientation) { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2); - const screenX = root.parentScreen ? root.parentScreen.x : 0; - const screenY = root.parentScreen ? root.parentScreen.y : 0; - const relativeY = globalPos.y - screenY; - const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - const isLeft = root.axis?.edge === "left"; - const adjustedY = relativeY + root.minTooltipY; - const finalX = screenX + tooltipX; - tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft); - } else { - const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height); - const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height; - const isBottom = root.axis?.edge === "bottom"; - const tooltipY = isBottom ? (screenHeight - root.barThickness - root.barSpacing - Theme.spacingXS - 35) : (root.barThickness + root.barSpacing + Theme.spacingXS); - tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false); - } - } - } - onExited: { - if (root.hoveredItem === delegateItem) { - root.hoveredItem = null; - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - - tooltipLoader.active = false; - } - } - } - } - } - } - } - - Loader { - id: tooltipLoader - - active: false - - sourceComponent: DankTooltip {} - } - - Loader { - id: windowContextMenuLoader - active: false - sourceComponent: PanelWindow { - id: contextMenuWindow - - WindowBlur { - targetWindow: contextMenuWindow - blurX: contextMenuRect.x - blurY: contextMenuRect.y - blurWidth: contextMenuWindow.isVisible ? contextMenuRect.width : 0 - blurHeight: contextMenuWindow.isVisible ? contextMenuRect.height : 0 - blurRadius: Theme.cornerRadius - } - - property var currentWindow: null - property bool isVisible: false - property point anchorPos: Qt.point(0, 0) - property bool isVertical: false - property string edge: "top" - - // New properties for bar context - property int triggerBarPosition: (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top) - property real triggerBarThickness: 0 - property real triggerBarSpacing: 0 - property var triggerBarConfig: null - - readonly property real effectiveBarThickness: { - if (triggerBarThickness > 0 && triggerBarSpacing > 0) { - return triggerBarThickness + triggerBarSpacing; - } - return Math.max(26 + (barConfig?.innerPadding ?? 4) * 0.6, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))) + (barConfig?.spacing ?? 4); - } - - property var barBounds: { - if (!contextMenuWindow.screen || !triggerBarConfig) { - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - return SettingsData.getBarBounds(contextMenuWindow.screen, effectiveBarThickness, triggerBarPosition, triggerBarConfig); - } - - property real barY: barBounds.y - - function showAt(x, y, vertical, barEdge) { - screen = root.parentScreen; - anchorPos = Qt.point(x, y); - isVertical = vertical ?? false; - edge = barEdge ?? "top"; - isVisible = true; - visible = true; - - if (screen) { - TrayMenuManager.registerMenu(screen.name, contextMenuWindow); - } - } - - function close() { - isVisible = false; - visible = false; - windowContextMenuLoader.active = false; - - if (screen) { - TrayMenuManager.unregisterMenu(screen.name); - } - } - - implicitWidth: 100 - implicitHeight: 40 - visible: false - color: "transparent" - - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - - anchors { - top: true - left: true - right: true - bottom: true - } - - Component.onDestruction: { - if (screen) { - TrayMenuManager.unregisterMenu(screen.name); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - contextMenuWindow.close(); - } - } - - MouseArea { - anchors.fill: parent - onClicked: contextMenuWindow.close() - } - - Rectangle { - id: contextMenuRect - x: { - if (contextMenuWindow.isVertical) { - if (contextMenuWindow.edge === "left") { - return Math.min(contextMenuWindow.width - width - 10, contextMenuWindow.anchorPos.x); - } else { - return Math.max(10, contextMenuWindow.anchorPos.x - width); - } - } else { - const left = 10; - const right = contextMenuWindow.width - width - 10; - const want = contextMenuWindow.anchorPos.x - width / 2; - return Math.max(left, Math.min(right, want)); - } - } - y: { - if (contextMenuWindow.isVertical) { - const top = Math.max(barY, 10); - const bottom = contextMenuWindow.height - height - 10; - const want = contextMenuWindow.anchorPos.y - height / 2; - return Math.max(top, Math.min(bottom, want)); - } else { - return contextMenuWindow.anchorPos.y; - } - } - width: 100 - height: 32 - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.width: BlurService.enabled ? BlurService.borderWidth : 1 - border.color: BlurService.enabled ? BlurService.borderColor : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - - Rectangle { - anchors.fill: parent - radius: parent.radius - color: closeMouseArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - } - - StyledText { - anchors.centerIn: parent - text: I18n.tr("Close") - font.pixelSize: Theme.fontSizeSmall - color: Theme.widgetTextColor - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (contextMenuWindow.currentWindow) { - contextMenuWindow.currentWindow.close(); - } - contextMenuWindow.close(); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml deleted file mode 100644 index 7fb9362..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml +++ /dev/null @@ -1,1893 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Hyprland -import Quickshell.Services.SystemTray -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - enableBackgroundHover: false - enableCursor: false - - property var parentWindow: null - property var widgetData: null - property string section: "right" - property bool isAtBottom: false - property bool isAutoHideBar: false - property bool useOverflowPopup: !widgetData?.trayUseInlineExpansion - readonly property var hiddenTrayIds: { - const envValue = Quickshell.env("DMS_HIDE_TRAYIDS") || ""; - return envValue ? envValue.split(",").map(id => id.trim().toLowerCase()) : []; - } - readonly property var allTrayItems: { - if (!hiddenTrayIds.length) { - return SystemTray.items.values; - } - return SystemTray.items.values.filter(item => { - const itemId = item?.id || ""; - return !hiddenTrayIds.includes(itemId.toLowerCase()); - }); - } - function getTrayItemKey(item) { - const id = item?.id || ""; - const tooltipTitle = item?.tooltipTitle || ""; - if (!tooltipTitle || tooltipTitle === id) { - return id; - } - return `${id}::${tooltipTitle}`; - } - - function trayIconSourceFor(trayItem) { - let icon = trayItem && trayItem.icon; - if (typeof icon === 'string' || icon instanceof String) { - if (icon === "") - return ""; - if (icon.includes("?path=")) { - const split = icon.split("?path="); - if (split.length !== 2) - return icon; - const name = split[0]; - const path = split[1]; - let fileName = name.substring(name.lastIndexOf("/") + 1); - if (fileName.startsWith("dropboxstatus")) { - fileName = `hicolor/16x16/status/${fileName}`; - } - return `file://${path}/${fileName}`; - } - if (icon.startsWith("/") && !icon.startsWith("file://")) - return `file://${icon}`; - return icon; - } - return ""; - } - - function activateInlineTrayItem(trayItem, anchorItem) { - if (!trayItem) - return; - if (!trayItem.onlyMenu) { - trayItem.activate(); - return; - } - if (!trayItem.hasMenu) - return; - root.showForTrayItem(trayItem, anchorItem, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - - function openInlineTrayContextMenu(trayItem, areaItem, mouse, anchorItem) { - if (!trayItem) { - return; - } - if (!trayItem.hasMenu) { - const gp = areaItem.mapToGlobal(mouse.x, mouse.y); - root.callContextMenuFallback(trayItem.id, Math.round(gp.x), Math.round(gp.y)); - return; - } - root.showForTrayItem(trayItem, anchorItem, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - - function toggleIconName() { - const edge = root.axis?.edge; - if (root.useOverflowPopup) { - switch (edge) { - case "left": - return root.menuOpen ? "keyboard_arrow_left" : "keyboard_arrow_right"; - case "right": - return root.menuOpen ? "keyboard_arrow_right" : "keyboard_arrow_left"; - case "bottom": - return root.menuOpen ? "keyboard_arrow_down" : "keyboard_arrow_up"; - case "top": - return root.menuOpen ? "keyboard_arrow_up" : "keyboard_arrow_down"; - } - } - - if (edge === "left" || edge === "right") { - return root.menuOpen == (root.section !== "right") ? "keyboard_arrow_up" : "keyboard_arrow_down"; - } - - return root.menuOpen != (root.section === "right") ? "keyboard_arrow_left" : "keyboard_arrow_right"; - } - - // ! TODO - replace with either native dbus client (like plugins use) or just a DMS cli or something - function callContextMenuFallback(trayItemId, globalX, globalY) { - const script = ['ITEMS=$(dbus-send --session --print-reply --dest=org.kde.StatusNotifierWatcher /StatusNotifierWatcher org.freedesktop.DBus.Properties.Get string:org.kde.StatusNotifierWatcher string:RegisteredStatusNotifierItems 2>/dev/null)', 'while IFS= read -r line; do', ' line="${line#*\\\"}"', ' line="${line%\\\"*}"', ' [ -z "$line" ] && continue', ' BUS="${line%%/*}"', ' OBJ="/${line#*/}"', ' ID=$(dbus-send --session --print-reply --dest="$BUS" "$OBJ" org.freedesktop.DBus.Properties.Get string:org.kde.StatusNotifierItem string:Id 2>/dev/null | grep -oP "(?<=\\\")(.*?)(?=\\\")" | tail -1)', ' if [ "$ID" = "$1" ]; then', ' dbus-send --session --type=method_call --dest="$BUS" "$OBJ" org.kde.StatusNotifierItem.ContextMenu int32:"$2" int32:"$3"', ' exit 0', ' fi', 'done <<< "$ITEMS"',].join("\n"); - Quickshell.execDetached(["bash", "-c", script, "_", trayItemId, String(globalX), String(globalY)]); - } - - property int _trayOrderTrigger: 0 - - Connections { - target: SessionData - function onTrayItemOrderChanged() { - root._trayOrderTrigger++; - } - } - - function sortByPreferredOrder(items, trigger) { - void trigger; - const savedOrder = SessionData.trayItemOrder || []; - const orderMap = new Map(); - savedOrder.forEach((key, idx) => orderMap.set(key, idx)); - - return [...items].sort((a, b) => { - const keyA = getTrayItemKey(a); - const keyB = getTrayItemKey(b); - const orderA = orderMap.has(keyA) ? orderMap.get(keyA) : 10000 + items.indexOf(a); - const orderB = orderMap.has(keyB) ? orderMap.get(keyB) : 10000 + items.indexOf(b); - return orderA - orderB; - }); - } - - readonly property var allSortedTrayItems: sortByPreferredOrder(allTrayItems, _trayOrderTrigger) - readonly property var allSortedTrayItemKeys: allSortedTrayItems.map(item => getTrayItemKey(item)) - readonly property var mainBarItemsRaw: allSortedTrayItems.filter(item => !SessionData.isHiddenTrayId(root.getTrayItemKey(item))) - readonly property var mainBarItems: mainBarItemsRaw.map((item, idx) => ({ - key: getTrayItemKey(item), - item: item - })) - readonly property var hiddenBarItems: allSortedTrayItems.filter(item => SessionData.isHiddenTrayId(root.getTrayItemKey(item))) - readonly property bool reverseInlineHorizontal: !useOverflowPopup && !isVerticalOrientation && section === "right" - readonly property bool reverseInlineVertical: !useOverflowPopup && isVerticalOrientation && section === "right" - readonly property var displayedMainBarItems: reverseInlineHorizontal ? [...mainBarItems].reverse() : mainBarItems - readonly property var displayedInlineExpandedItems: (reverseInlineHorizontal ? [...hiddenBarItems].reverse() : hiddenBarItems).map(item => ({ - key: getTrayItemKey(item), - item: item - })) - - function moveTrayItemInFullOrder(visibleFromIndex, visibleToIndex) { - if (visibleFromIndex === visibleToIndex || visibleFromIndex < 0 || visibleToIndex < 0) - return; - - const fromKey = mainBarItems[visibleFromIndex]?.key ?? null; - const toKey = mainBarItems[visibleToIndex]?.key ?? null; - if (!fromKey || !toKey) - return; - - const fullOrder = [...allSortedTrayItemKeys]; - const fullFromIndex = fullOrder.indexOf(fromKey); - const fullToIndex = fullOrder.indexOf(toKey); - if (fullFromIndex < 0 || fullToIndex < 0) - return; - - const movedKey = fullOrder.splice(fullFromIndex, 1)[0]; - fullOrder.splice(fullToIndex, 0, movedKey); - SessionData.setTrayItemOrder(fullOrder); - } - - property int draggedIndex: -1 - property int dropTargetIndex: -1 - property bool suppressShiftAnimation: false - readonly property bool hasHiddenItems: allTrayItems.length > mainBarItems.length - readonly property bool inlineExpanded: hasHiddenItems && !useOverflowPopup && menuOpen - visible: allTrayItems.length > 0 - opacity: allTrayItems.length > 0 ? 1 : 0 - - states: [ - State { - name: "hidden_horizontal" - when: allTrayItems.length === 0 && !isVerticalOrientation - PropertyChanges { - target: root - width: 0 - } - }, - State { - name: "hidden_vertical" - when: allTrayItems.length === 0 && isVerticalOrientation - PropertyChanges { - target: root - height: 0 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "width,height" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - readonly property real trayItemSize: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) + 6 - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - const estimatedTopBarHeight = barThickness + barSpacing; - return estimatedTopBarHeight; - } - - return 0; - } - - readonly property string autoBarShadowDirection: { - const edge = root.axis?.edge; - switch (edge) { - case "top": - return "top"; - case "bottom": - return "bottom"; - case "left": - return "left"; - case "right": - return "right"; - default: - return "bottom"; - } - } - readonly property string effectiveShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection - - property bool menuOpen: false - property var currentTrayMenu: null - - content: Component { - Item { - implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0 - implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0 - - Loader { - id: layoutLoader - anchors.centerIn: parent - sourceComponent: root.isVerticalOrientation ? columnComp : rowComp - } - } - } - - Component { - id: rowComp - Row { - spacing: 0 - layoutDirection: root.reverseInlineHorizontal ? Qt.RightToLeft : Qt.LeftToRight - - Repeater { - model: ScriptModel { - values: root.displayedMainBarItems - objectProp: "key" - } - - delegate: Item { - id: delegateRoot - property var trayItem: modelData.item - property string itemKey: modelData.key - property string iconSource: root.trayIconSourceFor(trayItem) - - width: root.trayItemSize - height: root.barThickness - z: dragHandler.dragging ? 100 : 0 - - property real shiftOffset: { - if (root.draggedIndex < 0) - return 0; - if (index === root.draggedIndex) - return 0; - const dragIdx = root.draggedIndex; - const dropIdx = root.dropTargetIndex; - const shiftAmount = root.trayItemSize; - if (dropIdx < 0) - return 0; - if (dragIdx < dropIdx && index > dragIdx && index <= dropIdx) - return -shiftAmount; - if (dragIdx > dropIdx && index >= dropIdx && index < dragIdx) - return shiftAmount; - return 0; - } - - transform: Translate { - x: delegateRoot.shiftOffset - Behavior on x { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - Item { - id: dragHandler - anchors.fill: parent - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - property bool longPressing: false - - Timer { - id: longPressTimer - interval: 400 - repeat: false - onTriggered: dragHandler.longPressing = true - } - } - - Rectangle { - id: visualContent - width: root.trayItemSize - height: root.trayItemSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: trayItemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - border.width: dragHandler.dragging ? 2 : 0 - border.color: Theme.primary - opacity: dragHandler.dragging ? 0.8 : 1.0 - - transform: Translate { - x: dragHandler.dragging ? dragHandler.dragAxisOffset : 0 - } - - IconImage { - id: iconImg - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: delegateRoot.iconSource - asynchronous: true - smooth: true - mipmap: true - visible: status === Image.Ready - } - - Text { - anchors.centerIn: parent - visible: !iconImg.visible - text: { - const itemId = trayItem?.id || ""; - if (!itemId) - return "?"; - return itemId.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - DankRipple { - id: itemRipple - cornerRadius: Theme.cornerRadius - } - } - - MouseArea { - id: trayItemArea - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton - cursorShape: dragHandler.longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor - - onPressed: mouse => { - const pos = mapToItem(visualContent, mouse.x, mouse.y); - itemRipple.trigger(pos.x, pos.y); - if (mouse.button === Qt.LeftButton) { - dragHandler.dragStartPos = Qt.point(mouse.x, mouse.y); - longPressTimer.start(); - } - } - - onReleased: mouse => { - longPressTimer.stop(); - const wasDragging = dragHandler.dragging; - const didReorder = wasDragging && root.dropTargetIndex >= 0 && root.dropTargetIndex !== root.draggedIndex; - - if (didReorder) { - root.suppressShiftAnimation = true; - root.moveTrayItemInFullOrder(root.draggedIndex, root.dropTargetIndex); - Qt.callLater(() => root.suppressShiftAnimation = false); - } - - dragHandler.longPressing = false; - dragHandler.dragging = false; - dragHandler.dragAxisOffset = 0; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - if (!delegateRoot.trayItem) - return; - if (!delegateRoot.trayItem.onlyMenu) { - delegateRoot.trayItem.activate(); - return; - } - if (!delegateRoot.trayItem.hasMenu) - return; - if (root.useOverflowPopup) - root.menuOpen = false; - root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - - onPositionChanged: mouse => { - if (dragHandler.longPressing && !dragHandler.dragging) { - const distance = Math.abs(mouse.x - dragHandler.dragStartPos.x); - if (distance > 5) { - dragHandler.dragging = true; - root.draggedIndex = root.reverseInlineHorizontal ? (root.mainBarItems.length - 1 - index) : index; - root.dropTargetIndex = root.draggedIndex; - } - } - if (!dragHandler.dragging) - return; - - const axisOffset = mouse.x - dragHandler.dragStartPos.x; - dragHandler.dragAxisOffset = axisOffset; - const itemSize = root.trayItemSize; - const slotOffset = Math.round(axisOffset / itemSize); - const visualTargetIndex = Math.max(0, Math.min(root.mainBarItems.length - 1, index + slotOffset)); - const newTargetIndex = root.reverseInlineHorizontal ? (root.mainBarItems.length - 1 - visualTargetIndex) : visualTargetIndex; - if (newTargetIndex !== root.dropTargetIndex) { - root.dropTargetIndex = newTargetIndex; - } - } - - onClicked: mouse => { - if (dragHandler.dragging) - return; - if (mouse.button !== Qt.RightButton) - return; - if (!delegateRoot.trayItem?.hasMenu) { - const gp = trayItemArea.mapToGlobal(mouse.x, mouse.y); - root.callContextMenuFallback(delegateRoot.trayItem.id, Math.round(gp.x), Math.round(gp.y)); - return; - } - if (root.useOverflowPopup) - root.menuOpen = false; - root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - } - } - } - - Item { - width: root.trayItemSize - height: root.barThickness - visible: root.hasHiddenItems - - Rectangle { - id: caretButton - width: root.trayItemSize - height: root.trayItemSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: caretArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: root.toggleIconName() - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - } - - DankRipple { - id: caretRipple - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: caretArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - caretRipple.trigger(mouse.x, mouse.y); - } - onClicked: root.menuOpen = !root.menuOpen - } - } - } - - Repeater { - model: ScriptModel { - values: root.displayedInlineExpandedItems - objectProp: "key" - } - - delegate: inlineExpandedTrayItemDelegate - } - } - } - - Component { - id: inlineExpandedTrayItemDelegate - - Item { - property var trayItem: modelData.item - property string itemKey: modelData.key - property string iconSource: root.trayIconSourceFor(trayItem) - - width: root.isVerticalOrientation ? root.barThickness : (root.inlineExpanded ? root.trayItemSize : 0) - height: root.isVerticalOrientation ? (root.inlineExpanded ? root.trayItemSize : 0) : root.barThickness - visible: width > 0 || height > 0 - - Behavior on width { - enabled: !root.isVerticalOrientation - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on height { - enabled: root.isVerticalOrientation - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Rectangle { - id: inlineVisualContent - width: root.trayItemSize - height: root.trayItemSize - x: root.isVerticalOrientation ? Math.round((parent.width - width) / 2) : (root.reverseInlineHorizontal ? parent.width - width : 0) - y: root.isVerticalOrientation ? (root.reverseInlineVertical ? parent.height - height : 0) : Math.round((parent.height - height) / 2) - radius: Theme.cornerRadius - color: inlineTrayItemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - opacity: root.inlineExpanded ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - IconImage { - id: inlineIconImg - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: iconSource - asynchronous: true - smooth: true - mipmap: true - visible: status === Image.Ready - } - - Text { - anchors.centerIn: parent - visible: !inlineIconImg.visible - text: { - const itemId = trayItem?.id || ""; - if (!itemId) - return "?"; - return itemId.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - DankRipple { - id: inlineItemRipple - cornerRadius: Theme.cornerRadius - } - } - - MouseArea { - id: inlineTrayItemArea - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton - cursorShape: Qt.PointingHandCursor - enabled: root.inlineExpanded - - onPressed: mouse => { - const pos = mapToItem(inlineVisualContent, mouse.x, mouse.y); - inlineItemRipple.trigger(pos.x, pos.y); - } - - onClicked: mouse => { - if (mouse.button === Qt.LeftButton) { - root.activateInlineTrayItem(trayItem, inlineVisualContent); - return; - } - if (mouse.button !== Qt.RightButton) - return; - root.openInlineTrayContextMenu(trayItem, inlineTrayItemArea, mouse, inlineVisualContent); - } - } - } - } - - Component { - id: verticalMainTrayItemDelegate - - Item { - property var trayItem: modelData.item - property string itemKey: modelData.key - property string iconSource: root.trayIconSourceFor(trayItem) - - width: root.barThickness - height: root.trayItemSize - z: dragHandler.dragging ? 100 : 0 - - property real shiftOffset: { - if (root.draggedIndex < 0) - return 0; - if (index === root.draggedIndex) - return 0; - const dragIdx = root.draggedIndex; - const dropIdx = root.dropTargetIndex; - const shiftAmount = root.trayItemSize; - if (dropIdx < 0) - return 0; - if (dragIdx < dropIdx && index > dragIdx && index <= dropIdx) - return -shiftAmount; - if (dragIdx > dropIdx && index >= dropIdx && index < dragIdx) - return shiftAmount; - return 0; - } - - transform: Translate { - y: shiftOffset - Behavior on y { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - Item { - id: dragHandler - anchors.fill: parent - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - property bool longPressing: false - - Timer { - id: longPressTimer - interval: 400 - repeat: false - onTriggered: dragHandler.longPressing = true - } - } - - Rectangle { - id: visualContent - width: root.trayItemSize - height: root.trayItemSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: trayItemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - border.width: dragHandler.dragging ? 2 : 0 - border.color: Theme.primary - opacity: dragHandler.dragging ? 0.8 : 1.0 - - transform: Translate { - y: dragHandler.dragging ? dragHandler.dragAxisOffset : 0 - } - - IconImage { - id: iconImg - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: iconSource - asynchronous: true - smooth: true - mipmap: true - visible: status === Image.Ready - } - - Text { - anchors.centerIn: parent - visible: !iconImg.visible - text: { - const itemId = trayItem?.id || ""; - if (!itemId) - return "?"; - return itemId.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - DankRipple { - id: itemRipple - cornerRadius: Theme.cornerRadius - } - } - - MouseArea { - id: trayItemArea - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton - cursorShape: dragHandler.longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor - - onPressed: mouse => { - const pos = mapToItem(visualContent, mouse.x, mouse.y); - itemRipple.trigger(pos.x, pos.y); - if (mouse.button === Qt.LeftButton) { - dragHandler.dragStartPos = Qt.point(mouse.x, mouse.y); - longPressTimer.start(); - } - } - - onReleased: mouse => { - longPressTimer.stop(); - const wasDragging = dragHandler.dragging; - const didReorder = wasDragging && root.dropTargetIndex >= 0 && root.dropTargetIndex !== root.draggedIndex; - - if (didReorder) { - root.suppressShiftAnimation = true; - root.moveTrayItemInFullOrder(root.draggedIndex, root.dropTargetIndex); - Qt.callLater(() => root.suppressShiftAnimation = false); - } - - dragHandler.longPressing = false; - dragHandler.dragging = false; - dragHandler.dragAxisOffset = 0; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - if (!trayItem) - return; - if (!trayItem.onlyMenu) { - trayItem.activate(); - return; - } - if (!trayItem.hasMenu) - return; - if (root.useOverflowPopup) - root.menuOpen = false; - root.showForTrayItem(trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - - onPositionChanged: mouse => { - if (dragHandler.longPressing && !dragHandler.dragging) { - const distance = Math.abs(mouse.y - dragHandler.dragStartPos.y); - if (distance > 5) { - dragHandler.dragging = true; - root.draggedIndex = index; - root.dropTargetIndex = root.draggedIndex; - } - } - if (!dragHandler.dragging) - return; - - const axisOffset = mouse.y - dragHandler.dragStartPos.y; - dragHandler.dragAxisOffset = axisOffset; - const itemSize = root.trayItemSize; - const slotOffset = Math.round(axisOffset / itemSize); - const newTargetIndex = Math.max(0, Math.min(root.mainBarItems.length - 1, index + slotOffset)); - if (newTargetIndex !== root.dropTargetIndex) { - root.dropTargetIndex = newTargetIndex; - } - } - - onClicked: mouse => { - if (dragHandler.dragging) - return; - if (mouse.button !== Qt.RightButton) - return; - root.openInlineTrayContextMenu(trayItem, trayItemArea, mouse, visualContent); - } - } - } - } - - Component { - id: columnComp - Column { - spacing: 0 - - // Column lacks layoutDirection, so we use four repeaters with mutually exclusive models to control whether main items or expanded items appear above/ below the toggle button. - // When reverseInlineVertical is true the first and third repeaters are empty and the second and fourth are active, and vice-versa. - // Because items are swapped between repeaters rather than reversed within a single list, vertical drag-and-drop indices don't need remapping (unlike the horizontal RightToLeft case). - Repeater { - model: ScriptModel { - values: root.reverseInlineVertical ? [] : root.displayedMainBarItems - objectProp: "key" - } - delegate: verticalMainTrayItemDelegate - } - - Repeater { - model: ScriptModel { - values: root.reverseInlineVertical ? root.displayedInlineExpandedItems : [] - objectProp: "key" - } - delegate: inlineExpandedTrayItemDelegate - } - - Item { - width: root.barThickness - height: root.trayItemSize - visible: root.hasHiddenItems - - Rectangle { - id: caretButtonVert - width: root.trayItemSize - height: root.trayItemSize - anchors.centerIn: parent - radius: Theme.cornerRadius - color: caretAreaVert.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: root.toggleIconName() - size: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetTextColor - } - - DankRipple { - id: caretRippleVert - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: caretAreaVert - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - caretRippleVert.trigger(mouse.x, mouse.y); - } - onClicked: root.menuOpen = !root.menuOpen - } - } - } - - Repeater { - model: ScriptModel { - values: root.reverseInlineVertical ? [] : root.displayedInlineExpandedItems - objectProp: "key" - } - delegate: inlineExpandedTrayItemDelegate - } - - Repeater { - model: ScriptModel { - values: root.reverseInlineVertical ? root.displayedMainBarItems : [] - objectProp: "key" - } - delegate: verticalMainTrayItemDelegate - } - } - } - - PanelWindow { - id: overflowMenu - - WindowBlur { - targetWindow: overflowMenu - blurX: menuContainer.x - blurY: menuContainer.y - blurWidth: root.menuOpen ? menuContainer.width : 0 - blurHeight: root.menuOpen ? menuContainer.height : 0 - blurRadius: Theme.cornerRadius - } - - visible: root.useOverflowPopup && root.menuOpen - screen: root.parentScreen - WlrLayershell.layer: WlrLayershell.Top - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: { - if (!root.menuOpen) - return WlrKeyboardFocus.None; - if (CompositorService.useHyprlandFocusGrab) - return WlrKeyboardFocus.OnDemand; - return WlrKeyboardFocus.Exclusive; - } - WlrLayershell.namespace: "dms:tray-overflow-menu" - color: "transparent" - - HyprlandFocusGrab { - windows: [overflowMenu] - active: CompositorService.useHyprlandFocusGrab && root.useOverflowPopup && root.menuOpen - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - if (root.useOverflowPopup) - root.menuOpen = false; - } - } - - Component.onDestruction: { - if (root.parentScreen) { - TrayMenuManager.unregisterMenu(root.parentScreen.name); - } - } - - function close() { - root.menuOpen = false; - } - - anchors { - top: true - left: true - right: true - bottom: true - } - - readonly property real dpr: (typeof CompositorService !== "undefined" && CompositorService.getScreenScale) ? CompositorService.getScreenScale(overflowMenu.screen) : (screen?.devicePixelRatio || 1) - property point anchorPos: Qt.point(screen.width / 2, screen.height / 2) - - property var barBounds: { - if (!overflowMenu.screen || !root.barConfig) { - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - return SettingsData.getBarBounds(overflowMenu.screen, root.barThickness + root.barSpacing, barPosition, root.barConfig); - } - - property real barX: barBounds.x - property real barY: barBounds.y - property real barWidth: barBounds.width - property real barHeight: barBounds.height - - readonly property int barPosition: root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)) - readonly property var adjacentBarInfo: parentScreen ? SettingsData.getAdjacentBarInfo(parentScreen, barPosition, root.barConfig) : ({ - "topBar": 0, - "bottomBar": 0, - "leftBar": 0, - "rightBar": 0 - }) - readonly property real effectiveBarSize: root.barThickness + root.barSpacing - - readonly property real maskX: { - const triggeringBarX = (barPosition === 2) ? effectiveBarSize : 0; - const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0; - return Math.max(triggeringBarX, adjacentLeftBar); - } - - readonly property real maskY: { - const triggeringBarY = (barPosition === 0) ? effectiveBarSize : 0; - const adjacentTopBar = adjacentBarInfo?.topBar ?? 0; - return Math.max(triggeringBarY, adjacentTopBar); - } - - readonly property real maskWidth: { - const triggeringBarRight = (barPosition === 3) ? effectiveBarSize : 0; - const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0; - const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar); - return Math.max(100, width - maskX - rightExclusion); - } - - readonly property real maskHeight: { - const triggeringBarBottom = (barPosition === 1) ? effectiveBarSize : 0; - const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0; - const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar); - return Math.max(100, height - maskY - bottomExclusion); - } - - mask: Region { - item: Rectangle { - x: overflowMenu.maskX - y: overflowMenu.maskY - width: overflowMenu.maskWidth - height: overflowMenu.maskHeight - } - } - - onVisibleChanged: { - if (visible) { - if (currentTrayMenu) { - currentTrayMenu.showMenu = false; - } - if (root.parentScreen) { - TrayMenuManager.registerMenu(root.parentScreen.name, overflowMenu); - } - PopoutManager.closeAllPopouts(); - ModalManager.closeAllModalsExcept(null); - updatePosition(); - } else if (!visible && root.parentScreen) { - TrayMenuManager.unregisterMenu(root.parentScreen.name); - } - } - - MouseArea { - x: overflowMenu.maskX - y: overflowMenu.maskY - width: overflowMenu.maskWidth - height: overflowMenu.maskHeight - z: -1 - enabled: root.menuOpen - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: mouse => { - const clickX = mouse.x + overflowMenu.maskX; - const clickY = mouse.y + overflowMenu.maskY; - const outsideContent = clickX < menuContainer.x || clickX > menuContainer.x + menuContainer.width || clickY < menuContainer.y || clickY > menuContainer.y + menuContainer.height; - - if (!outsideContent) - return; - root.menuOpen = false; - } - } - - FocusScope { - id: overflowFocusScope - anchors.fill: parent - focus: true - - Keys.onEscapePressed: { - root.menuOpen = false; - } - } - - function updatePosition() { - const globalPos = root.mapToGlobal(0, 0); - const screenX = screen.x || 0; - const screenY = screen.y || 0; - const relativeX = globalPos.x - screenX; - const relativeY = globalPos.y - screenY; - - if (root.isVerticalOrientation) { - const edge = root.axis?.edge; - let targetX = edge === "left" ? root.barThickness + root.barSpacing + Theme.popupDistance : screen.width - (root.barThickness + root.barSpacing + Theme.popupDistance); - const adjustedY = relativeY + root.height / 2 + root.minTooltipY; - anchorPos = Qt.point(targetX, adjustedY); - } else { - let targetY = root.isAtBottom ? screen.height - (root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance) : root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance; - anchorPos = Qt.point(relativeX + root.width / 2, targetY); - } - } - - Item { - id: menuContainer - objectName: "overflowMenuContainer" - - readonly property real rawWidth: { - const itemCount = root.hiddenBarItems.length; - const cols = Math.min(5, itemCount); - const itemSize = root.trayItemSize + 4; - const spacing = 2; - return cols * itemSize + (cols - 1) * spacing + Theme.spacingS * 2; - } - readonly property real rawHeight: { - const itemCount = root.hiddenBarItems.length; - const cols = Math.min(5, itemCount); - const rows = Math.ceil(itemCount / cols); - const itemSize = root.trayItemSize + 4; - const spacing = 2; - return rows * itemSize + (rows - 1) * spacing + Theme.spacingS * 2; - } - - readonly property real alignedWidth: Theme.px(rawWidth, overflowMenu.dpr) - readonly property real alignedHeight: Theme.px(rawHeight, overflowMenu.dpr) - - width: alignedWidth - height: alignedHeight - - x: Theme.snap((() => { - if (root.isVerticalOrientation) { - const edge = root.axis?.edge; - if (edge === "left") { - const targetX = overflowMenu.anchorPos.x; - return Math.min(overflowMenu.screen.width - alignedWidth - 10, targetX); - } else { - const targetX = overflowMenu.anchorPos.x - alignedWidth; - return Math.max(10, targetX); - } - } else { - const left = 10; - const right = overflowMenu.width - alignedWidth - 10; - const want = overflowMenu.anchorPos.x - alignedWidth / 2; - return Math.max(left, Math.min(right, want)); - } - })(), overflowMenu.dpr) - - y: Theme.snap((() => { - if (root.isVerticalOrientation) { - const top = Math.max(overflowMenu.barY, 10); - const bottom = overflowMenu.height - alignedHeight - 10; - const want = overflowMenu.anchorPos.y - alignedHeight / 2; - return Math.max(top, Math.min(bottom, want)); - } else { - if (root.isAtBottom) { - const targetY = overflowMenu.anchorPos.y - alignedHeight; - return Math.max(10, targetY); - } else { - const targetY = overflowMenu.anchorPos.y; - return Math.min(overflowMenu.screen.height - alignedHeight - 10, targetY); - } - } - })(), overflowMenu.dpr) - - opacity: root.menuOpen ? 1 : 0 - scale: root.menuOpen ? 1 : 0.85 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - ElevationShadow { - id: bgShadowLayer - anchors.fill: parent - level: Theme.elevationLevel3 - direction: root.effectiveShadowDirection - fallbackOffset: 6 - targetColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - targetRadius: Theme.cornerRadius - sourceRect.antialiasing: true - sourceRect.smooth: true - shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled - layer.smooth: true - layer.textureSize: Qt.size(Math.round(width * overflowMenu.dpr * 2), Math.round(height * overflowMenu.dpr * 2)) - layer.textureMirroring: ShaderEffectSource.MirrorVertically - layer.samples: 4 - } - - Rectangle { - anchors.fill: parent - color: "transparent" - radius: Theme.cornerRadius - border.color: BlurService.borderColor - border.width: BlurService.borderWidth - z: 100 - } - - Grid { - id: menuGrid - anchors.centerIn: parent - columns: Math.min(5, root.hiddenBarItems.length) - spacing: 2 - rowSpacing: 2 - - Repeater { - model: root.hiddenBarItems - - delegate: Rectangle { - property var trayItem: modelData - property string iconSource: root.trayIconSourceFor(trayItem) - - width: root.trayItemSize + 4 - height: root.trayItemSize + 4 - radius: Theme.cornerRadius - color: itemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(Theme.surfaceContainer, 0) - - IconImage { - id: menuIconImg - anchors.centerIn: parent - width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - source: parent.iconSource - asynchronous: true - smooth: true - mipmap: true - visible: status === Image.Ready - } - - Text { - anchors.centerIn: parent - visible: !menuIconImg.visible - text: { - const itemId = trayItem?.id || ""; - if (!itemId) - return "?"; - return itemId.charAt(0).toUpperCase(); - } - font.pixelSize: 10 - color: Theme.widgetTextColor - } - - MouseArea { - id: itemArea - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton - cursorShape: Qt.PointingHandCursor - onClicked: mouse => { - if (!trayItem) - return; - if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) { - trayItem.activate(); - root.menuOpen = false; - return; - } - if (!trayItem.hasMenu) { - const gp = itemArea.mapToGlobal(mouse.x, mouse.y); - root.callContextMenuFallback(trayItem.id, Math.round(gp.x), Math.round(gp.y)); - return; - } - root.showForTrayItem(trayItem, menuContainer, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis); - } - } - } - } - } - } - } - - Component { - id: trayMenuComponent - - Rectangle { - id: menuRoot - - property var trayItem: null - property var anchorItem: null - property var parentScreen: null - property bool isAtBottom: false - property bool isVertical: false - property var axis: null - property bool showMenu: false - property var menuHandle: null - - ListModel { - id: entryStack - } - function topEntry() { - return entryStack.count ? entryStack.get(entryStack.count - 1).handle : null; - } - - function showForTrayItem(item, anchor, screen, atBottom, vertical, axisObj) { - trayItem = item; - anchorItem = anchor; - parentScreen = screen; - isAtBottom = atBottom; - isVertical = vertical; - axis = axisObj; - menuHandle = item?.menu; - - if (parentScreen) { - for (var i = 0; i < Quickshell.screens.length; i++) { - const s = Quickshell.screens[i]; - if (s === parentScreen) { - menuWindow.screen = s; - break; - } - } - } - - showMenu = true; - } - - function close() { - showMenu = false; - } - - Connections { - target: menuWindow - function onVisibleChanged() { - if (menuWindow.visible && parentScreen) { - TrayMenuManager.registerMenu(parentScreen.name, menuRoot); - } else if (!menuWindow.visible && parentScreen) { - TrayMenuManager.unregisterMenu(parentScreen.name); - } - } - } - - Component.onDestruction: { - if (parentScreen) { - TrayMenuManager.unregisterMenu(parentScreen.name); - } - } - - Connections { - target: PopoutManager - function onPopoutOpening() { - menuRoot.close(); - } - } - - function closeWithAction() { - close(); - } - - function showSubMenu(entry) { - if (!entry || !entry.hasChildren) - return; - - entryStack.append({ - handle: entry - }); - - const h = entry.menu || entry; - if (h && typeof h.updateLayout === "function") - h.updateLayout(); - - submenuHydrator.menu = h; - submenuHydrator.open(); - Qt.callLater(() => submenuHydrator.close()); - } - - function goBack() { - if (!entryStack.count) - return; - entryStack.remove(entryStack.count - 1); - } - - width: 0 - height: 0 - color: "transparent" - - PanelWindow { - id: menuWindow - - WindowBlur { - targetWindow: menuWindow - blurX: trayMenuContainer.x - blurY: trayMenuContainer.y - blurWidth: menuRoot.showMenu ? trayMenuContainer.width : 0 - blurHeight: menuRoot.showMenu ? trayMenuContainer.height : 0 - blurRadius: Theme.cornerRadius - } - - WlrLayershell.namespace: "dms:tray-menu-window" - visible: menuRoot.showMenu && (menuRoot.trayItem?.hasMenu ?? false) - WlrLayershell.layer: WlrLayershell.Top - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: { - if (!menuRoot.showMenu) - return WlrKeyboardFocus.None; - if (CompositorService.useHyprlandFocusGrab) - return WlrKeyboardFocus.OnDemand; - return WlrKeyboardFocus.Exclusive; - } - color: "transparent" - - HyprlandFocusGrab { - windows: [menuWindow] - active: CompositorService.useHyprlandFocusGrab && menuRoot.showMenu - } - - anchors { - top: true - left: true - right: true - bottom: true - } - - readonly property real dpr: (typeof CompositorService !== "undefined" && CompositorService.getScreenScale) ? CompositorService.getScreenScale(menuWindow.screen) : (screen?.devicePixelRatio || 1) - property point anchorPos: Qt.point(screen.width / 2, screen.height / 2) - - property var barBounds: { - if (!menuWindow.screen || !root.barConfig) { - return { - "x": 0, - "y": 0, - "width": 0, - "height": 0, - "wingSize": 0 - }; - } - const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - return SettingsData.getBarBounds(menuWindow.screen, root.barThickness + root.barSpacing, barPosition, root.barConfig); - } - - property real barX: barBounds.x - property real barY: barBounds.y - property real barWidth: barBounds.width - property real barHeight: barBounds.height - - readonly property int barPosition: root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)) - readonly property var adjacentBarInfo: menuRoot.parentScreen ? SettingsData.getAdjacentBarInfo(menuRoot.parentScreen, barPosition, root.barConfig) : ({ - "topBar": 0, - "bottomBar": 0, - "leftBar": 0, - "rightBar": 0 - }) - readonly property real effectiveBarSize: root.barThickness + root.barSpacing - - readonly property real maskX: { - const triggeringBarX = (barPosition === 2) ? effectiveBarSize : 0; - const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0; - return Math.max(triggeringBarX, adjacentLeftBar); - } - - readonly property real maskY: { - const triggeringBarY = (barPosition === 0) ? effectiveBarSize : 0; - const adjacentTopBar = adjacentBarInfo?.topBar ?? 0; - return Math.max(triggeringBarY, adjacentTopBar); - } - - readonly property real maskWidth: { - const triggeringBarRight = (barPosition === 3) ? effectiveBarSize : 0; - const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0; - const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar); - return Math.max(100, width - maskX - rightExclusion); - } - - readonly property real maskHeight: { - const triggeringBarBottom = (barPosition === 1) ? effectiveBarSize : 0; - const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0; - const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar); - return Math.max(100, height - maskY - bottomExclusion); - } - - mask: Region { - item: Rectangle { - x: menuWindow.maskX - y: menuWindow.maskY - width: menuWindow.maskWidth - height: menuWindow.maskHeight - } - } - - onVisibleChanged: { - if (visible) { - updatePosition(); - if (root.useOverflowPopup) - root.menuOpen = false; - PopoutManager.closeAllPopouts(); - ModalManager.closeAllModalsExcept(null); - } - } - - MouseArea { - x: menuWindow.maskX - y: menuWindow.maskY - width: menuWindow.maskWidth - height: menuWindow.maskHeight - z: -1 - enabled: menuRoot.showMenu - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: mouse => { - const clickX = mouse.x + menuWindow.maskX; - const clickY = mouse.y + menuWindow.maskY; - const outsideContent = clickX < trayMenuContainer.x || clickX > trayMenuContainer.x + trayMenuContainer.width || clickY < trayMenuContainer.y || clickY > trayMenuContainer.y + trayMenuContainer.height; - - if (!outsideContent) - return; - menuRoot.close(); - } - } - - FocusScope { - id: menuFocusScope - anchors.fill: parent - focus: true - - Keys.onEscapePressed: { - if (entryStack.count > 0) { - menuRoot.goBack(); - } else { - menuRoot.close(); - } - } - } - - function updatePosition() { - const targetItem = (typeof menuRoot !== "undefined" && menuRoot.anchorItem) ? menuRoot.anchorItem : root; - - const isFromOverflowMenu = targetItem.objectName === "overflowMenuContainer"; - - if (isFromOverflowMenu) { - if (menuRoot.isVertical) { - const edge = menuRoot.axis?.edge; - let targetX = edge === "left" ? root.barThickness + root.barSpacing + Theme.popupDistance : screen.width - (root.barThickness + root.barSpacing + Theme.popupDistance); - const targetY = targetItem.y + targetItem.height / 2; - anchorPos = Qt.point(targetX, targetY); - } else { - const targetX = targetItem.x + targetItem.width / 2; - let targetY = menuRoot.isAtBottom ? screen.height - (root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance) : root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance; - anchorPos = Qt.point(targetX, targetY); - } - } else { - const globalPos = targetItem.mapToGlobal(0, 0); - const screenX = screen.x || 0; - const screenY = screen.y || 0; - const relativeX = globalPos.x - screenX; - const relativeY = globalPos.y - screenY; - - if (menuRoot.isVertical) { - const edge = menuRoot.axis?.edge; - let targetX = edge === "left" ? root.barThickness + root.barSpacing + Theme.popupDistance : screen.width - (root.barThickness + root.barSpacing + Theme.popupDistance); - const adjustedY = relativeY + targetItem.height / 2 + root.minTooltipY; - anchorPos = Qt.point(targetX, adjustedY); - } else { - let targetY = menuRoot.isAtBottom ? screen.height - (root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance) : root.barThickness + root.barSpacing + (barConfig?.bottomGap ?? 0) + Theme.popupDistance; - anchorPos = Qt.point(relativeX + targetItem.width / 2, targetY); - } - } - } - - Item { - id: trayMenuContainer - - readonly property real rawWidth: Math.min(500, Math.max(250, menuColumn.implicitWidth + Theme.spacingS * 2)) - readonly property real rawHeight: Math.max(40, menuColumn.implicitHeight + Theme.spacingS * 2) - - readonly property real alignedWidth: Theme.px(rawWidth, menuWindow.dpr) - readonly property real alignedHeight: Theme.px(rawHeight, menuWindow.dpr) - - width: alignedWidth - height: alignedHeight - - x: Theme.snap((() => { - if (menuRoot.isVertical) { - const edge = menuRoot.axis?.edge; - if (edge === "left") { - const targetX = menuWindow.anchorPos.x; - return Math.min(menuWindow.screen.width - alignedWidth - 10, targetX); - } else { - const targetX = menuWindow.anchorPos.x - alignedWidth; - return Math.max(10, targetX); - } - } else { - const left = 10; - const right = menuWindow.width - alignedWidth - 10; - const want = menuWindow.anchorPos.x - alignedWidth / 2; - return Math.max(left, Math.min(right, want)); - } - })(), menuWindow.dpr) - - y: Theme.snap((() => { - if (menuRoot.isVertical) { - const top = Math.max(menuWindow.barY, 10); - const bottom = menuWindow.height - alignedHeight - 10; - const want = menuWindow.anchorPos.y - alignedHeight / 2; - return Math.max(top, Math.min(bottom, want)); - } else { - if (menuRoot.isAtBottom) { - const targetY = menuWindow.anchorPos.y - alignedHeight; - return Math.max(10, targetY); - } else { - const targetY = menuWindow.anchorPos.y; - return Math.min(menuWindow.screen.height - alignedHeight - 10, targetY); - } - } - })(), menuWindow.dpr) - - opacity: menuRoot.showMenu ? 1 : 0 - scale: menuRoot.showMenu ? 1 : 0.85 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - ElevationShadow { - id: menuBgShadowLayer - anchors.fill: parent - level: Theme.elevationLevel3 - direction: root.effectiveShadowDirection - fallbackOffset: 6 - targetColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - targetRadius: Theme.cornerRadius - sourceRect.antialiasing: true - shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled - layer.smooth: true - layer.textureSize: Qt.size(Math.round(width * menuWindow.dpr), Math.round(height * menuWindow.dpr)) - layer.textureMirroring: ShaderEffectSource.MirrorVertically - } - - Rectangle { - anchors.fill: parent - color: "transparent" - radius: Theme.cornerRadius - border.color: BlurService.borderColor - border.width: BlurService.borderWidth - z: 100 - } - - QsMenuAnchor { - id: submenuHydrator - anchor.window: menuWindow - } - - QsMenuOpener { - id: rootOpener - menu: menuRoot.menuHandle - } - - QsMenuOpener { - id: subOpener - menu: { - const e = menuRoot.topEntry(); - return e ? (e.menu || e) : null; - } - } - - Column { - id: menuColumn - - width: parent.width - Theme.spacingS * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - spacing: 1 - - Rectangle { - visible: entryStack.count === 0 - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: visibilityToggleArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(Theme.surfaceContainer, 0) - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: menuRoot.trayItem?.id || "Unknown" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - elide: Text.ElideMiddle - width: parent.width - Theme.spacingS * 2 - 24 - } - - DankIcon { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - name: SessionData.isHiddenTrayId(root.getTrayItemKey(menuRoot.trayItem)) ? "visibility" : "visibility_off" - size: 16 - color: Theme.widgetTextColor - } - - MouseArea { - id: visibilityToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const itemKey = root.getTrayItemKey(menuRoot.trayItem); - if (!itemKey) - return; - if (SessionData.isHiddenTrayId(itemKey)) { - SessionData.showTrayId(itemKey); - } else { - SessionData.hideTrayId(itemKey); - } - menuRoot.closeWithAction(); - } - } - } - - Rectangle { - visible: entryStack.count === 0 - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Rectangle { - visible: entryStack.count > 0 - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: backArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(Theme.surfaceContainer, 0) - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankIcon { - name: "arrow_back" - size: 16 - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Back") - font.pixelSize: Theme.fontSizeSmall - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: backArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: menuRoot.goBack() - } - } - - Rectangle { - visible: entryStack.count > 0 - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Repeater { - model: entryStack.count ? (subOpener.children ? subOpener.children : (menuRoot.topEntry()?.children || [])) : rootOpener.children - - Rectangle { - property var menuEntry: modelData - - width: menuColumn.width - height: menuEntry?.isSeparator ? 1 : 28 - radius: menuEntry?.isSeparator ? 0 : Theme.cornerRadius - color: { - if (menuEntry?.isSeparator) - return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2); - return itemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(Theme.surfaceContainer, 0); - } - - MouseArea { - id: itemArea - anchors.fill: parent - hoverEnabled: true - enabled: !menuEntry?.isSeparator && (menuEntry?.enabled !== false) - cursorShape: Qt.PointingHandCursor - - onClicked: { - if (!menuEntry || menuEntry.isSeparator) - return; - if (menuEntry.hasChildren) { - menuRoot.showSubMenu(menuEntry); - return; - } - - if (typeof menuEntry.activate === "function") { - menuEntry.activate(); - } else if (typeof menuEntry.triggered === "function") { - menuEntry.triggered(); - } - Qt.createQmlObject('import QtQuick; Timer { interval: 80; running: true; repeat: false; onTriggered: menuRoot.closeWithAction() }', menuRoot); - } - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - visible: !menuEntry?.isSeparator - - Rectangle { - width: 16 - height: 16 - anchors.verticalCenter: parent.verticalCenter - visible: menuEntry?.buttonType !== undefined && menuEntry.buttonType !== 0 - radius: menuEntry?.buttonType === 2 ? 8 : 2 - border.width: 1 - border.color: Theme.outline - color: "transparent" - - Rectangle { - anchors.centerIn: parent - width: parent.width - 6 - height: parent.height - 6 - radius: parent.radius - 3 - color: Theme.primary - visible: menuEntry?.checkState === 2 - } - - DankIcon { - anchors.centerIn: parent - name: "check" - size: 10 - color: Theme.primaryText - visible: menuEntry?.buttonType === 1 && menuEntry?.checkState === 2 - } - } - - Item { - width: 16 - height: 16 - anchors.verticalCenter: parent.verticalCenter - visible: (menuEntry?.icon ?? "") !== "" - - Image { - anchors.fill: parent - source: menuEntry?.icon || "" - sourceSize.width: 16 - sourceSize.height: 16 - fillMode: Image.PreserveAspectFit - smooth: true - } - } - - StyledText { - text: menuEntry?.text || "" - font.pixelSize: Theme.fontSizeSmall - color: (menuEntry?.enabled !== false) ? Theme.surfaceText : Theme.surfaceTextMedium - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - width: Math.max(150, parent.width - 64) - wrapMode: Text.NoWrap - } - - Item { - width: 16 - height: 16 - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "chevron_right" - size: 14 - color: Theme.widgetTextColor - visible: menuEntry?.hasChildren ?? false - } - } - } - } - } - } - } - } - } - } - - function showForTrayItem(item, anchor, screen, atBottom, vertical, axisObj) { - if (!screen) - return; - if (currentTrayMenu) { - currentTrayMenu.showMenu = false; - currentTrayMenu.destroy(); - currentTrayMenu = null; - } - - PopoutManager.closeAllPopouts(); - ModalManager.closeAllModalsExcept(null); - - currentTrayMenu = trayMenuComponent.createObject(null); - if (!currentTrayMenu) - return; - currentTrayMenu.showForTrayItem(item, anchor, screen, atBottom, vertical ?? false, axisObj); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml deleted file mode 100644 index 696c76c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml +++ /dev/null @@ -1,187 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - property bool isActive: false - readonly property bool hasUpdates: SystemUpdateService.updateCount > 0 - readonly property bool isChecking: SystemUpdateService.isChecking - readonly property bool shouldHide: SettingsData.updaterHideWidget && !hasUpdates && !isChecking && !SystemUpdateService.hasError - - opacity: shouldHide ? 0 : 1 - - states: [ - State { - name: "hidden_horizontal" - when: root.shouldHide && !isVerticalOrientation - PropertyChanges { - target: root - width: 0 - } - }, - State { - name: "hidden_vertical" - when: root.shouldHide && isVerticalOrientation - PropertyChanges { - target: root - height: 0 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "width,height" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Ref { - service: SystemUpdateService - } - - content: Component { - Item { - implicitWidth: root.isVerticalOrientation ? root.widgetThickness : updaterIcon.implicitWidth - implicitHeight: root.widgetThickness - - DankIcon { - id: statusIcon - anchors.centerIn: parent - visible: root.isVerticalOrientation - name: { - if (root.isChecking) - return "refresh"; - if (SystemUpdateService.hasError) - return "error"; - if (root.hasUpdates) - return "system_update_alt"; - return "check_circle"; - } - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (SystemUpdateService.hasError) - return Theme.error; - if (root.hasUpdates) - return Theme.primary; - return root.isActive ? Theme.primary : Theme.surfaceText; - } - - RotationAnimation { - id: rotationAnimation - target: statusIcon - property: "rotation" - from: 0 - to: 360 - duration: 1000 - running: root.isChecking - loops: Animation.Infinite - - onRunningChanged: { - if (!running) { - statusIcon.rotation = 0; - } - } - } - } - - Rectangle { - width: 8 - height: 8 - radius: 4 - color: Theme.error - anchors.right: parent.right - anchors.top: parent.top - anchors.rightMargin: (barConfig?.removeWidgetPadding ?? false) ? 0 : 6 - anchors.topMargin: (barConfig?.removeWidgetPadding ?? false) ? 0 : 6 - visible: root.isVerticalOrientation && root.hasUpdates && !root.isChecking - } - - Row { - id: updaterIcon - anchors.centerIn: parent - spacing: Theme.spacingXS - visible: !root.isVerticalOrientation - - DankIcon { - id: statusIconHorizontal - anchors.verticalCenter: parent.verticalCenter - name: { - if (root.isChecking) - return "refresh"; - if (SystemUpdateService.hasError) - return "error"; - if (root.hasUpdates) - return "system_update_alt"; - return "check_circle"; - } - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: { - if (SystemUpdateService.hasError) - return Theme.error; - if (root.hasUpdates) - return Theme.primary; - return root.isActive ? Theme.primary : Theme.surfaceText; - } - - RotationAnimation { - id: rotationAnimationHorizontal - target: statusIconHorizontal - property: "rotation" - from: 0 - to: 360 - duration: 1000 - running: root.isChecking - loops: Animation.Infinite - - onRunningChanged: { - if (!running) { - statusIconHorizontal.rotation = 0; - } - } - } - } - - StyledText { - id: countText - anchors.verticalCenter: parent.verticalCenter - text: SystemUpdateService.updateCount.toString() - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - visible: root.hasUpdates && !root.isChecking - } - } - } - } - - MouseArea { - z: 1 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onPressed: mouse => { - root.triggerRipple(this, mouse.x, mouse.y); - if (popoutTarget && popoutTarget.setTriggerPosition) { - const globalPos = root.visualContent.mapToItem(null, 0, 0); - const currentScreen = parentScreen || Screen; - const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth, root.barSpacing, barPosition, root.barConfig); - popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen, barPosition, barThickness, root.barSpacing, root.barConfig); - } - root.clicked(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Vpn.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Vpn.qml deleted file mode 100644 index fec33d0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Vpn.qml +++ /dev/null @@ -1,141 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - Ref { - service: DMSNetworkService - } - - property bool isHovered: clickArea.containsMouse - property bool isAutoHideBar: false - - readonly property real minTooltipY: { - if (!parentScreen || !isVerticalOrientation) { - return 0; - } - - if (isAutoHideBar) { - return 0; - } - - if (parentScreen.y > 0) { - return barThickness + barSpacing; - } - - return 0; - } - - signal toggleVpnPopup - - content: Component { - Item { - implicitWidth: icon.width - implicitHeight: root.widgetThickness - root.horizontalPadding * 2 - - DankIcon { - id: icon - - name: DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off" - size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: DMSNetworkService.connected ? Theme.primary : Theme.widgetIconColor - opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 - anchors.centerIn: parent - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.InOutQuad - } - } - } - } - } - - Loader { - id: tooltipLoader - active: false - sourceComponent: DankTooltip {} - } - - MouseArea { - id: clickArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton - enabled: !DMSNetworkService.isBusy - onPressed: event => { - root.triggerRipple(this, event.x, event.y); - switch (event.button) { - case Qt.RightButton: - DMSNetworkService.toggleVpn(); - return; - case Qt.LeftButton: - root.toggleVpnPopup(); - return; - } - } - onEntered: { - if (!root.parentScreen || (popoutTarget?.shouldBeVisible)) - return; - tooltipLoader.active = true; - if (!tooltipLoader.item) - return; - let tooltipText = ""; - if (!DMSNetworkService.connected) { - tooltipText = "VPN Disconnected"; - } else { - const names = DMSNetworkService.activeNames || []; - if (names.length <= 1) { - const name = names[0] || ""; - const maxLength = 25; - const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name; - tooltipText = "VPN Connected • " + displayName; - } else { - const name = names[0]; - const maxLength = 20; - const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name; - tooltipText = "VPN Connected • " + displayName + " +" + (names.length - 1); - } - } - - if (root.isVerticalOrientation) { - const globalPos = mapToGlobal(width / 2, height / 2); - const currentScreen = root.parentScreen || Screen; - const screenX = currentScreen ? currentScreen.x : 0; - const screenY = currentScreen ? currentScreen.y : 0; - const relativeY = globalPos.y - screenY; - const adjustedY = relativeY + root.minTooltipY; - const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (currentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS); - const isLeft = root.axis?.edge === "left"; - tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft); - } else { - const isBottom = root.axis?.edge === "bottom"; - const globalPos = mapToGlobal(width / 2, 0); - const currentScreen = root.parentScreen || Screen; - - let tooltipY; - if (isBottom) { - const tooltipHeight = Theme.fontSizeSmall * 1.5 + Theme.spacingS * 2; - tooltipY = currentScreen.height - root.barThickness - root.barSpacing - Theme.spacingXS - tooltipHeight; - } else { - tooltipY = root.barThickness + root.barSpacing + Theme.spacingXS; - } - - tooltipLoader.item.show(tooltipText, globalPos.x, tooltipY, currentScreen, false, false); - } - } - onExited: { - if (tooltipLoader.item) { - tooltipLoader.item.hide(); - } - tooltipLoader.active = false; - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Weather.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Weather.qml deleted file mode 100644 index 5dbe53a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/Weather.qml +++ /dev/null @@ -1,80 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.Plugins -import qs.Services -import qs.Widgets - -BasePill { - id: root - - visible: SettingsData.weatherEnabled - - Ref { - service: WeatherService - } - - content: Component { - Item { - implicitWidth: { - if (!SettingsData.weatherEnabled) return 0 - if (root.isVerticalOrientation) return root.widgetThickness - root.horizontalPadding * 2 - return Math.min(100 - root.horizontalPadding * 2, weatherRow.implicitWidth) - } - implicitHeight: root.isVerticalOrientation ? weatherColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2) - - Column { - id: weatherColumn - visible: root.isVerticalOrientation - anchors.centerIn: parent - spacing: 1 - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.barIconSize(root.barThickness, -6, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetIconColor - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (!WeatherService.weather.available) { - return "--"; - } - const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp; - return temp; - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Row { - id: weatherRow - visible: !root.isVerticalOrientation - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.barIconSize(root.barThickness, -6, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - color: Theme.widgetIconColor - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - if (!WeatherService.weather.available) { - return "--°" + (SettingsData.useFahrenheit ? "F" : "C"); - } - const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp; - return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C"); - } - font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) - color: Theme.widgetTextColor - anchors.verticalCenter: parent.verticalCenter - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml deleted file mode 100644 index 3721e35..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml +++ /dev/null @@ -1,1981 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Widgets -import Quickshell.Hyprland -import Quickshell.I3 -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property bool isVertical: axis?.isVertical ?? false - property var axis: null - property string screenName: "" - property real widgetHeight: 30 - property real barThickness: 48 - property var barConfig: null - property var blurBarWindow: null - property var hyprlandOverviewLoader: null - property var parentScreen: null - - readonly property real _leftMargin: { - if (isVertical) - return 0; - root.x; - if (!root.parent) - return 0; - const gap = root.mapToItem(null, 0, 0).x; - return (gap > 0 && gap < 30) ? gap + 5 : 0; - } - readonly property real _rightMargin: { - if (isVertical) - return 0; - root.x; - root.width; - if (!root.parent || !blurBarWindow) - return 0; - const gap = blurBarWindow.width - root.mapToItem(null, root.width, 0).x; - return (gap > 0 && gap < 30) ? gap + 5 : 0; - } - readonly property real _topMargin: { - if (!isVertical) - return 0; - root.y; - if (!root.parent) - return 0; - const gap = root.mapToItem(null, 0, 0).y; - return (gap > 0 && gap < 30) ? gap + 5 : 0; - } - readonly property real _bottomMargin: { - if (!isVertical) - return 0; - root.y; - root.height; - if (!root.parent || !blurBarWindow) - return 0; - const gap = blurBarWindow.height - root.mapToItem(null, 0, root.height).y; - return (gap > 0 && gap < 30) ? gap + 5 : 0; - } - - property int _desktopEntriesUpdateTrigger: 0 - readonly property var sortedToplevels: { - return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName); - } - - readonly property string effectiveScreenName: { - if (!SettingsData.workspaceFollowFocus) - return root.screenName; - - switch (CompositorService.compositor) { - case "niri": - return NiriService.currentOutput || root.screenName; - case "hyprland": - return Hyprland.focusedWorkspace?.monitor?.name || root.screenName; - case "dwl": - return DwlService.activeOutput || root.screenName; - case "sway": - case "scroll": - case "miracle": - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - return focusedWs?.monitor?.name || root.screenName; - default: - return root.screenName; - } - } - - readonly property bool useExtWorkspace: DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && !CompositorService.isMiracle && ExtWorkspaceService.extWorkspaceAvailable) - - Connections { - target: DesktopEntries - function onApplicationsChanged() { - _desktopEntriesUpdateTrigger++; - } - } - - property var currentWorkspace: { - if (useExtWorkspace) - return getExtWorkspaceActiveWorkspace(); - - switch (CompositorService.compositor) { - case "niri": - return getNiriActiveWorkspace(); - case "hyprland": - return getHyprlandActiveWorkspace(); - case "dwl": - const activeTags = getDwlActiveTags(); - return activeTags.length > 0 ? activeTags[0] : -1; - case "sway": - case "scroll": - case "miracle": - return getSwayActiveWorkspace(); - default: - return 1; - } - } - property var dwlActiveTags: { - if (CompositorService.isDwl) { - return getDwlActiveTags(); - } - return []; - } - property var workspaceList: { - if (useExtWorkspace) { - const baseList = getExtWorkspaceWorkspaces(); - return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList; - } - - let baseList; - switch (CompositorService.compositor) { - case "niri": - baseList = getNiriWorkspaces(); - break; - case "hyprland": - baseList = getHyprlandWorkspaces(); - break; - case "dwl": - baseList = getDwlTags(); - break; - case "sway": - case "scroll": - case "miracle": - baseList = getSwayWorkspaces(); - break; - default: - return [1]; - } - return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList; - } - - function getSwayWorkspaces() { - const workspaces = I3.workspaces?.values || []; - if (workspaces.length === 0) - return [ - { - "num": 1 - } - ]; - - function mapWorkspace(ws) { - return { - "num": ws.number, - "name": ws.name, - "focused": ws.focused, - "active": ws.active, - "urgent": ws.urgent, - "monitor": ws.monitor - }; - } - - if (!root.screenName || SettingsData.workspaceFollowFocus) { - return workspaces.slice().sort((a, b) => a.num - b.num).map(mapWorkspace); - } - - const monitorWorkspaces = workspaces.filter(ws => ws.monitor?.name === root.screenName); - return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.num - b.num).map(mapWorkspace) : [ - { - "num": 1 - } - ]; - } - - function getSwayActiveWorkspace() { - if (!root.screenName || SettingsData.workspaceFollowFocus) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - return focusedWs ? focusedWs.num : 1; - } - - const focusedWs = I3.workspaces?.values?.find(ws => ws.monitor?.name === root.screenName && ws.focused === true); - return focusedWs ? focusedWs.num : 1; - } - - function getHyprlandWorkspaces() { - const workspaces = Hyprland.workspaces?.values || []; - if (workspaces.length === 0) { - return [ - { - id: 1, - name: "1" - } - ]; - } - - let filtered = workspaces.filter(ws => ws.id > -1); - if (filtered.length === 0) { - return [ - { - id: 1, - name: "1" - } - ]; - } - - if (!root.screenName || SettingsData.workspaceFollowFocus) { - filtered = filtered.slice().sort((a, b) => a.id - b.id); - } else { - const monitorWorkspaces = filtered.filter(ws => ws.monitor?.name === root.screenName); - filtered = monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.id - b.id) : [ - { - id: 1, - name: "1" - } - ]; - } - - if (!SettingsData.showOccupiedWorkspacesOnly) { - return filtered; - } - - const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || []); - const activeWsId = root.currentWorkspace; - return filtered.filter(ws => { - if (ws.id === activeWsId) - return true; - return hyprlandToplevels.some(tl => tl.workspace?.id === ws.id); - }); - } - - function getHyprlandActiveWorkspace() { - if (!root.screenName || SettingsData.workspaceFollowFocus) { - return Hyprland.focusedWorkspace?.id || 1; - } - - const monitor = Hyprland.monitors?.values?.find(m => m.name === root.screenName); - return monitor?.activeWorkspace?.id || 1; - } - - function getWorkspaceIcons(ws) { - _desktopEntriesUpdateTrigger; - if (!SettingsData.showWorkspaceApps || !ws) { - return []; - } - - let targetWorkspaceId; - if (CompositorService.isNiri) { - if (!ws || typeof ws !== "object") { - const wsNumber = typeof ws === "number" ? ws : -1; - if (wsNumber <= 0) { - return []; - } - const workspace = NiriService.allWorkspaces.find(w => w.idx + 1 === wsNumber && w.output === root.effectiveScreenName); - if (!workspace) { - return []; - } - targetWorkspaceId = workspace.id; - } else { - if (ws.id === undefined || ws.id === -1 || ws.idx === -1) { - return []; - } - targetWorkspaceId = ws.id; - } - } else if (CompositorService.isHyprland) { - targetWorkspaceId = ws.id !== undefined ? ws.id : ws; - } else if (CompositorService.isDwl) { - if (typeof ws !== "object" || ws.tag === undefined) { - return []; - } - targetWorkspaceId = ws.tag; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - targetWorkspaceId = ws.num !== undefined ? ws.num : ws; - } else { - return []; - } - - const wins = CompositorService.isNiri ? (NiriService.windows || []) : CompositorService.sortedToplevels; - - const byApp = {}; - let isActiveWs = false; - if (CompositorService.isNiri) { - isActiveWs = NiriService.allWorkspaces.some(ws => ws.id === targetWorkspaceId && ws.is_active); - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true); - isActiveWs = focusedWs ? (focusedWs.num === targetWorkspaceId) : false; - } else if (CompositorService.isDwl) { - const output = DwlService.getOutputState(root.effectiveScreenName); - if (output && output.tags) { - const tag = output.tags.find(t => t.tag === targetWorkspaceId); - isActiveWs = tag ? (tag.state === 1) : false; - } - } else { - isActiveWs = targetWorkspaceId === root.currentWorkspace; - } - - wins.forEach((w, i) => { - if (!w) { - return; - } - - let winWs = null; - if (CompositorService.isNiri) { - winWs = w.workspace_id; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - winWs = w.workspace?.num; - } else { - const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || []); - const hyprToplevel = hyprlandToplevels.find(ht => ht.wayland === w); - winWs = hyprToplevel?.workspace?.id; - } - - if (winWs === undefined || winWs === null || winWs !== targetWorkspaceId) { - return; - } - - const keyBase = (w.app_id || w.appId || w.class || w.windowClass || "unknown"); - const moddedId = Paths.moddedAppId(keyBase); - const key = isActiveWs || !SettingsData.groupWorkspaceApps ? `${moddedId}_${i}` : moddedId; - - if (!byApp[key]) { - const isQuickshell = keyBase === "org.quickshell" || keyBase === "com.danklinux.dms"; - const isSteamApp = Paths.isSteamApp(moddedId); - const desktopEntry = DesktopEntries.heuristicLookup(moddedId); - const icon = Paths.getAppIcon(moddedId, desktopEntry); - const appName = Paths.getAppName(moddedId, desktopEntry); - byApp[key] = { - "type": "icon", - "icon": icon, - "isQuickshell": isQuickshell, - "isSteamApp": isSteamApp, - "active": !!((w.activated || w.is_focused) || (CompositorService.isNiri && w.is_focused)), - "count": 1, - "windowId": w.address || w.id, - "fallbackText": appName || "" - }; - } else { - byApp[key].count++; - if ((w.activated || w.is_focused) || (CompositorService.isNiri && w.is_focused)) { - byApp[key].active = true; - } - } - }); - - return Object.values(byApp); - } - - function padWorkspaces(list) { - const padded = list.slice(); - let placeholder; - if (useExtWorkspace) { - placeholder = { - "id": "", - "name": "", - "active": false, - "hidden": true - }; - } else if (CompositorService.isNiri) { - placeholder = { - "id": -1, - "idx": -1, - "name": "" - }; - } else if (CompositorService.isHyprland) { - placeholder = { - "id": -1, - "name": "" - }; - } else if (CompositorService.isDwl) { - placeholder = { - "tag": -1 - }; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - placeholder = { - "num": -1 - }; - } else { - placeholder = -1; - } - while (padded.length < 3) { - padded.push(placeholder); - } - return padded; - } - - function getNiriWorkspaces() { - if (NiriService.allWorkspaces.length === 0) { - return [ - { - "id": 1, - "idx": 0, - "name": "" - }, - { - "id": 2, - "idx": 1, - "name": "" - } - ]; - } - - const fallbackWorkspaces = [ - { - "id": 1, - "idx": 0, - "name": "" - }, - { - "id": 2, - "idx": 1, - "name": "" - } - ]; - - let workspaces; - if (!root.screenName || SettingsData.workspaceFollowFocus) { - const currentWorkspaces = NiriService.getCurrentOutputWorkspaces(); - workspaces = currentWorkspaces.length > 0 ? currentWorkspaces : fallbackWorkspaces; - } else { - const displayWorkspaces = NiriService.allWorkspaces.filter(ws => ws.output === root.screenName); - workspaces = displayWorkspaces.length > 0 ? displayWorkspaces : fallbackWorkspaces; - } - - workspaces = workspaces.slice().sort((a, b) => a.idx - b.idx); - - if (!SettingsData.showOccupiedWorkspacesOnly) { - return workspaces; - } - - return workspaces.filter(ws => { - if (ws.is_active) - return true; - return NiriService.windows?.some(win => win.workspace_id === ws.id) ?? false; - }); - } - - function getNiriActiveWorkspace() { - if (NiriService.allWorkspaces.length === 0) { - return 1; - } - - if (!root.screenName || SettingsData.workspaceFollowFocus) { - return NiriService.getCurrentWorkspaceNumber(); - } - - const activeWs = NiriService.allWorkspaces.find(ws => ws.output === root.screenName && ws.is_active); - return activeWs ? activeWs.idx : 1; - } - - function getDwlTags() { - if (!DwlService.dwlAvailable) - return []; - - const targetScreen = root.effectiveScreenName; - const output = DwlService.getOutputState(targetScreen); - if (!output || !output.tags || output.tags.length === 0) - return []; - - if (SettingsData.dwlShowAllTags) { - return output.tags.map(tag => ({ - "tag": tag.tag, - "state": tag.state, - "clients": tag.clients, - "focused": tag.focused - })); - } - - const visibleTagIndices = DwlService.getVisibleTags(targetScreen); - return visibleTagIndices.map(tagIndex => { - const tagData = output.tags.find(t => t.tag === tagIndex); - return { - "tag": tagIndex, - "state": tagData?.state ?? 0, - "clients": tagData?.clients ?? 0, - "focused": tagData?.focused ?? false - }; - }); - } - - function getDwlActiveTags() { - if (!DwlService.dwlAvailable) - return []; - - return DwlService.getActiveTags(root.effectiveScreenName); - } - - function getExtWorkspaceWorkspaces() { - const groups = ExtWorkspaceService.groups; - if (!ExtWorkspaceService.extWorkspaceAvailable || groups.length === 0) { - return [ - { - "id": "1", - "name": "1", - "active": false - } - ]; - } - - const group = groups.find(g => g.outputs && g.outputs.includes(root.screenName)); - if (!group || !group.workspaces) { - return [ - { - "id": "1", - "name": "1", - "active": false - } - ]; - } - - let visible = group.workspaces.filter(ws => !ws.hidden); - - const hasValidCoordinates = visible.some(ws => ws.coordinates && ws.coordinates.length > 0); - if (hasValidCoordinates) { - visible = visible.sort((a, b) => { - const coordsA = a.coordinates || [0, 0]; - const coordsB = b.coordinates || [0, 0]; - if (coordsA[0] !== coordsB[0]) - return coordsA[0] - coordsB[0]; - return coordsA[1] - coordsB[1]; - }); - } - - visible = visible.map(ws => ({ - id: ws.id, - name: ws.name, - coordinates: ws.coordinates, - state: ws.state, - active: ws.active, - urgent: ws.urgent, - hidden: ws.hidden, - groupID: group.id - })); - - return visible.length > 0 ? visible : [ - { - "id": "1", - "name": "1", - "active": false - } - ]; - } - - function getExtWorkspaceActiveWorkspace() { - if (!ExtWorkspaceService.extWorkspaceAvailable) { - return 1; - } - - const activeWs = ExtWorkspaceService.getActiveWorkspaceForOutput(root.screenName); - return activeWs ? (activeWs.id || activeWs.name || "1") : "1"; - } - - readonly property real dpr: parentScreen ? CompositorService.getScreenScale(parentScreen) : 1 - readonly property real padding: (root.barConfig?.removeWidgetPadding ?? false) ? 0 : Theme.snap((root.barConfig?.widgetPadding ?? 12) * (widgetHeight / 30), dpr) - readonly property real visualWidth: isVertical ? widgetHeight : (workspaceRow.implicitWidth + padding * 2) - readonly property real visualHeight: isVertical ? (workspaceRow.implicitHeight + padding * 2) : widgetHeight - readonly property real appIconSize: Theme.barIconSize(barThickness, -6 + SettingsData.workspaceAppIconSizeOffset, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale) - - function getRealWorkspaces() { - return root.workspaceList.filter(ws => { - if (useExtWorkspace) - return ws && (ws.id !== "" || ws.name !== "") && !ws.hidden; - if (CompositorService.isNiri) - return ws && ws.idx !== -1; - if (CompositorService.isHyprland) - return ws && ws.id !== -1; - if (CompositorService.isDwl) - return ws && ws.tag !== -1; - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - return ws && ws.num !== -1; - return ws !== -1; - }); - } - - function switchToWorkspaceByModelData(data) { - if (!data) - return; - - if (root.useExtWorkspace && (data.id || data.name)) { - ExtWorkspaceService.activateWorkspace(data.id || data.name, data.groupID || ""); - return; - } - - switch (CompositorService.compositor) { - case "niri": - if (data.idx !== undefined) - NiriService.switchToWorkspace(data.idx); - break; - case "hyprland": - if (data.id) - Hyprland.dispatch(`workspace ${data.id}`); - break; - case "dwl": - if (data.tag !== undefined) - DwlService.switchToTag(root.screenName, data.tag); - break; - case "sway": - case "scroll": - case "miracle": - if (data.num) - try { - I3.dispatch(`workspace number ${data.num}`); - } catch (_) {} - break; - } - } - - function findClosestWorkspaceIndex(localX, localY) { - if (workspaceRepeater.count === 0) - return -1; - - let closestIdx = -1; - let closestDist = Infinity; - - for (let i = 0; i < workspaceRepeater.count; i++) { - const item = workspaceRepeater.itemAt(i); - if (!item) - continue; - const center = item.mapToItem(root, item.width / 2, item.height / 2); - const dist = isVertical ? Math.abs(localY - center.y) : Math.abs(localX - center.x); - if (dist < closestDist) { - closestDist = dist; - closestIdx = i; - } - } - return closestIdx; - } - - function switchWorkspace(direction) { - if (useExtWorkspace) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - const currentIndex = realWorkspaces.findIndex(ws => (ws.id || ws.name) === root.currentWorkspace); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex === validIndex) { - return; - } - - const nextWorkspace = realWorkspaces[nextIndex]; - ExtWorkspaceService.activateWorkspace(nextWorkspace.id || nextWorkspace.name, nextWorkspace.groupID || ""); - } else if (CompositorService.isNiri) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - const currentIndex = realWorkspaces.findIndex(ws => ws && ws.idx === root.currentWorkspace); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex === validIndex) { - return; - } - - const nextWorkspace = realWorkspaces[nextIndex]; - if (!nextWorkspace || nextWorkspace.idx === undefined) { - return; - } - NiriService.switchToWorkspace(nextWorkspace.idx); - } else if (CompositorService.isHyprland) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - const currentIndex = realWorkspaces.findIndex(ws => ws.id === root.currentWorkspace); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex === validIndex) { - return; - } - - Hyprland.dispatch(`workspace ${realWorkspaces[nextIndex].id}`); - } else if (CompositorService.isDwl) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - const currentIndex = realWorkspaces.findIndex(ws => ws.tag === root.currentWorkspace); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex === validIndex) { - return; - } - - DwlService.switchToTag(root.screenName, realWorkspaces[nextIndex].tag); - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - const realWorkspaces = getRealWorkspaces(); - if (realWorkspaces.length < 2) { - return; - } - - const currentIndex = realWorkspaces.findIndex(ws => ws.num === root.currentWorkspace); - const validIndex = currentIndex === -1 ? 0 : currentIndex; - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0); - - if (nextIndex === validIndex) { - return; - } - - try { - I3.dispatch(`workspace number ${realWorkspaces[nextIndex].num}`); - } catch (_) {} - } - } - - function getWorkspaceIndexFallback(modelData, index) { - if (root.useExtWorkspace) - return index + 1; - if (CompositorService.isNiri) - return (modelData?.idx !== undefined && modelData?.idx !== -1) ? modelData.idx : ""; - if (CompositorService.isHyprland) - return modelData?.id || ""; - if (CompositorService.isDwl) - return (modelData?.tag !== undefined) ? (modelData.tag + 1) : ""; - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - return modelData?.num || ""; - return modelData - 1; - } - - function getWorkspaceIndex(modelData, index) { - let isPlaceholder; - if (root.useExtWorkspace) { - isPlaceholder = modelData?.hidden === true; - } else if (CompositorService.isNiri) { - isPlaceholder = modelData?.idx === -1; - } else if (CompositorService.isHyprland) { - isPlaceholder = modelData?.id === -1; - } else if (CompositorService.isDwl) { - isPlaceholder = modelData?.tag === -1; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - isPlaceholder = modelData?.num === -1; - } else { - isPlaceholder = modelData === -1; - } - - if (isPlaceholder) - return index + 1; - - let workspaceName = ""; - if (SettingsData.showWorkspaceName) { - workspaceName = modelData?.name ?? ""; - - if (workspaceName && workspaceName !== "") { - if (root.isVertical) { - workspaceName = workspaceName.charAt(0); - } - } else { - workspaceName = ""; - } - } - - if (workspaceName) { - if (SettingsData.showWorkspaceIndex) { - const indexLabel = getWorkspaceIndexFallback(modelData, index); - return indexLabel ? `${indexLabel}: ${workspaceName}` : workspaceName; - } - return workspaceName; - } - - return getWorkspaceIndexFallback(modelData, index); - } - - readonly property bool hasNativeWorkspaceSupport: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle - readonly property bool hasWorkspaces: getRealWorkspaces().length > 0 - readonly property bool shouldShow: hasNativeWorkspaceSupport || (useExtWorkspace && hasWorkspaces) - - width: shouldShow ? (isVertical ? barThickness : visualWidth) : 0 - height: shouldShow ? (isVertical ? visualHeight : barThickness) : 0 - visible: shouldShow - - Item { - id: visualBackground - width: root.visualWidth - height: root.visualHeight - anchors.centerIn: parent - - Rectangle { - id: outline - anchors.centerIn: parent - width: { - const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return parent.width + borderWidth * 2; - } - height: { - const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0; - return parent.height + borderWidth * 2; - } - radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius - color: "transparent" - border.width: { - if (barConfig?.widgetOutlineEnabled ?? false) { - return barConfig?.widgetOutlineThickness ?? 1; - } - return 0; - } - border.color: { - if (!(barConfig?.widgetOutlineEnabled ?? false)) { - return "transparent"; - } - const colorOption = barConfig?.widgetOutlineColor || "primary"; - const opacity = barConfig?.widgetOutlineOpacity ?? 1.0; - switch (colorOption) { - case "surfaceText": - return Theme.withAlpha(Theme.surfaceText, opacity); - case "secondary": - return Theme.withAlpha(Theme.secondary, opacity); - case "primary": - return Theme.withAlpha(Theme.primary, opacity); - default: - return Theme.withAlpha(Theme.primary, opacity); - } - } - } - - Rectangle { - id: background - anchors.fill: parent - radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius - color: { - if ((barConfig?.noBackground ?? false)) - return "transparent"; - const baseColor = Theme.widgetBaseBackgroundColor; - const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0; - if (Theme.widgetBackgroundHasAlpha) { - return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * transparency); - } - return Theme.withAlpha(baseColor, transparency); - } - } - } - - MouseArea { - id: edgeMouseArea - z: -1 - x: -root._leftMargin - y: -root._topMargin - width: root.width + root._leftMargin + root._rightMargin - height: root.height + root._topMargin + root._bottomMargin - acceptedButtons: Qt.LeftButton | Qt.RightButton - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - - property real touchpadAccumulator: 0 - property real mouseAccumulator: 0 - property bool scrollInProgress: false - - Timer { - id: scrollCooldown - interval: 100 - onTriggered: parent.scrollInProgress = false - } - - onClicked: mouse => { - const rootPos = edgeMouseArea.mapToItem(root, mouse.x, mouse.y); - switch (mouse.button) { - case Qt.RightButton: - if (CompositorService.isNiri) { - NiriService.toggleOverview(); - } else if (CompositorService.isHyprland && root.hyprlandOverviewLoader?.item) { - root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen; - } - break; - case Qt.LeftButton: - const idx = root.findClosestWorkspaceIndex(rootPos.x, rootPos.y); - if (idx >= 0) - root.switchToWorkspaceByModelData(root.workspaceList[idx]); - break; - } - } - - onWheel: wheel => { - if (Math.abs(wheel.angleDelta.x) > Math.abs(wheel.angleDelta.y)) { - wheel.accepted = false; - return; - } - - if (scrollInProgress) - return; - - const delta = wheel.angleDelta.y; - const isTouchpad = wheel.pixelDelta && wheel.pixelDelta.y !== 0; - const reverse = SettingsData.reverseScrolling ? -1 : 1; - - if (isTouchpad) { - touchpadAccumulator += delta; - if (Math.abs(touchpadAccumulator) < 500) - return; - const direction = touchpadAccumulator * reverse < 0 ? 1 : -1; - root.switchWorkspace(direction); - scrollInProgress = true; - scrollCooldown.restart(); - touchpadAccumulator = 0; - return; - } - - mouseAccumulator += delta; - if (Math.abs(mouseAccumulator) < 120) - return; - const direction = mouseAccumulator * reverse < 0 ? 1 : -1; - root.switchWorkspace(direction); - scrollInProgress = true; - scrollCooldown.restart(); - mouseAccumulator = 0; - } - } - - property int dragSourceIndex: -1 - property int dragTargetIndex: -1 - property bool suppressShiftAnimation: false - - onWorkspaceListChanged: { - if (dragSourceIndex >= 0) { - dragSourceIndex = -1; - dragTargetIndex = -1; - suppressShiftAnimation = false; - } - } - - Flow { - id: workspaceRow - - x: isVertical ? visualBackground.x : (parent.width - implicitWidth) / 2 - y: isVertical ? (parent.height - implicitHeight) / 2 : visualBackground.y - spacing: Theme.spacingS - flow: isVertical ? Flow.TopToBottom : Flow.LeftToRight - - Repeater { - id: workspaceRepeater - model: ScriptModel { - values: root.workspaceList - } - - Item { - id: delegateRoot - - property bool isDropTarget: root.dragTargetIndex === index - - z: dragHandler.dragging ? 1000 : 1 - - property real shiftOffset: { - if (root.dragSourceIndex < 0 || index === root.dragSourceIndex) - return 0; - const dragIdx = root.dragSourceIndex; - const dropIdx = root.dragTargetIndex; - if (dropIdx < 0) - return 0; - const shiftAmount = delegateRoot.width + Theme.spacingS; - if (dragIdx < dropIdx && index > dragIdx && index <= dropIdx) - return -shiftAmount; - if (dragIdx > dropIdx && index >= dropIdx && index < dragIdx) - return shiftAmount; - return 0; - } - - transform: Translate { - x: root.isVertical ? 0 : delegateRoot.shiftOffset - y: root.isVertical ? delegateRoot.shiftOffset : 0 - Behavior on x { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - Behavior on y { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - property bool isActive: { - if (root.useExtWorkspace) - return (modelData?.id || modelData?.name) === root.currentWorkspace; - if (CompositorService.isNiri) - return !!(modelData && modelData.idx === root.currentWorkspace); - if (CompositorService.isHyprland) - return !!(modelData && modelData.id === root.currentWorkspace); - if (CompositorService.isDwl) - return !!(modelData && root.dwlActiveTags.includes(modelData.tag)); - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - return !!(modelData && modelData.num === root.currentWorkspace); - return modelData === root.currentWorkspace; - } - property bool isOccupied: { - if (CompositorService.isHyprland) - return Array.from(Hyprland.toplevels?.values || []).some(tl => tl.workspace?.id === modelData?.id); - if (CompositorService.isDwl) - return modelData.clients > 0; - if (CompositorService.isNiri) { - const workspace = NiriService.allWorkspaces.find(ws => ws.idx + 1 === modelData && ws.output === root.effectiveScreenName); - return workspace ? (NiriService.windows?.some(win => win.workspace_id === workspace.id) ?? false) : false; - } - return false; - } - property bool isPlaceholder: { - if (root.useExtWorkspace) - return !!(modelData && modelData.hidden); - if (CompositorService.isNiri) - return !!(modelData && modelData.idx === -1); - if (CompositorService.isHyprland) - return !!(modelData && modelData.id === -1); - if (CompositorService.isDwl) - return !!(modelData && modelData.tag === -1); - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - return !!(modelData && modelData.num === -1); - return modelData === -1; - } - property bool isHovered: mouseArea.containsMouse - - property var loadedWorkspaceData: null - property bool loadedIsUrgent: false - property bool isUrgent: { - if (root.useExtWorkspace) - return modelData?.urgent ?? false; - if (CompositorService.isHyprland) - return modelData?.urgent ?? false; - if (CompositorService.isNiri) - return loadedIsUrgent; - if (CompositorService.isDwl) - return modelData?.state === 2; - if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - return loadedIsUrgent; - return false; - } - readonly property var loadedIconData: { - if (isPlaceholder) - return null; - const name = modelData?.name; - if (!name) - return null; - return SettingsData.getWorkspaceNameIcon(name); - } - readonly property bool loadedHasIcon: loadedIconData !== null - property var loadedIcons: [] - - readonly property int stableIconCount: { - if (!SettingsData.showWorkspaceApps || isPlaceholder) - return 0; - - let targetWorkspaceId; - if (root.useExtWorkspace) { - targetWorkspaceId = modelData?.id || modelData?.name; - } else if (CompositorService.isNiri) { - targetWorkspaceId = modelData?.id; - } else if (CompositorService.isHyprland) { - targetWorkspaceId = modelData?.id; - } else if (CompositorService.isDwl) { - targetWorkspaceId = modelData?.tag; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - targetWorkspaceId = modelData?.num; - } - if (targetWorkspaceId === undefined || targetWorkspaceId === null) - return 0; - - const wins = CompositorService.isNiri ? (NiriService.windows || []) : CompositorService.sortedToplevels; - const seen = {}; - let groupedCount = 0; - let totalCount = 0; - - for (let i = 0; i < wins.length; i++) { - const w = wins[i]; - if (!w) - continue; - - let winWs = null; - if (CompositorService.isNiri) { - winWs = w.workspace_id; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - winWs = w.workspace?.num; - } else if (CompositorService.isHyprland) { - const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || []); - const hyprToplevel = hyprlandToplevels.find(ht => ht.wayland === w); - winWs = hyprToplevel?.workspace?.id; - } - - if (winWs !== targetWorkspaceId) - continue; - totalCount++; - - const appKey = w.app_id || w.appId || w.class || w.windowClass || "unknown"; - if (!seen[appKey]) { - seen[appKey] = true; - groupedCount++; - } - } - - return (SettingsData.groupWorkspaceApps && !isActive) ? groupedCount : totalCount; - } - - readonly property real baseWidth: root.isVertical ? (SettingsData.showWorkspaceApps ? Math.max(widgetHeight * 0.7, root.appIconSize + Theme.spacingXS * 2) : widgetHeight * 0.5) : (isActive ? Math.max(root.widgetHeight * 1.05, root.appIconSize * 1.6) : Math.max(root.widgetHeight * 0.7, root.appIconSize * 1.2)) - readonly property real baseHeight: root.isVertical ? (isActive ? Math.max(root.widgetHeight * 1.05, root.appIconSize * 1.6) : Math.max(root.widgetHeight * 0.7, root.appIconSize * 1.2)) : (SettingsData.showWorkspaceApps ? Math.max(widgetHeight * 0.7, root.appIconSize + Theme.spacingXS * 2) : widgetHeight * 0.5) - readonly property bool hasWorkspaceName: SettingsData.showWorkspaceName && modelData?.name && modelData.name !== "" - readonly property bool workspaceNamesEnabled: SettingsData.showWorkspaceName && (CompositorService.isNiri || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - readonly property real contentImplicitWidth: appIconsLoader.item?.contentWidth ?? 0 - readonly property real contentImplicitHeight: appIconsLoader.item?.contentHeight ?? 0 - - readonly property real iconsExtraWidth: { - if (!root.isVertical && SettingsData.showWorkspaceApps && stableIconCount > 0) { - const numIcons = Math.min(stableIconCount, SettingsData.maxWorkspaceIcons); - return numIcons * root.appIconSize + (numIcons > 0 ? (numIcons - 1) * Theme.spacingXS : 0) + (isActive ? Theme.spacingXS : 0); - } - return 0; - } - readonly property real iconsExtraHeight: { - if (root.isVertical && SettingsData.showWorkspaceApps && stableIconCount > 0) { - const numIcons = Math.min(stableIconCount, SettingsData.maxWorkspaceIcons); - return numIcons * root.appIconSize + (numIcons > 0 ? (numIcons - 1) * Theme.spacingXS : 0) + (isActive ? Theme.spacingXS : 0); - } - return 0; - } - - readonly property real visualWidth: { - if (contentImplicitWidth <= 0) - return baseWidth + iconsExtraWidth; - const padding = root.isVertical ? Theme.spacingXS : Theme.spacingS; - return Math.max(baseWidth + iconsExtraWidth, contentImplicitWidth + padding); - } - readonly property real visualHeight: { - if (contentImplicitHeight <= 0) - return baseHeight + iconsExtraHeight; - const padding = root.isVertical ? Theme.spacingS : Theme.spacingXS; - return Math.max(baseHeight + iconsExtraHeight, contentImplicitHeight + padding); - } - - readonly property color unfocusedColor: { - switch (SettingsData.workspaceUnfocusedColorMode) { - case "s": - return Theme.surface; - case "sc": - return Theme.surfaceContainer; - case "sch": - return Theme.surfaceContainerHigh; - default: - return Theme.surfaceTextAlpha; - } - } - - readonly property color activeColor: { - switch (SettingsData.workspaceColorMode) { - case "s": - return Theme.surface; - case "sc": - return Theme.surfaceContainer; - case "sch": - return Theme.surfaceContainerHigh; - case "none": - return unfocusedColor; - default: - return Theme.primary; - } - } - - readonly property color occupiedColor: { - switch (SettingsData.workspaceOccupiedColorMode) { - case "sec": - return Theme.secondary; - case "s": - return Theme.surface; - case "sc": - return Theme.surfaceContainer; - case "sch": - return Theme.surfaceContainerHigh; - case "schh": - return Theme.surfaceContainerHighest; - default: - return unfocusedColor; - } - } - - readonly property color urgentColor: { - switch (SettingsData.workspaceUrgentColorMode) { - case "primary": - return Theme.primary; - case "secondary": - return Theme.secondary; - case "s": - return Theme.surface; - case "sc": - return Theme.surfaceContainer; - default: - return Theme.error; - } - } - - readonly property color focusedBorderColor: { - switch (SettingsData.workspaceFocusedBorderColor) { - case "surfaceText": - return Theme.surfaceText; - case "secondary": - return Theme.secondary; - default: - return Theme.primary; - } - } - - function getContrastingIconColor(bgColor) { - const luminance = 0.299 * bgColor.r + 0.587 * bgColor.g + 0.114 * bgColor.b; - return luminance > 0.4 ? Qt.rgba(0.15, 0.15, 0.15, 1) : Qt.rgba(0.8, 0.8, 0.8, 1); - } - - readonly property color quickshellIconActiveColor: getContrastingIconColor(activeColor) - readonly property color quickshellIconInactiveColor: getContrastingIconColor(unfocusedColor) - - Item { - id: dragHandler - anchors.fill: parent - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - - Connections { - target: root - function onWorkspaceListChanged() { - if (dragHandler.dragging) { - dragHandler.dragging = false; - dragHandler.dragAxisOffset = 0; - mouseArea.mousePressed = false; - } - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: !isPlaceholder - cursorShape: isPlaceholder ? Qt.ArrowCursor : (dragHandler.dragging ? Qt.ClosedHandCursor : Qt.PointingHandCursor) - enabled: !isPlaceholder - acceptedButtons: Qt.LeftButton | Qt.RightButton - - property bool mousePressed: false - - onPressed: mouse => { - if (mouse.button === Qt.LeftButton && CompositorService.isNiri && SettingsData.workspaceDragReorder && !isPlaceholder) { - mousePressed = true; - dragHandler.dragStartPos = Qt.point(mouse.x, mouse.y); - } - } - - onPositionChanged: mouse => { - if (!mousePressed || !CompositorService.isNiri || !SettingsData.workspaceDragReorder || isPlaceholder) - return; - - if (!dragHandler.dragging) { - const distance = root.isVertical ? Math.abs(mouse.y - dragHandler.dragStartPos.y) : Math.abs(mouse.x - dragHandler.dragStartPos.x); - if (distance > 5) { - dragHandler.dragging = true; - root.dragSourceIndex = index; - root.dragTargetIndex = index; - } - } - - if (!dragHandler.dragging) - return; - - const rawAxisOffset = root.isVertical ? (mouse.y - dragHandler.dragStartPos.y) : (mouse.x - dragHandler.dragStartPos.x); - - const itemSize = (root.isVertical ? delegateRoot.height : delegateRoot.width) + Theme.spacingS; - const maxOffsetPositive = (root.workspaceList.length - 1 - index) * itemSize; - const maxOffsetNegative = -index * itemSize; - const axisOffset = Math.max(maxOffsetNegative, Math.min(maxOffsetPositive, rawAxisOffset)); - dragHandler.dragAxisOffset = axisOffset; - - const slotOffset = Math.round(axisOffset / itemSize); - const newTargetIndex = Math.max(0, Math.min(root.workspaceList.length - 1, index + slotOffset)); - - if (newTargetIndex !== root.dragTargetIndex) { - root.dragTargetIndex = newTargetIndex; - } - } - - onReleased: mouse => { - const wasDragging = dragHandler.dragging; - const didReorder = wasDragging && root.dragTargetIndex >= 0 && root.dragTargetIndex !== root.dragSourceIndex; - - if (didReorder) { - const sourceWs = root.workspaceList[root.dragSourceIndex]; - const targetWs = root.workspaceList[root.dragTargetIndex]; - - if (sourceWs && targetWs && sourceWs.idx !== undefined && targetWs.idx !== undefined) { - root.suppressShiftAnimation = true; - NiriService.moveWorkspaceToIndex(sourceWs.idx, targetWs.idx); - Qt.callLater(() => root.suppressShiftAnimation = false); - } - } - - mousePressed = false; - dragHandler.dragging = false; - dragHandler.dragAxisOffset = 0; - root.dragSourceIndex = -1; - root.dragTargetIndex = -1; - - if (wasDragging || isPlaceholder) - return; - - if (mouse.button === Qt.LeftButton) { - if (root.useExtWorkspace && (modelData?.id || modelData?.name)) { - ExtWorkspaceService.activateWorkspace(modelData.id || modelData.name, modelData.groupID || ""); - } else if (CompositorService.isNiri) { - if (modelData && modelData.idx !== undefined) { - NiriService.switchToWorkspace(modelData.idx); - } - } else if (CompositorService.isHyprland && modelData?.id) { - Hyprland.dispatch(`workspace ${modelData.id}`); - } else if (CompositorService.isDwl && modelData?.tag !== undefined) { - DwlService.switchToTag(root.screenName, modelData.tag); - } else if ((CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) && modelData?.num) { - try { - I3.dispatch(`workspace number ${modelData.num}`); - } catch (_) {} - } - } else if (mouse.button === Qt.RightButton) { - if (CompositorService.isNiri) { - NiriService.toggleOverview(); - } else if (CompositorService.isHyprland && root.hyprlandOverviewLoader?.item) { - root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen; - } else if (CompositorService.isDwl && modelData?.tag !== undefined) { - DwlService.toggleTag(root.screenName, modelData.tag); - } - } - } - } - - Timer { - id: dataUpdateTimer - interval: 50 - onTriggered: { - if (isPlaceholder) { - delegateRoot.loadedWorkspaceData = null; - delegateRoot.loadedIcons = []; - delegateRoot.loadedIsUrgent = false; - return; - } - - var wsData = null; - if (root.useExtWorkspace) { - wsData = modelData; - } else if (CompositorService.isNiri) { - wsData = modelData || null; - } else if (CompositorService.isHyprland) { - wsData = modelData; - } else if (CompositorService.isDwl) { - wsData = modelData; - } else if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - wsData = modelData; - } - delegateRoot.loadedWorkspaceData = wsData; - if (CompositorService.isNiri) { - const workspaceId = wsData?.id; - delegateRoot.loadedIsUrgent = workspaceId ? NiriService.windows.some(w => w.workspace_id === workspaceId && w.is_urgent) : false; - } else { - delegateRoot.loadedIsUrgent = wsData?.urgent ?? false; - } - - if (SettingsData.showWorkspaceApps) { - if (CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) { - delegateRoot.loadedIcons = root.getWorkspaceIcons(modelData); - } else if (CompositorService.isNiri) { - delegateRoot.loadedIcons = root.getWorkspaceIcons(isPlaceholder ? null : modelData); - } else { - delegateRoot.loadedIcons = root.getWorkspaceIcons(CompositorService.isHyprland ? modelData : (modelData === -1 ? null : modelData)); - } - } else { - delegateRoot.loadedIcons = []; - } - } - } - - function updateAllData() { - dataUpdateTimer.restart(); - } - - width: root.isVertical ? root.widgetHeight : visualWidth - height: root.isVertical ? visualHeight : root.widgetHeight - - Behavior on width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on height { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Rectangle { - id: focusedBorderRing - x: root.isVertical ? (root.widgetHeight - width) / 2 : (parent.width - width) / 2 - y: root.isVertical ? (parent.height - height) / 2 : (root.widgetHeight - height) / 2 - width: { - const borderWidth = (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? SettingsData.workspaceFocusedBorderThickness : 0; - return delegateRoot.visualWidth + borderWidth * 2; - } - height: { - const borderWidth = (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? SettingsData.workspaceFocusedBorderThickness : 0; - return delegateRoot.visualHeight + borderWidth * 2; - } - radius: Theme.cornerRadius - color: "transparent" - border.width: (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? SettingsData.workspaceFocusedBorderThickness : 0 - border.color: (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? focusedBorderColor : "transparent" - - Behavior on width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on height { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on border.width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - - Rectangle { - id: visualContent - width: delegateRoot.visualWidth - height: delegateRoot.visualHeight - x: root.isVertical ? (root.widgetHeight - width) / 2 : (parent.width - width) / 2 - y: root.isVertical ? (parent.height - height) / 2 : (root.widgetHeight - height) / 2 - radius: Theme.cornerRadius - color: isActive ? activeColor : isUrgent ? urgentColor : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.withAlpha(unfocusedColor, 0.7) : isOccupied ? occupiedColor : unfocusedColor - opacity: dragHandler.dragging ? 0.8 : 1.0 - - border.width: dragHandler.dragging ? 2 : (isUrgent ? 2 : (isDropTarget ? 2 : 0)) - border.color: dragHandler.dragging ? Theme.primary : (isUrgent ? urgentColor : (isDropTarget ? Theme.primary : "transparent")) - - transform: Translate { - x: root.isVertical ? 0 : (dragHandler.dragging ? dragHandler.dragAxisOffset : 0) - y: root.isVertical ? (dragHandler.dragging ? dragHandler.dragAxisOffset : 0) : 0 - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on height { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on border.width { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Loader { - id: appIconsLoader - anchors.fill: parent - active: SettingsData.showWorkspaceApps || SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName || loadedHasIcon - sourceComponent: Item { - id: contentRoot - readonly property real contentWidth: contentRow.item?.implicitWidth ?? 0 - readonly property real contentHeight: contentRow.item?.implicitHeight ?? 0 - - Loader { - id: contentRow - anchors.centerIn: parent - sourceComponent: root.isVertical ? columnLayout : rowLayout - } - - Component { - id: rowLayout - Row { - spacing: 4 - visible: loadedIcons.length > 0 || SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName || loadedHasIcon - - Item { - visible: loadedHasIcon && loadedIconData?.type === "icon" - width: wsIcon.width - height: root.appIconSize - - DankIcon { - id: wsIcon - anchors.verticalCenter: parent.verticalCenter - name: loadedIconData?.value ?? "" - size: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - weight: (isActive && !isPlaceholder) ? 500 : 400 - } - } - - Item { - visible: loadedHasIcon && loadedIconData?.type === "text" - width: wsText.implicitWidth - height: root.appIconSize - - StyledText { - id: wsText - anchors.verticalCenter: parent.verticalCenter - text: loadedIconData?.value ?? "" - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal - } - } - - Item { - visible: ((SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName) && !loadedHasIcon) || (loadedHasIcon && SettingsData.showWorkspaceName && hasWorkspaceName) - width: wsIndexText.implicitWidth - height: root.appIconSize - - StyledText { - id: wsIndexText - anchors.verticalCenter: parent.verticalCenter - text: loadedHasIcon ? (modelData?.name ?? "") : root.getWorkspaceIndex(modelData, index) - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal - } - } - - Repeater { - model: ScriptModel { - values: loadedIcons.slice(0, SettingsData.maxWorkspaceIcons) - } - delegate: Item { - width: root.appIconSize - height: root.appIconSize - readonly property bool appHighlightActive: SettingsData.workspaceActiveAppHighlightEnabled && modelData.active - readonly property color appBorderColor: appHighlightActive ? focusedBorderColor : Theme.primarySelected - readonly property color appGlyphColor: appHighlightActive ? focusedBorderColor : Theme.primary - readonly property real appOpacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6 - - IconImage { - id: rowAppIcon - anchors.fill: parent - source: modelData.icon || "" - opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: !modelData.isQuickshell && !modelData.isSteamApp && status === Image.Ready - } - - Rectangle { - anchors.fill: parent - visible: !modelData.isQuickshell && !modelData.isSteamApp && rowAppIcon.status !== Image.Ready - color: Theme.surfaceContainer - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: appBorderColor - opacity: appOpacity - - StyledText { - anchors.centerIn: parent - text: (modelData.fallbackText || "?").charAt(0).toUpperCase() - font.pixelSize: parent.width * 0.45 - color: appGlyphColor - font.weight: Font.Bold - } - } - - Rectangle { - anchors.fill: parent - visible: !modelData.isQuickshell && modelData.isSteamApp && rowSteamIcon.status !== Image.Ready - color: Theme.surfaceContainer - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: appBorderColor - opacity: appOpacity - - DankIcon { - anchors.centerIn: parent - size: parent.width * 0.7 - name: "sports_esports" - color: appGlyphColor - } - } - - IconImage { - anchors.fill: parent - source: modelData.icon - opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isQuickshell - layer.enabled: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: appHighlightActive ? focusedBorderColor : (isActive ? quickshellIconActiveColor : quickshellIconInactiveColor) - } - } - - IconImage { - id: rowSteamIcon - anchors.fill: parent - source: modelData.icon - opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isSteamApp && modelData.icon - } - - DankIcon { - anchors.centerIn: parent - size: root.appIconSize - name: "sports_esports" - color: appHighlightActive ? focusedBorderColor : Theme.widgetTextColor - opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isSteamApp && !modelData.icon - } - - Rectangle { - anchors.fill: parent - visible: (rowAppIcon.visible || rowSteamIcon.visible || modelData.isQuickshell) && appHighlightActive - color: "transparent" - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: focusedBorderColor - z: 1 - } - - MouseArea { - id: rowAppMouseArea - anchors.fill: parent - enabled: isActive - cursorShape: Qt.PointingHandCursor - onClicked: { - const winId = modelData.windowId; - if (!winId) - return; - if (CompositorService.isHyprland) { - Hyprland.dispatch(`focuswindow address:${winId}`); - } else if (CompositorService.isNiri) { - NiriService.focusWindow(winId); - } - } - } - - Rectangle { - visible: modelData.count > 1 && !isActive - width: root.appIconSize * 0.67 - height: root.appIconSize * 0.67 - radius: root.appIconSize * 0.33 - color: "black" - border.color: "white" - border.width: 1 - anchors.right: parent.right - anchors.bottom: parent.bottom - z: 2 - - Text { - anchors.centerIn: parent - text: modelData.count - font.pixelSize: root.appIconSize * 0.44 - color: "white" - } - } - } - } - } - } - - Component { - id: columnLayout - Column { - spacing: 4 - visible: loadedIcons.length > 0 || SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName || loadedHasIcon - - DankIcon { - visible: loadedHasIcon && loadedIconData?.type === "icon" - anchors.horizontalCenter: parent.horizontalCenter - name: loadedIconData?.value ?? "" - size: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - weight: (isActive && !isPlaceholder) ? 500 : 400 - } - - StyledText { - visible: loadedHasIcon && loadedIconData?.type === "text" - anchors.horizontalCenter: parent.horizontalCenter - text: loadedIconData?.value ?? "" - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal - } - - StyledText { - visible: ((SettingsData.showWorkspaceIndex || SettingsData.showWorkspaceName) && !loadedHasIcon) || (loadedHasIcon && SettingsData.showWorkspaceName && hasWorkspaceName) - anchors.horizontalCenter: parent.horizontalCenter - text: loadedHasIcon ? (root.isVertical ? (modelData?.name ?? "").charAt(0) : (modelData?.name ?? "")) : root.getWorkspaceIndex(modelData, index) - color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium - font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText) - font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal - } - - Repeater { - model: ScriptModel { - values: loadedIcons.slice(0, SettingsData.maxWorkspaceIcons) - } - delegate: Item { - width: root.appIconSize - height: root.appIconSize - readonly property bool appHighlightActive: SettingsData.workspaceActiveAppHighlightEnabled && modelData.active - readonly property color appBorderColor: appHighlightActive ? focusedBorderColor : Theme.primarySelected - readonly property color appGlyphColor: appHighlightActive ? focusedBorderColor : Theme.primary - readonly property real appOpacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6 - - IconImage { - id: colAppIcon - anchors.fill: parent - source: modelData.icon || "" - opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: !modelData.isQuickshell && !modelData.isSteamApp && status === Image.Ready - } - - Rectangle { - anchors.fill: parent - visible: !modelData.isQuickshell && !modelData.isSteamApp && colAppIcon.status !== Image.Ready - color: Theme.surfaceContainer - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: appBorderColor - opacity: appOpacity - - StyledText { - anchors.centerIn: parent - text: (modelData.fallbackText || "?").charAt(0).toUpperCase() - font.pixelSize: parent.width * 0.45 - color: appGlyphColor - font.weight: Font.Bold - } - } - - Rectangle { - anchors.fill: parent - visible: !modelData.isQuickshell && modelData.isSteamApp && colSteamIcon.status !== Image.Ready - color: Theme.surfaceContainer - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: appBorderColor - opacity: appOpacity - - DankIcon { - anchors.centerIn: parent - size: parent.width * 0.7 - name: "sports_esports" - color: appGlyphColor - } - } - - IconImage { - anchors.fill: parent - source: modelData.icon - opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isQuickshell - layer.enabled: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: appHighlightActive ? focusedBorderColor : (isActive ? quickshellIconActiveColor : quickshellIconInactiveColor) - } - } - - IconImage { - id: colSteamIcon - anchors.fill: parent - source: modelData.icon - opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isSteamApp && modelData.icon - } - - DankIcon { - anchors.centerIn: parent - size: root.appIconSize - name: "sports_esports" - color: appHighlightActive ? focusedBorderColor : Theme.widgetTextColor - opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6 - visible: modelData.isSteamApp && !modelData.icon - } - - Rectangle { - anchors.fill: parent - visible: (colAppIcon.visible || colSteamIcon.visible || modelData.isQuickshell) && appHighlightActive - color: "transparent" - radius: Theme.cornerRadius * (root.appIconSize / 40) - border.width: 1 - border.color: focusedBorderColor - z: 1 - } - - MouseArea { - id: colAppMouseArea - anchors.fill: parent - enabled: isActive - cursorShape: Qt.PointingHandCursor - onClicked: { - const winId = modelData.windowId; - if (!winId) - return; - if (CompositorService.isHyprland) { - Hyprland.dispatch(`focuswindow address:${winId}`); - } else if (CompositorService.isNiri) { - NiriService.focusWindow(winId); - } - } - } - - Rectangle { - visible: modelData.count > 1 && !isActive - width: root.appIconSize * 0.67 - height: root.appIconSize * 0.67 - radius: root.appIconSize * 0.33 - color: "black" - border.color: "white" - border.width: 1 - anchors.right: parent.right - anchors.bottom: parent.bottom - z: 2 - - Text { - anchors.centerIn: parent - text: modelData.count - font.pixelSize: root.appIconSize * 0.44 - color: "white" - } - } - } - } - } - } - } - } - } - - Component.onCompleted: updateAllData() - - Connections { - target: CompositorService - function onSortedToplevelsChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: NiriService - enabled: CompositorService.isNiri - function onAllWorkspacesChanged() { - delegateRoot.updateAllData(); - } - function onWindowUrgentChanged() { - delegateRoot.updateAllData(); - } - function onWindowsChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: SettingsData - function onShowWorkspaceAppsChanged() { - delegateRoot.updateAllData(); - } - function onWorkspaceNameIconsChanged() { - delegateRoot.updateAllData(); - } - function onAppIdSubstitutionsChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: DwlService - enabled: CompositorService.isDwl - function onStateChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: Hyprland.workspaces - enabled: CompositorService.isHyprland - function onValuesChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: I3.workspaces - enabled: (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) - function onValuesChanged() { - delegateRoot.updateAllData(); - } - } - Connections { - target: ExtWorkspaceService - enabled: root.useExtWorkspace - function onStateChanged() { - delegateRoot.updateAllData(); - } - } - } - } - } - - Component.onCompleted: { - if (useExtWorkspace && !DMSService.activeSubscriptions.includes("extworkspace")) { - DMSService.addSubscription("extworkspace"); - } - _updateBlurRegistration(); - } - - property bool _blurRegistered: false - readonly property bool _shouldBlur: BlurService.enabled && blurBarWindow && blurBarWindow.registerBlurWidget && !(barConfig?.noBackground ?? false) && root.visible && root.width > 0 - - on_ShouldBlurChanged: _updateBlurRegistration() - - function _updateBlurRegistration() { - if (_shouldBlur && !_blurRegistered) { - blurBarWindow.registerBlurWidget(visualBackground); - _blurRegistered = true; - } else if (!_shouldBlur && _blurRegistered) { - if (blurBarWindow && blurBarWindow.unregisterBlurWidget) - blurBarWindow.unregisterBlurWidget(visualBackground); - _blurRegistered = false; - } - } - - Component.onDestruction: { - if (_blurRegistered && blurBarWindow && blurBarWindow.unregisterBlurWidget) - blurBarWindow.unregisterBlurWidget(visualBackground); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/DankDashPopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/DankDashPopout.qml deleted file mode 100644 index 34b324c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/DankDashPopout.qml +++ /dev/null @@ -1,425 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: root - - layerNamespace: "dms:dash" - - property bool dashVisible: false - property var triggerScreen: null - property int currentTabIndex: 0 - - popupWidth: SettingsData.showWeekNumber ? 736 : 700 - popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 500 - triggerWidth: 80 - screen: triggerScreen - shouldBeVisible: dashVisible - - property bool __focusArmed: false - property bool __contentReady: false - - property var __mediaTabRef: null - - property int __dropdownType: 0 - property point __dropdownAnchor: Qt.point(0, 0) - property bool __dropdownRightEdge: false - property var __dropdownPlayer: null - property var __dropdownPlayers: [] - - function __showVolumeDropdown(pos, rightEdge, player, players) { - __dropdownAnchor = pos; - __dropdownRightEdge = rightEdge; - __dropdownPlayer = player; - __dropdownPlayers = players; - __dropdownType = 1; - } - - function __showAudioDevicesDropdown(pos, rightEdge) { - __dropdownAnchor = pos; - __dropdownRightEdge = rightEdge; - __dropdownType = 2; - } - - function __showPlayersDropdown(pos, rightEdge, player, players) { - __dropdownAnchor = pos; - __dropdownRightEdge = rightEdge; - __dropdownPlayer = player; - __dropdownPlayers = players; - __dropdownType = 3; - } - - function __hideDropdowns() { - __volumeCloseTimer.stop(); - __dropdownType = 0; - __mediaTabRef?.resetDropdownStates(); - } - - function __startCloseTimer() { - __volumeCloseTimer.restart(); - } - - function __stopCloseTimer() { - __volumeCloseTimer.stop(); - } - - Timer { - id: __volumeCloseTimer - interval: 400 - onTriggered: { - if (__dropdownType === 1) { - __hideDropdowns(); - } - } - } - - overlayContent: Component { - MediaDropdownOverlay { - dropdownType: root.__dropdownType - anchorPos: root.__dropdownAnchor - isRightEdge: root.__dropdownRightEdge - activePlayer: root.__dropdownPlayer - allPlayers: root.__dropdownPlayers - onCloseRequested: root.__hideDropdowns() - onPanelEntered: root.__stopCloseTimer() - onPanelExited: root.__startCloseTimer() - onVolumeChanged: volume => { - const player = root.__dropdownPlayer; - const isChrome = player?.identity?.toLowerCase().includes("chrome") || player?.identity?.toLowerCase().includes("chromium"); - const usePlayerVolume = player && player.volumeSupported && !isChrome; - if (usePlayerVolume) { - player.volume = volume; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = volume; - } - } - onPlayerSelected: player => { - const currentPlayer = MprisController.activePlayer; - if (currentPlayer && currentPlayer !== player && currentPlayer.canPause) { - currentPlayer.pause(); - } - MprisController.setActivePlayer(player); - root.__hideDropdowns(); - } - onDeviceSelected: device => { - root.__hideDropdowns(); - } - } - } - - function __tryFocusOnce() { - if (!__focusArmed) - return; - const win = root.window; - if (!win || !win.visible) - return; - if (!contentLoader.item) - return; - if (win.requestActivate) - win.requestActivate(); - contentLoader.item.forceActiveFocus(Qt.TabFocusReason); - - if (contentLoader.item.activeFocus) - __focusArmed = false; - } - - onDashVisibleChanged: { - if (dashVisible) { - __focusArmed = true; - __contentReady = !!contentLoader.item; - open(); - __tryFocusOnce(); - } else { - __focusArmed = false; - __contentReady = false; - __hideDropdowns(); - close(); - } - } - - Connections { - target: contentLoader - function onLoaded() { - __contentReady = true; - if (__focusArmed) - __tryFocusOnce(); - } - } - - Connections { - target: root.window ? root.window : null - enabled: !!root.window - function onVisibleChanged() { - if (__focusArmed) - __tryFocusOnce(); - } - } - - onBackgroundClicked: { - dashVisible = false; - } - - content: Component { - Rectangle { - id: mainContainer - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: Math.max(700, pages.implicitWidth + (Theme.spacingM * 2)) - implicitHeight: contentColumn.height + Theme.spacingM * 2 - color: "transparent" - focus: true - - Component.onCompleted: { - if (root.shouldBeVisible) { - mainContainer.forceActiveFocus(); - } - } - - Connections { - target: root - function onShouldBeVisibleChanged() { - if (root.shouldBeVisible) { - Qt.callLater(function () { - mainContainer.forceActiveFocus(); - }); - } - } - } - - Keys.onPressed: function (event) { - if (event.key === Qt.Key_Escape) { - root.dashVisible = false; - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Tab && !(event.modifiers & Qt.ShiftModifier)) { - let nextIndex = root.currentTabIndex + 1; - while (nextIndex < tabBar.model.length && tabBar.model[nextIndex] && tabBar.model[nextIndex].isAction) { - nextIndex++; - } - if (nextIndex >= tabBar.model.length) { - nextIndex = 0; - } - root.currentTabIndex = nextIndex; - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier))) { - let prevIndex = root.currentTabIndex - 1; - while (prevIndex >= 0 && tabBar.model[prevIndex] && tabBar.model[prevIndex].isAction) { - prevIndex--; - } - if (prevIndex < 0) { - prevIndex = tabBar.model.length - 1; - while (prevIndex >= 0 && tabBar.model[prevIndex] && tabBar.model[prevIndex].isAction) { - prevIndex--; - } - } - if (prevIndex >= 0) { - root.currentTabIndex = prevIndex; - } - event.accepted = true; - return; - } - - if (root.currentTabIndex === 2 && wallpaperLoader.item?.handleKeyEvent) { - if (wallpaperLoader.item.handleKeyEvent(event)) { - event.accepted = true; - return; - } - } - } - - Column { - id: contentColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - DankTabBar { - id: tabBar - - width: parent.width - height: 48 - currentIndex: root.currentTabIndex - spacing: Theme.spacingS - equalWidthTabs: true - enableArrowNavigation: false - focus: false - activeFocusOnTab: false - nextFocusTarget: { - const item = pages.currentItem; - if (!item) - return null; - if (item.focusTarget) - return item.focusTarget; - return item; - } - - model: { - let tabs = [ - { - "icon": "dashboard", - "text": I18n.tr("Overview") - }, - { - "icon": "music_note", - "text": I18n.tr("Media") - }, - { - "icon": "wallpaper", - "text": I18n.tr("Wallpapers") - } - ]; - - if (SettingsData.weatherEnabled) { - tabs.push({ - "icon": "wb_sunny", - "text": I18n.tr("Weather") - }); - } - - tabs.push({ - "icon": "settings", - "text": I18n.tr("Settings"), - "isAction": true - }); - return tabs; - } - - onTabClicked: function (index) { - root.currentTabIndex = index; - } - - onActionTriggered: function (index) { - let settingsIndex = SettingsData.weatherEnabled ? 4 : 3; - if (index === settingsIndex) { - dashVisible = false; - PopoutService.focusOrToggleSettings(); - } - } - } - - Item { - width: parent.width - height: Theme.spacingXS - } - - Item { - id: pages - width: parent.width - height: implicitHeight - implicitWidth: currentItem && currentItem.implicitWidth > 0 ? currentItem.implicitWidth : (700 - Theme.spacingM * 2) - implicitHeight: { - if (root.currentTabIndex === 0) - return overviewLoader.item?.implicitHeight ?? 410; - if (root.currentTabIndex === 1) - return mediaLoader.item?.implicitHeight ?? 410; - if (root.currentTabIndex === 2) - return wallpaperLoader.item?.implicitHeight ?? 410; - if (SettingsData.weatherEnabled && root.currentTabIndex === 3) - return weatherLoader.item?.implicitHeight ?? 410; - return 410; - } - - readonly property var currentItem: { - if (root.currentTabIndex === 0) - return overviewLoader.item; - if (root.currentTabIndex === 1) - return mediaLoader.item; - if (root.currentTabIndex === 2) - return wallpaperLoader.item; - if (root.currentTabIndex === 3) - return weatherLoader.item; - return null; - } - - Loader { - id: overviewLoader - anchors.fill: parent - active: root.currentTabIndex === 0 - visible: active - sourceComponent: Component { - OverviewTab { - onCloseDash: root.dashVisible = false - onSwitchToWeatherTab: { - if (SettingsData.weatherEnabled) { - root.currentTabIndex = 3; - } - } - onSwitchToMediaTab: { - root.currentTabIndex = 1; - } - } - } - } - - Loader { - id: mediaLoader - anchors.fill: parent - active: root.currentTabIndex === 1 - visible: active - sourceComponent: Component { - MediaPlayerTab { - targetScreen: root.screen - popoutX: root.alignedX - popoutY: root.alignedY - popoutWidth: root.alignedWidth - popoutHeight: root.alignedHeight - contentOffsetY: Theme.spacingM + 48 + Theme.spacingS + Theme.spacingXS - section: root.triggerSection - barPosition: root.effectiveBarPosition - Component.onCompleted: root.__mediaTabRef = this - onShowVolumeDropdown: (pos, screen, rightEdge, player, players) => { - root.__showVolumeDropdown(pos, rightEdge, player, players); - } - onShowAudioDevicesDropdown: (pos, screen, rightEdge) => { - root.__showAudioDevicesDropdown(pos, rightEdge); - } - onShowPlayersDropdown: (pos, screen, rightEdge, player, players) => { - root.__showPlayersDropdown(pos, rightEdge, player, players); - } - onHideDropdowns: root.__hideDropdowns() - onVolumeButtonExited: root.__startCloseTimer() - } - } - } - - Loader { - id: wallpaperLoader - anchors.fill: parent - active: root.currentTabIndex === 2 - visible: active - sourceComponent: Component { - WallpaperTab { - active: true - tabBarItem: tabBar - keyForwardTarget: mainContainer - targetScreen: root.screen - parentPopout: root - } - } - } - - Loader { - id: weatherLoader - anchors.fill: parent - active: SettingsData.weatherEnabled && root.currentTabIndex === 3 - visible: active - sourceComponent: Component { - WeatherTab {} - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaDropdownOverlay.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaDropdownOverlay.qml deleted file mode 100644 index 35dfe97..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaDropdownOverlay.qml +++ /dev/null @@ -1,513 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell.Services.Pipewire -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property int dropdownType: 0 - property var activePlayer: null - property var allPlayers: [] - property point anchorPos: Qt.point(0, 0) - property bool isRightEdge: false - - property bool __isChromeBrowser: { - if (!activePlayer?.identity) - return false; - const id = activePlayer.identity.toLowerCase(); - return id.includes("chrome") || id.includes("chromium"); - } - property bool usePlayerVolume: activePlayer && activePlayer.volumeSupported && !__isChromeBrowser - property real currentVolume: usePlayerVolume ? activePlayer.volume : (AudioService.sink?.audio?.volume ?? 0) - property bool volumeAvailable: (activePlayer && activePlayer.volumeSupported && !__isChromeBrowser) || (AudioService.sink && AudioService.sink.audio) - property var availableDevices: { - const hidden = SessionData.hiddenOutputDeviceNames ?? []; - return Pipewire.nodes.values.filter(node => { - if (!node.audio || !node.isSink || node.isStream) - return false; - return !hidden.includes(node.name); - }); - } - - signal closeRequested - signal deviceSelected(var device) - signal playerSelected(var player) - signal volumeChanged(real volume) - signal panelEntered - signal panelExited - - property int __volumeHoverCount: 0 - - function volumeAreaEntered() { - __volumeHoverCount++; - panelEntered(); - } - - function volumeAreaExited() { - __volumeHoverCount--; - Qt.callLater(() => { - if (__volumeHoverCount <= 0) - panelExited(); - }); - } - - Rectangle { - id: volumePanel - visible: dropdownType === 1 && volumeAvailable - width: 60 - height: 180 - x: isRightEdge ? anchorPos.x : anchorPos.x - width - y: anchorPos.y - height / 2 - radius: Theme.cornerRadius * 2 - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: 1 - - opacity: dropdownType === 1 ? 1 : 0 - scale: dropdownType === 1 ? 1 : 0.96 - transformOrigin: isRightEdge ? Item.Left : Item.Right - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - ElevationShadow { - id: volumeShadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: volumePanel.radius - targetColor: volumePanel.color - borderColor: volumePanel.border.color - borderWidth: volumePanel.border.width - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - MouseArea { - anchors.fill: parent - anchors.margins: -12 - hoverEnabled: true - onEntered: volumeAreaEntered() - onExited: volumeAreaExited() - } - - Item { - anchors.fill: parent - anchors.margins: Theme.spacingS - - Item { - id: volumeSlider - width: parent.width * 0.5 - height: parent.height - Theme.spacingXL * 2 - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - Rectangle { - width: parent.width - height: parent.height - anchors.centerIn: parent - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - radius: Theme.cornerRadius - } - - Rectangle { - width: parent.width - height: volumeAvailable ? (Math.min(1.0, currentVolume) * parent.height) : 0 - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - bottomLeftRadius: Theme.cornerRadius - bottomRightRadius: Theme.cornerRadius - } - - Rectangle { - width: parent.width + 8 - height: 8 - radius: Theme.cornerRadius - y: { - const ratio = volumeAvailable ? Math.min(1.0, currentVolume) : 0; - const travel = parent.height - height; - return Math.max(0, Math.min(travel, travel * (1 - ratio))); - } - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.primary - border.width: 3 - border.color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1.0) - } - - MouseArea { - anchors.fill: parent - anchors.margins: -12 - enabled: volumeAvailable - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - preventStealing: true - - onEntered: volumeAreaEntered() - onExited: volumeAreaExited() - onPressed: mouse => updateVolume(mouse) - onPositionChanged: mouse => { - if (pressed) - updateVolume(mouse); - } - onClicked: mouse => updateVolume(mouse) - - function updateVolume(mouse) { - if (!volumeAvailable) - return; - const ratio = 1.0 - (mouse.y / height); - const volume = Math.max(0, Math.min(1, ratio)); - root.volumeChanged(volume); - } - } - } - - StyledText { - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: Theme.spacingL - text: volumeAvailable ? Math.round(currentVolume * 100) + "%" : "0%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - } - - Rectangle { - id: audioDevicesPanel - visible: dropdownType === 2 - width: 280 - height: Math.max(200, Math.min(280, availableDevices.length * 50 + 100)) - x: isRightEdge ? anchorPos.x : anchorPos.x - width - y: anchorPos.y - height / 2 - radius: Theme.cornerRadius * 2 - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.98) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6) - border.width: 2 - - opacity: dropdownType === 2 ? 1 : 0 - scale: dropdownType === 2 ? 1 : 0.96 - transformOrigin: isRightEdge ? Item.Left : Item.Right - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - ElevationShadow { - id: audioDevicesShadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: audioDevicesPanel.radius - targetColor: audioDevicesPanel.color - borderColor: audioDevicesPanel.border.color - borderWidth: audioDevicesPanel.border.width - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - - StyledText { - text: I18n.tr("Audio Output Devices (") + availableDevices.length + ")" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignHCenter - bottomPadding: Theme.spacingM - } - - DankFlickable { - width: parent.width - height: parent.height - 40 - contentHeight: deviceColumn.height - clip: true - - Column { - id: deviceColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: availableDevices - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: deviceMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: modelData === AudioService.sink ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: modelData === AudioService.sink ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - - DankIcon { - name: getAudioDeviceIcon(modelData) - size: 20 - color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - - function getAudioDeviceIcon(device) { - if (!device?.name) - return "speaker"; - const name = device.name.toLowerCase(); - if (name.includes("bluez") || name.includes("bluetooth")) - return "headset"; - if (name.includes("hdmi")) - return "tv"; - if (name.includes("usb")) - return "headset"; - return "speaker"; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 20 - Theme.spacingM * 2 - - StyledText { - text: AudioService.displayName(modelData) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === AudioService.sink ? Font.Medium : Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - - StyledText { - text: modelData === AudioService.sink ? "Active" : "Available" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: parent.width - } - } - } - - MouseArea { - id: deviceMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData) { - Pipewire.preferredDefaultAudioSink = modelData; - root.deviceSelected(modelData); - } - } - } - } - } - } - } - } - } - - Rectangle { - id: playersPanel - visible: dropdownType === 3 - width: 240 - height: Math.max(180, Math.min(240, (allPlayers?.length || 0) * 50 + 80)) - x: isRightEdge ? anchorPos.x : anchorPos.x - width - y: anchorPos.y - height / 2 - radius: Theme.cornerRadius * 2 - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.98) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6) - border.width: 2 - - opacity: dropdownType === 3 ? 1 : 0 - scale: dropdownType === 3 ? 1 : 0.96 - transformOrigin: isRightEdge ? Item.Left : Item.Right - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial - } - } - - ElevationShadow { - id: playersShadowLayer - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: playersPanel.radius - targetColor: playersPanel.color - borderColor: playersPanel.border.color - borderWidth: playersPanel.border.width - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - - StyledText { - text: I18n.tr("Media Players (") + (allPlayers?.length || 0) + ")" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignHCenter - bottomPadding: Theme.spacingM - } - - DankFlickable { - width: parent.width - height: parent.height - 40 - contentHeight: playerColumn.height - clip: true - - Column { - id: playerColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: allPlayers || [] - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: playerMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: modelData === activePlayer ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: modelData === activePlayer ? 2 : 1 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - - DankIcon { - name: "music_note" - size: 20 - color: modelData === activePlayer ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 20 - Theme.spacingM * 2 - - StyledText { - text: { - if (!modelData) - return "Unknown Player"; - const identity = modelData.identity || "Unknown Player"; - const trackTitle = modelData.trackTitle || ""; - return trackTitle.length > 0 ? identity + " - " + trackTitle : identity; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: modelData === activePlayer ? Font.Medium : Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - - StyledText { - text: { - if (!modelData) - return ""; - const artist = modelData.trackArtist || ""; - const isActive = modelData === activePlayer; - if (artist.length > 0) - return artist + (isActive ? " (Active)" : ""); - return isActive ? "Active" : "Available"; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - wrapMode: Text.NoWrap - width: parent.width - } - } - } - - MouseArea { - id: playerMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData?.identity) { - root.playerSelected(modelData); - } - } - } - } - } - } - } - } - } - - MouseArea { - anchors.fill: parent - z: -1 - enabled: dropdownType !== 0 - onClicked: closeRequested() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaPlayerTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaPlayerTab.qml deleted file mode 100644 index c6d7bfc..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/MediaPlayerTab.qml +++ /dev/null @@ -1,785 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import Quickshell.Services.Mpris -import Quickshell.Io -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property MprisPlayer activePlayer: MprisController.activePlayer - property var allPlayers: MprisController.availablePlayers - property var targetScreen: null - property real popoutX: 0 - property real popoutY: 0 - property real popoutWidth: 0 - property real popoutHeight: 0 - property real contentOffsetY: 0 - property string section: "" - property int barPosition: SettingsData.Position.Top - - signal showVolumeDropdown(point pos, var screen, bool rightEdge, var player, var players) - signal showAudioDevicesDropdown(point pos, var screen, bool rightEdge) - signal showPlayersDropdown(point pos, var screen, bool rightEdge, var player, var players) - signal hideDropdowns - signal volumeButtonExited - - property bool volumeExpanded: false - property bool devicesExpanded: false - property bool playersExpanded: false - - function resetDropdownStates() { - volumeExpanded = false; - devicesExpanded = false; - playersExpanded = false; - } - - DankTooltipV2 { - id: sharedTooltip - } - - readonly property bool isRightEdge: { - if (barPosition === SettingsData.Position.Right) - return true; - if (barPosition === SettingsData.Position.Left) - return false; - return section === "right"; - } - readonly property bool __isChromeBrowser: { - if (!activePlayer?.identity) - return false; - const id = activePlayer.identity.toLowerCase(); - return id.includes("chrome") || id.includes("chromium"); - } - readonly property bool volumeAvailable: (activePlayer && activePlayer.volumeSupported && !__isChromeBrowser) || (AudioService.sink && AudioService.sink.audio) - readonly property bool usePlayerVolume: activePlayer && activePlayer.volumeSupported && !__isChromeBrowser - readonly property real currentVolume: usePlayerVolume ? activePlayer.volume : (AudioService.sink?.audio?.volume ?? 0) - - property bool isSwitching: false - - // Derived "no players" state: always correct, no timers. - readonly property int _playerCount: allPlayers ? allPlayers.length : 0 - readonly property bool _noneAvailable: _playerCount === 0 - readonly property bool _trulyIdle: activePlayer && activePlayer.playbackState === MprisPlaybackState.Stopped && !activePlayer.trackTitle && !activePlayer.trackArtist - readonly property bool showNoPlayerNow: (!_switchHold) && (_noneAvailable || _trulyIdle) - - property bool _switchHold: false - Timer { - id: _switchHoldTimer - interval: 650 - repeat: false - onTriggered: _switchHold = false - } - - onActivePlayerChanged: { - if (!activePlayer) { - isSwitching = false; - _switchHold = false; - return; - } - isSwitching = true; - _switchHold = true; - _switchHoldTimer.restart(); - TrackArtService.loadArtwork(activePlayer.trackArtUrl); - } - - function maybeFinishSwitch() { - if (activePlayer && activePlayer.trackTitle !== "") { - isSwitching = false; - _switchHold = false; - } - } - - readonly property real ratio: { - if (!activePlayer || !activePlayer.length || activePlayer.length <= 0) { - return 0; - } - const pos = (activePlayer.position || 0) % Math.max(1, activePlayer.length); - const calculatedRatio = pos / activePlayer.length; - return Math.max(0, Math.min(1, calculatedRatio)); - } - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: playerContent.height + playerContent.anchors.topMargin * 2 - - Connections { - target: activePlayer - function onTrackTitleChanged() { - _switchHoldTimer.restart(); - maybeFinishSwitch(); - } - function onTrackArtUrlChanged() { - TrackArtService.loadArtwork(activePlayer.trackArtUrl); - } - } - - Connections { - target: MprisController - function onAvailablePlayersChanged() { - const count = (MprisController.availablePlayers?.length || 0); - if (count === 0) { - isSwitching = false; - _switchHold = false; - } else { - _switchHold = true; - _switchHoldTimer.restart(); - } - } - } - - function getAudioDeviceIcon(device) { - if (!device || !device.name) - return "speaker"; - - const name = device.name.toLowerCase(); - - if (name.includes("bluez") || name.includes("bluetooth")) - return "headset"; - if (name.includes("hdmi")) - return "tv"; - if (name.includes("usb")) - return "headset"; - if (name.includes("analog") || name.includes("built-in")) - return "speaker"; - - return "speaker"; - } - - function getVolumeIcon() { - if (!volumeAvailable) - return "volume_off"; - - const volume = currentVolume; - - if (usePlayerVolume) { - if (volume === 0.0) - return "music_off"; - return "music_note"; - } - - if (volume === 0.0) - return "volume_off"; - if (volume <= 0.33) - return "volume_down"; - if (volume <= 0.66) - return "volume_up"; - return "volume_up"; - } - - function adjustVolume(step) { - if (!volumeAvailable) - return; - const maxVol = usePlayerVolume ? 100 : AudioService.sinkMaxVolume; - const current = Math.round(currentVolume * 100); - const newVolume = Math.min(maxVol, Math.max(0, current + step)); - - SessionData.suppressOSDTemporarily(); - if (usePlayerVolume) { - activePlayer.volume = newVolume / 100; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = newVolume / 100; - } - } - - property bool isSeeking: false - - Timer { - interval: 1000 - running: activePlayer?.playbackState === MprisPlaybackState.Playing && !isSeeking - repeat: true - onTriggered: activePlayer?.positionChanged() - } - - Item { - id: bgContainer - anchors.fill: parent - visible: TrackArtService._bgArtSource !== "" - - Image { - id: bgImage - anchors.centerIn: parent - width: Math.max(parent.width, parent.height) * 1.1 - height: width - source: TrackArtService._bgArtSource - fillMode: Image.PreserveAspectCrop - asynchronous: true - cache: true - visible: false - onStatusChanged: { - if (status === Image.Ready) - maybeFinishSwitch(); - } - } - - Item { - id: blurredBg - anchors.fill: parent - visible: false - - MultiEffect { - anchors.centerIn: parent - width: bgImage.width - height: bgImage.height - source: bgImage - blurEnabled: true - blurMax: 64 - blur: 0.8 - saturation: -0.2 - brightness: -0.25 - } - } - - Rectangle { - id: bgMask - anchors.fill: parent - radius: Theme.cornerRadius - visible: false - layer.enabled: true - } - - MultiEffect { - anchors.fill: parent - source: blurredBg - maskEnabled: true - maskSource: bgMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1.0 - opacity: 0.7 - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.surface - opacity: 0.3 - } - } - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - visible: showNoPlayerNow - - DankIcon { - name: "music_note" - size: Theme.iconSize * 3 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No Active Players") - font.pixelSize: Theme.fontSizeLarge - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Item { - anchors.fill: parent - clip: false - visible: !_noneAvailable && (!showNoPlayerNow) - ColumnLayout { - id: playerContent - width: 484 - height: 370 - spacing: Theme.spacingXS - anchors.top: parent.top - anchors.topMargin: 20 - anchors.horizontalCenter: parent.horizontalCenter - - Item { - width: parent.width - height: 200 - clip: false - - DankAlbumArt { - width: Math.min(parent.width * 0.8, parent.height * 0.9) - height: width - anchors.centerIn: parent - activePlayer: root.activePlayer - } - } - - // Song Info and Controls Section - Item { - width: parent.width - Layout.fillHeight: true - - Column { - id: songInfo - width: parent.width - spacing: Theme.spacingXS - anchors.top: parent.top - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: activePlayer?.trackTitle || I18n.tr("Unknown Track") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight - wrapMode: Text.WordWrap - maximumLineCount: 2 - } - - StyledText { - text: activePlayer?.trackTitle || I18n.tr("Unknown Artist") - font.pixelSize: Theme.fontSizeMedium - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8) - width: parent.width - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight - wrapMode: Text.WordWrap - maximumLineCount: 1 - } - - StyledText { - text: activePlayer?.trackAlbum || "" - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - width: parent.width - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight - wrapMode: Text.WordWrap - maximumLineCount: 1 - visible: text.length > 0 - } - } - - Item { - id: seekbarContainer - width: parent.width - anchors.top: songInfo.bottom - anchors.bottom: playbackControls.top - anchors.horizontalCenter: parent.horizontalCenter - - Column { - width: parent.width - spacing: 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: parent.height * 0.2 - - DankSeekbar { - width: parent.width * 0.8 - height: 20 - anchors.horizontalCenter: parent.horizontalCenter - activePlayer: root.activePlayer - isSeeking: root.isSeeking - onIsSeekingChanged: root.isSeeking = isSeeking - } - - Item { - width: parent.width * 0.8 - height: 16 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - text: { - if (!activePlayer) - return "0:00"; - const rawPos = Math.max(0, activePlayer.position || 0); - const pos = activePlayer.length ? rawPos % Math.max(1, activePlayer.length) : rawPos; - const minutes = Math.floor(pos / 60); - const seconds = Math.floor(pos % 60); - const timeStr = minutes + ":" + (seconds < 10 ? "0" : "") + seconds; - return timeStr; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - text: { - if (!activePlayer || !activePlayer.length) - return "0:00"; - const dur = Math.max(0, activePlayer.length || 0); - const minutes = Math.floor(dur / 60); - const seconds = Math.floor(dur % 60); - return minutes + ":" + (seconds < 10 ? "0" : "") + seconds; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - Item { - id: playbackControls - width: parent.width - height: 50 - anchors.bottom: parent.bottom - - Row { - anchors.centerIn: parent - spacing: Theme.spacingM - height: parent.height - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - visible: activePlayer && activePlayer.shuffleSupported - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: shuffleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "shuffle" - size: 20 - color: activePlayer && activePlayer.shuffle ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: shuffleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (activePlayer && activePlayer.canControl && activePlayer.shuffleSupported) { - activePlayer.shuffle = !activePlayer.shuffle; - } - } - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: prevBtnArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_previous" - size: 24 - color: Theme.surfaceText - } - - MouseArea { - id: prevBtnArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: MprisController.previousOrRewind() - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 50 - height: 50 - radius: 25 - anchors.centerIn: parent - color: Theme.primary - - DankIcon { - anchors.centerIn: parent - name: activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow" - size: 28 - color: Theme.background - weight: 500 - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer && activePlayer.togglePlaying() - } - - ElevationShadow { - anchors.fill: parent - z: -1 - level: Theme.elevationLevel1 - fallbackOffset: 1 - targetRadius: parent.radius - targetColor: parent.color - shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2 - shadowEnabled: Theme.elevationEnabled - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: nextBtnArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_next" - size: 24 - color: Theme.surfaceText - } - - MouseArea { - id: nextBtnArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer && activePlayer.next() - } - } - } - - Item { - width: 50 - height: 50 - anchors.verticalCenter: parent.verticalCenter - visible: activePlayer && activePlayer.loopSupported - - Rectangle { - width: 40 - height: 40 - radius: 20 - anchors.centerIn: parent - color: repeatArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: { - if (!activePlayer) - return "repeat"; - switch (activePlayer.loopState) { - case MprisLoopState.Track: - return "repeat_one"; - case MprisLoopState.Playlist: - return "repeat"; - default: - return "repeat"; - } - } - size: 20 - color: activePlayer && activePlayer.loopState !== MprisLoopState.None ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: repeatArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (activePlayer && activePlayer.canControl && activePlayer.loopSupported) { - switch (activePlayer.loopState) { - case MprisLoopState.None: - activePlayer.loopState = MprisLoopState.Playlist; - break; - case MprisLoopState.Playlist: - activePlayer.loopState = MprisLoopState.Track; - break; - case MprisLoopState.Track: - activePlayer.loopState = MprisLoopState.None; - break; - } - } - } - } - } - } - } - } - } - } - } - - Rectangle { - id: playerSelectorButton - width: 40 - height: 40 - radius: 20 - x: isRightEdge ? Theme.spacingM : parent.width - 40 - Theme.spacingM - y: 185 - color: playerSelectorArea.containsMouse || playersExpanded ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: 1 - z: 100 - visible: (allPlayers?.length || 0) >= 1 - - DankIcon { - anchors.centerIn: parent - name: "assistant_device" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: playerSelectorArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (playersExpanded) { - hideDropdowns(); - return; - } - hideDropdowns(); - playersExpanded = true; - const buttonsOnRight = !isRightEdge; - const btnY = playerSelectorButton.y + playerSelectorButton.height / 2; - const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX; - const screenY = popoutY + contentOffsetY + btnY; - showPlayersDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight, activePlayer, allPlayers); - } - onEntered: sharedTooltip.show(I18n.tr("Media Players"), playerSelectorButton, 0, 0, isRightEdge ? "right" : "left") - onExited: sharedTooltip.hide() - } - } - - Rectangle { - id: volumeButton - width: 40 - height: 40 - radius: 20 - x: isRightEdge ? Theme.spacingM : parent.width - 40 - Theme.spacingM - y: 130 - color: volumeButtonArea.containsMouse && volumeAvailable || volumeExpanded ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, volumeAvailable ? 0.3 : 0.15) - border.width: 1 - z: 101 - enabled: volumeAvailable - - property real previousVolume: 0.0 - - DankIcon { - anchors.centerIn: parent - name: getVolumeIcon() - size: 18 - color: volumeAvailable && currentVolume > 0 ? Theme.primary : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, volumeAvailable ? 1.0 : 0.5) - } - - MouseArea { - id: volumeButtonArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onEntered: { - if (volumeExpanded) - return; - hideDropdowns(); - volumeExpanded = true; - const buttonsOnRight = !isRightEdge; - const btnY = volumeButton.y + volumeButton.height / 2; - const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX; - const screenY = popoutY + contentOffsetY + btnY; - showVolumeDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight, activePlayer, allPlayers); - } - onExited: { - if (volumeExpanded) - volumeButtonExited(); - } - onClicked: { - SessionData.suppressOSDTemporarily(); - if (currentVolume > 0) { - volumeButton.previousVolume = currentVolume; - if (usePlayerVolume) { - activePlayer.volume = 0; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = 0; - } - } else { - const restoreVolume = volumeButton.previousVolume > 0 ? volumeButton.previousVolume : 0.5; - if (usePlayerVolume) { - activePlayer.volume = restoreVolume; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = restoreVolume; - } - } - } - onWheel: wheelEvent => { - SessionData.suppressOSDTemporarily(); - const delta = wheelEvent.angleDelta.y; - const current = (currentVolume * 100) || 0; - const maxVol = usePlayerVolume ? 100 : AudioService.sinkMaxVolume; - const newVolume = delta > 0 ? Math.min(maxVol, current + 5) : Math.max(0, current - 5); - - if (usePlayerVolume) { - activePlayer.volume = newVolume / 100; - } else if (AudioService.sink?.audio) { - AudioService.sink.audio.volume = newVolume / 100; - } - wheelEvent.accepted = true; - } - } - } - - Rectangle { - id: audioDevicesButton - width: 40 - height: 40 - radius: 20 - x: isRightEdge ? Theme.spacingM : parent.width - 40 - Theme.spacingM - y: 240 - color: audioDevicesArea.containsMouse || devicesExpanded ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: 1 - z: 100 - - DankIcon { - anchors.centerIn: parent - name: devicesExpanded ? "expand_less" : "speaker" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: audioDevicesArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (devicesExpanded) { - hideDropdowns(); - return; - } - hideDropdowns(); - devicesExpanded = true; - const buttonsOnRight = !isRightEdge; - const btnY = audioDevicesButton.y + audioDevicesButton.height / 2; - const screenX = buttonsOnRight ? (popoutX + popoutWidth) : popoutX; - const screenY = popoutY + contentOffsetY + btnY; - showAudioDevicesDropdown(Qt.point(screenX, screenY), targetScreen, buttonsOnRight); - } - onEntered: sharedTooltip.show(I18n.tr("Output Device"), audioDevicesButton, 0, 0, isRightEdge ? "right" : "left") - onExited: sharedTooltip.hide() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml deleted file mode 100644 index 1972f06..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/CalendarOverviewCard.qml +++ /dev/null @@ -1,539 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - - property bool showEventDetails: false - property date selectedDate: systemClock.date - property var selectedDateEvents: [] - property bool hasEvents: selectedDateEvents && selectedDateEvents.length > 0 - - signal closeDash - - function weekStartQt() { - if (SettingsData.firstDayOfWeek >= 7 || SettingsData.firstDayOfWeek < 0) { - return Qt.locale().firstDayOfWeek; - } - return SettingsData.firstDayOfWeek; - } - - function weekStartJs() { - return weekStartQt() % 7; - } - - function startOfWeek(dateObj) { - const d = new Date(dateObj); - const jsDow = d.getDay(); - const diff = (jsDow - weekStartJs() + 7) % 7; - d.setDate(d.getDate() - diff); - return d; - } - - function endOfWeek(dateObj) { - const d = new Date(dateObj); - const jsDow = d.getDay(); - const add = (weekStartJs() + 6 - jsDow + 7) % 7; - d.setDate(d.getDate() + add); - return d; - } - - function getWeekNumber(dateObj) { - // Set time to noon to avoid potential Daylight Saving Time related bugs - const weekStartDay = startOfWeek(dateObj); - weekStartDay.setHours(12, 0, 0, 0); - - let week1Start; - - if (weekStartJs() === 1) { - // ISO 8601 Standard, week start on Monday - // A week belongs to the year its Thursday falls in - // So we have to get the yearTarget from weekStartDay instead of dateObj - let yearTarget = weekStartDay; - yearTarget.setDate(yearTarget.getDate() + 3); // Monday + 3 = Thursday - - // Week 1 is the week containing Jan 4th - const jan4 = new Date(yearTarget.getFullYear(), 0, 4); - week1Start = startOfWeek(jan4); - } else { - // Traditional / US Standard, week start on Sunday - // A week belongs to the year its Sunday falls in - let yearTarget = weekStartDay; - yearTarget.setDate(yearTarget.getDate() + 6); // Monday + 6 = Sunday - - // Week 1 is the week containing Jan 1st - const jan1 = new Date(yearTarget.getFullYear(), 0, 1); - week1Start = startOfWeek(jan1); - } - - week1Start.setHours(12, 0, 0, 0); - - const diffDays = Math.round((weekStartDay.getTime() - week1Start.getTime()) / 86400000); // Number of miliseconds in a day - return Math.floor(diffDays / 7) + 1; - } - - function updateSelectedDateEvents() { - if (CalendarService && CalendarService.khalAvailable) { - const events = CalendarService.getEventsForDate(selectedDate); - selectedDateEvents = events; - } else { - selectedDateEvents = []; - } - } - - function loadEventsForMonth() { - if (!CalendarService || !CalendarService.khalAvailable) { - return; - } - - const firstOfMonth = new Date(calendarGrid.displayDate.getFullYear(), calendarGrid.displayDate.getMonth(), 1); - const lastOfMonth = new Date(calendarGrid.displayDate.getFullYear(), calendarGrid.displayDate.getMonth() + 1, 0); - - const startDate = startOfWeek(firstOfMonth); - startDate.setDate(startDate.getDate() - 7); - - const endDate = endOfWeek(lastOfMonth); - endDate.setDate(endDate.getDate() + 7); - - CalendarService.loadEvents(startDate, endDate); - } - - onSelectedDateChanged: updateSelectedDateEvents() - Component.onCompleted: { - loadEventsForMonth(); - updateSelectedDateEvents(); - } - - Connections { - function onEventsByDateChanged() { - updateSelectedDateEvents(); - } - - function onKhalAvailableChanged() { - if (CalendarService && CalendarService.khalAvailable) { - loadEventsForMonth(); - } - updateSelectedDateEvents(); - } - - target: CalendarService - enabled: CalendarService !== null - } - - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05) - border.width: 1 - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Item { - width: parent.width - height: 40 - visible: showEventDetails - - Rectangle { - width: 32 - height: 32 - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - radius: Theme.cornerRadius - color: backButtonArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "arrow_back" - size: 14 - color: Theme.primary - } - - MouseArea { - id: backButtonArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.showEventDetails = false - } - } - - StyledText { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 32 + Theme.spacingS * 2 - anchors.rightMargin: Theme.spacingS - height: 40 - anchors.verticalCenter: parent.verticalCenter - text: { - const dateStr = Qt.formatDate(selectedDate, "MMM d"); - if (selectedDateEvents && selectedDateEvents.length > 0) { - const eventCount = selectedDateEvents.length === 1 ? I18n.tr("1 event") : selectedDateEvents.length + " " + I18n.tr("events"); - return dateStr + " • " + eventCount; - } - return dateStr; - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight - } - } - - Row { - width: parent.width - height: 28 - visible: !showEventDetails - - Rectangle { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: prevMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "chevron_left" - size: 14 - color: Theme.primary - } - - MouseArea { - id: prevMonthArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - let newDate = new Date(calendarGrid.displayDate); - newDate.setMonth(newDate.getMonth() - 1); - calendarGrid.displayDate = newDate; - loadEventsForMonth(); - } - } - } - - StyledText { - width: parent.width - 56 - height: 28 - text: calendarGrid.displayDate.toLocaleDateString(I18n.locale(), "MMMM yyyy") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - - Rectangle { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: nextMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "chevron_right" - size: 14 - color: Theme.primary - } - - MouseArea { - id: nextMonthArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - let newDate = new Date(calendarGrid.displayDate); - newDate.setMonth(newDate.getMonth() + 1); - calendarGrid.displayDate = newDate; - loadEventsForMonth(); - } - } - } - } - - Row { - width: parent.width - height: parent.height - 28 - Theme.spacingS - visible: !showEventDetails - spacing: SettingsData.showWeekNumber ? Theme.spacingS : 0 - - Column { - id: weekNumberColumn - visible: SettingsData.showWeekNumber - width: SettingsData.showWeekNumber ? 28 : 0 - height: parent.height - spacing: Theme.spacingS - - Item { - width: parent.width - height: 18 - } - - Grid { - width: parent.width - height: parent.height - 18 - Theme.spacingS - columns: 1 - rows: 6 - - Repeater { - model: 6 - Rectangle { - width: parent.width - height: parent.height / 6 - color: "transparent" - - StyledText { - anchors.centerIn: parent - text: { - const rowDate = new Date(calendarGrid.firstDay); - rowDate.setDate(rowDate.getDate() + index * 7); - return root.getWeekNumber(rowDate); - } - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - } - } - } - } - } - - Column { - width: SettingsData.showWeekNumber ? (parent.width - weekNumberColumn.width - parent.spacing) : parent.width - height: parent.height - spacing: Theme.spacingS - - Row { - width: parent.width - height: 18 - - Repeater { - model: { - const days = []; - const qtFirst = weekStartQt(); - for (let i = 0; i < 7; ++i) { - const qtDay = ((qtFirst - 1 + i) % 7) + 1; - days.push(I18n.locale().dayName(qtDay, Locale.ShortFormat)); - } - return days; - } - - Rectangle { - width: parent.width / 7 - height: 18 - color: "transparent" - - StyledText { - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - } - } - } - } - - Grid { - id: calendarGrid - width: parent.width - height: parent.height - 18 - Theme.spacingS - columns: 7 - rows: 6 - - property date displayDate: systemClock.date - property date selectedDate: systemClock.date - - readonly property date firstDay: { - const firstOfMonth = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1); - return startOfWeek(firstOfMonth); - } - - Repeater { - model: 42 - - Rectangle { - readonly property date dayDate: { - const date = new Date(parent.firstDay); - date.setDate(date.getDate() + index); - return date; - } - readonly property bool isCurrentMonth: dayDate.getMonth() === calendarGrid.displayDate.getMonth() - readonly property bool isToday: dayDate.toDateString() === new Date().toDateString() - readonly property bool isSelected: dayDate.toDateString() === calendarGrid.selectedDate.toDateString() - - width: parent.width / 7 - height: parent.height / 6 - color: "transparent" - - Rectangle { - anchors.centerIn: parent - width: Math.min(parent.width - 4, parent.height - 4, 32) - height: width - color: isToday ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : dayArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - radius: Theme.cornerRadius - - StyledText { - anchors.centerIn: parent - text: dayDate.getDate() - font.pixelSize: Theme.fontSizeSmall - color: isToday ? Theme.primary : isCurrentMonth ? Theme.surfaceText : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4) - font.weight: isToday ? Font.Medium : Font.Normal - } - - Rectangle { - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottomMargin: 4 - width: 12 - height: 2 - radius: Theme.cornerRadius - visible: CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate) - color: isToday ? Qt.lighter(Theme.primary, 1.3) : Theme.primary - opacity: isToday ? 0.9 : 0.7 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - MouseArea { - id: dayArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate)) { - root.selectedDate = dayDate; - root.showEventDetails = true; - } - } - } - } - } - } - } - } - - DankListView { - width: parent.width - Theme.spacingS * 2 - height: parent.height - (showEventDetails ? 40 : 28 + 18) - Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - model: selectedDateEvents - visible: showEventDetails - clip: true - spacing: Theme.spacingXS - - delegate: Rectangle { - width: parent ? parent.width : 0 - height: eventContent.implicitHeight + Theme.spacingS - radius: Theme.cornerRadius - color: { - if (modelData.url && eventMouseArea.containsMouse) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12); - } else if (eventMouseArea.containsMouse) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06); - } - return Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency); - } - border.color: { - if (modelData.url && eventMouseArea.containsMouse) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - } else if (eventMouseArea.containsMouse) { - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15); - } - return "transparent"; - } - border.width: 1 - - Rectangle { - width: 3 - height: parent.height - 6 - anchors.left: parent.left - anchors.leftMargin: 3 - anchors.verticalCenter: parent.verticalCenter - radius: Theme.cornerRadius - color: Theme.primary - opacity: 0.8 - } - - Column { - id: eventContent - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingS + 6 - anchors.rightMargin: Theme.spacingXS - spacing: 2 - - StyledText { - width: parent.width - text: modelData.title - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - maximumLineCount: 1 - } - - StyledText { - width: parent.width - text: { - if (!modelData || modelData.allDay) { - return I18n.tr("All day"); - } else if (modelData.start && modelData.end) { - const timeFormat = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - const startTime = Qt.formatTime(modelData.start, timeFormat); - if (modelData.start.toDateString() !== modelData.end.toDateString() || modelData.start.getTime() !== modelData.end.getTime()) { - return startTime + " – " + Qt.formatTime(modelData.end, timeFormat); - } - return startTime; - } - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - font.weight: Font.Normal - visible: text !== "" - } - } - - MouseArea { - id: eventMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: modelData.url ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: modelData.url !== "" - onClicked: { - if (modelData.url && modelData.url !== "") { - if (Qt.openUrlExternally(modelData.url) === false) { - console.warn("Failed to open URL: " + modelData.url); - } else { - root.closeDash(); - } - } - } - } - } - } - } - - SystemClock { - id: systemClock - precision: SystemClock.Hours - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/Card.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/Card.qml deleted file mode 100644 index 8996c81..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/Card.qml +++ /dev/null @@ -1,24 +0,0 @@ -import QtQuick -import qs.Common - -Rectangle { - id: card - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property int pad: Theme.spacingM - - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 1 - - default property alias content: contentItem.data - - Item { - id: contentItem - anchors.fill: parent - anchors.margins: card.pad - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/ClockCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/ClockCard.qml deleted file mode 100644 index 5f597c3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/ClockCard.qml +++ /dev/null @@ -1,113 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import qs.Common -import qs.Widgets - -Card { - id: root - - Column { - anchors.centerIn: parent - spacing: 0 - - Column { - spacing: -8 - anchors.horizontalCenter: parent.horizontalCenter - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: { - if (SettingsData.use24HourClock) { - return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(0) - } else { - const hours = systemClock?.date?.getHours() - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours - return String(display).padStart(2, '0').charAt(0) - } - } - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: { - if (SettingsData.use24HourClock) { - return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(1) - } else { - const hours = systemClock?.date?.getHours() - const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours - return String(display).padStart(2, '0').charAt(1) - } - } - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - } - - Row { - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0) - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1) - font.pixelSize: 48 - color: Theme.primary - font.weight: Font.Medium - width: 28 - horizontalAlignment: Text.AlignHCenter - } - } - } - - Row { - visible: SettingsData.showSeconds - spacing: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: String(systemClock?.date?.getSeconds()).padStart(2, '0') - font.pixelSize: 24 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.7) - font.weight: Font.Medium - horizontalAlignment: Text.AlignHCenter - } - } - - Item { - width: 1 - height: Theme.spacingXS - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: systemClock?.date?.toLocaleDateString(I18n.locale(), "MMM dd") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - SystemClock { - id: systemClock - precision: SettingsData.showSeconds ? SystemClock.Seconds : SystemClock.Minutes - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml deleted file mode 100644 index 35f4f47..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml +++ /dev/null @@ -1,211 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Shapes -import Quickshell.Services.Mpris -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - clip: false - - signal clicked() - - property MprisPlayer activePlayer: MprisController.activePlayer - property real currentPosition: activePlayer?.positionSupported ? activePlayer.position : 0 - property real displayPosition: currentPosition - - readonly property real ratio: { - if (!activePlayer || activePlayer.length <= 0) return 0 - const pos = displayPosition % Math.max(1, activePlayer.length) - const calculatedRatio = pos / activePlayer.length - return Math.max(0, Math.min(1, calculatedRatio)) - } - - onActivePlayerChanged: { - if (activePlayer?.positionSupported) { - currentPosition = Qt.binding(() => activePlayer?.position || 0) - } else { - currentPosition = 0 - } - } - - Timer { - interval: 300 - running: activePlayer?.playbackState === MprisPlaybackState.Playing && !isSeeking - repeat: true - onTriggered: activePlayer?.positionSupported && activePlayer.positionChanged() - } - - property bool isSeeking: false - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - visible: !activePlayer - - DankIcon { - name: "music_note" - size: Theme.iconSize - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No Media") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - anchors.centerIn: parent - width: parent.width - Theme.spacingXS * 2 - spacing: Theme.spacingL - visible: activePlayer - - Item { - width: 140 - height: 110 - anchors.horizontalCenter: parent.horizontalCenter - clip: false - - DankAlbumArt { - width: 110 - height: 80 - anchors.centerIn: parent - activePlayer: root.activePlayer - albumSize: 76 - animationScale: 1.05 - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - topPadding: Theme.spacingL - - StyledText { - text: activePlayer?.trackTitle || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - elide: Text.ElideRight - maximumLineCount: 1 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: activePlayer?.trackArtist || I18n.tr("Unknown Artist") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - width: parent.width - elide: Text.ElideRight - maximumLineCount: 1 - horizontalAlignment: Text.AlignHCenter - } - } - - DankSeekbar { - width: parent.width + 4 - height: 20 - x: -2 - activePlayer: root.activePlayer - isSeeking: root.isSeeking - onIsSeekingChanged: root.isSeeking = isSeeking - } - - Item { - width: parent.width - height: 32 - - Row { - spacing: Theme.spacingS - anchors.centerIn: parent - - Rectangle { - width: 28 - height: 28 - radius: 14 - anchors.verticalCenter: playPauseButton.verticalCenter - color: prevArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_previous" - size: 14 - color: Theme.surfaceText - } - - MouseArea { - id: prevArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: MprisController.previousOrRewind() - } - } - - Rectangle { - id: playPauseButton - width: 32 - height: 32 - radius: 16 - color: Theme.primary - - DankIcon { - anchors.centerIn: parent - name: activePlayer?.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow" - size: 16 - color: Theme.background - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer?.togglePlaying() - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - anchors.verticalCenter: playPauseButton.verticalCenter - color: nextArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "skip_next" - size: 14 - color: Theme.surfaceText - } - - MouseArea { - id: nextArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: activePlayer?.next() - } - } - } - } - } - - MouseArea { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.bottomMargin: 123 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - visible: activePlayer - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/SystemMonitorCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/SystemMonitorCard.qml deleted file mode 100644 index cb7089b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/SystemMonitorCard.qml +++ /dev/null @@ -1,178 +0,0 @@ -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - - Component.onCompleted: { - DgopService.addRef(["cpu", "memory", "system"]) - } - Component.onDestruction: { - DgopService.removeRef(["cpu", "memory", "system"]) - } - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingM - - // CPU Bar - Column { - width: (parent.width - 2 * Theme.spacingM) / 3 - height: parent.height - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: parent.height - Theme.iconSizeSmall - Theme.spacingS - radius: 4 - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - - Rectangle { - width: parent.width - height: parent.height * Math.min((DgopService.cpuUsage || 6) / 100, 1) - radius: parent.radius - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: { - if (DgopService.cpuUsage > 80) return Theme.error - if (DgopService.cpuUsage > 60) return Theme.warning - return Theme.primary - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Item { - width: parent.width - height: Theme.iconSizeSmall - - DankIcon { - name: "memory" - size: Theme.iconSizeSmall - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - color: { - if (DgopService.cpuUsage > 80) return Theme.error - if (DgopService.cpuUsage > 60) return Theme.warning - return Theme.primary - } - } - } - } - - // Temperature Bar - Column { - width: (parent.width - 2 * Theme.spacingM) / 3 - height: parent.height - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: parent.height - Theme.iconSizeSmall - Theme.spacingS - radius: 4 - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - - Rectangle { - width: parent.width - height: parent.height * Math.min(Math.max((DgopService.cpuTemperature || 40) / 100, 0), 1) - radius: parent.radius - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: { - if (DgopService.cpuTemperature > 85) return Theme.error - if (DgopService.cpuTemperature > 69) return Theme.warning - return Theme.primary - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Item { - width: parent.width - height: Theme.iconSizeSmall - - DankIcon { - name: "device_thermostat" - size: Theme.iconSizeSmall - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - color: { - if (DgopService.cpuTemperature > 85) return Theme.error - if (DgopService.cpuTemperature > 69) return Theme.warning - return Theme.primary - } - } - } - } - - // RAM Bar - Column { - width: (parent.width - 2 * Theme.spacingM) / 3 - height: parent.height - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: parent.height - Theme.iconSizeSmall - Theme.spacingS - radius: 4 - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - - Rectangle { - width: parent.width - height: parent.height * Math.min((DgopService.memoryUsage || 42) / 100, 1) - radius: parent.radius - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - color: { - if (DgopService.memoryUsage > 90) return Theme.error - if (DgopService.memoryUsage > 75) return Theme.warning - return Theme.primary - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Item { - width: parent.width - height: Theme.iconSizeSmall - - DankIcon { - name: "developer_board" - size: Theme.iconSizeSmall - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - color: { - if (DgopService.memoryUsage > 90) return Theme.error - if (DgopService.memoryUsage > 75) return Theme.warning - return Theme.primary - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/UserInfoCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/UserInfoCard.qml deleted file mode 100644 index 0d90b44..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/UserInfoCard.qml +++ /dev/null @@ -1,110 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - Component.onCompleted: DgopService.addRef("system") - Component.onDestruction: DgopService.removeRef("system") - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankCircularImage { - id: avatarContainer - - width: 77 - height: 77 - anchors.verticalCenter: parent.verticalCenter - imageSource: { - if (PortalService.profileImage === "") - return ""; - - if (PortalService.profileImage.startsWith("/")) - return "file://" + PortalService.profileImage; - - return PortalService.profileImage; - } - fallbackIcon: "person" - } - - Column { - spacing: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: UserInfoService.username || I18n.tr("brandon") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - horizontalAlignment: Text.AlignLeft - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingS - - SystemLogo { - width: 16 - height: 16 - anchors.verticalCenter: parent.verticalCenter - colorOverride: Theme.primary - } - - StyledText { - text: { - if (CompositorService.isNiri) - return I18n.tr("on Niri"); - if (CompositorService.isHyprland) - return I18n.tr("on Hyprland"); - // technically they might not be on mangowc, but its what we support in the docs - if (CompositorService.isDwl) - return I18n.tr("on MangoWC"); - if (CompositorService.isSway) - return I18n.tr("on Sway"); - if (CompositorService.isScroll) - return I18n.tr("on Scroll"); - if (CompositorService.isMiracle) - return I18n.tr("on Miracle WM"); - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8) - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - width: parent.parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - 16 - Theme.spacingS - horizontalAlignment: Text.AlignLeft - } - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingS - - DankIcon { - name: "schedule" - size: 16 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: DgopService.shortUptime || I18n.tr("up") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.verticalCenter: parent.verticalCenter - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml deleted file mode 100644 index 0bba92e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml +++ /dev/null @@ -1,94 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Services -import qs.Widgets - -Card { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - signal clicked - - Component.onCompleted: WeatherService.addRef() - Component.onDestruction: WeatherService.removeRef() - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - visible: !WeatherService.weather.available - - DankIcon { - name: "cloud_off" - size: 24 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: WeatherService.weather.loading ? I18n.tr("Loading...") : I18n.tr("No Weather") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - - Button { - text: I18n.tr("Refresh") - flat: true - visible: !WeatherService.weather.loading - anchors.horizontalCenter: parent.horizontalCenter - onClicked: WeatherService.forceRefresh() - } - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingL - visible: WeatherService.weather.available - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: 48 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - anchors.left: parent.left - text: { - const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp; - if (temp === undefined || temp === null) - return "--°" + (SettingsData.useFahrenheit ? "F" : "C"); - return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C"); - } - font.pixelSize: Theme.fontSizeXLarge + 4 - color: Theme.surfaceText - font.weight: Font.Light - } - - StyledText { - text: WeatherService.getWeatherCondition(WeatherService.weather.wCode) - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - elide: Text.ElideRight - width: parent.parent.parent.width - 48 - Theme.spacingL * 2 - horizontalAlignment: Text.AlignLeft - } - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/OverviewTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/OverviewTab.qml deleted file mode 100644 index de7ea35..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/OverviewTab.qml +++ /dev/null @@ -1,75 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modules.DankDash.Overview - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: 410 - - signal switchToWeatherTab - signal switchToMediaTab - signal closeDash - - Item { - anchors.fill: parent - // Clock - top left (narrower and shorter) - ClockCard { - x: 0 - y: 0 - width: parent.width * 0.2 - Theme.spacingM * 2 - height: 180 - } - - // Weather - top middle-left (narrower) - WeatherOverviewCard { - x: SettingsData.weatherEnabled ? parent.width * 0.2 - Theme.spacingM : 0 - y: 0 - width: SettingsData.weatherEnabled ? parent.width * 0.3 : 0 - height: 100 - visible: SettingsData.weatherEnabled - - onClicked: root.switchToWeatherTab() - } - - // UserInfo - top middle-right (extend when weather disabled) - UserInfoCard { - x: SettingsData.weatherEnabled ? parent.width * 0.5 : parent.width * 0.2 - Theme.spacingM - y: 0 - width: SettingsData.weatherEnabled ? parent.width * 0.5 : parent.width * 0.8 - height: 100 - } - - // SystemMonitor - middle left (narrow and shorter) - SystemMonitorCard { - x: 0 - y: 180 + Theme.spacingM - width: parent.width * 0.2 - Theme.spacingM * 2 - height: 220 - } - - // Calendar - bottom middle (wider and taller) - CalendarOverviewCard { - x: parent.width * 0.2 - Theme.spacingM - y: 100 + Theme.spacingM - width: parent.width * 0.6 - height: 300 - - onCloseDash: root.closeDash() - } - - // Media - bottom right (narrow and taller) - MediaOverviewCard { - x: parent.width * 0.8 - y: 100 + Theme.spacingM - width: parent.width * 0.2 - height: 300 - - onClicked: root.switchToMediaTab() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WallpaperTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WallpaperTab.qml deleted file mode 100644 index 1f35b00..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WallpaperTab.qml +++ /dev/null @@ -1,590 +0,0 @@ -import Qt.labs.folderlistmodel -import QtCore -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Modals.FileBrowser -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: 410 - - property string wallpaperDir: "" - property int currentPage: 0 - property int itemsPerPage: 16 - property int totalPages: Math.max(1, Math.ceil(wallpaperFolderModel.count / itemsPerPage)) - property bool active: false - property Item focusTarget: wallpaperGrid - property Item tabBarItem: null - property int gridIndex: 0 - property Item keyForwardTarget: null - property var parentPopout: null - property int lastPage: 0 - property bool enableAnimation: false - property string homeDir: StandardPaths.writableLocation(StandardPaths.HomeLocation) - property string selectedFileName: "" - property var targetScreen: null - property string targetScreenName: targetScreen ? targetScreen.name : "" - - signal requestTabChange(int newIndex) - - function getCurrentWallpaper() { - if (SessionData.perMonitorWallpaper && targetScreenName) { - return SessionData.getMonitorWallpaper(targetScreenName); - } - return SessionData.wallpaperPath; - } - - function setCurrentWallpaper(path) { - if (SessionData.perMonitorWallpaper && targetScreenName) { - SessionData.setMonitorWallpaper(targetScreenName, path); - } else { - SessionData.setWallpaper(path); - } - } - - onCurrentPageChanged: { - if (currentPage !== lastPage) { - enableAnimation = false; - lastPage = currentPage; - } - updateSelectedFileName(); - } - - onGridIndexChanged: { - updateSelectedFileName(); - } - - onVisibleChanged: { - if (visible && active) { - setInitialSelection(); - } - } - - Component.onCompleted: { - loadWallpaperDirectory(); - } - - onActiveChanged: { - if (active && visible) { - setInitialSelection(); - } - } - - function handleKeyEvent(event) { - const columns = 4; - const currentCol = gridIndex % columns; - const visibleCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - if (gridIndex >= 0 && gridIndex < visibleCount) { - const absoluteIndex = currentPage * itemsPerPage + gridIndex; - if (absoluteIndex < wallpaperFolderModel.count) { - const filePath = wallpaperFolderModel.get(absoluteIndex, "filePath"); - if (filePath) { - setCurrentWallpaper(filePath.toString().replace(/^file:\/\//, '')); - } - } - } - return true; - } - - if (event.key === Qt.Key_Right || event.key === Qt.Key_L) { - if (I18n.isRtl) { - if (gridIndex > 0) { - gridIndex--; - } else if (currentPage > 0) { - currentPage--; - const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - gridIndex = prevPageCount - 1; - } - } else { - if (gridIndex + 1 < visibleCount) { - gridIndex++; - } else if (currentPage < totalPages - 1) { - gridIndex = 0; - currentPage++; - } - } - return true; - } - - if (event.key === Qt.Key_Left || event.key === Qt.Key_H) { - if (I18n.isRtl) { - if (gridIndex + 1 < visibleCount) { - gridIndex++; - } else if (currentPage < totalPages - 1) { - gridIndex = 0; - currentPage++; - } - } else { - if (gridIndex > 0) { - gridIndex--; - } else if (currentPage > 0) { - currentPage--; - const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - gridIndex = prevPageCount - 1; - } - } - return true; - } - - if (event.key === Qt.Key_Down || event.key === Qt.Key_J) { - if (gridIndex + columns < visibleCount) { - gridIndex += columns; - } else if (currentPage < totalPages - 1) { - gridIndex = currentCol; - currentPage++; - } - return true; - } - - if (event.key === Qt.Key_Up || event.key === Qt.Key_K) { - if (gridIndex >= columns) { - gridIndex -= columns; - } else if (currentPage > 0) { - currentPage--; - const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - const prevPageRows = Math.ceil(prevPageCount / columns); - gridIndex = (prevPageRows - 1) * columns + currentCol; - gridIndex = Math.min(gridIndex, prevPageCount - 1); - } - return true; - } - - if (event.key === Qt.Key_PageUp && currentPage > 0) { - gridIndex = 0; - currentPage--; - return true; - } - - if (event.key === Qt.Key_PageDown && currentPage < totalPages - 1) { - gridIndex = 0; - currentPage++; - return true; - } - - if (event.key === Qt.Key_Home && event.modifiers & Qt.ControlModifier) { - gridIndex = 0; - currentPage = 0; - return true; - } - - if (event.key === Qt.Key_End && event.modifiers & Qt.ControlModifier) { - currentPage = totalPages - 1; - const lastPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage); - gridIndex = Math.max(0, lastPageCount - 1); - return true; - } - - return false; - } - - function setInitialSelection() { - const currentWallpaper = getCurrentWallpaper(); - if (!currentWallpaper || wallpaperFolderModel.count === 0) { - gridIndex = 0; - updateSelectedFileName(); - Qt.callLater(() => { - enableAnimation = true; - }); - return; - } - - for (var i = 0; i < wallpaperFolderModel.count; i++) { - const filePath = wallpaperFolderModel.get(i, "filePath"); - if (filePath && filePath.toString().replace(/^file:\/\//, '') === currentWallpaper) { - const targetPage = Math.floor(i / itemsPerPage); - const targetIndex = i % itemsPerPage; - currentPage = targetPage; - gridIndex = targetIndex; - updateSelectedFileName(); - Qt.callLater(() => { - enableAnimation = true; - }); - return; - } - } - gridIndex = 0; - updateSelectedFileName(); - Qt.callLater(() => { - enableAnimation = true; - }); - } - - function loadWallpaperDirectory() { - const currentWallpaper = getCurrentWallpaper(); - - if (!currentWallpaper || currentWallpaper.startsWith("#")) { - if (CacheData.wallpaperLastPath && CacheData.wallpaperLastPath !== "") { - wallpaperDir = CacheData.wallpaperLastPath; - } else { - wallpaperDir = ""; - } - return; - } - - wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/')); - } - - function updateSelectedFileName() { - if (wallpaperFolderModel.count === 0) { - selectedFileName = ""; - return; - } - - const absoluteIndex = currentPage * itemsPerPage + gridIndex; - if (absoluteIndex < wallpaperFolderModel.count) { - const filePath = wallpaperFolderModel.get(absoluteIndex, "filePath"); - if (filePath) { - const pathStr = filePath.toString().replace(/^file:\/\//, ''); - selectedFileName = pathStr.substring(pathStr.lastIndexOf('/') + 1); - return; - } - } - selectedFileName = ""; - } - - Connections { - target: SessionData - function onWallpaperPathChanged() { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - function onMonitorWallpapersChanged() { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - function onPerMonitorWallpaperChanged() { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - } - - onTargetScreenNameChanged: { - loadWallpaperDirectory(); - if (visible && active) { - setInitialSelection(); - } - } - - Connections { - target: wallpaperFolderModel - function onCountChanged() { - if (wallpaperFolderModel.status === FolderListModel.Ready) { - if (visible && active) { - setInitialSelection(); - } - updateSelectedFileName(); - } - } - function onStatusChanged() { - if (wallpaperFolderModel.status === FolderListModel.Ready && wallpaperFolderModel.count > 0) { - if (visible && active) { - setInitialSelection(); - } - updateSelectedFileName(); - } - } - } - - FolderListModel { - id: wallpaperFolderModel - - showDirsFirst: false - showDotAndDotDot: false - showHidden: false - caseSensitive: false - nameFilters: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - showFiles: true - showDirs: false - sortField: FolderListModel.Name - folder: wallpaperDir ? "file://" + wallpaperDir.split('/').map(s => encodeURIComponent(s)).join('/') : "" - } - - FileBrowserSurfaceModal { - id: wallpaperBrowser - - browserTitle: I18n.tr("Select Wallpaper Directory", "wallpaper directory file browser title") - browserIcon: "folder_open" - browserType: "wallpaper" - showHiddenFiles: false - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - parentPopout: root.parentPopout - - onFileSelected: path => { - const cleanPath = path.replace(/^file:\/\//, ''); - setCurrentWallpaper(cleanPath); - - const dirPath = cleanPath.substring(0, cleanPath.lastIndexOf('/')); - if (dirPath) { - wallpaperDir = dirPath; - CacheData.wallpaperLastPath = dirPath; - CacheData.saveCache(); - } - close(); - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: parent.height - 50 - - GridView { - id: wallpaperGrid - anchors.centerIn: parent - width: parent.width - Theme.spacingS - height: parent.height - Theme.spacingS - cellWidth: width / 4 - cellHeight: height / 4 - clip: true - enabled: root.active - interactive: root.active - boundsBehavior: Flickable.StopAtBounds - keyNavigationEnabled: false - activeFocusOnTab: false - highlightFollowsCurrentItem: true - highlightMoveDuration: enableAnimation ? Theme.shortDuration : 0 - focus: false - - highlight: Item { - z: 1000 - Rectangle { - anchors.fill: parent - anchors.margins: Theme.spacingXS - color: "transparent" - border.width: 3 - border.color: Theme.primary - radius: Theme.cornerRadius - } - } - - model: { - const startIndex = currentPage * itemsPerPage; - const endIndex = Math.min(startIndex + itemsPerPage, wallpaperFolderModel.count); - const items = []; - for (var i = startIndex; i < endIndex; i++) { - const filePath = wallpaperFolderModel.get(i, "filePath"); - if (filePath) { - items.push(filePath.toString().replace(/^file:\/\//, '')); - } - } - return items; - } - - onModelChanged: { - const clampedIndex = model.length > 0 ? Math.min(Math.max(0, gridIndex), model.length - 1) : 0; - if (gridIndex !== clampedIndex) { - gridIndex = clampedIndex; - } - } - - onCountChanged: { - if (count > 0) { - const clampedIndex = Math.min(gridIndex, count - 1); - currentIndex = clampedIndex; - positionViewAtIndex(clampedIndex, GridView.Contain); - } - Qt.callLater(() => { - enableAnimation = true; - }); - } - - Connections { - target: root - function onGridIndexChanged() { - if (wallpaperGrid.count > 0) { - wallpaperGrid.currentIndex = gridIndex; - if (!enableAnimation) { - wallpaperGrid.positionViewAtIndex(gridIndex, GridView.Contain); - } - } - } - } - - delegate: Item { - width: wallpaperGrid.cellWidth - height: wallpaperGrid.cellHeight - - property string wallpaperPath: modelData || "" - property bool isSelected: getCurrentWallpaper() === modelData - - Rectangle { - id: wallpaperCard - anchors.fill: parent - anchors.margins: Theme.spacingXS - color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) - radius: Theme.cornerRadius - clip: true - - Rectangle { - anchors.fill: parent - color: isSelected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15) : "transparent" - radius: parent.radius - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - id: maskRect - width: thumbnailImage.width - height: thumbnailImage.height - radius: Theme.cornerRadius - visible: false - layer.enabled: true - } - - CachingImage { - id: thumbnailImage - anchors.fill: parent - imagePath: modelData || "" - maxCacheSize: 256 - - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskThresholdMin: 0.5 - maskSpreadAtMin: 1.0 - maskSource: maskRect - } - } - - StateLayer { - anchors.fill: parent - cornerRadius: parent.radius - stateColor: Theme.primary - } - - MouseArea { - id: wallpaperMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - - onClicked: { - gridIndex = index; - if (modelData) { - setCurrentWallpaper(modelData); - } - } - } - } - } - } - - StyledText { - anchors.centerIn: parent - visible: wallpaperFolderModel.count === 0 - text: I18n.tr("No wallpapers found\n\nClick the folder icon below to browse") - font.pixelSize: 14 - color: Theme.outline - horizontalAlignment: Text.AlignHCenter - } - } - - Column { - width: parent.width - height: 50 - - Row { - width: parent.width - height: 32 - spacing: Theme.spacingS - - Item { - width: (parent.width - controlsRow.width - browseButton.width - Theme.spacingS) / 2 - height: parent.height - } - - Row { - id: controlsRow - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankActionButton { - anchors.verticalCenter: parent.verticalCenter - iconName: "skip_previous" - iconSize: 20 - buttonSize: 32 - enabled: currentPage > 0 - opacity: enabled ? 1.0 : 0.3 - onClicked: { - if (currentPage > 0) { - currentPage--; - } - } - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: wallpaperFolderModel.count > 0 - ? (wallpaperFolderModel.count === 1 - ? I18n.tr("%1 wallpaper • %2 / %3").arg(wallpaperFolderModel.count).arg(currentPage + 1).arg(totalPages) - : I18n.tr("%1 wallpapers • %2 / %3").arg(wallpaperFolderModel.count).arg(currentPage + 1).arg(totalPages)) - : I18n.tr("No wallpapers") - font.pixelSize: 14 - color: Theme.surfaceText - opacity: 0.7 - } - - DankActionButton { - anchors.verticalCenter: parent.verticalCenter - iconName: "skip_next" - iconSize: 20 - buttonSize: 32 - enabled: currentPage < totalPages - 1 - opacity: enabled ? 1.0 : 0.3 - onClicked: { - if (currentPage < totalPages - 1) { - currentPage++; - } - } - } - } - - DankActionButton { - id: browseButton - anchors.verticalCenter: parent.verticalCenter - iconName: "folder_open" - iconSize: 20 - buttonSize: 32 - opacity: 0.7 - onClicked: wallpaperBrowser.open() - } - } - - StyledText { - width: parent.width - height: 18 - text: selectedFileName - font.pixelSize: 12 - color: Theme.surfaceText - opacity: 0.5 - visible: selectedFileName !== "" - elide: Text.ElideMiddle - horizontalAlignment: Text.AlignHCenter - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherForecastCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherForecastCard.qml deleted file mode 100644 index 5c57b65..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherForecastCard.qml +++ /dev/null @@ -1,206 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - radius: Theme.cornerRadius - - property var date: null - property var daily: true - property var forecastData: null - property var dense: false - - readonly property bool isCurrent: { - if (daily) { - date ? WeatherService.calendarDayDifference(new Date(), date) === 0 : false; - } else { - date ? WeatherService.calendarHourDifference(new Date(), date) === 0 : false; - } - } - - readonly property string dateText: { - if (daily) - return root.forecastData?.day ?? "--"; - if (!root.forecastData?.rawTime) - return root.forecastData?.time ?? "--"; - try { - const date = new Date(root.forecastData.rawTime); - const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - return date.toLocaleTimeString(Qt.locale(), format); - } catch (e) { - return root.forecastData?.time ?? "--"; - } - } - - readonly property var minTemp: WeatherService.formatTemp(root.forecastData?.tempMin) - readonly property var maxTemp: WeatherService.formatTemp(root.forecastData?.tempMax) - readonly property string minMaxTempText: (minTemp ?? "--") + "/" + (maxTemp ?? "--") - - readonly property var temp: WeatherService.formatTemp(root.forecastData?.temp) - readonly property string tempText: temp ?? "--" - - readonly property var feelsLikeTemp: WeatherService.formatTemp(root.forecastData?.feelsLike) - readonly property string feelsLikeText: feelsLikeTemp ?? "--" - - readonly property var humidity: WeatherService.formatPercent(root.forecastData?.humidity) - readonly property string humidityText: humidity ?? "--" - - readonly property var wind: { - SettingsData.windSpeedUnit; - SettingsData.useFahrenheit; - return WeatherService.formatSpeed(root.forecastData?.wind); - } - readonly property string windText: wind ?? "--" - - readonly property var pressure: { - SettingsData.useFahrenheit; - return WeatherService.formatPressure(root.forecastData?.pressure); - } - readonly property string pressureText: pressure ?? "--" - - readonly property var precipitation: root.forecastData?.precipitationProbability - readonly property string precipitationText: precipitation + "%" ?? "--" - - readonly property var visibility: WeatherService.formatVisibility(root.forecastData?.visibility) - readonly property string visibilityText: visibility ?? "--" - - readonly property var values: daily ? [] : [ - { - "name"// 'name': "Temperature", - : - // 'text': root.tempText, - // 'icon': "thermometer" - // }, { - // 'name': "Feels Like", - // 'text': root.feelsLikeText, - // 'icon': "thermostat" - // }, { - I18n.tr("Humidity"), - "text": root.humidityText, - "icon": "humidity_low" - }, - { - "name": I18n.tr("Wind Speed"), - "text": root.windText, - "icon": "air" - }, - { - "name": I18n.tr("Pressure"), - "text": root.pressureText, - "icon": "speed" - }, - { - "name": I18n.tr("Precipitation Chance"), - "text": root.precipitationText, - "icon": "rainy" - }, - { - "name": I18n.tr("Visibility"), - "text": root.visibilityText, - "icon": "wb_sunny" - } - ] - - color: isCurrent ? Theme.withAlpha(Theme.primary, 0.1) : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: isCurrent ? Theme.withAlpha(Theme.primary, 0.3) : "transparent" - border.width: isCurrent ? 1 : 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: root.forecastData != null ? root.dateText : I18n.tr("Forecast Not Available") - font.pixelSize: Theme.fontSizeSmall - color: root.isCurrent ? Theme.primary : (root.forecastData ? Theme.surfaceText : Theme.outline) - font.weight: root.isCurrent ? Font.Medium : Font.Normal - anchors.horizontalCenter: parent.horizontalCenter - } - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - visible: root.forecastData != null - - Column { - spacing: Theme.spacingXS - - DankIcon { - name: root.forecastData ? WeatherService.getWeatherIcon(root.forecastData.wCode || 0, root.forecastData.isDay ?? true) : "cloud" - size: Theme.iconSize - color: root.isCurrent ? Theme.primary : Theme.withAlpha(Theme.primary, 0.8) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.daily ? root.minMaxTempText : root.tempText - font.pixelSize: Theme.fontSizeSmall - color: root.isCurrent ? Theme.primary : Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.feelsLikeText - font.pixelSize: Theme.fontSizeSmall - color: root.isCurrent ? Theme.primary : Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - visible: !root.daily - } - } - - Column { - id: detailsColumn - spacing: 2 - visible: !root.dense - width: implicitWidth - - states: [ - State { - name: "dense" - when: root.dense - PropertyChanges { - target: detailsColumn - opacity: 0 - width: 0 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "opacity,width" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - Repeater { - model: root.values.length - Row { - spacing: 2 - - DankIcon { - name: root.values[index].icon - size: 8 - color: Theme.withAlpha(Theme.surfaceText, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.values[index].text - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.withAlpha(Theme.surfaceText, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherTab.qml deleted file mode 100644 index 21ea656..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DankDash/WeatherTab.qml +++ /dev/null @@ -1,1124 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Shapes -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - implicitWidth: SettingsData.showWeekNumber ? 736 : 700 - implicitHeight: 410 - property bool syncing: false - property bool showHourly: false - property bool available: WeatherService.weather.available - - function syncFrom(type) { - if (!dailyLoader.item || !hourlyLoader.item) - return; - const hourlyList = hourlyLoader.item; - const dailyList = dailyLoader.item; - syncing = true; - - try { - if (type === "hour") { - const date = new Date(); - date.setHours(hourlyList.currentIndex); - dateStepper.currentDate = date; - - dailyList.currentIndex = Math.max(0, Math.min((WeatherService.weather.forecast?.length ?? 1) - 1, WeatherService.calendarDayDifference((new Date()), date))); - } else if (type === "day") { - const date = new Date(dateStepper.currentDate); - date.setMonth((new Date()).getMonth()); - date.setDate((new Date()).getDate() + dailyList.currentIndex); - dateStepper.currentDate = date; - - const hourIndex = Math.max(0, Math.min((WeatherService.weather.hourlyForecast?.length ?? 1) - 1, WeatherService.calendarHourDifference((new Date()), date) + (new Date).getHours())); - hourlyList.currentIndex = hourIndex; - } else if (type === "date") { - const date = dateStepper.currentDate; - dailyList.currentIndex = Math.max(0, Math.min((WeatherService.weather.forecast?.length ?? 1) - 1, WeatherService.calendarDayDifference((new Date()), date))); - hourlyList.currentIndex = Math.max(0, Math.min((WeatherService.weather.hourlyForecast?.length ?? 1) - 1, WeatherService.calendarHourDifference((new Date()), date) + (new Date()).getHours())); - } - } catch (e) { - console.warn("Weather Date Sync Error:", e); - } - - syncing = false; - } - - readonly property string sunriseTimeText: { - if (!WeatherService.weather.rawSunrise) - return WeatherService.weather.sunrise || ""; - try { - const date = new Date(WeatherService.weather.rawSunrise); - const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - return date.toLocaleTimeString(Qt.locale(), format); - } catch (e) { - return WeatherService.weather.sunrise || ""; - } - } - - readonly property string sunsetTimeText: { - if (!WeatherService.weather.rawSunset) - return WeatherService.weather.sunset || ""; - try { - const date = new Date(WeatherService.weather.rawSunset); - const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"; - return date.toLocaleTimeString(Qt.locale(), format); - } catch (e) { - return WeatherService.weather.sunset || ""; - } - } - - readonly property var heroMetrics: { - SettingsData.useFahrenheit; - SettingsData.windSpeedUnit; - return [ - { - "icon": "humidity_low", - "label": I18n.tr("Humidity"), - "value": WeatherService.formatPercent(WeatherService.weather.humidity) ?? "--" - }, - { - "icon": "air", - "label": I18n.tr("Wind"), - "value": WeatherService.formatSpeed(WeatherService.weather.wind) ?? "--" - }, - { - "icon": "speed", - "label": I18n.tr("Pressure"), - "value": WeatherService.formatPressure(WeatherService.weather.pressure) ?? "--" - }, - { - "icon": "rainy", - "label": I18n.tr("Precipitation"), - "value": (WeatherService.weather.precipitationProbability ?? 0) + "%" - }, - { - "icon": "wb_twilight", - "label": I18n.tr("Sunrise"), - "value": root.sunriseTimeText || "--" - }, - { - "icon": "bedtime", - "label": I18n.tr("Sunset"), - "value": root.sunsetTimeText || "--" - } - ]; - } - - Column { - id: unavailableColumn - anchors.centerIn: parent - spacing: Theme.spacingL - visible: !root.available - - DankIcon { - name: "cloud_off" - size: Theme.iconSize * 2 - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - Row { - width: refreshButtonTwo.width + refreshText.width - height: refreshButtonTwo.height - spacing: Theme.spacingS - - StyledText { - id: refreshText - text: I18n.tr("No Weather Data Available") - font.pixelSize: Theme.fontSizeLarge - color: Theme.withAlpha(Theme.surfaceText, 0.7) - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - id: refreshButtonTwo - name: "refresh" - size: Theme.iconSize - 4 - color: Theme.withAlpha(Theme.surfaceText, 0.4) - anchors.top: parent.top - anchors.verticalCenter: parent.verticalCenter - - property bool isRefreshing: false - enabled: !isRefreshing - - MouseArea { - id: refreshButtonMouseAreaTwo - anchors.fill: parent - hoverEnabled: true - cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ForbiddenCursor - enabled: parent.enabled - - Timer { - id: hoverDelayTwo - interval: 300 - repeat: false - onTriggered: { - refreshButtonTooltipTwo.show(I18n.tr("Refresh Weather"), refreshButtonTwo, 0, 0, "left"); - } - } - - onEntered: { - hoverDelayTwo.restart(); - } - - onExited: { - hoverDelayTwo.stop(); - refreshButtonTooltipTwo.hide(); - } - - onClicked: { - refreshButtonTwo.isRefreshing = true; - WeatherService.forceRefresh(); - refreshTimerTwo.restart(); - } - } - - DankTooltipV2 { - id: refreshButtonTooltipTwo - } - - Timer { - id: refreshTimerTwo - interval: 2000 - onTriggered: refreshButtonTwo.isRefreshing = false - } - - NumberAnimation on rotation { - running: refreshButtonTwo.isRefreshing - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - } - } - } - } - - Column { - id: mainColumn - anchors.fill: parent - visible: root.available - spacing: Theme.spacingS - - Rectangle { - id: heroCard - width: parent.width - height: heroContent.height + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) - border.color: Theme.withAlpha(Theme.outline, 0.08) - border.width: 1 - - Column { - id: heroContent - x: Theme.spacingL - y: Theme.spacingL - width: parent.width - Theme.spacingL * 2 - spacing: Theme.spacingM - - Item { - width: parent.width - height: Math.max(heroLeft.height, heroMetricsGrid.height) - - Row { - id: heroLeft - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingL - - DankIcon { - id: weatherIcon - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.iconSize * 2 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - - layer.enabled: Theme.elevationEnabled - layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1) - shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1) - shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) : 0 - blurMax: Theme.elevationBlurMax - shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) - shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2 - } - } - - Column { - id: tempColumn - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - Item { - anchors.left: parent.left - width: tempText.width + unitText.width + Theme.spacingXS - height: tempText.height - - StyledText { - id: tempText - LayoutMirroring.enabled: false - text: (SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" - font.pixelSize: Theme.fontSizeXLarge + 8 - color: Theme.surfaceText - font.weight: Font.Light - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: unitText - LayoutMirroring.enabled: false - text: SettingsData.useFahrenheit ? "F" : "C" - font.pixelSize: Theme.fontSizeMedium - color: Theme.withAlpha(Theme.surfaceText, 0.7) - anchors.left: tempText.right - anchors.leftMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (WeatherService.weather.available) - SettingsData.set("useFahrenheit", !SettingsData.useFahrenheit); - } - enabled: WeatherService.weather.available - } - } - } - - StyledText { - text: WeatherService.getWeatherCondition(WeatherService.weather.wCode) - font.pixelSize: Theme.fontSizeMedium - color: Theme.withAlpha(Theme.surfaceText, 0.7) - anchors.left: parent.left - } - - StyledText { - property var feelsLike: SettingsData.useFahrenheit ? (WeatherService.weather.feelsLikeF || WeatherService.weather.tempF) : (WeatherService.weather.feelsLike || WeatherService.weather.temp) - text: I18n.tr("Feels Like %1°", "weather feels like temperature").arg(feelsLike) - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.left: parent.left - } - - StyledText { - text: WeatherService.weather.city || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.5) - visible: text.length > 0 - anchors.left: parent.left - } - } - } - - Grid { - id: heroMetricsGrid - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - columns: 3 - columnSpacing: Theme.spacingXL - rowSpacing: Theme.spacingS - - Repeater { - model: root.heroMetrics - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: modelData.icon - size: Theme.iconSizeSmall - 2 - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 2 - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.5) - anchors.left: parent.left - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.left: parent.left - } - } - } - } - } - } - } - } - - Item { - id: skyDateRow - width: parent.width - height: dateStepper.height - - Item { - id: dateStepper - height: dateStepperInner.height + Theme.spacingM * 2 - width: dateStepperInner.width - - property var currentDate: new Date() - - readonly property var changeDate: (magnitudeIndex, sign) => { - switch (magnitudeIndex) { - case 0: - break; - case 1: - var newDate = new Date(dateStepper.currentDate); - newDate.setMonth(dateStepper.currentDate.getMonth() + sign * 1); - dateStepper.currentDate = newDate; - break; - case 2: - dateStepper.currentDate = new Date(dateStepper.currentDate.getTime() + sign * 24 * 3600 * 1000); - break; - case 3: - dateStepper.currentDate = new Date(dateStepper.currentDate.getTime() + sign * 3600 * 1000); - break; - case 4: - dateStepper.currentDate = new Date(dateStepper.currentDate.getTime() + sign * 5 * 60 * 1000); - break; - } - } - readonly property var splitDate: Qt.formatDateTime(dateStepper.currentDate, SettingsData.use24HourClock ? "yyyy.MM.dd.HH.mm" : "yyyy.MM.dd.hh.mm.AP").split('.') - - Item { - id: dateStepperInner - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - readonly property var space: Theme.spacingXS - width: yearStepper.width + monthStepper.width + dayStepper.width + hourStepper.width + minuteStepper.width + (suffix.visible ? suffix.width : 0) + 10.5 * space + 2 * dateStepperInnerPadding.width - height: Math.max(yearStepper.height, monthStepper.height, dayStepper.height, hourStepper.height, minuteStepper.height) - - Item { - id: dateStepperInnerPadding - width: dateResetButton.width - } - - DankNumberStepper { - id: yearStepper - anchors.left: dateStepperInnerPadding.right - anchors.leftMargin: parent.space - width: implicitWidth - text: dateStepper.splitDate[0] - } - - DankNumberStepper { - id: monthStepper - width: implicitWidth - anchors.left: yearStepper.right - anchors.leftMargin: parent.space - text: dateStepper.splitDate[1] - onIncrement: () => dateStepper.changeDate(1, +1) - onDecrement: () => dateStepper.changeDate(1, -1) - } - - DankNumberStepper { - id: dayStepper - width: implicitWidth - anchors.left: monthStepper.right - anchors.leftMargin: parent.space - text: dateStepper.splitDate[2] - onIncrement: () => dateStepper.changeDate(2, +1) - onDecrement: () => dateStepper.changeDate(2, -1) - } - - DankNumberStepper { - id: hourStepper - width: implicitWidth - anchors.left: dayStepper.right - anchors.leftMargin: 1.5 * parent.space - text: dateStepper.splitDate[3] - onIncrement: () => dateStepper.changeDate(3, +1) - onDecrement: () => dateStepper.changeDate(3, -1) - } - - DankNumberStepper { - id: minuteStepper - width: implicitWidth - anchors.left: hourStepper.right - anchors.leftMargin: parent.space - text: dateStepper.splitDate[4] - onIncrement: () => dateStepper.changeDate(4, +1) - onDecrement: () => dateStepper.changeDate(4, -1) - } - - Item { - anchors.verticalCenter: parent.verticalCenter - anchors.left: yearStepper.right - anchors.right: monthStepper.left - StyledText { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - text: "-" - } - } - Item { - anchors.verticalCenter: parent.verticalCenter - anchors.left: monthStepper.right - anchors.right: dayStepper.left - StyledText { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - text: "-" - } - } - Item { - anchors.verticalCenter: parent.verticalCenter - anchors.left: hourStepper.right - anchors.right: minuteStepper.left - StyledText { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - text: ":" - } - } - StyledText { - id: suffix - visible: !SettingsData.use24HourClock - anchors.verticalCenter: minuteStepper.verticalCenter - anchors.left: minuteStepper.right - anchors.leftMargin: 2 * parent.space - isMonospace: true - text: dateStepper.splitDate[5] ?? "" - font.pixelSize: Theme.fontSizeSmall - } - DankActionButton { - id: dateResetButton - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - enabled: Math.abs(dateStepper.currentDate - new Date()) > 1000 - iconColor: enabled ? Theme.blendAlpha(Theme.surfaceText, 0.5) : "transparent" - iconSize: 12 - buttonSize: 20 - iconName: "replay" - onClicked: { - dateStepper.currentDate = new Date(); - } - } - } - - onCurrentDateChanged: if (!syncing) - root.syncFrom("date") - } - - Rectangle { - id: skyBox - anchors.left: dateStepper.right - anchors.leftMargin: Theme.spacingM - anchors.right: parent.right - height: parent.height - - LayoutMirroring.enabled: false - LayoutMirroring.childrenInherit: true - - property var backgroundOpacity: 0.3 - property var sunTime: WeatherService.getCurrentSunTime(dateStepper.currentDate) - property var periodIndex: sunTime?.periodIndex - property var periodPercent: sunTime?.periodPercent - property var blackColor: Theme.blend(Theme.surface, Qt.rgba(0, 0, 0, 255), 0.2) - property var redColor: Theme.secondary - property var blueColor: Theme.primary - function blackBlue(r) { - return Theme.blend(blackColor, blueColor, r); - } - property var topColor: { - const colorMap = [blackColor, Theme.withAlpha(blackBlue(0.0), 0.8), Theme.withAlpha(blackBlue(0.2), 0.7), Theme.withAlpha(blackBlue(0.5), 0.6), Theme.withAlpha(blackBlue(0.7), 0.6), Theme.withAlpha(blackBlue(0.9), 0.6), Theme.withAlpha(blackBlue(1.0), 0.6), Theme.withAlpha(blackBlue(0.9), 0.6), Theme.withAlpha(blackBlue(0.7), 0.6), Theme.withAlpha(blackBlue(0.5), 0.6), Theme.withAlpha(blackBlue(0.2), 0.7), Theme.withAlpha(blackBlue(0.0), 0.8), blackColor, blackColor]; - const index = periodIndex ?? 0; - return Theme.blend(colorMap[index], colorMap[index + 1], periodPercent ?? 0); - } - property var sunColor: { - const colorMap = [Theme.withAlpha(redColor, 0.05), Theme.withAlpha(redColor, 0.1), Theme.withAlpha(redColor, 0.3), Theme.withAlpha(redColor, 0.4), Theme.withAlpha(redColor, 0.5), Theme.withAlpha(blueColor, 0.2), Theme.withAlpha(blueColor, 0.0), Theme.withAlpha(blueColor, 0.2), Theme.withAlpha(redColor, 0.5), Theme.withAlpha(redColor, 0.4), Theme.withAlpha(redColor, 0.3), Theme.withAlpha(redColor, 0.1), Theme.withAlpha(redColor, 0.05), Theme.withAlpha(redColor, 0.0)]; - const index = periodIndex ?? 0; - return Theme.blend(colorMap[index], colorMap[index + 1], periodPercent ?? 0); - } - - color: "transparent" - - Rectangle { - anchors.fill: parent - opacity: skyBox.backgroundOpacity - - gradient: Gradient { - GradientStop { - position: 0.0 - color: Theme.withAlpha(skyBox.blackColor, 0.0) - } - GradientStop { - position: 0.05 - color: skyBox.topColor - } - GradientStop { - position: 0.3 - color: skyBox.topColor - } - GradientStop { - position: 0.5 - color: skyBox.topColor - } - GradientStop { - position: 0.501 - color: skyBox.blackColor - } - GradientStop { - position: 0.9 - color: skyBox.blackColor - } - GradientStop { - position: 1.0 - color: Theme.withAlpha(skyBox.blackColor, 0.0) - } - } - } - - property var currentDate: dateStepper.currentDate - property var hMargin: 0 - property var vMargin: Theme.spacingM - property var effectiveHeight: skyBox.height - 2 * vMargin - property var effectiveWidth: skyBox.width - 2 * hMargin - - StyledText { - text: parent.sunTime?.period ?? "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceText, 0.7) - x: 0 - y: 0 - } - - Shape { - id: skyShape - anchors.left: parent.left - anchors.top: parent.top - anchors.right: parent.right - height: parent.height / 2 - opacity: skyBox.backgroundOpacity - - ShapePath { - strokeColor: "transparent" - fillGradient: RadialGradient { - centerX: skyBox.hMargin + sun.x + sun.width / 2 - centerY: skyBox.vMargin + sun.y + 30 - centerRadius: { - const a = Math.abs((skyBox.sunTime?.dayPercent ?? 0) - 0.5); - const out = 200 * (0.5 - a * a); - return out; - } - focalX: skyBox.hMargin + sun.x + sun.width / 2 - focalY: skyBox.vMargin + sun.y - GradientStop { - position: 0 - color: skyBox.sunColor - } - GradientStop { - position: 0.3 - color: Theme.blendAlpha(skyBox.sunColor, 0.5) - } - GradientStop { - position: 1 - color: "transparent" - } - } - PathLine { - x: 0 - y: 0 - } - PathLine { - x: skyShape.width - y: 0 - } - PathLine { - x: skyShape.width - y: skyShape.height - } - PathLine { - x: 0 - y: skyShape.height - } - } - - ShapePath { - strokeColor: "transparent" - fillGradient: RadialGradient { - centerX: sun.x - centerY: sun.y - centerRadius: 500 - focalX: centerX - focalY: centerY + 0.99 * (centerRadius - focalRadius) - focalRadius: 10 - GradientStop { - position: 0 - color: skyBox.sunColor - } - GradientStop { - position: 0.45 - color: skyBox.sunColor - } - GradientStop { - position: 0.55 - color: "transparent" - } - GradientStop { - position: 1 - color: "transparent" - } - } - PathLine { - x: 0 - y: 0 - } - PathLine { - x: skyShape.width - y: 0 - } - PathLine { - x: skyShape.width - y: skyShape.height - } - PathLine { - x: 0 - y: skyShape.height - } - } - } - - Canvas { - id: ecliptic - anchors.fill: parent - property var points: WeatherService.getEcliptic(dateStepper.currentDate) - - function getX(index) { - return points[index].h * skyBox.effectiveWidth + skyBox.hMargin; - } - function getY(index) { - return points[index].v * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 + skyBox.vMargin; - } - - onPointsChanged: requestPaint() - - onPaint: { - var ctx = getContext("2d"); - ctx.clearRect(0, 0, width, height); - if (!points || points.length === 0) - return; - ctx.beginPath(); - ctx.moveTo(getX(0), getY(0)); - for (var i = 1; i < points.length; i++) { - ctx.lineTo(getX(i), getY(i)); - } - ctx.strokeStyle = Theme.withAlpha(Theme.outline, 0.2); - ctx.stroke(); - } - } - - property real latitude: WeatherService.getLocation()?.latitude ?? 0 - property real sunDeclination: WeatherService.getSunDeclination(dateStepper.currentDate) - - readonly property bool solarNoonIsSouth: latitude > sunDeclination - - StyledText { - id: middle - text: skyBox.solarNoonIsSouth ? "S" : "N" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - x: skyBox.width / 2 - middle.width / 2 - y: skyBox.height / 2 - middle.height / 2 - } - - StyledText { - id: left - text: skyBox.solarNoonIsSouth ? "E" : "W" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - x: skyBox.width / 4 - left.width / 2 - y: skyBox.height / 2 - left.height / 2 - } - - StyledText { - id: right - text: skyBox.solarNoonIsSouth ? "W" : "E" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - x: 3 * skyBox.width / 4 - right.width / 2 - y: skyBox.height / 2 - right.height / 2 - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: right.right - anchors.right: skyBox.right - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: middle.right - anchors.right: right.left - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: left.right - anchors.right: middle.left - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - Rectangle { - height: 1 - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - anchors.left: skyBox.left - anchors.right: left.left - anchors.verticalCenter: middle.verticalCenter - color: Theme.outline - } - - DankNFIcon { - id: moonPhase - name: WeatherService.getMoonPhase(skyBox.currentDate) || "" - size: Theme.fontSizeXLarge - color: Theme.withAlpha(Theme.surfaceText, 0.7) - rotation: (WeatherService.getMoonAngle(skyBox.currentDate) || 0) / Math.PI * 180 - visible: !!pos - - property var pos: WeatherService.getSkyArcPosition(skyBox.currentDate, false) - x: (pos?.h ?? 0) * skyBox.effectiveWidth - (moonPhase.width / 2) + skyBox.hMargin - y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (moonPhase.height / 2) + skyBox.vMargin - - layer.enabled: Theme.elevationEnabled - layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) - shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) - shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 - blurMax: Theme.elevationBlurMax - shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) - } - } - - DankIcon { - id: sun - name: "light_mode" - size: Theme.fontSizeXLarge - color: Theme.primary - visible: !!pos - - property var pos: WeatherService.getSkyArcPosition(skyBox.currentDate, true) - x: (pos?.h ?? 0) * skyBox.effectiveWidth - (sun.width / 2) + skyBox.hMargin - y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (sun.height / 2) + skyBox.vMargin - - layer.enabled: Theme.elevationEnabled - layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) - shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) - shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 - blurMax: Theme.elevationBlurMax - shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) - } - } - } - } - - Item { - id: chipsRow - width: parent.width - height: forecastChips.height - - DankFilterChips { - id: forecastChips - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - model: [I18n.tr("Daily"), I18n.tr("Hourly")] - currentIndex: root.showHourly ? 1 : 0 - showCheck: false - showCounts: false - onSelectionChanged: index => { - root.showHourly = index === 1; - } - } - - DankActionButton { - id: denseButton - anchors.right: refreshButton.left - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - visible: root.showHourly && hourlyLoader.item !== null - iconName: SessionData.weatherHourlyDetailed ? "tile_large" : "tile_medium" - onClicked: SessionData.setWeatherHourlyDetailed(!SessionData.weatherHourlyDetailed) - } - - DankIcon { - id: refreshButton - name: "refresh" - size: Theme.iconSize - 4 - color: Theme.withAlpha(Theme.surfaceText, 0.4) - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - property bool isRefreshing: false - enabled: !isRefreshing - - MouseArea { - id: refreshButtonMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ForbiddenCursor - enabled: parent.enabled - - Timer { - id: hoverDelay - interval: 300 - repeat: false - onTriggered: { - refreshButtonTooltip.show(I18n.tr("Refresh Weather"), refreshButton, 0, 0, "left"); - } - } - - onEntered: { - hoverDelay.restart(); - } - - onExited: { - hoverDelay.stop(); - refreshButtonTooltip.hide(); - } - - onClicked: { - refreshButton.isRefreshing = true; - WeatherService.forceRefresh(); - refreshTimer.restart(); - } - } - - DankTooltipV2 { - id: refreshButtonTooltip - } - - Timer { - id: refreshTimer - interval: 2000 - onTriggered: refreshButton.isRefreshing = false - } - - NumberAnimation on rotation { - running: refreshButton.isRefreshing - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - } - } - } - - Item { - width: parent.width - height: root.height - heroCard.height - skyDateRow.height - chipsRow.height - mainColumn.spacing * 3 - - Loader { - id: dailyLoader - anchors.fill: parent - sourceComponent: dailyComponent - active: root.visible && root.available - visible: !root.showHourly - asynchronous: true - opacity: 0 - onLoaded: { - root.syncing = true; - item.currentIndex = item.initialIndex; - item.positionViewAtIndex(item.initialIndex, ListView.SnapPosition); - root.syncing = false; - opacity = 1; - } - } - - Loader { - id: hourlyLoader - anchors.fill: parent - sourceComponent: hourlyComponent - active: root.visible && root.available - visible: root.showHourly - asynchronous: true - opacity: 0 - onLoaded: { - root.syncing = true; - item.currentIndex = item.initialIndex; - item.positionViewAtIndex(item.initialIndex, ListView.SnapPosition); - root.syncing = false; - opacity = 1; - } - } - } - } - - Component { - id: hourlyComponent - ListView { - id: hourlyList - anchors.fill: parent - orientation: ListView.Horizontal - spacing: Theme.spacingS - clip: true - snapMode: ListView.SnapToItem - highlightRangeMode: ListView.StrictlyEnforceRange - highlightMoveDuration: 0 - interactive: true - - property var cardHeight: height - property var cardWidth: ((hourlyList.width + hourlyList.spacing) / hourlyList.visibleCount) - hourlyList.spacing - property int initialIndex: (new Date()).getHours() - property bool dense: !SessionData.weatherHourlyDetailed - property int visibleCount: dense ? 10 : 5 - - model: WeatherService.weather.hourlyForecast?.length ?? 0 - - delegate: WeatherForecastCard { - width: hourlyList.cardWidth - height: hourlyList.cardHeight - dense: hourlyList.dense - daily: false - - date: { - const d = new Date(); - d.setHours(index); - return d; - } - forecastData: WeatherService.weather.hourlyForecast[index] - } - - onCurrentIndexChanged: if (!syncing) - root.syncFrom("hour") - - states: [ - State { - name: "denseState" - when: hourlyList.dense - PropertyChanges { - target: hourlyList - visibleCount: 10 - } - }, - State { - name: "normalState" - when: !hourlyList.dense - PropertyChanges { - target: hourlyList - visibleCount: 5 - } - } - ] - - transitions: [ - Transition { - NumberAnimation { - properties: "visibleCount" - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - ] - - MouseArea { - anchors.fill: parent - onWheel: wheel => { - if (wheel.modifiers & Qt.ShiftModifier) { - if (wheel.angleDelta.y % 120 == 0 && wheel.angleDelta.x == 0) { - const newIndex = hourlyList.currentIndex - Math.sign(wheel.angleDelta.y); - if (newIndex < hourlyList.model && newIndex >= 0) { - hourlyList.currentIndex = newIndex; - wheel.accepted = true; - return; - } - } - } - wheel.accepted = false; - } - } - } - } - - Component { - id: dailyComponent - ListView { - id: dailyList - anchors.fill: parent - orientation: ListView.Horizontal - spacing: Theme.spacingS - clip: true - snapMode: ListView.SnapToItem - highlightRangeMode: ListView.StrictlyEnforceRange - highlightMoveDuration: 0 - interactive: true - - property var cardHeight: height - property var cardWidth: ((dailyList.width + dailyList.spacing) / dailyList.visibleCount) - dailyList.spacing - property int initialIndex: 0 - property bool dense: false - property int visibleCount: 7 - - model: WeatherService.weather.forecast?.length ?? 0 - - delegate: WeatherForecastCard { - width: dailyList.cardWidth - height: dailyList.cardHeight - dense: true - daily: true - - date: { - const date = new Date(); - date.setDate(date.getDate() + index); - return date; - } - forecastData: WeatherService.weather.forecast[index] - } - - onCurrentIndexChanged: if (!syncing) - root.syncFrom("day") - - MouseArea { - anchors.fill: parent - onWheel: wheel => { - if (wheel.modifiers & Qt.ShiftModifier) { - if (wheel.angleDelta.y % 120 == 0 && wheel.angleDelta.x == 0) { - const newIndex = dailyList.currentIndex - Math.sign(wheel.angleDelta.y); - if (newIndex < dailyList.model && newIndex >= 0) { - dailyList.currentIndex = newIndex; - wheel.accepted = true; - return; - } - } - } - wheel.accepted = false; - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DesktopWidgetLayer.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DesktopWidgetLayer.qml deleted file mode 100644 index 384025f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/DesktopWidgetLayer.qml +++ /dev/null @@ -1,110 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Modules.Plugins -import qs.Modules.BuiltinDesktopPlugins - -Variants { - id: root - model: Quickshell.screens - - Component.onCompleted: Qt.callLater(autoEnablePluginsForInstances) - - function autoEnablePluginsForInstances() { - const instances = SettingsData.desktopWidgetInstances || []; - const pluginTypes = new Set(); - - for (const inst of instances) { - if (!inst.enabled) - continue; - if (inst.widgetType === "desktopClock" || inst.widgetType === "systemMonitor") - continue; - pluginTypes.add(inst.widgetType); - } - - for (const pluginId of pluginTypes) { - if (PluginService.isPluginLoaded(pluginId)) - continue; - if (!PluginService.availablePlugins[pluginId]) - continue; - PluginService.enablePlugin(pluginId); - } - } - - Connections { - target: PluginService - function onPluginListUpdated() { - Qt.callLater(root.autoEnablePluginsForInstances); - } - } - - QtObject { - id: screenDelegate - - required property var modelData - - readonly property var screen: modelData - readonly property string screenKey: SettingsData.getScreenDisplayName(screen) - - function shouldShowOnScreen(prefs) { - if (!Array.isArray(prefs) || prefs.length === 0 || prefs.includes("all")) - return true; - return prefs.some(p => { - if (typeof p === "string") - return p === screenKey || p === modelData.name; - return p?.name === modelData.name || p === screenKey; - }); - } - - property Component clockComponent: Component { - DesktopClockWidget {} - } - - property Component systemMonitorComponent: Component { - SystemMonitorWidget {} - } - - property Instantiator widgetInstantiator: Instantiator { - model: ScriptModel { - objectProp: "id" - values: SettingsData.desktopWidgetInstances - } - - DesktopPluginWrapper { - required property var modelData - required property int index - - readonly property string instanceIdRef: modelData.id - readonly property var liveInstanceData: { - const instances = SettingsData.desktopWidgetInstances || []; - return instances.find(inst => inst.id === instanceIdRef) ?? modelData; - } - - readonly property bool shouldBeVisible: { - if (!liveInstanceData.enabled) - return false; - const prefs = liveInstanceData.config?.displayPreferences ?? ["all"]; - return screenDelegate.shouldShowOnScreen(prefs); - } - - pluginId: liveInstanceData.widgetType - instanceId: instanceIdRef - instanceData: liveInstanceData - builtinComponent: { - switch (liveInstanceData.widgetType) { - case "desktopClock": - return screenDelegate.clockComponent; - case "systemMonitor": - return screenDelegate.systemMonitorComponent; - default: - return null; - } - } - pluginService: (liveInstanceData.widgetType !== "desktopClock" && liveInstanceData.widgetType !== "systemMonitor") ? PluginService : null - screen: screenDelegate.screen - widgetEnabled: shouldBeVisible - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/Dock.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/Dock.qml deleted file mode 100644 index 136f23a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/Dock.qml +++ /dev/null @@ -1,671 +0,0 @@ -pragma ComponentBehavior: Bound -import QtQuick -import QtQuick.Shapes -import Quickshell -import Quickshell.Hyprland -import Quickshell.Wayland -import qs.Common -import qs.Services -import qs.Widgets - -Variants { - id: dockVariants - model: SettingsData.getFilteredScreens("dock") - - property var contextMenu - - delegate: PanelWindow { - id: dock - - WindowBlur { - targetWindow: dock - blurX: dockBackground.x + dockContainer.x + dockMouseArea.x + dockCore.x + dockSlide.x - blurY: dockBackground.y + dockContainer.y + dockMouseArea.y + dockCore.y + dockSlide.y - blurWidth: dock.hasApps && dock.reveal ? dockBackground.width : 0 - blurHeight: dock.hasApps && dock.reveal ? dockBackground.height : 0 - blurRadius: Theme.cornerRadius - } - - WlrLayershell.namespace: "dms:dock" - - readonly property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right - - anchors { - top: !isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top) : true - bottom: !isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom) : true - left: !isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Left) - right: !isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Right) - } - - property var modelData: item - property bool autoHide: SettingsData.dockAutoHide || SettingsData.dockSmartAutoHide - property real backgroundTransparency: SettingsData.dockTransparency - property bool groupByApp: SettingsData.dockGroupByApp - readonly property int borderThickness: SettingsData.dockBorderEnabled ? SettingsData.dockBorderThickness : 0 - - readonly property int hasApps: dockApps.implicitWidth > 0 || dockApps.implicitHeight > 0 - - readonly property real widgetHeight: SettingsData.dockIconSize - readonly property real effectiveBarHeight: widgetHeight + SettingsData.dockSpacing * 2 + 10 + borderThickness * 2 - function getBarHeight(barConfig) { - if (!barConfig) - return 0; - const innerPadding = barConfig.innerPadding ?? 4; - const widgetThickness = Math.max(20, 26 + innerPadding * 0.6); - const barThickness = Math.max(widgetThickness + innerPadding + 4, Theme.barHeight - 4 - (8 - innerPadding)); - const spacing = barConfig.spacing ?? 4; - const bottomGap = barConfig.bottomGap ?? 0; - return barThickness + spacing + bottomGap; - } - - readonly property real barSpacing: { - const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default"); - if (!defaultBar) - return 0; - - const barPos = defaultBar.position ?? SettingsData.Position.Top; - const barIsHorizontal = (barPos === SettingsData.Position.Top || barPos === SettingsData.Position.Bottom); - const barIsVertical = (barPos === SettingsData.Position.Left || barPos === SettingsData.Position.Right); - const samePosition = (SettingsData.dockPosition === barPos); - const dockIsHorizontal = !isVertical; - const dockIsVertical = isVertical; - - if (!(defaultBar.visible ?? true)) - return 0; - const spacing = defaultBar.spacing ?? 4; - const bottomGap = defaultBar.bottomGap ?? 0; - if (dockIsHorizontal && barIsHorizontal && samePosition) { - return spacing + effectiveBarHeight + bottomGap; - } - if (dockIsVertical && barIsVertical && samePosition) { - return spacing + effectiveBarHeight + bottomGap; - } - return 0; - } - - readonly property real adjacentTopBarHeight: { - if (!isVertical || autoHide) - return 0; - const screenName = dock.modelData?.name ?? ""; - const topBar = SettingsData.barConfigs.find(bc => { - if (!bc.enabled || bc.autoHide || !(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Top && bc.position !== 0) - return false; - const onThisScreen = bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all") || bc.screenPreferences.includes(screenName); - return onThisScreen; - }); - return getBarHeight(topBar); - } - - readonly property real adjacentLeftBarWidth: { - if (isVertical || autoHide) - return 0; - const screenName = dock.modelData?.name ?? ""; - const leftBar = SettingsData.barConfigs.find(bc => { - if (!bc.enabled || bc.autoHide || !(bc.visible ?? true)) - return false; - if (bc.position !== SettingsData.Position.Left && bc.position !== 2) - return false; - const onThisScreen = bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all") || bc.screenPreferences.includes(screenName); - return onThisScreen; - }); - return getBarHeight(leftBar); - } - - readonly property real dockMargin: SettingsData.dockSpacing - readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin - readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1 - function px(v) { - return Math.round(v * _dpr) / _dpr; - } - - property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData) - property bool revealSticky: false - - readonly property bool shouldHideForWindows: { - if (!SettingsData.dockSmartAutoHide) - return false; - if (!CompositorService.isNiri && !CompositorService.isHyprland) - return false; - - const screenName = dock.modelData?.name ?? ""; - const dockThickness = effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin; - const screenWidth = dock.screen?.width ?? 0; - const screenHeight = dock.screen?.height ?? 0; - - if (CompositorService.isNiri) { - NiriService.windows; - - let currentWorkspaceId = null; - for (let i = 0; i < NiriService.allWorkspaces.length; i++) { - const ws = NiriService.allWorkspaces[i]; - if (ws.output === screenName && ws.is_active) { - currentWorkspaceId = ws.id; - break; - } - } - - if (currentWorkspaceId === null) - return false; - - for (let i = 0; i < NiriService.windows.length; i++) { - const win = NiriService.windows[i]; - if (win.workspace_id !== currentWorkspaceId) - continue; - - // Get window position and size from layout data - const tilePos = win.layout?.tile_pos_in_workspace_view; - const winSize = win.layout?.window_size || win.layout?.tile_size; - - if (tilePos && winSize) { - const winX = tilePos[0]; - const winY = tilePos[1]; - const winW = winSize[0]; - const winH = winSize[1]; - - switch (SettingsData.dockPosition) { - case SettingsData.Position.Top: - if (winY < dockThickness) - return true; - break; - case SettingsData.Position.Bottom: - if (winY + winH > screenHeight - dockThickness) - return true; - break; - case SettingsData.Position.Left: - if (winX < dockThickness) - return true; - break; - case SettingsData.Position.Right: - if (winX + winW > screenWidth - dockThickness) - return true; - break; - } - } else if (!win.is_floating) { - return true; - } - } - - return false; - } - - // Hyprland implementation - Hyprland.focusedWorkspace; - const filtered = CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName); - - if (filtered.length === 0) - return false; - - for (let i = 0; i < filtered.length; i++) { - const toplevel = filtered[i]; - - let hyprToplevel = null; - if (Hyprland.toplevels) { - const hyprToplevels = Array.from(Hyprland.toplevels.values); - for (let j = 0; j < hyprToplevels.length; j++) { - if (hyprToplevels[j].wayland === toplevel) { - hyprToplevel = hyprToplevels[j]; - break; - } - } - } - - if (!hyprToplevel?.lastIpcObject) - continue; - - const ipc = hyprToplevel.lastIpcObject; - const at = ipc.at; - const size = ipc.size; - if (!at || !size) - continue; - - const monX = hyprToplevel.monitor?.x ?? 0; - const monY = hyprToplevel.monitor?.y ?? 0; - - const winX = at[0] - monX; - const winY = at[1] - monY; - const winW = size[0]; - const winH = size[1]; - - switch (SettingsData.dockPosition) { - case SettingsData.Position.Top: - if (winY < dockThickness) - return true; - break; - case SettingsData.Position.Bottom: - if (winY + winH > screenHeight - dockThickness) - return true; - break; - case SettingsData.Position.Left: - if (winX < dockThickness) - return true; - break; - case SettingsData.Position.Right: - if (winX + winW > screenWidth - dockThickness) - return true; - break; - } - } - - return false; - } - - Timer { - id: revealHold - interval: 250 - repeat: false - onTriggered: dock.revealSticky = false - } - - property bool reveal: { - if (CompositorService.isNiri && NiriService.inOverview && SettingsData.dockOpenOnOverview) { - return true; - } - - // Smart auto-hide: show dock when no windows overlap, hide when they do - if (SettingsData.dockSmartAutoHide) { - if (shouldHideForWindows) - return dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky; - return true; // No overlapping windows - show dock - } - - // Regular auto-hide: always hide unless hovering - return !autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky; - } - - onContextMenuOpenChanged: { - if (!contextMenuOpen && autoHide && !dockMouseArea.containsMouse) { - revealSticky = true; - revealHold.restart(); - } - } - - Connections { - target: SettingsData - function onDockTransparencyChanged() { - dock.backgroundTransparency = SettingsData.dockTransparency; - } - } - - screen: modelData - visible: { - if (CompositorService.isNiri && NiriService.inOverview) { - return SettingsData.dockOpenOnOverview; - } - return SettingsData.showDock; - } - color: "transparent" - - exclusiveZone: { - if (!SettingsData.showDock || autoHide) - return -1; - if (barSpacing > 0) - return -1; - return px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin); - } - - property real animationHeadroom: Math.ceil(SettingsData.dockIconSize * 0.35) - - implicitWidth: isVertical ? (px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0 - implicitHeight: !isVertical ? (px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0 - - Item { - id: maskItem - parent: dock.contentItem - visible: false - readonly property bool expanded: dock.reveal - x: { - const baseX = dockCore.x + dockMouseArea.x; - if (isVertical && SettingsData.dockPosition === SettingsData.Position.Right) - return baseX - (expanded ? animationHeadroom + borderThickness : 0); - return baseX - (expanded ? borderThickness : 0); - } - y: { - const baseY = dockCore.y + dockMouseArea.y; - if (!isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom) - return baseY - (expanded ? animationHeadroom + borderThickness : 0); - return baseY - (expanded ? borderThickness : 0); - } - width: dockMouseArea.width + (isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 : 0) - height: dockMouseArea.height + (!isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 : 0) - } - - mask: Region { - item: maskItem - } - - property var hoveredButton: { - if (!dockApps.children[0]) { - return null; - } - const layoutItem = dockApps.children[0]; - const flowLayout = layoutItem.children[0]; - let repeater = null; - for (var i = 0; i < flowLayout.children.length; i++) { - const child = flowLayout.children[i]; - if (child && typeof child.count !== "undefined" && typeof child.itemAt === "function") { - repeater = child; - break; - } - } - if (!repeater || !repeater.itemAt) { - return null; - } - for (var i = 0; i < repeater.count; i++) { - const item = repeater.itemAt(i); - if (item && item.dockButton && item.dockButton.showTooltip) { - return item.dockButton; - } - } - return null; - } - - DankTooltip { - id: dockTooltip - targetScreen: dock.screen - } - - Timer { - id: tooltipRevealDelay - interval: 250 - repeat: false - onTriggered: dock.showTooltipForHoveredButton() - } - - function showTooltipForHoveredButton() { - dockTooltip.hide(); - if (!dock.hoveredButton || !dock.reveal || slideXAnimation.running || slideYAnimation.running) - return; - - const buttonGlobalPos = dock.hoveredButton.mapToGlobal(0, 0); - const tooltipText = dock.hoveredButton.tooltipText || ""; - if (!tooltipText) - return; - - const screenX = dock.screen ? (dock.screen.x || 0) : 0; - const screenY = dock.screen ? (dock.screen.y || 0) : 0; - const screenHeight = dock.screen ? dock.screen.height : 0; - - const gap = Theme.spacingS; - const bgMargin = barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness; - const btnW = dock.hoveredButton.width; - const btnH = dock.hoveredButton.height; - - if (!dock.isVertical) { - const isBottom = SettingsData.dockPosition === SettingsData.Position.Bottom; - const globalX = buttonGlobalPos.x + btnW / 2 + adjacentLeftBarWidth; - const tooltipHeight = 32; - const totalFromEdge = bgMargin + dockBackground.height + dock.borderThickness + gap; - const screenRelativeY = isBottom ? (screenHeight - totalFromEdge - tooltipHeight) : totalFromEdge; - dockTooltip.show(tooltipText, globalX, screenRelativeY, dock.screen, false, false); - return; - } - - const isLeft = SettingsData.dockPosition === SettingsData.Position.Left; - const screenWidth = dock.screen ? dock.screen.width : 0; - const totalFromEdge = bgMargin + dockBackground.width + dock.borderThickness + gap; - const tooltipX = isLeft ? (screenX + totalFromEdge) : (screenX + screenWidth - totalFromEdge); - const screenRelativeY = buttonGlobalPos.y - screenY + btnH / 2 + adjacentTopBarHeight; - dockTooltip.show(tooltipText, tooltipX, screenRelativeY, dock.screen, isLeft, !isLeft); - } - - Connections { - target: dock - function onRevealChanged() { - if (!dock.reveal) { - tooltipRevealDelay.stop(); - dockTooltip.hide(); - } else { - tooltipRevealDelay.restart(); - } - } - - function onHoveredButtonChanged() { - dock.showTooltipForHoveredButton(); - } - } - - Item { - id: dockCore - anchors.fill: parent - x: isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? animationHeadroom : 0 - y: !isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? animationHeadroom : 0 - - Connections { - target: dockMouseArea - function onContainsMouseChanged() { - if (dockMouseArea.containsMouse) { - dock.revealSticky = true; - revealHold.stop(); - } else { - if (dock.autoHide && !dock.contextMenuOpen) { - revealHold.restart(); - } - } - } - } - - MouseArea { - id: dockMouseArea - property real currentScreen: modelData ? modelData : dock.screen - property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920 - property real screenHeight: currentScreen ? currentScreen.geometry.height : 1080 - property real maxDockWidth: screenWidth * 0.98 - property real maxDockHeight: screenHeight * 0.98 - - height: { - if (dock.isVertical) { - // Keep the taller hit area regardless of the reveal state to prevent shrinking loop - return Math.min(Math.max(dockBackground.height + 64, 200), maxDockHeight); - } - return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1; - } - width: { - if (dock.isVertical) { - return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1; - } - // Keep the wider hit area regardless of the reveal state to prevent shrinking loop - return Math.min(dockBackground.width + 8 + dock.borderThickness, maxDockWidth); - } - anchors { - top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top) : undefined - bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined) : undefined - horizontalCenter: !dock.isVertical ? parent.horizontalCenter : undefined - left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? undefined : parent.left) : undefined - right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined - verticalCenter: dock.isVertical ? parent.verticalCenter : undefined - } - hoverEnabled: true - acceptedButtons: Qt.NoButton - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on width { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Item { - id: dockContainer - anchors.fill: parent - clip: false - - transform: Translate { - id: dockSlide - x: { - if (!dock.isVertical) - return 0; - if (dock.reveal) - return 0; - const hideDistance = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin + 10; - if (SettingsData.dockPosition === SettingsData.Position.Right) { - return hideDistance; - } else { - return -hideDistance; - } - } - y: { - if (dock.isVertical) - return 0; - if (dock.reveal) - return 0; - const hideDistance = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin + 10; - if (SettingsData.dockPosition === SettingsData.Position.Bottom) { - return hideDistance; - } else { - return -hideDistance; - } - } - - Behavior on x { - NumberAnimation { - id: slideXAnimation - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on y { - NumberAnimation { - id: slideYAnimation - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - } - - Item { - id: dockBackground - objectName: "dockBackground" - anchors { - top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top ? parent.top : undefined) : undefined - bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined) : undefined - horizontalCenter: !dock.isVertical ? parent.horizontalCenter : undefined - left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Left ? parent.left : undefined) : undefined - right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined - verticalCenter: dock.isVertical ? parent.verticalCenter : undefined - } - anchors.topMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Top ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0 - anchors.bottomMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0 - anchors.leftMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Left ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0 - anchors.rightMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0 - - implicitWidth: dock.isVertical ? (dockApps.implicitHeight + SettingsData.dockSpacing * 2) : (dockApps.implicitWidth + SettingsData.dockSpacing * 2) - implicitHeight: dock.isVertical ? (dockApps.implicitWidth + SettingsData.dockSpacing * 2) : (dockApps.implicitHeight + SettingsData.dockSpacing * 2) - width: implicitWidth - height: implicitHeight - - layer.enabled: true - clip: false - - Rectangle { - anchors.fill: parent - color: Theme.withAlpha(Theme.surfaceContainer, backgroundTransparency) - radius: Theme.cornerRadius - } - - Rectangle { - anchors.fill: parent - color: "transparent" - radius: Theme.cornerRadius - border.color: BlurService.borderColor - border.width: BlurService.borderWidth - z: 100 - } - } - - Shape { - id: dockBorderShape - x: dockBackground.x - borderThickness - y: dockBackground.y - borderThickness - width: dockBackground.width + borderThickness * 2 - height: dockBackground.height + borderThickness * 2 - visible: SettingsData.dockBorderEnabled && dock.hasApps - preferredRendererType: Shape.CurveRenderer - - readonly property real borderThickness: Math.max(1, dock.borderThickness) - readonly property real i: borderThickness / 2 - readonly property real cr: Theme.cornerRadius - readonly property real w: dockBackground.width - readonly property real h: dockBackground.height - - readonly property color borderColor: { - const opacity = SettingsData.dockBorderOpacity; - switch (SettingsData.dockBorderColor) { - case "secondary": - return Theme.withAlpha(Theme.secondary, opacity); - case "primary": - return Theme.withAlpha(Theme.primary, opacity); - default: - return Theme.withAlpha(Theme.surfaceText, opacity); - } - } - - ShapePath { - fillColor: "transparent" - strokeColor: dockBorderShape.borderColor - strokeWidth: dockBorderShape.borderThickness - joinStyle: ShapePath.RoundJoin - capStyle: ShapePath.FlatCap - - PathSvg { - path: { - const bt = dockBorderShape.borderThickness; - const i = dockBorderShape.i; - const cr = dockBorderShape.cr + bt - i; - const w = dockBorderShape.w; - const h = dockBorderShape.h; - - let d = `M ${i + cr} ${i}`; - d += ` L ${i + w + 2 * (bt - i) - cr} ${i}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + w + 2 * (bt - i)} ${i + cr}`; - d += ` L ${i + w + 2 * (bt - i)} ${i + h + 2 * (bt - i) - cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + w + 2 * (bt - i) - cr} ${i + h + 2 * (bt - i)}`; - d += ` L ${i + cr} ${i + h + 2 * (bt - i)}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h + 2 * (bt - i) - cr}`; - d += ` L ${i} ${i + cr}`; - if (cr > 0) - d += ` A ${cr} ${cr} 0 0 1 ${i + cr} ${i}`; - d += " Z"; - return d; - } - } - } - } - - DockApps { - id: dockApps - - anchors.top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top ? dockBackground.top : undefined) : undefined - anchors.bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? dockBackground.bottom : undefined) : undefined - anchors.horizontalCenter: !dock.isVertical ? dockBackground.horizontalCenter : undefined - anchors.left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Left ? dockBackground.left : undefined) : undefined - anchors.right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? dockBackground.right : undefined) : undefined - anchors.verticalCenter: dock.isVertical ? dockBackground.verticalCenter : undefined - anchors.topMargin: !dock.isVertical ? SettingsData.dockSpacing : 0 - anchors.bottomMargin: !dock.isVertical ? SettingsData.dockSpacing : 0 - anchors.leftMargin: dock.isVertical ? SettingsData.dockSpacing : 0 - anchors.rightMargin: dock.isVertical ? SettingsData.dockSpacing : 0 - - contextMenu: dockVariants.contextMenu - groupByApp: dock.groupByApp - isVertical: dock.isVertical - dockScreen: dock.screen - iconSize: dock.widgetHeight - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockAppButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockAppButton.qml deleted file mode 100644 index 1d9fb75..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockAppButton.qml +++ /dev/null @@ -1,670 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Hyprland -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - clip: false - property var appData - property var contextMenu: null - property var dockApps: null - property int index: -1 - property var parentDockScreen: null - property bool longPressing: false - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - property int targetIndex: -1 - property int originalIndex: -1 - property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right - property bool showWindowTitle: false - property string windowTitle: "" - property bool isHovered: mouseArea.containsMouse && !dragging - property bool showTooltip: mouseArea.containsMouse && !dragging - property var cachedDesktopEntry: null - property real actualIconSize: 40 - property bool shouldShowIndicator: { - if (!appData) - return false; - if (appData.type === "window") - return true; - if (appData.type === "grouped") - return appData.windowCount > 0; - return appData.isRunning; - } - readonly property string coreIconColorOverride: SettingsData.dockLauncherLogoColorOverride - readonly property bool coreIconHasCustomColor: coreIconColorOverride !== "" && coreIconColorOverride !== "primary" && coreIconColorOverride !== "surface" - readonly property color effectiveCoreIconColor: { - if (coreIconColorOverride === "primary") - return Theme.primary; - if (coreIconColorOverride === "surface") - return Theme.surfaceText; - if (coreIconColorOverride !== "") - return coreIconColorOverride; - return Theme.surfaceText; - } - readonly property real effectiveCoreIconBrightness: coreIconHasCustomColor ? SettingsData.dockLauncherLogoBrightness : 0.0 - readonly property real effectiveCoreIconContrast: coreIconHasCustomColor ? SettingsData.dockLauncherLogoContrast : 0.0 - - function updateDesktopEntry() { - if (!appData || appData.appId === "__SEPARATOR__") { - cachedDesktopEntry = null; - return; - } - if (appData.isCoreApp) { - cachedDesktopEntry = null; - return; - } - const moddedId = Paths.moddedAppId(appData.appId); - cachedDesktopEntry = DesktopEntries.heuristicLookup(moddedId); - } - - Component.onCompleted: updateDesktopEntry() - - onAppDataChanged: updateDesktopEntry() - - Connections { - target: DesktopEntries - function onApplicationsChanged() { - updateDesktopEntry(); - } - } - - Connections { - target: SettingsData - function onAppIdSubstitutionsChanged() { - updateDesktopEntry(); - } - } - property bool isWindowFocused: { - if (!appData) { - return false; - } - - if (appData.type === "window") { - const toplevel = getToplevelObject(); - if (!toplevel) { - return false; - } - return toplevel.activated; - } else if (appData.type === "grouped") { - // For grouped apps, check if any window is focused - const allToplevels = ToplevelManager.toplevels.values; - for (let i = 0; i < allToplevels.length; i++) { - const toplevel = allToplevels[i]; - if (toplevel.appId === appData.appId && toplevel.activated) { - return true; - } - } - } - - return false; - } - property string tooltipText: { - if (!appData || !appData.appId) { - return ""; - } - - let appName; - if (appData.isCoreApp && appData.coreAppData) { - appName = appData.coreAppData.name || appData.appId; - } else { - appName = Paths.getAppName(appData.appId, cachedDesktopEntry); - } - - if ((appData.type === "window" && showWindowTitle) || (appData.type === "grouped" && appData.windowTitle)) { - const title = appData.type === "window" ? windowTitle : appData.windowTitle; - return appName + (title ? " • " + title : ""); - } - - return appName; - } - - function getToplevelObject() { - return appData?.toplevel || null; - } - - function getGroupedToplevels() { - return appData?.allWindows?.map(w => w.toplevel).filter(t => t !== null) || []; - } - - function getHyprToplevelForWayland(waylandToplevel) { - if (!waylandToplevel || !CompositorService.isHyprland || !Hyprland.toplevels) - return null; - const hyprToplevels = Array.from(Hyprland.toplevels.values); - for (let i = 0; i < hyprToplevels.length; i++) { - if (hyprToplevels[i].wayland === waylandToplevel) - return hyprToplevels[i]; - } - return null; - } - - function getSpecialWorkspaceName(waylandToplevel) { - const hyprToplevel = getHyprToplevelForWayland(waylandToplevel); - if (!hyprToplevel) - return ""; - const wsName = String(hyprToplevel.lastIpcObject?.workspace?.name || hyprToplevel.workspace?.name || ""); - if (!wsName.startsWith("special:")) - return ""; - return wsName.slice("special:".length); - } - - function restoreSpecialWorkspaceWindow(waylandToplevel) { - if (!SettingsData.dockRestoreSpecialWorkspaceOnClick || !CompositorService.isHyprland || !waylandToplevel) - return false; - - const specialName = getSpecialWorkspaceName(waylandToplevel); - if (!specialName) - return false; - - Hyprland.dispatch("togglespecialworkspace " + specialName); - Qt.callLater(() => waylandToplevel.activate()); - return true; - } - onIsHoveredChanged: { - if (mouseArea.pressed || dragging) - return; - if (isHovered) { - exitAnimation.stop(); - if (!bounceAnimation.running) { - bounceAnimation.restart(); - } - } else { - bounceAnimation.stop(); - exitAnimation.restart(); - } - } - - readonly property bool animateX: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right - readonly property real animationDistance: actualIconSize - readonly property real animationDirection: { - if (SettingsData.dockPosition === SettingsData.Position.Bottom) - return -1; - if (SettingsData.dockPosition === SettingsData.Position.Top) - return 1; - if (SettingsData.dockPosition === SettingsData.Position.Right) - return -1; - if (SettingsData.dockPosition === SettingsData.Position.Left) - return 1; - return -1; - } - - SequentialAnimation { - id: bounceAnimation - - running: false - - NumberAnimation { - target: root - property: "hoverAnimOffset" - to: animationDirection * animationDistance * 0.25 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedAccel - } - - NumberAnimation { - target: root - property: "hoverAnimOffset" - to: animationDirection * animationDistance * 0.2 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedDecel - } - } - - NumberAnimation { - id: exitAnimation - - running: false - target: root - property: "hoverAnimOffset" - to: 0 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedDecel - } - - Timer { - id: longPressTimer - - interval: 500 - repeat: false - onTriggered: { - if (appData && appData.isPinned) { - longPressing = true; - } - } - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - hoverEnabled: true - enabled: true - preventStealing: dragging || longPressing - cursorShape: longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onPressed: mouse => { - if (mouse.button === Qt.LeftButton && appData && appData.isPinned) { - dragStartPos = Qt.point(mouse.x, mouse.y); - longPressTimer.start(); - } - } - onReleased: mouse => { - longPressTimer.stop(); - - const wasDragging = dragging; - const didReorder = wasDragging && targetIndex >= 0 && targetIndex !== originalIndex && dockApps; - - if (didReorder) - dockApps.movePinnedApp(originalIndex, targetIndex); - - longPressing = false; - dragging = false; - dragAxisOffset = 0; - targetIndex = -1; - originalIndex = -1; - - if (dockApps) { - dockApps.draggedIndex = -1; - dockApps.dropTargetIndex = -1; - } - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - handleLeftClick(); - } - - function handleLeftClick() { - if (!appData) - return; - - switch (appData.type) { - case "pinned": - if (!appData.appId) - return; - if (appData.isCoreApp && appData.coreAppData) { - AppSearchService.executeCoreApp(appData.coreAppData); - return; - } - const pinnedEntry = cachedDesktopEntry; - if (pinnedEntry) { - AppUsageHistoryData.addAppUsage({ - "id": appData.appId, - "name": pinnedEntry.name || appData.appId, - "icon": pinnedEntry.icon ? String(pinnedEntry.icon) : "", - "exec": pinnedEntry.exec || "", - "comment": pinnedEntry.comment || "" - }); - } - SessionService.launchDesktopEntry(pinnedEntry); - break; - case "window": - const windowToplevel = getToplevelObject(); - if (windowToplevel) { - if (restoreSpecialWorkspaceWindow(windowToplevel)) - return; - windowToplevel.activate(); - } - break; - case "grouped": - if (appData.windowCount === 0) { - if (!appData.appId) - return; - if (appData.isCoreApp && appData.coreAppData) { - AppSearchService.executeCoreApp(appData.coreAppData); - return; - } - const groupedEntry = cachedDesktopEntry; - if (groupedEntry) { - AppUsageHistoryData.addAppUsage({ - "id": appData.appId, - "name": groupedEntry.name || appData.appId, - "icon": groupedEntry.icon ? String(groupedEntry.icon) : "", - "exec": groupedEntry.exec || "", - "comment": groupedEntry.comment || "" - }); - } - SessionService.launchDesktopEntry(groupedEntry); - } else if (appData.windowCount === 1) { - const groupedToplevel = getToplevelObject(); - if (groupedToplevel) { - if (restoreSpecialWorkspaceWindow(groupedToplevel)) - return; - groupedToplevel.activate(); - } - } else if (contextMenu) { - const shouldHidePin = appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms"; - contextMenu.showForButton(root, appData, root.height + 25, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps); - } - break; - } - } - onPositionChanged: mouse => { - if (longPressing && !dragging) { - const distance = Math.sqrt(Math.pow(mouse.x - dragStartPos.x, 2) + Math.pow(mouse.y - dragStartPos.y, 2)); - if (distance > 5) { - dragging = true; - targetIndex = index; - originalIndex = index; - if (dockApps) { - dockApps.draggedIndex = index; - dockApps.dropTargetIndex = index; - } - } - } - - if (!dragging || !dockApps) - return; - - const axisOffset = isVertical ? (mouse.y - dragStartPos.y) : (mouse.x - dragStartPos.x); - dragAxisOffset = axisOffset; - - const spacing = Math.min(8, Math.max(4, actualIconSize * 0.08)); - const itemSize = actualIconSize * 1.2 + spacing; - const slotOffset = Math.round(axisOffset / itemSize); - const newTargetIndex = Math.max(0, Math.min(dockApps.pinnedAppCount - 1, originalIndex + slotOffset)); - - if (newTargetIndex !== targetIndex) { - targetIndex = newTargetIndex; - dockApps.dropTargetIndex = newTargetIndex; - } - } - onClicked: mouse => { - if (!appData) - return; - - if (mouse.button === Qt.MiddleButton) { - switch (appData.type) { - case "window": - appData.toplevel?.close(); - break; - case "grouped": - if (contextMenu) { - const shouldHidePin = appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms"; - contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps); - } - break; - default: - if (!appData.appId) - return; - const desktopEntry = cachedDesktopEntry; - if (desktopEntry) { - AppUsageHistoryData.addAppUsage({ - "id": appData.appId, - "name": desktopEntry.name || appData.appId, - "icon": desktopEntry.icon ? String(desktopEntry.icon) : "", - "exec": desktopEntry.exec || "", - "comment": desktopEntry.comment || "" - }); - } - SessionService.launchDesktopEntry(desktopEntry); - break; - } - } else if (mouse.button === Qt.RightButton) { - if (!contextMenu) - return; - const shouldHidePin = appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms"; - contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps); - } - } - } - - property real hoverAnimOffset: 0 - - Item { - id: visualContent - anchors.fill: parent - - transform: Translate { - id: iconTransform - x: { - if (dragging && !isVertical) - return dragAxisOffset; - if (!dragging && isVertical) - return hoverAnimOffset; - return 0; - } - y: { - if (dragging && isVertical) - return dragAxisOffset; - if (!dragging && !isVertical) - return hoverAnimOffset; - return 0; - } - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) - border.width: 2 - border.color: Theme.primary - visible: dragging - z: -1 - } - - AppIconRenderer { - id: coreIcon - - anchors.centerIn: parent - iconSize: actualIconSize - iconValue: appData && appData.isCoreApp && appData.coreAppData ? (appData.coreAppData.icon || "") : "" - colorOverride: effectiveCoreIconColor - brightnessOverride: effectiveCoreIconBrightness - contrastOverride: effectiveCoreIconContrast - fallbackText: "?" - visible: iconValue !== "" - } - - IconImage { - id: iconImg - - anchors.centerIn: parent - implicitSize: appData && (appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms") ? actualIconSize * 0.85 : actualIconSize - source: { - if (!appData || appData.appId === "__SEPARATOR__") { - return ""; - } - if (appData.isCoreApp && appData.coreAppData) { - return ""; - } - return Paths.getAppIcon(appData.appId, cachedDesktopEntry); - } - mipmap: true - smooth: true - asynchronous: true - visible: status === Image.Ready && !coreIcon.visible - layer.enabled: appData && (appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms") - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: Theme.primary - } - } - - Rectangle { - width: actualIconSize - height: actualIconSize - anchors.centerIn: parent - visible: !coreIcon.visible && iconImg.status !== Image.Ready && appData && appData.appId && !Paths.isSteamApp(appData.appId) - color: Theme.surfaceLight - radius: Theme.cornerRadius - border.width: 1 - border.color: Theme.primarySelected - - Text { - anchors.centerIn: parent - text: { - if (!appData || !appData.appId) { - return "?"; - } - - let appName; - if (appData.isCoreApp && appData.coreAppData) { - appName = appData.coreAppData.name || appData.appId; - } else { - appName = Paths.getAppName(appData.appId, cachedDesktopEntry); - } - return appName.charAt(0).toUpperCase(); - } - font.pixelSize: Math.max(8, parent.width * 0.35) - color: Theme.primary - font.weight: Font.Bold - } - } - - DankIcon { - anchors.centerIn: parent - size: actualIconSize - name: "sports_esports" - color: Theme.surfaceText - visible: !coreIcon.visible && iconImg.status !== Image.Ready && appData && appData.appId && Paths.isSteamApp(appData.appId) - } - - Loader { - anchors.horizontalCenter: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? undefined : parent.horizontalCenter - anchors.verticalCenter: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? parent.verticalCenter : undefined - anchors.bottom: SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined - anchors.top: SettingsData.dockPosition === SettingsData.Position.Top ? parent.top : undefined - anchors.left: SettingsData.dockPosition === SettingsData.Position.Left ? parent.left : undefined - anchors.right: SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined - anchors.bottomMargin: SettingsData.dockPosition === SettingsData.Position.Bottom ? -(SettingsData.dockSpacing / 2 + 1.4) : 0 - anchors.topMargin: SettingsData.dockPosition === SettingsData.Position.Top ? -(SettingsData.dockSpacing / 2 + 1.4) : 0 - anchors.leftMargin: SettingsData.dockPosition === SettingsData.Position.Left ? -(SettingsData.dockSpacing / 2 + 1.4) : 0 - anchors.rightMargin: SettingsData.dockPosition === SettingsData.Position.Right ? -(SettingsData.dockSpacing / 2 + 1.4) : 0 - - sourceComponent: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? columnIndicator : rowIndicator - - visible: root.shouldShowIndicator - } - } - - Component { - id: rowIndicator - - Row { - spacing: 2 - - Repeater { - model: { - if (!appData) - return 0; - if (appData.type === "grouped") { - return Math.min(appData.windowCount, 4); - } else if (appData.type === "window" || appData.isRunning) { - return 1; - } - return 0; - } - - Rectangle { - width: { - if (SettingsData.dockIndicatorStyle === "circle") { - return Math.max(4, actualIconSize * 0.1); - } - return appData && appData.type === "grouped" && appData.windowCount > 1 ? Math.max(3, actualIconSize * 0.1) : Math.max(6, actualIconSize * 0.2); - } - height: { - if (SettingsData.dockIndicatorStyle === "circle") { - return Math.max(4, actualIconSize * 0.1); - } - return Math.max(2, actualIconSize * 0.05); - } - radius: SettingsData.dockIndicatorStyle === "circle" ? width / 2 : Theme.cornerRadius - color: { - if (!appData) { - return "transparent"; - } - - if (appData.type !== "grouped" || appData.windowCount === 1) { - if (isWindowFocused) { - return Theme.primary; - } - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6); - } - - if (appData.type === "grouped" && appData.windowCount > 1) { - const groupToplevels = getGroupedToplevels(); - if (index < groupToplevels.length && groupToplevels[index].activated) { - return Theme.primary; - } - } - - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6); - } - } - } - } - } - - Component { - id: columnIndicator - - Column { - spacing: 2 - - Repeater { - model: { - if (!appData) - return 0; - if (appData.type === "grouped") { - return Math.min(appData.windowCount, 4); - } else if (appData.type === "window" || appData.isRunning) { - return 1; - } - return 0; - } - - Rectangle { - width: { - if (SettingsData.dockIndicatorStyle === "circle") { - return Math.max(4, actualIconSize * 0.1); - } - return Math.max(2, actualIconSize * 0.05); - } - height: { - if (SettingsData.dockIndicatorStyle === "circle") { - return Math.max(4, actualIconSize * 0.1); - } - return appData && appData.type === "grouped" && appData.windowCount > 1 ? Math.max(3, actualIconSize * 0.1) : Math.max(6, actualIconSize * 0.2); - } - radius: SettingsData.dockIndicatorStyle === "circle" ? width / 2 : Theme.cornerRadius - color: { - if (!appData) { - return "transparent"; - } - - if (appData.type !== "grouped" || appData.windowCount === 1) { - if (isWindowFocused) { - return Theme.primary; - } - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6); - } - - if (appData.type === "grouped" && appData.windowCount > 1) { - const groupToplevels = getGroupedToplevels(); - if (index < groupToplevels.length && groupToplevels[index].activated) { - return Theme.primary; - } - } - - return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockApps.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockApps.qml deleted file mode 100644 index dbdc517..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockApps.qml +++ /dev/null @@ -1,646 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Hyprland -import qs.Common -import qs.Services - -Item { - id: root - - property var contextMenu: null - property bool requestDockShow: false - property int pinnedAppCount: 0 - property bool groupByApp: false - property bool isVertical: false - property var dockScreen: null - property real iconSize: 40 - property int draggedIndex: -1 - property int dropTargetIndex: -1 - property bool suppressShiftAnimation: false - property int maxVisibleApps: SettingsData.dockMaxVisibleApps - property int maxVisibleRunningApps: SettingsData.dockMaxVisibleRunningApps - property bool overflowExpanded: false - property int overflowItemCount: 0 - - readonly property real baseImplicitWidth: isVertical ? baseAppHeight : baseAppWidth - readonly property real baseImplicitHeight: isVertical ? baseAppWidth : baseAppHeight - readonly property real baseAppWidth: { - let count = 0; - const items = repeater.dockItems; - for (let i = 0; i < items.length; i++) { - const item = items[i]; - if (item.isInOverflow) - continue; - if (item.type === "separator") { - count += 8 / (iconSize * 1.2); - } else { - count += 1; - } - } - return count * (iconSize * 1.2) + Math.max(0, count - 1) * layoutFlow.spacing; - } - readonly property real baseAppHeight: iconSize - - clip: false - implicitWidth: isVertical ? appLayout.height : appLayout.width - implicitHeight: isVertical ? appLayout.width : appLayout.height - - function dockIndexToPinnedIndex(dockIndex) { - if (!SettingsData.dockLauncherEnabled) - return dockIndex; - - const launcherPos = SessionData.dockLauncherPosition; - return dockIndex < launcherPos ? dockIndex : dockIndex - 1; - } - - function movePinnedApp(fromDockIndex, toDockIndex) { - const fromPinnedIndex = dockIndexToPinnedIndex(fromDockIndex); - const toPinnedIndex = dockIndexToPinnedIndex(toDockIndex); - - if (fromPinnedIndex === toPinnedIndex) - return; - - const currentPinned = [...(SessionData.pinnedApps || [])]; - if (fromPinnedIndex < 0 || fromPinnedIndex >= currentPinned.length || toPinnedIndex < 0 || toPinnedIndex >= currentPinned.length) - return; - - const movedApp = currentPinned.splice(fromPinnedIndex, 1)[0]; - currentPinned.splice(toPinnedIndex, 0, movedApp); - SessionData.setPinnedApps(currentPinned); - } - - Item { - id: appLayout - width: layoutFlow.width - height: layoutFlow.height - - Behavior on width { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - anchors.horizontalCenter: root.isVertical ? undefined : parent.horizontalCenter - anchors.verticalCenter: root.isVertical ? parent.verticalCenter : undefined - anchors.left: root.isVertical && SettingsData.dockPosition === SettingsData.Position.Left ? parent.left : undefined - anchors.right: root.isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined - anchors.top: root.isVertical ? undefined : parent.top - - Flow { - id: layoutFlow - flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight - spacing: Math.min(8, Math.max(4, root.iconSize * 0.08)) - - Repeater { - id: repeater - - property var dockItems: [] - - model: ScriptModel { - values: repeater.dockItems - objectProp: "uniqueKey" - } - - Component.onCompleted: updateModel() - - function isOnScreen(toplevel, screenName) { - if (!toplevel.screens) - return false; - for (let i = 0; i < toplevel.screens.length; i++) { - if (toplevel.screens[i]?.name === screenName) - return true; - } - return false; - } - - function getCoreAppData(appId) { - if (typeof AppSearchService === "undefined") - return null; - const coreApps = AppSearchService.coreApps || []; - for (let i = 0; i < coreApps.length; i++) { - if (coreApps[i].builtInPluginId === appId) - return coreApps[i]; - } - return null; - } - - function getCoreAppDataByTitle(windowTitle) { - if (typeof AppSearchService === "undefined" || !windowTitle) - return null; - const coreApps = AppSearchService.coreApps || []; - for (let i = 0; i < coreApps.length; i++) { - if (coreApps[i].name === windowTitle) - return coreApps[i]; - } - return null; - } - - function buildBaseItems() { - const items = []; - const pinnedApps = [...(SessionData.pinnedApps || [])]; - const allToplevels = CompositorService.sortedToplevels; - const sortedToplevels = (SettingsData.dockIsolateDisplays && root.dockScreen) ? allToplevels.filter(t => isOnScreen(t, root.dockScreen.name)) : allToplevels; - - if (root.groupByApp) { - return buildGroupedItems(pinnedApps, sortedToplevels); - } - return buildUngroupedItems(pinnedApps, sortedToplevels); - } - - function buildGroupedItems(pinnedApps, sortedToplevels) { - const items = []; - const appGroups = new Map(); - - pinnedApps.forEach(rawAppId => { - const appId = Paths.moddedAppId(rawAppId); - const coreAppData = getCoreAppData(appId); - appGroups.set(appId, { - appId: appId, - isPinned: true, - windows: [], - isCoreApp: coreAppData !== null, - coreAppData: coreAppData - }); - }); - - sortedToplevels.forEach((toplevel, index) => { - const rawAppId = toplevel.appId || "unknown"; - let appId = Paths.moddedAppId(rawAppId); - let coreAppData = null; - - if (rawAppId === "org.quickshell" || rawAppId === "com.danklinux.dms") { - coreAppData = getCoreAppDataByTitle(toplevel.title); - if (coreAppData) - appId = coreAppData.builtInPluginId; - } - - if (!appGroups.has(appId)) { - appGroups.set(appId, { - appId: appId, - isPinned: false, - windows: [], - isCoreApp: coreAppData !== null, - coreAppData: coreAppData - }); - } - appGroups.get(appId).windows.push({ - toplevel: toplevel, - index: index - }); - }); - - const pinnedGroups = []; - const unpinnedGroups = []; - - appGroups.forEach((group, appId) => { - const firstWindow = group.windows.length > 0 ? group.windows[0] : null; - const item = { - uniqueKey: "grouped_" + appId, - type: "grouped", - appId: appId, - toplevel: firstWindow ? firstWindow.toplevel : null, - isPinned: group.isPinned, - isRunning: group.windows.length > 0, - windowCount: group.windows.length, - allWindows: group.windows, - isCoreApp: group.isCoreApp || false, - coreAppData: group.coreAppData || null, - isInOverflow: false - }; - (group.isPinned ? pinnedGroups : unpinnedGroups).push(item); - }); - - pinnedGroups.forEach(item => items.push(item)); - insertLauncher(items); - - if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) { - items.push(createSeparator("separator_grouped")); - } - unpinnedGroups.forEach(item => items.push(item)); - - root.pinnedAppCount = pinnedGroups.length + (SettingsData.dockLauncherEnabled ? 1 : 0); - return { - items, - pinnedCount: pinnedGroups.length, - runningCount: unpinnedGroups.length - }; - } - - function buildUngroupedItems(pinnedApps, sortedToplevels) { - const items = []; - const runningAppIds = new Set(); - const windowItems = []; - - sortedToplevels.forEach((toplevel, index) => { - let uniqueKey = "window_" + index; - if (CompositorService.isHyprland && Hyprland.toplevels) { - const hyprlandToplevels = Array.from(Hyprland.toplevels.values); - for (let i = 0; i < hyprlandToplevels.length; i++) { - if (hyprlandToplevels[i].wayland === toplevel) { - uniqueKey = "window_" + hyprlandToplevels[i].address; - break; - } - } - } - - const rawAppId = toplevel.appId || "unknown"; - const moddedAppId = Paths.moddedAppId(rawAppId); - let coreAppData = null; - let isCoreApp = false; - - if (rawAppId === "org.quickshell" || rawAppId === "com.danklinux.dms") { - coreAppData = getCoreAppDataByTitle(toplevel.title); - if (coreAppData) - isCoreApp = true; - } - - const finalAppId = isCoreApp ? coreAppData.builtInPluginId : moddedAppId; - windowItems.push({ - uniqueKey: uniqueKey, - type: "window", - appId: finalAppId, - toplevel: toplevel, - isPinned: false, - isRunning: true, - isCoreApp: isCoreApp, - coreAppData: coreAppData, - isInOverflow: false - }); - runningAppIds.add(finalAppId); - }); - - const remainingWindowItems = windowItems.slice(); - - pinnedApps.forEach(rawAppId => { - const appId = Paths.moddedAppId(rawAppId); - const coreAppData = getCoreAppData(appId); - const matchIndex = remainingWindowItems.findIndex(item => item.appId === appId); - - if (matchIndex !== -1) { - const windowItem = remainingWindowItems.splice(matchIndex, 1)[0]; - windowItem.isPinned = true; - windowItem.uniqueKey = "pinned_" + appId; - if (!windowItem.isCoreApp && coreAppData) { - windowItem.isCoreApp = true; - windowItem.coreAppData = coreAppData; - } - items.push(windowItem); - } else { - items.push({ - uniqueKey: "pinned_" + appId, - type: "pinned", - appId: appId, - toplevel: null, - isPinned: true, - isRunning: runningAppIds.has(appId), - isCoreApp: coreAppData !== null, - coreAppData: coreAppData, - isInOverflow: false - }); - } - }); - - root.pinnedAppCount = pinnedApps.length + (SettingsData.dockLauncherEnabled ? 1 : 0); - insertLauncher(items); - - if (pinnedApps.length > 0 && remainingWindowItems.length > 0) { - items.push(createSeparator("separator_ungrouped")); - } - remainingWindowItems.forEach(item => items.push(item)); - - return { - items, - pinnedCount: pinnedApps.length, - runningCount: remainingWindowItems.length - }; - } - - function insertLauncher(targetArray) { - if (!SettingsData.dockLauncherEnabled) - return; - const launcherItem = { - uniqueKey: "launcher_button", - type: "launcher", - appId: "__LAUNCHER__", - toplevel: null, - isPinned: true, - isRunning: false - }; - const pos = Math.max(0, Math.min(SessionData.dockLauncherPosition, targetArray.length)); - targetArray.splice(pos, 0, launcherItem); - } - - function createSeparator(key) { - return { - uniqueKey: key, - type: "separator", - appId: "__SEPARATOR__", - toplevel: null, - isPinned: false, - isRunning: false - }; - } - - function markAsOverflow(item) { - return { - uniqueKey: item.uniqueKey, - type: item.type, - appId: item.appId, - toplevel: item.toplevel, - isPinned: item.isPinned, - isRunning: item.isRunning, - windowCount: item.windowCount, - allWindows: item.allWindows, - isCoreApp: item.isCoreApp, - coreAppData: item.coreAppData, - isInOverflow: true - }; - } - - function markAsVisible(item) { - return { - uniqueKey: item.uniqueKey, - type: item.type, - appId: item.appId, - toplevel: item.toplevel, - isPinned: item.isPinned, - isRunning: item.isRunning, - windowCount: item.windowCount, - allWindows: item.allWindows, - isCoreApp: item.isCoreApp, - coreAppData: item.coreAppData, - isInOverflow: false - }; - } - - function applyOverflow(baseResult) { - const { - items - } = baseResult; - const maxPinned = root.maxVisibleApps; - const maxRunning = root.maxVisibleRunningApps; - - const pinnedItems = items.filter(i => (i.type === "pinned" || i.type === "grouped" || i.type === "window") && i.isPinned && i.appId !== "__LAUNCHER__"); - const runningItems = items.filter(i => (i.type === "window" || i.type === "grouped") && i.isRunning && !i.isPinned); - - const pinnedOverflow = maxPinned > 0 && pinnedItems.length > maxPinned; - const runningOverflow = maxRunning > 0 && runningItems.length > maxRunning; - - if (!pinnedOverflow && !runningOverflow) { - root.overflowItemCount = 0; - return items.map(i => markAsVisible(i)); - } - - const visiblePinnedKeys = new Set(pinnedOverflow ? pinnedItems.slice(0, maxPinned).map(i => i.uniqueKey) : pinnedItems.map(i => i.uniqueKey)); - const visibleRunningKeys = new Set(runningOverflow ? runningItems.slice(0, maxRunning).map(i => i.uniqueKey) : runningItems.map(i => i.uniqueKey)); - - const overflowPinnedCount = pinnedOverflow ? pinnedItems.length - maxPinned : 0; - const overflowRunningCount = runningOverflow ? runningItems.length - maxRunning : 0; - const totalOverflow = overflowPinnedCount + overflowRunningCount; - root.overflowItemCount = totalOverflow; - - const finalItems = []; - let addedSeparator = false; - - for (let i = 0; i < items.length; i++) { - const item = items[i]; - switch (item.type) { - case "launcher": - finalItems.push(item); - break; - case "separator": - break; - case "pinned": - case "grouped": - case "window": - if (item.isPinned && item.appId !== "__LAUNCHER__") { - if (visiblePinnedKeys.has(item.uniqueKey)) { - finalItems.push(markAsVisible(item)); - } else { - finalItems.push(markAsOverflow(item)); - } - } else if (item.isRunning && !item.isPinned) { - if (!addedSeparator && finalItems.length > 0) { - finalItems.push(createSeparator("separator_overflow")); - addedSeparator = true; - } - if (visibleRunningKeys.has(item.uniqueKey)) { - finalItems.push(markAsVisible(item)); - } else { - finalItems.push(markAsOverflow(item)); - } - } - break; - } - } - - if (totalOverflow > 0) { - const toggleIndex = finalItems.findIndex(i => i.type === "separator"); - const insertPos = toggleIndex >= 0 ? toggleIndex : finalItems.length; - finalItems.splice(insertPos, 0, { - uniqueKey: "overflow_toggle", - type: "overflow-toggle", - appId: "__OVERFLOW_TOGGLE__", - toplevel: null, - isPinned: false, - isRunning: false, - overflowCount: totalOverflow - }); - } - - return finalItems; - } - - function updateModel() { - const baseResult = buildBaseItems(); - dockItems = applyOverflow(baseResult); - } - - delegate: Item { - id: delegateItem - - property var dockButton: itemData.type === "launcher" ? launcherButton : button - property var itemData: modelData - readonly property bool isOverflowToggle: itemData.type === "overflow-toggle" - readonly property bool isInOverflow: itemData.isInOverflow === true - - clip: false - z: (itemData.type === "launcher" ? launcherButton.dragging : button.dragging) ? 100 : 0 - visible: !isInOverflow || root.overflowExpanded - opacity: (isInOverflow && !root.overflowExpanded) ? 0 : 1 - scale: (isInOverflow && !root.overflowExpanded) ? 0.8 : 1 - - width: (isInOverflow && !root.overflowExpanded) ? 0 : (itemData.type === "separator" ? (root.isVertical ? root.iconSize : 8) : (root.isVertical ? root.iconSize : root.iconSize * 1.2)) - height: (isInOverflow && !root.overflowExpanded) ? 0 : (itemData.type === "separator" ? (root.isVertical ? 8 : root.iconSize) : (root.isVertical ? root.iconSize * 1.2 : root.iconSize)) - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - property real shiftOffset: { - if (root.draggedIndex < 0 || !itemData.isPinned || itemData.type === "separator") - return 0; - if (model.index === root.draggedIndex) - return 0; - - const dragIdx = root.draggedIndex; - const dropIdx = root.dropTargetIndex; - const myIdx = model.index; - const shiftAmount = root.iconSize * 1.2 + layoutFlow.spacing; - - if (dropIdx < 0) - return 0; - if (dragIdx < dropIdx && myIdx > dragIdx && myIdx <= dropIdx) - return -shiftAmount; - if (dragIdx > dropIdx && myIdx >= dropIdx && myIdx < dragIdx) - return shiftAmount; - return 0; - } - - transform: Translate { - x: root.isVertical ? 0 : delegateItem.shiftOffset - y: root.isVertical ? delegateItem.shiftOffset : 0 - - Behavior on x { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - - Behavior on y { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - Rectangle { - visible: itemData.type === "separator" - width: root.isVertical ? root.iconSize * 0.5 : 2 - height: root.isVertical ? 2 : root.iconSize * 0.5 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - radius: 1 - anchors.centerIn: parent - } - - DockOverflowButton { - id: overflowButton - visible: isOverflowToggle - anchors.centerIn: parent - width: delegateItem.width - height: delegateItem.height - actualIconSize: root.iconSize - overflowCount: itemData.overflowCount || 0 - overflowExpanded: root.overflowExpanded - isVertical: root.isVertical - onClicked: root.overflowExpanded = !root.overflowExpanded - } - - DockLauncherButton { - id: launcherButton - visible: itemData.type === "launcher" - anchors.centerIn: parent - width: delegateItem.width - height: delegateItem.height - actualIconSize: root.iconSize - dockApps: root - index: model.index - } - - DockAppButton { - id: button - visible: !isOverflowToggle && itemData.type !== "separator" && itemData.type !== "launcher" - anchors.centerIn: parent - width: delegateItem.width - height: delegateItem.height - actualIconSize: root.iconSize - appData: itemData - contextMenu: root.contextMenu - dockApps: root - index: model.index - parentDockScreen: root.dockScreen - showWindowTitle: itemData?.type === "window" || itemData?.type === "grouped" - windowTitle: { - const title = itemData?.toplevel?.title || "(Unnamed)"; - return title.length > 50 ? title.substring(0, 47) + "..." : title; - } - } - } - } - } - } - - Connections { - target: CompositorService - function onToplevelsChanged() { - repeater.updateModel(); - } - } - - Connections { - target: SessionData - function onPinnedAppsChanged() { - root.suppressShiftAnimation = true; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - repeater.updateModel(); - Qt.callLater(() => { - root.suppressShiftAnimation = false; - }); - } - function onDockLauncherPositionChanged() { - root.suppressShiftAnimation = true; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - repeater.updateModel(); - Qt.callLater(() => { - root.suppressShiftAnimation = false; - }); - } - } - - Connections { - target: SettingsData - function onDockIsolateDisplaysChanged() { - repeater.updateModel(); - } - function onDockLauncherEnabledChanged() { - root.suppressShiftAnimation = true; - root.draggedIndex = -1; - root.dropTargetIndex = -1; - repeater.updateModel(); - Qt.callLater(() => { - root.suppressShiftAnimation = false; - }); - } - function onDockMaxVisibleAppsChanged() { - repeater.updateModel(); - } - function onDockMaxVisibleRunningAppsChanged() { - repeater.updateModel(); - } - } - - onGroupByAppChanged: repeater.updateModel() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockContextMenu.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockContextMenu.qml deleted file mode 100644 index 183f331..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockContextMenu.qml +++ /dev/null @@ -1,585 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Common -import qs.Services -import qs.Widgets - -PanelWindow { - id: root - - WindowBlur { - targetWindow: root - blurX: menuContainer.x - blurY: menuContainer.y - blurWidth: root.visible ? menuContainer.width : 0 - blurHeight: root.visible ? menuContainer.height : 0 - blurRadius: Theme.cornerRadius - } - - WlrLayershell.namespace: "dms:dock-context-menu" - - property var appData: null - property var anchorItem: null - property real dockVisibleHeight: 40 - property int margin: 10 - property bool hidePin: false - property var desktopEntry: null - property bool isDmsWindow: appData?.appId === "org.quickshell" || appData?.appId === "com.danklinux.dms" - property var dockApps: null - - function showForButton(button, data, dockHeight, hidePinOption, entry, dockScreen, parentDockApps) { - if (dockScreen) { - root.screen = dockScreen; - } - - anchorItem = button; - appData = data; - dockVisibleHeight = dockHeight || 40; - hidePin = hidePinOption || false; - desktopEntry = entry || null; - dockApps = parentDockApps || null; - - visible = true; - } - function close() { - visible = false; - } - - screen: null - visible: false - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - anchors { - top: true - left: true - right: true - bottom: true - } - - property point anchorPos: Qt.point(screen.width / 2, screen.height - 100) - - onAnchorItemChanged: updatePosition() - onVisibleChanged: { - if (visible) { - updatePosition(); - } - } - - function updatePosition() { - if (!anchorItem) { - anchorPos = Qt.point(screen.width / 2, screen.height - 100); - return; - } - - const dockWindow = anchorItem.Window.window; - if (!dockWindow) { - anchorPos = Qt.point(screen.width / 2, screen.height - 100); - return; - } - - const buttonPosInDock = anchorItem.mapToItem(dockWindow.contentItem, 0, 0); - let actualDockHeight = root.dockVisibleHeight; - - function findDockBackground(item) { - if (item.objectName === "dockBackground") { - return item; - } - for (var i = 0; i < item.children.length; i++) { - const found = findDockBackground(item.children[i]); - if (found) { - return found; - } - } - return null; - } - - const dockBackground = findDockBackground(dockWindow.contentItem); - let actualDockWidth = dockWindow.width; - if (dockBackground) { - actualDockHeight = dockBackground.height; - actualDockWidth = dockBackground.width; - } - - const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right; - const dockMargin = SettingsData.dockMargin + 16; - let buttonScreenX, buttonScreenY; - - if (isVertical) { - const dockContentHeight = dockWindow.height; - const screenHeight = root.screen.height; - const dockTopMargin = Math.round((screenHeight - dockContentHeight) / 2); - buttonScreenY = dockTopMargin + buttonPosInDock.y + anchorItem.height / 2; - - if (SettingsData.dockPosition === SettingsData.Position.Right) { - buttonScreenX = root.screen.width - actualDockWidth - dockMargin - 20; - } else { - buttonScreenX = actualDockWidth + dockMargin + 20; - } - } else { - const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom; - - if (isDockAtBottom) { - buttonScreenY = root.screen.height - actualDockHeight - dockMargin - 20; - } else { - buttonScreenY = actualDockHeight + dockMargin + 20; - } - - const dockContentWidth = dockWindow.width; - const screenWidth = root.screen.width; - const dockLeftMargin = Math.round((screenWidth - dockContentWidth) / 2); - buttonScreenX = dockLeftMargin + buttonPosInDock.x + anchorItem.width / 2; - } - - anchorPos = Qt.point(buttonScreenX, buttonScreenY); - } - - Rectangle { - id: menuContainer - - x: { - const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right; - if (isVertical) { - const isDockAtRight = SettingsData.dockPosition === SettingsData.Position.Right; - if (isDockAtRight) { - return Math.max(10, root.anchorPos.x - width + 30); - } else { - return Math.min(root.width - width - 10, root.anchorPos.x - 30); - } - } else { - const left = 10; - const right = root.width - width - 10; - const want = root.anchorPos.x - width / 2; - return Math.max(left, Math.min(right, want)); - } - } - y: { - const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right; - if (isVertical) { - const top = 10; - const bottom = root.height - height - 10; - const want = root.anchorPos.y - height / 2; - return Math.max(top, Math.min(bottom, want)); - } else { - const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom; - if (isDockAtBottom) { - return Math.max(10, root.anchorPos.y - height + 30); - } else { - return Math.min(root.height - height - 10, root.anchorPos.y - 30); - } - } - } - - width: Math.min(400, Math.max(180, menuColumn.implicitWidth + Theme.spacingS * 2)) - height: menuColumn.implicitHeight + Theme.spacingS * 2 - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: BlurService.enabled ? BlurService.borderColor : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: BlurService.enabled ? BlurService.borderWidth : 1 - - opacity: root.visible ? 1 : 0 - visible: opacity > 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: -1 - } - - Column { - id: menuColumn - width: parent.width - Theme.spacingS * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingS - spacing: 1 - - // Window list for grouped apps - Repeater { - model: { - if (!root.appData || root.appData.type !== "grouped") - return []; - - const toplevels = []; - const allToplevels = ToplevelManager.toplevels.values; - for (let i = 0; i < allToplevels.length; i++) { - const toplevel = allToplevels[i]; - if (toplevel.appId === root.appData.appId) { - toplevels.push(toplevel); - } - } - return toplevels; - } - - Rectangle { - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: windowArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: closeButton.left - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - text: (modelData && modelData.title) ? modelData.title : I18n.tr("(Unnamed)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - Rectangle { - id: closeButton - anchors.right: parent.right - anchors.rightMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - width: 20 - height: 20 - radius: 10 - color: closeMouseArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.2) : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "close" - size: 12 - color: closeMouseArea.containsMouse ? Theme.error : Theme.surfaceText - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData && modelData.close) { - modelData.close(); - } - root.close(); - } - } - } - - DankRipple { - id: windowRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: windowArea - anchors.fill: parent - anchors.rightMargin: 24 - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => windowRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (modelData && modelData.activate) { - modelData.activate(); - } - root.close(); - } - } - } - } - - Rectangle { - visible: { - if (!root.appData) - return false; - if (root.appData.type !== "grouped") - return false; - return root.appData.windowCount > 0; - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Repeater { - model: root.desktopEntry && root.desktopEntry.actions ? root.desktopEntry.actions : [] - - Rectangle { - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: actionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Item { - anchors.verticalCenter: parent.verticalCenter - width: 16 - height: 16 - visible: modelData.icon && modelData.icon !== "" - - IconImage { - anchors.fill: parent - source: modelData.icon ? Paths.resolveIconPath(modelData.icon) : "" - smooth: true - asynchronous: true - visible: status === Image.Ready - } - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: modelData.name || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - - DankRipple { - id: actionRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: actionArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => actionRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (modelData) { - SessionService.launchDesktopAction(root.desktopEntry, modelData); - } - root.close(); - } - } - } - } - - Rectangle { - visible: { - if (!root.desktopEntry?.actions || root.desktopEntry.actions.length === 0) { - return false; - } - return !root.hidePin || (!root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand); - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Rectangle { - visible: !root.hidePin - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: pinArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: root.appData && root.appData.isPinned ? "keep_off" : "push_pin" - size: 14 - color: Theme.surfaceText - opacity: 0.7 - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: root.appData && root.appData.isPinned ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - - DankRipple { - id: pinRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: pinArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (!root.appData) - return; - - if (root.appData.isPinned) { - SessionData.removePinnedApp(root.appData.appId); - } else { - SessionData.addPinnedApp(root.appData.appId); - } - root.close(); - } - } - } - - Rectangle { - visible: { - const hasNvidia = !root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand; - const hasWindow = root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0)); - const hasPinOption = !root.hidePin; - const hasContentAbove = hasPinOption || hasNvidia; - return hasContentAbove && hasWindow; - } - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - Rectangle { - visible: !root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: nvidiaArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "memory" - size: 14 - color: Theme.surfaceText - opacity: 0.7 - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Launch on dGPU") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - - DankRipple { - id: nvidiaRipple - rippleColor: Theme.surfaceText - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: nvidiaArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => nvidiaRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (root.desktopEntry) { - SessionService.launchDesktopEntry(root.desktopEntry, true); - } - root.close(); - } - } - } - - Rectangle { - visible: root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0)) - width: parent.width - height: 28 - radius: Theme.cornerRadius - color: closeArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankIcon { - anchors.verticalCenter: parent.verticalCenter - name: "close" - size: 14 - color: closeArea.containsMouse ? Theme.error : Theme.surfaceText - opacity: 0.7 - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: root.appData && root.appData.type === "grouped" ? I18n.tr("Close All Windows") : I18n.tr("Close Window") - font.pixelSize: Theme.fontSizeSmall - color: closeArea.containsMouse ? Theme.error : Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - - DankRipple { - id: closeRipple - rippleColor: Theme.error - cornerRadius: Theme.cornerRadius - } - - MouseArea { - id: closeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: mouse => closeRipple.trigger(mouse.x, mouse.y) - onClicked: { - if (root.appData?.type === "window") { - root.appData?.toplevel?.close(); - } else if (root.appData?.type === "grouped") { - root.appData?.allWindows?.forEach(window => window.toplevel?.close()); - } - root.close(); - } - } - } - } - } - - MouseArea { - anchors.fill: parent - z: -1 - onClicked: root.close() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockLauncherButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockLauncherButton.qml deleted file mode 100644 index 84b52ba..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockLauncherButton.qml +++ /dev/null @@ -1,296 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell.Widgets -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - clip: false - property var dockApps: null - property int index: -1 - property bool longPressing: false - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property real dragAxisOffset: 0 - property int targetIndex: -1 - property int originalIndex: -1 - property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right - property bool isHovered: mouseArea.containsMouse && !dragging - property bool showTooltip: mouseArea.containsMouse && !dragging - property real actualIconSize: 40 - - readonly property string tooltipText: I18n.tr("Applications") - - readonly property color effectiveLogoColor: { - const override = SettingsData.dockLauncherLogoColorOverride; - if (override === "primary") - return Theme.primary; - if (override === "surface") - return Theme.surfaceText; - if (override !== "") - return override; - return Theme.surfaceText; - } - - onIsHoveredChanged: { - if (mouseArea.pressed || dragging) - return; - if (isHovered) { - exitAnimation.stop(); - if (!bounceAnimation.running) { - bounceAnimation.restart(); - } - } else { - bounceAnimation.stop(); - exitAnimation.restart(); - } - } - - readonly property bool animateX: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right - readonly property real animationDistance: actualIconSize - readonly property real animationDirection: { - if (SettingsData.dockPosition === SettingsData.Position.Bottom) - return -1; - if (SettingsData.dockPosition === SettingsData.Position.Top) - return 1; - if (SettingsData.dockPosition === SettingsData.Position.Right) - return -1; - if (SettingsData.dockPosition === SettingsData.Position.Left) - return 1; - return -1; - } - - SequentialAnimation { - id: bounceAnimation - - running: false - - NumberAnimation { - target: root - property: "hoverAnimOffset" - to: animationDirection * animationDistance * 0.25 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedAccel - } - - NumberAnimation { - target: root - property: "hoverAnimOffset" - to: animationDirection * animationDistance * 0.2 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedDecel - } - } - - NumberAnimation { - id: exitAnimation - - running: false - target: root - property: "hoverAnimOffset" - to: 0 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedDecel - } - - Timer { - id: longPressTimer - - interval: 500 - repeat: false - onTriggered: { - longPressing = true; - } - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - hoverEnabled: true - enabled: true - preventStealing: dragging || longPressing - cursorShape: longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - onPressed: mouse => { - if (mouse.button === Qt.LeftButton) { - dragStartPos = Qt.point(mouse.x, mouse.y); - longPressTimer.start(); - } - } - onReleased: mouse => { - longPressTimer.stop(); - - const wasDragging = dragging; - const didReorder = wasDragging && targetIndex >= 0 && dockApps; - - if (didReorder) { - SessionData.setDockLauncherPosition(targetIndex); - } - - longPressing = false; - dragging = false; - dragAxisOffset = 0; - targetIndex = -1; - originalIndex = -1; - - if (dockApps) { - dockApps.draggedIndex = -1; - dockApps.dropTargetIndex = -1; - } - - if (wasDragging || mouse.button !== Qt.LeftButton) - return; - - PopoutService.toggleDankLauncherV2(); - } - onPositionChanged: mouse => { - if (longPressing && !dragging) { - const distance = Math.sqrt(Math.pow(mouse.x - dragStartPos.x, 2) + Math.pow(mouse.y - dragStartPos.y, 2)); - if (distance > 5) { - dragging = true; - targetIndex = index; - originalIndex = index; - if (dockApps) { - dockApps.draggedIndex = index; - dockApps.dropTargetIndex = index; - } - } - } - - if (!dragging || !dockApps) - return; - - const axisOffset = isVertical ? (mouse.y - dragStartPos.y) : (mouse.x - dragStartPos.x); - dragAxisOffset = axisOffset; - - const spacing = Math.min(8, Math.max(4, actualIconSize * 0.08)); - const itemSize = actualIconSize * 1.2 + spacing; - const slotOffset = Math.round(axisOffset / itemSize); - const newTargetIndex = Math.max(0, Math.min(dockApps.pinnedAppCount, originalIndex + slotOffset)); - - if (newTargetIndex !== targetIndex) { - targetIndex = newTargetIndex; - dockApps.dropTargetIndex = newTargetIndex; - } - } - } - - property real hoverAnimOffset: 0 - - Item { - id: visualContent - anchors.fill: parent - - transform: Translate { - x: dragging && !isVertical ? dragAxisOffset : (!dragging && isVertical ? hoverAnimOffset : 0) - y: dragging && isVertical ? dragAxisOffset : (!dragging && !isVertical ? hoverAnimOffset : 0) - } - - Item { - anchors.centerIn: parent - width: actualIconSize - height: actualIconSize - - DankIcon { - visible: SettingsData.dockLauncherLogoMode === "apps" - anchors.centerIn: parent - name: "apps" - size: actualIconSize - 4 - color: Theme.widgetIconColor - } - - SystemLogo { - visible: SettingsData.dockLauncherLogoMode === "os" - anchors.centerIn: parent - width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - colorOverride: effectiveLogoColor - brightnessOverride: SettingsData.dockLauncherLogoBrightness - contrastOverride: SettingsData.dockLauncherLogoContrast - } - - IconImage { - visible: SettingsData.dockLauncherLogoMode === "dank" - anchors.centerIn: parent - width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - smooth: true - mipmap: true - asynchronous: true - source: "file://" + Theme.shellDir + "/assets/danklogo.svg" - layer.enabled: effectiveLogoColor !== "" - layer.smooth: true - layer.mipmap: true - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: effectiveLogoColor - } - } - - IconImage { - visible: SettingsData.dockLauncherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle || CompositorService.isLabwc) - anchors.centerIn: parent - width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - smooth: true - asynchronous: true - source: { - if (CompositorService.isNiri) { - return "file://" + Theme.shellDir + "/assets/niri.svg"; - } else if (CompositorService.isHyprland) { - return "file://" + Theme.shellDir + "/assets/hyprland.svg"; - } else if (CompositorService.isDwl) { - return "file://" + Theme.shellDir + "/assets/mango.png"; - } else if (CompositorService.isSway) { - return "file://" + Theme.shellDir + "/assets/sway.svg"; - } else if (CompositorService.isScroll) { - return "file://" + Theme.shellDir + "/assets/sway.svg"; - } else if (CompositorService.isMiracle) { - return "file://" + Theme.shellDir + "/assets/miraclewm.svg"; - } else if (CompositorService.isLabwc) { - return "file://" + Theme.shellDir + "/assets/labwc.png"; - } - return ""; - } - layer.enabled: effectiveLogoColor !== "" - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: effectiveLogoColor - brightness: { - SettingsData.dockLauncherLogoBrightness; - } - contrast: { - SettingsData.dockLauncherLogoContrast; - } - } - } - - IconImage { - visible: SettingsData.dockLauncherLogoMode === "custom" && SettingsData.dockLauncherLogoCustomPath !== "" - anchors.centerIn: parent - width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset - smooth: true - asynchronous: true - source: SettingsData.dockLauncherLogoCustomPath ? "file://" + SettingsData.dockLauncherLogoCustomPath.replace("file://", "") : "" - layer.enabled: effectiveLogoColor !== "" - layer.effect: MultiEffect { - saturation: 0 - colorization: 1 - colorizationColor: effectiveLogoColor - brightness: SettingsData.dockLauncherLogoBrightness - contrast: SettingsData.dockLauncherLogoContrast - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockOverflowButton.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockOverflowButton.qml deleted file mode 100644 index 0d6b439..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Dock/DockOverflowButton.qml +++ /dev/null @@ -1,75 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Item { - id: root - - property real actualIconSize: 40 - property int overflowCount: 0 - property bool overflowExpanded: false - property bool isVertical: false - - signal clicked - - Rectangle { - id: buttonBackground - anchors.centerIn: parent - width: actualIconSize - height: actualIconSize - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, mouseArea.containsMouse ? 0.2 : 0.1) - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - DankIcon { - id: arrowIcon - anchors.centerIn: parent - size: actualIconSize * 0.6 - name: "expand_more" - color: Theme.surfaceText - rotation: isVertical ? (overflowExpanded ? 180 : 0) : (overflowExpanded ? 90 : -90) - - Behavior on rotation { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - } - } - - Rectangle { - visible: overflowCount > 0 && !overflowExpanded && SettingsData.dockShowOverflowBadge - anchors.right: buttonBackground.right - anchors.top: buttonBackground.top - anchors.rightMargin: -4 - anchors.topMargin: -4 - width: Math.max(18, badgeText.width + 8) - height: 18 - radius: 9 - color: Theme.primary - z: 10 - - StyledText { - id: badgeText - anchors.centerIn: parent - text: `+${overflowCount}` - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Bold - color: Theme.onPrimary - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.clicked() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdEnv.js b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdEnv.js deleted file mode 100644 index fcce181..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdEnv.js +++ /dev/null @@ -1,20 +0,0 @@ -.pragma library - -function readBoolOverride(envReader, names, fallbackValue) { - for (let i = 0; i < names.length; i++) { - const name = names[i]; - const raw = envReader(name); - if (raw === undefined || raw === null || raw === "") - continue; - - const normalized = String(raw).trim().toLowerCase(); - if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") - return true; - if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") - return false; - - console.warn("Invalid boolean override for", name + ":", raw, "- trying next override/fallback"); - } - - return fallbackValue; -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdMemory.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdMemory.qml deleted file mode 100644 index da949d3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdMemory.qml +++ /dev/null @@ -1,128 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import "GreetdEnv.js" as GreetdEnv - -Singleton { - id: root - - readonly property string greetCfgDir: Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter" - readonly property string sessionConfigPath: greetCfgDir + "/session.json" - readonly property string memoryFile: greetCfgDir + "/.local/state/memory.json" - readonly property bool rememberLastSession: GreetdEnv.readBoolOverride(Quickshell.env, ["DMS_GREET_REMEMBER_LAST_SESSION", "DMS_SAVE_SESSION"], true) - readonly property bool rememberLastUser: GreetdEnv.readBoolOverride(Quickshell.env, ["DMS_GREET_REMEMBER_LAST_USER", "DMS_SAVE_USERNAME"], true) - - property string lastSessionId: "" - property string lastSuccessfulUser: "" - property bool memoryReady: false - property bool isLightMode: false - property bool nightModeEnabled: false - - Component.onCompleted: { - loadMemory(); - loadSessionConfig(); - } - - function loadMemory() { - parseMemory(memoryFileView.text()); - } - - function loadSessionConfig() { - parseSessionConfig(sessionConfigFileView.text()); - } - - function parseSessionConfig(content) { - try { - if (content && content.trim()) { - const config = JSON.parse(content); - isLightMode = config.isLightMode !== undefined ? config.isLightMode : false; - nightModeEnabled = config.nightModeEnabled !== undefined ? config.nightModeEnabled : false; - } - } catch (e) { - console.warn("Failed to parse greeter session config:", e); - } - } - - function parseMemory(content) { - try { - if (!content || !content.trim()) - return; - const memory = JSON.parse(content); - lastSessionId = rememberLastSession ? (memory.lastSessionId || "") : ""; - lastSuccessfulUser = rememberLastUser ? (memory.lastSuccessfulUser || "") : ""; - if (!rememberLastSession || !rememberLastUser) - saveMemory(); - } catch (e) { - console.warn("Failed to parse greetd memory:", e); - } - } - - function saveMemory() { - let memory = {}; - if (rememberLastSession && lastSessionId) - memory.lastSessionId = lastSessionId; - if (rememberLastUser && lastSuccessfulUser) - memory.lastSuccessfulUser = lastSuccessfulUser; - memoryFileView.setText(JSON.stringify(memory, null, 2)); - } - - function setLastSessionId(id) { - if (!rememberLastSession) { - if (lastSessionId !== "") { - lastSessionId = ""; - saveMemory(); - } - return; - } - lastSessionId = id || ""; - saveMemory(); - } - - function setLastSuccessfulUser(username) { - if (!rememberLastUser) { - if (lastSuccessfulUser !== "") { - lastSuccessfulUser = ""; - saveMemory(); - } - return; - } - lastSuccessfulUser = username || ""; - saveMemory(); - } - - FileView { - id: memoryFileView - path: root.memoryFile - blockLoading: false - blockWrites: false - atomicWrites: true - watchChanges: false - printErrors: false - onLoaded: { - parseMemory(memoryFileView.text()); - root.memoryReady = true; - } - onLoadFailed: { - root.memoryReady = true; - } - } - - FileView { - id: sessionConfigFileView - path: root.sessionConfigPath - blockLoading: false - blockWrites: true - atomicWrites: false - watchChanges: false - printErrors: true - onLoaded: { - parseSessionConfig(sessionConfigFileView.text()); - } - onLoadFailed: error => { - console.warn("Could not load greeter session config from", root.sessionConfigPath, "error:", error); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdSettings.qml deleted file mode 100644 index e1f670c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreetdSettings.qml +++ /dev/null @@ -1,199 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import "GreetdEnv.js" as GreetdEnv - -Singleton { - id: root - - readonly property string configPath: { - const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter"; - return greetCfgDir + "/settings.json"; - } - - readonly property string _greeterCacheDir: { - const i = root.configPath.lastIndexOf("/"); - return i >= 0 ? root.configPath.substring(0, i) : ""; - } - readonly property string greeterWallpaperOverridePath: root._greeterCacheDir ? (root._greeterCacheDir + "/greeter_wallpaper_override.jpg") : "" - - property string currentThemeName: "purple" - property bool settingsLoaded: false - property string customThemeFile: "" - property var registryThemeVariants: ({}) - property string matugenScheme: "scheme-tonal-spot" - property bool use24HourClock: true - property bool showSeconds: false - property bool padHours12Hour: false - property bool greeterUse24HourClock: true - property bool greeterShowSeconds: false - property bool greeterPadHours12Hour: false - property string greeterLockDateFormat: "" - property string greeterFontFamily: "" - property string greeterWallpaperFillMode: "" - property bool useFahrenheit: false - property bool nightModeEnabled: false - property string weatherLocation: "New York, NY" - property string weatherCoordinates: "40.7128,-74.0060" - property bool useAutoLocation: false - property bool weatherEnabled: true - property string iconTheme: "System Default" - property bool useOSLogo: false - property string osLogoColorOverride: "" - property real osLogoBrightness: 0.5 - property real osLogoContrast: 1 - property string fontFamily: "Inter Variable" - property string monoFontFamily: "Fira Code" - property int fontWeight: Font.Normal - property real fontScale: 1.0 - property real cornerRadius: 12 - property string widgetBackgroundColor: "sch" - property string lockDateFormat: "" - property bool lockScreenShowPowerActions: true - property bool lockScreenShowProfileImage: true - property bool rememberLastSession: true - property bool rememberLastUser: true - property bool greeterEnableFprint: false - property bool greeterEnableU2f: false - property string greeterWallpaperPath: "" - property bool powerActionConfirm: true - property real powerActionHoldDuration: 0.5 - property var powerMenuActions: ["reboot", "logout", "poweroff", "lock", "suspend", "restart"] - property string powerMenuDefaultAction: "logout" - property bool powerMenuGridLayout: false - property var screenPreferences: ({}) - property int animationSpeed: 2 - property string wallpaperFillMode: "Fill" - - function parseSettings(content) { - try { - let settings = {}; - if (content && content.trim()) { - settings = JSON.parse(content); - } - - const envRememberLastSession = GreetdEnv.readBoolOverride(Quickshell.env, ["DMS_GREET_REMEMBER_LAST_SESSION", "DMS_SAVE_SESSION"], undefined); - const envRememberLastUser = GreetdEnv.readBoolOverride(Quickshell.env, ["DMS_GREET_REMEMBER_LAST_USER", "DMS_SAVE_USERNAME"], undefined); - - currentThemeName = settings.currentThemeName !== undefined ? settings.currentThemeName : "purple"; - customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : ""; - registryThemeVariants = settings.registryThemeVariants !== undefined ? - settings.registryThemeVariants : ({}); - matugenScheme = settings.matugenScheme !== undefined ? settings.matugenScheme : "scheme-tonal-spot"; - use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true; - showSeconds = settings.showSeconds !== undefined ? settings.showSeconds : false; - padHours12Hour = settings.padHours12Hour !== undefined ? settings.padHours12Hour : false; - greeterUse24HourClock = settings.greeterUse24HourClock !== undefined ? settings.greeterUse24HourClock : use24HourClock; - greeterShowSeconds = settings.greeterShowSeconds !== undefined ? settings.greeterShowSeconds : showSeconds; - greeterPadHours12Hour = settings.greeterPadHours12Hour !== undefined ? settings.greeterPadHours12Hour : padHours12Hour; - greeterLockDateFormat = settings.greeterLockDateFormat !== undefined ? settings.greeterLockDateFormat : ""; - greeterFontFamily = settings.greeterFontFamily !== undefined ? settings.greeterFontFamily : ""; - greeterWallpaperFillMode = settings.greeterWallpaperFillMode !== undefined ? settings.greeterWallpaperFillMode : ""; - useFahrenheit = settings.useFahrenheit !== undefined ? settings.useFahrenheit : false; - nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false; - weatherLocation = settings.weatherLocation !== undefined ? settings.weatherLocation : "New York, NY"; - weatherCoordinates = settings.weatherCoordinates !== undefined ? settings.weatherCoordinates : "40.7128,-74.0060"; - useAutoLocation = settings.useAutoLocation !== undefined ? settings.useAutoLocation : false; - weatherEnabled = settings.weatherEnabled !== undefined ? settings.weatherEnabled : true; - iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default"; - useOSLogo = settings.useOSLogo !== undefined ? settings.useOSLogo : false; - osLogoColorOverride = settings.osLogoColorOverride !== undefined ? settings.osLogoColorOverride : ""; - osLogoBrightness = settings.osLogoBrightness !== undefined ? settings.osLogoBrightness : 0.5; - osLogoContrast = settings.osLogoContrast !== undefined ? settings.osLogoContrast : 1; - fontFamily = settings.fontFamily !== undefined ? settings.fontFamily : Theme.defaultFontFamily; - monoFontFamily = settings.monoFontFamily !== undefined ? settings.monoFontFamily : Theme.defaultMonoFontFamily; - fontWeight = settings.fontWeight !== undefined ? settings.fontWeight : Font.Normal; - fontScale = settings.fontScale !== undefined ? settings.fontScale : 1.0; - cornerRadius = settings.cornerRadius !== undefined ? settings.cornerRadius : 12; - widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"; - lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : ""; - lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true; - lockScreenShowProfileImage = settings.lockScreenShowProfileImage !== undefined ? settings.lockScreenShowProfileImage : true; - if (envRememberLastSession !== undefined) { - rememberLastSession = envRememberLastSession; - } else { - rememberLastSession = settings.greeterRememberLastSession !== undefined ? settings.greeterRememberLastSession : settings.rememberLastSession !== undefined ? settings.rememberLastSession : true; - } - if (envRememberLastUser !== undefined) { - rememberLastUser = envRememberLastUser; - } else { - rememberLastUser = settings.greeterRememberLastUser !== undefined ? settings.greeterRememberLastUser : settings.rememberLastUser !== undefined ? settings.rememberLastUser : true; - } - greeterEnableFprint = settings.greeterEnableFprint !== undefined ? settings.greeterEnableFprint : false; - greeterEnableU2f = settings.greeterEnableU2f !== undefined ? settings.greeterEnableU2f : false; - greeterWallpaperPath = settings.greeterWallpaperPath !== undefined ? settings.greeterWallpaperPath : ""; - powerActionConfirm = settings.powerActionConfirm !== undefined ? settings.powerActionConfirm : true; - powerActionHoldDuration = settings.powerActionHoldDuration !== undefined ? settings.powerActionHoldDuration : 0.5; - powerMenuActions = settings.powerMenuActions !== undefined ? settings.powerMenuActions : ["reboot", "logout", "poweroff", "lock", "suspend", "restart"]; - powerMenuDefaultAction = settings.powerMenuDefaultAction !== undefined ? settings.powerMenuDefaultAction : "logout"; - powerMenuGridLayout = settings.powerMenuGridLayout !== undefined ? settings.powerMenuGridLayout : false; - screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({}); - animationSpeed = settings.animationSpeed !== undefined ? settings.animationSpeed : 2; - wallpaperFillMode = settings.wallpaperFillMode !== undefined ? settings.wallpaperFillMode : "Fill"; - - if (typeof Theme !== "undefined") { - if (currentThemeName === "custom" && customThemeFile) { - Theme.loadCustomThemeFromFile(customThemeFile); - } - Theme.applyGreeterTheme(currentThemeName); - } - } catch (e) { - console.warn("Failed to parse greetd settings:", e); - } finally { - settingsLoaded = true; - } - } - - function getEffectiveTimeFormat() { - const use24 = greeterUse24HourClock; - const secs = greeterShowSeconds; - const pad = greeterPadHours12Hour; - if (use24) - return secs ? "hh:mm:ss" : "hh:mm"; - if (pad) - return secs ? "hh:mm:ss AP" : "hh:mm AP"; - return secs ? "h:mm:ss AP" : "h:mm AP"; - } - - function getEffectiveLockDateFormat() { - const fmt = (greeterLockDateFormat !== undefined && greeterLockDateFormat !== "") ? greeterLockDateFormat : lockDateFormat; - return fmt && fmt.length > 0 ? fmt : Locale.LongFormat; - } - - function getEffectiveWallpaperFillMode() { - return (greeterWallpaperFillMode && greeterWallpaperFillMode !== "") ? greeterWallpaperFillMode : wallpaperFillMode; - } - - function getEffectiveFontFamily() { - return (greeterFontFamily && greeterFontFamily !== "") ? greeterFontFamily : fontFamily; - } - - function getFilteredScreens(componentId) { - const prefs = screenPreferences && screenPreferences[componentId] || ["all"]; - if (prefs.includes("all")) { - return Quickshell.screens; - } - return Quickshell.screens.filter(screen => prefs.includes(screen.name)); - } - - FileView { - id: settingsFile - path: root.configPath - blockLoading: false - blockWrites: true - atomicWrites: false - watchChanges: false - printErrors: true - onLoaded: { - parseSettings(settingsFile.text()); - } - onLoadFailed: error => { - console.warn("Failed to load greetd settings:", error); - root.parseSettings(""); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml deleted file mode 100644 index fa82315..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml +++ /dev/null @@ -1,1908 +0,0 @@ -import QtCore -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import Qt.labs.folderlistmodel -import Quickshell -import Quickshell.Hyprland -import Quickshell.Io -import Quickshell.Services.Greetd -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Lock - -Item { - id: root - - function encodeFileUrl(path) { - if (!path) - return ""; - return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/'); - } - - readonly property string xdgDataDirs: Quickshell.env("XDG_DATA_DIRS") - property string screenName: "" - property string hyprlandCurrentLayout: "" - property string hyprlandKeyboard: "" - property int hyprlandLayoutCount: 0 - property bool isPrimaryScreen: !Quickshell.screens?.length || screenName === Quickshell.screens[0]?.name - - signal launchRequested - - property bool weatherInitialized: false - property bool awaitingExternalAuth: false - property bool pendingPasswordResponse: false - property bool passwordSubmitRequested: false - property bool cancelingExternalAuthForPassword: false - property int defaultAuthTimeoutMs: 10000 - property int externalAuthTimeoutMs: 30000 - property int memoryFlushDelayMs: 120 - property string pendingLaunchCommand: "" - property var pendingLaunchEnv: [] - property int passwordFailureCount: 0 - property int passwordAttemptLimitHint: 0 - property string authFeedbackMessage: "" - property string greetdPamText: "" - property string systemAuthPamText: "" - property string commonAuthPamText: "" - property string passwordAuthPamText: "" - property string systemLoginPamText: "" - property string systemLocalLoginPamText: "" - property string commonAuthPcPamText: "" - property string loginPamText: "" - property string faillockConfigText: "" - property bool greeterWallpaperOverrideExists: false - property string externalAuthAutoStartedForUser: "" - property int passwordSessionTransitionRetryCount: 0 - property int maxPasswordSessionTransitionRetries: 2 - property bool fprintdProbeComplete: false - property bool fprintdHasDevice: false - // Falls back to PAM-only detection until the fprintd D-Bus probe completes. - readonly property bool greeterPamHasFprint: greeterPamStackHasModule("pam_fprintd") && (!fprintdProbeComplete || fprintdHasDevice) - readonly property bool greeterPamHasU2f: greeterPamStackHasModule("pam_u2f") - readonly property bool greeterExternalAuthAvailable: (greeterPamHasFprint && GreetdSettings.greeterEnableFprint) || (greeterPamHasU2f && GreetdSettings.greeterEnableU2f) - readonly property bool greeterPamHasExternalAuth: greeterPamHasFprint || greeterPamHasU2f - - function initWeatherService() { - if (weatherInitialized) - return; - if (!GreetdSettings.settingsLoaded) - return; - if (!GreetdSettings.weatherEnabled) - return; - weatherInitialized = true; - WeatherService.addRef(); - WeatherService.forceRefresh(); - } - - function stripPamComment(line) { - if (!line) - return ""; - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("//")) - return ""; - const hashIdx = trimmed.indexOf("//"); - if (hashIdx >= 0) - return trimmed.substring(0, hashIdx).trim(); - return trimmed; - } - - function pamModuleEnabled(pamText, moduleName) { - if (!pamText || !moduleName) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (line.includes(moduleName)) - return true; - } - return false; - } - - function pamTextIncludesFile(pamText, filename) { - if (!pamText || !filename) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (line.includes(filename) && (line.includes("include") || line.includes("substack") || line.startsWith("@include"))) - return true; - } - return false; - } - - function greeterPamStackHasModule(moduleName) { - if (pamModuleEnabled(greetdPamText, moduleName)) - return true; - const includedPamStacks = [ - ["system-auth", systemAuthPamText], - ["common-auth", commonAuthPamText], - ["password-auth", passwordAuthPamText], - ["system-login", systemLoginPamText], - ["system-local-login", systemLocalLoginPamText], - ["common-auth-pc", commonAuthPcPamText], - ["login", loginPamText] - ]; - for (let i = 0; i < includedPamStacks.length; i++) { - const stack = includedPamStacks[i]; - if (pamTextIncludesFile(greetdPamText, stack[0]) && pamModuleEnabled(stack[1], moduleName)) - return true; - } - return false; - } - - function usesPamLockoutPolicy(pamText) { - if (!pamText) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (line.includes("pam_faillock.so") || line.includes("pam_tally2.so") || line.includes("pam_tally.so")) - return true; - } - return false; - } - - function parsePamLineDenyValue(pamText) { - if (!pamText) - return -1; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (!line.includes("pam_faillock.so") && !line.includes("pam_tally2.so") && !line.includes("pam_tally.so")) - continue; - const denyMatch = line.match(/\bdeny\s*=\s*(\d+)\b/i); - if (!denyMatch) - continue; - const parsed = parseInt(denyMatch[1], 10); - if (!isNaN(parsed)) - return parsed; - } - return -1; - } - - function parseFaillockDenyValue(configText) { - if (!configText) - return -1; - const lines = configText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - const denyMatch = line.match(/^deny\s*=\s*(\d+)\s*$/i); - if (!denyMatch) - continue; - const parsed = parseInt(denyMatch[1], 10); - if (!isNaN(parsed)) - return parsed; - } - return -1; - } - - function refreshPasswordAttemptPolicyHint() { - const pamSources = [greetdPamText, systemAuthPamText, commonAuthPamText, passwordAuthPamText, systemLoginPamText, systemLocalLoginPamText, commonAuthPcPamText, loginPamText]; - let lockoutConfigured = false; - let denyFromPam = -1; - for (let i = 0; i < pamSources.length; i++) { - const source = pamSources[i]; - if (!source) - continue; - if (usesPamLockoutPolicy(source)) - lockoutConfigured = true; - const denyValue = parsePamLineDenyValue(source); - if (denyValue >= 0 && (denyFromPam < 0 || denyValue < denyFromPam)) - denyFromPam = denyValue; - } - - if (!lockoutConfigured) { - passwordAttemptLimitHint = 0; - return; - } - - const denyFromConfig = parseFaillockDenyValue(faillockConfigText); - if (denyFromConfig >= 0) { - passwordAttemptLimitHint = denyFromConfig; - return; - } - - if (denyFromPam >= 0) { - passwordAttemptLimitHint = denyFromPam; - return; - } - - // pam_faillock default deny value when no explicit config is set. - passwordAttemptLimitHint = 3; - } - - function isLikelyLockoutMessage(message) { - const lower = (message || "").toLowerCase(); - return lower.includes("account is locked") || lower.includes("too many") || lower.includes("maximum number of") || lower.includes("auth_err"); - } - - function currentAuthMessage() { - if (GreeterState.pamState === "error") - return I18n.tr("Authentication error - try again"); - if (GreeterState.pamState === "max") - return I18n.tr("Too many failed attempts - account may be locked"); - if (GreeterState.pamState === "fail") { - if (passwordAttemptLimitHint > 0) { - const attempt = Math.max(1, Math.min(passwordFailureCount, passwordAttemptLimitHint)); - const remaining = Math.max(passwordAttemptLimitHint - attempt, 0); - if (remaining > 0) { - return I18n.tr("Incorrect password - attempt %1 of %2 (lockout may follow)").arg(attempt).arg(passwordAttemptLimitHint); - } - return I18n.tr("Incorrect password - next failures may trigger account lockout"); - } - return I18n.tr("Incorrect password"); - } - return ""; - } - - function clearAuthFeedback() { - GreeterState.pamState = ""; - authFeedbackMessage = ""; - } - - function resetPasswordSessionTransition(clearSubmitRequest) { - cancelingExternalAuthForPassword = false; - passwordSessionTransitionRetryCount = 0; - if (clearSubmitRequest) - passwordSubmitRequested = false; - } - - Connections { - target: GreetdSettings - function onSettingsLoadedChanged() { - if (GreetdSettings.settingsLoaded) { - initWeatherService(); - if (isPrimaryScreen) { - applyLastSuccessfulUser(); - finalizeSessionSelection(); - } - } - } - - function onRememberLastUserChanged() { - if (!isPrimaryScreen) - return; - if (!GreetdSettings.rememberLastUser && GreetdMemory.lastSuccessfulUser) { - GreetdMemory.setLastSuccessfulUser(""); - } - applyLastSuccessfulUser(); - } - - function onRememberLastSessionChanged() { - if (!isPrimaryScreen) - return; - if (!GreetdSettings.rememberLastSession && GreetdMemory.lastSessionId) { - GreetdMemory.setLastSessionId(""); - } - finalizeSessionSelection(); - } - } - - FileView { - id: greetdPamWatcher - path: "/etc/pam.d/greetd" - printErrors: false - onLoaded: { - root.greetdPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.greetdPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: systemAuthPamWatcher - path: "/etc/pam.d/system-auth" - printErrors: false - onLoaded: { - root.systemAuthPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.systemAuthPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: commonAuthPamWatcher - path: "/etc/pam.d/common-auth" - printErrors: false - onLoaded: { - root.commonAuthPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.commonAuthPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: passwordAuthPamWatcher - path: "/etc/pam.d/password-auth" - printErrors: false - onLoaded: { - root.passwordAuthPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.passwordAuthPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: systemLoginPamWatcher - path: "/etc/pam.d/system-login" - printErrors: false - onLoaded: { - root.systemLoginPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.systemLoginPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: systemLocalLoginPamWatcher - path: "/etc/pam.d/system-local-login" - printErrors: false - onLoaded: { - root.systemLocalLoginPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.systemLocalLoginPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: commonAuthPcPamWatcher - path: "/etc/pam.d/common-auth-pc" - printErrors: false - onLoaded: { - root.commonAuthPcPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.commonAuthPcPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: loginPamWatcher - path: "/etc/pam.d/login" - printErrors: false - onLoaded: { - root.loginPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.loginPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: faillockConfigWatcher - path: "/etc/security/faillock.conf" - printErrors: false - onLoaded: { - root.faillockConfigText = text(); - root.refreshPasswordAttemptPolicyHint(); - } - onLoadFailed: { - root.faillockConfigText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - Component.onCompleted: { - initWeatherService(); - refreshPasswordAttemptPolicyHint(); - - if (isPrimaryScreen) - applyLastSuccessfulUser(); - - if (CompositorService.isHyprland) - updateHyprlandLayout(); - - fprintdDeviceProbe.running = true; - } - - function applyLastSuccessfulUser() { - if (!GreetdSettings.settingsLoaded || !GreetdSettings.rememberLastUser) - return; - const lastUser = GreetdMemory.lastSuccessfulUser; - if (lastUser && !GreeterState.showPasswordInput && !GreeterState.username) { - GreeterState.username = lastUser; - GreeterState.usernameInput = lastUser; - GreeterState.showPasswordInput = true; - PortalService.getGreeterUserProfileImage(lastUser); - maybeAutoStartExternalAuth(); - } - } - - function submitUsername(rawValue) { - const user = (rawValue || "").trim(); - if (!user) - return; - if (GreeterState.username !== user) { - passwordFailureCount = 0; - clearAuthFeedback(); - externalAuthAutoStartedForUser = ""; - } - GreeterState.username = user; - GreeterState.showPasswordInput = true; - PortalService.getGreeterUserProfileImage(user); - GreeterState.passwordBuffer = ""; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - maybeAutoStartExternalAuth(); - } - - function submitBufferedPassword() { - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - awaitingExternalAuth = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.restart(); - // Some PAM stacks expect an explicit empty response to advance U2F/fprint or fail normally. - Greetd.respond(GreeterState.passwordBuffer || ""); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - return true; - } - - function requestPasswordSessionTransition() { - const hasPasswordBuffer = GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0; - if (!passwordSubmitRequested && !hasPasswordBuffer) - return; - if (cancelingExternalAuthForPassword) - return; - if (passwordSessionTransitionRetryCount >= maxPasswordSessionTransitionRetries) { - pendingPasswordResponse = false; - awaitingExternalAuth = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - resetPasswordSessionTransition(true); - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - placeholderDelay.restart(); - Greetd.cancelSession(); - return; - } - cancelingExternalAuthForPassword = true; - passwordSessionTransitionRetryCount = passwordSessionTransitionRetryCount + 1; - awaitingExternalAuth = false; - pendingPasswordResponse = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - Greetd.cancelSession(); - } - - function startAuthSession(submitPassword) { - submitPassword = submitPassword === true; - if (!GreeterState.showPasswordInput || !GreeterState.username) - return; - if (GreeterState.unlocking) - return; - const hasPasswordBuffer = GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0; - if (Greetd.state !== GreetdState.Inactive) { - if (pendingPasswordResponse && submitPassword) - submitBufferedPassword(); - else if (submitPassword) - passwordSubmitRequested = true; - return; - } - if (cancelingExternalAuthForPassword) { - if (submitPassword) - passwordSubmitRequested = true; - return; - } - if (!submitPassword && !hasPasswordBuffer && !root.greeterExternalAuthAvailable) - return; - pendingPasswordResponse = false; - passwordSubmitRequested = submitPassword; - awaitingExternalAuth = !submitPassword && !hasPasswordBuffer && root.greeterExternalAuthAvailable; - // Use greeterExternalAuthAvailable so systems with pam_fprintd but no hardware don't incur the 30 s wait. - const waitingOnPamExternalBeforePassword = submitPassword && root.greeterExternalAuthAvailable; - authTimeout.interval = (awaitingExternalAuth || waitingOnPamExternalBeforePassword) ? externalAuthTimeoutMs : defaultAuthTimeoutMs; - authTimeout.restart(); - Greetd.createSession(GreeterState.username); - } - - function maybeAutoStartExternalAuth() { - if (!GreeterState.showPasswordInput || !GreeterState.username) - return; - if (!root.greeterExternalAuthAvailable) - return; - if (GreeterState.unlocking || Greetd.state !== GreetdState.Inactive) - return; - if (passwordSubmitRequested || cancelingExternalAuthForPassword) - return; - if (GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0) - return; - if (externalAuthAutoStartedForUser === GreeterState.username) - return; - - externalAuthAutoStartedForUser = GreeterState.username; - startAuthSession(false); - } - - function isExternalAuthPrompt(message, responseRequired) { - // Non-response PAM messages commonly represent waiting states (fprint/U2F/token touch). - return !responseRequired; - } - - Component.onDestruction: { - if (weatherInitialized) - WeatherService.removeRef(); - } - - function updateHyprlandLayout() { - if (CompositorService.isHyprland) { - hyprlandLayoutProcess.running = true; - } - } - - Process { - id: hyprlandLayoutProcess - running: false - command: ["hyprctl", "-j", "devices"] - stdout: StdioCollector { - onStreamFinished: { - try { - const data = JSON.parse(text); - const mainKeyboard = data.keyboards.find(kb => kb.main === true); - if (!mainKeyboard) { - hyprlandCurrentLayout = ""; - hyprlandLayoutCount = 0; - return; - } - hyprlandKeyboard = mainKeyboard.name; - if (mainKeyboard.active_keymap) { - const parts = mainKeyboard.active_keymap.split(" "); - hyprlandCurrentLayout = parts[0].substring(0, 2).toUpperCase(); - } else { - hyprlandCurrentLayout = ""; - } - hyprlandLayoutCount = mainKeyboard.layout ? mainKeyboard.layout.split(",").length : 0; - } catch (e) { - hyprlandCurrentLayout = ""; - hyprlandLayoutCount = 0; - } - } - } - } - - // Probe fprintd D-Bus for physically enrolled scanners to eliminate PAM stack false-positives. - Process { - id: fprintdDeviceProbe - running: false - // sh wrapper: emits PROBE_UNAVAILABLE if gdbus is absent or fprintd unreachable, - // keeping the PAM-only fallback active in those cases. - command: ["sh", "-c", - "command -v gdbus >/dev/null 2>&1 || { echo PROBE_UNAVAILABLE; exit 0; }; " + - "gdbus call --system " + - "--dest net.reactivated.Fprint " + - "--object-path /net/reactivated/Fprint/Manager " + - "--method net.reactivated.Fprint.Manager.GetDevices 2>/dev/null " + - "|| echo PROBE_UNAVAILABLE"] - stdout: StdioCollector { - onStreamFinished: { - if (text.includes("PROBE_UNAVAILABLE")) - return; // PAM-only fallback stays active - root.fprintdHasDevice = text.includes("objectpath"); - root.fprintdProbeComplete = true; - root.maybeAutoStartExternalAuth(); - } - } - onExited: function(exitCode, exitStatus) { - if (!root.fprintdProbeComplete) - root.maybeAutoStartExternalAuth(); // PAM-only fallback stays active - } - } - - Connections { - target: CompositorService.isHyprland ? Hyprland : null - enabled: CompositorService.isHyprland - - function onRawEvent(event) { - if (event.name === "activelayout") - updateHyprlandLayout(); - } - } - - Connections { - target: GreetdMemory - enabled: isPrimaryScreen - function onLastSuccessfulUserChanged() { - applyLastSuccessfulUser(); - } - function onMemoryReadyChanged() { - finalizeSessionSelection(); - } - } - - Connections { - target: GreeterState - function onUsernameChanged() { - if (GreeterState.username) { - PortalService.getGreeterUserProfileImage(GreeterState.username); - } - } - } - - FileView { - id: greeterWallpaperOverrideFile - path: GreetdSettings.greeterWallpaperOverridePath - printErrors: false - watchChanges: true - onLoaded: root.greeterWallpaperOverrideExists = true - onLoadFailed: root.greeterWallpaperOverrideExists = false - } - - Connections { - target: GreetdSettings - function onGreeterWallpaperOverridePathChanged() { - if (!GreetdSettings.greeterWallpaperOverridePath) { - root.greeterWallpaperOverrideExists = false; - return; - } - greeterWallpaperOverrideFile.reload(); - } - function onGreeterWallpaperPathChanged() { - if (!GreetdSettings.greeterWallpaperPath) { - root.greeterWallpaperOverrideExists = false; - return; - } - greeterWallpaperOverrideFile.reload(); - } - } - - DankBackdrop { - anchors.fill: parent - screenName: root.screenName - visible: { - if (GreetdSettings.greeterWallpaperPath !== "" && root.greeterWallpaperOverrideExists) - return false; - var _ = SessionData.perMonitorWallpaper; - var __ = SessionData.monitorWallpapers; - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - return !currentWallpaper || currentWallpaper === "" || (currentWallpaper && currentWallpaper.startsWith("#")); - } - } - - Image { - id: wallpaperBackground - - anchors.fill: parent - source: { - if (GreetdSettings.greeterWallpaperPath !== "" && root.greeterWallpaperOverrideExists) - return encodeFileUrl(GreetdSettings.greeterWallpaperOverridePath); - var _ = SessionData.perMonitorWallpaper; - var __ = SessionData.monitorWallpapers; - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - return (currentWallpaper && !currentWallpaper.startsWith("#")) ? encodeFileUrl(currentWallpaper) : ""; - } - fillMode: Theme.getFillMode(GreetdSettings.getEffectiveWallpaperFillMode()) - smooth: true - asynchronous: false - cache: true - visible: source !== "" - layer.enabled: true - - layer.effect: MultiEffect { - autoPaddingEnabled: false - blurEnabled: true - blur: 0.8 - blurMax: 32 - blurMultiplier: 1 - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - anchors.fill: parent - color: "black" - opacity: 0.4 - } - - SystemClock { - id: systemClock - precision: SystemClock.Seconds - } - - Rectangle { - anchors.fill: parent - color: "transparent" - - Item { - id: clockContainer - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.verticalCenter - anchors.bottomMargin: 60 - width: parent.width - height: clockText.implicitHeight - - Row { - id: clockText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - spacing: 0 - - property string fullTimeStr: { - const format = GreetdSettings.getEffectiveTimeFormat(); - return systemClock.date.toLocaleTimeString(I18n.locale(), format); - } - property var timeParts: fullTimeStr.split(':') - property string hours: timeParts[0] || "" - property string minutes: timeParts[1] || "" - property string secondsWithAmPm: timeParts.length > 2 ? timeParts[2] : "" - property string seconds: secondsWithAmPm.replace(/\s*(AM|PM|am|pm)$/i, '') - property string ampm: { - const match = fullTimeStr.match(/\s*(AM|PM|am|pm)$/i); - return match ? match[0].trim() : ""; - } - property bool hasSeconds: timeParts.length > 2 - - StyledText { - width: 75 - text: clockText.hours.length > 1 ? clockText.hours[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - width: 75 - text: clockText.hours.length > 1 ? clockText.hours[1] : clockText.hours.length > 0 ? clockText.hours[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: ":" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - } - - StyledText { - width: 75 - text: clockText.minutes.length > 0 ? clockText.minutes[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - width: 75 - text: clockText.minutes.length > 1 ? clockText.minutes[1] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: clockText.hasSeconds ? ":" : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.hasSeconds - } - - StyledText { - width: 75 - text: clockText.hasSeconds && clockText.seconds.length > 0 ? clockText.seconds[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - visible: clockText.hasSeconds - } - - StyledText { - width: 75 - text: clockText.hasSeconds && clockText.seconds.length > 1 ? clockText.seconds[1] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - visible: clockText.hasSeconds - } - - StyledText { - width: 20 - text: " " - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.ampm !== "" - } - - StyledText { - text: clockText.ampm - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.ampm !== "" - } - } - } - - StyledText { - id: dateText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: clockContainer.bottom - anchors.topMargin: 4 - text: { - return systemClock.date.toLocaleDateString(I18n.locale(), GreetdSettings.getEffectiveLockDateFormat()); - } - font.pixelSize: Theme.fontSizeXLarge - color: "white" - opacity: 0.9 - } - - Item { - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: dateText.bottom - anchors.topMargin: Theme.spacingL - width: 380 - height: 140 - - ColumnLayout { - anchors.fill: parent - spacing: Theme.spacingM - - RowLayout { - spacing: Theme.spacingL - Layout.fillWidth: true - - DankCircularImage { - Layout.preferredWidth: 60 - Layout.preferredHeight: 60 - imageSource: { - if (PortalService.profileImage === "") - return ""; - if (PortalService.profileImage.startsWith("/")) - return encodeFileUrl(PortalService.profileImage); - return PortalService.profileImage; - } - fallbackIcon: "person" - visible: GreetdSettings.lockScreenShowProfileImage - } - - Rectangle { - property bool showPassword: false - - Layout.fillWidth: true - Layout.preferredHeight: 60 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) - border.color: inputField.activeFocus ? Theme.primary : Qt.rgba(1, 1, 1, 0.3) - border.width: inputField.activeFocus ? 2 : 1 - - DankIcon { - id: lockIcon - - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - name: GreeterState.showPasswordInput ? "lock" : "person" - size: 20 - color: inputField.activeFocus ? Theme.primary : Theme.surfaceVariantText - } - - TextInput { - id: inputField - - property bool syncingFromState: false - - anchors.fill: parent - anchors.leftMargin: lockIcon.width + Theme.spacingM * 2 - anchors.rightMargin: { - let margin = Theme.spacingM; - if (GreeterState.showPasswordInput && revealButton.visible) { - margin += revealButton.width; - } - if (externalAuthButton.visible) { - margin += externalAuthButton.width; - } - if (virtualKeyboardButton.visible) { - margin += virtualKeyboardButton.width; - } - if (enterButton.visible) { - margin += enterButton.width + 2; - } - return margin; - } - opacity: 0 - focus: true - echoMode: GreeterState.showPasswordInput ? (parent.showPassword ? TextInput.Normal : TextInput.Password) : TextInput.Normal - onTextChanged: { - if (syncingFromState) - return; - if (GreeterState.showPasswordInput) { - GreeterState.passwordBuffer = text; - if (!text || text.length === 0) - root.passwordSubmitRequested = false; - } else { - GreeterState.usernameInput = text; - } - } - onAccepted: { - if (GreeterState.showPasswordInput) { - root.startAuthSession(true); - } else { - if (text.trim()) { - root.submitUsername(text); - syncingFromState = true; - text = ""; - syncingFromState = false; - } - } - } - - Component.onCompleted: { - syncingFromState = true; - text = GreeterState.showPasswordInput ? GreeterState.passwordBuffer : GreeterState.usernameInput; - syncingFromState = false; - if (isPrimaryScreen && !powerMenu.isVisible) - forceActiveFocus(); - } - onVisibleChanged: { - if (visible && isPrimaryScreen && !powerMenu.isVisible) - forceActiveFocus(); - } - } - - KeyboardController { - id: keyboard_controller - target: inputField - rootObject: root - } - - StyledText { - id: placeholder - - anchors.left: lockIcon.right - anchors.leftMargin: Theme.spacingM - anchors.right: (GreeterState.showPasswordInput && revealButton.visible ? revealButton.left : (externalAuthButton.visible ? externalAuthButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)))) - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - text: { - if (GreeterState.unlocking) { - return I18n.tr("Logging in..."); - } - if (Greetd.state !== GreetdState.Inactive && !awaitingExternalAuth && !pendingPasswordResponse) { - return I18n.tr("Authenticating..."); - } - if (GreeterState.showPasswordInput) { - return I18n.tr("Password..."); - } - return I18n.tr("Username..."); - } - color: (GreeterState.unlocking || (Greetd.state !== GreetdState.Inactive && !awaitingExternalAuth && !pendingPasswordResponse)) ? Theme.primary : Theme.outline - font.pixelSize: Theme.fontSizeMedium - opacity: (GreeterState.showPasswordInput ? GreeterState.passwordBuffer.length === 0 : GreeterState.usernameInput.length === 0) ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - StyledText { - anchors.left: lockIcon.right - anchors.leftMargin: Theme.spacingM - anchors.right: (GreeterState.showPasswordInput && revealButton.visible ? revealButton.left : (externalAuthButton.visible ? externalAuthButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)))) - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - text: { - if (GreeterState.showPasswordInput) { - if (parent.showPassword) { - return GreeterState.passwordBuffer; - } - return "•".repeat(GreeterState.passwordBuffer.length); - } - return GreeterState.usernameInput; - } - color: Theme.surfaceText - font.pixelSize: (GreeterState.showPasswordInput && !parent.showPassword) ? Theme.fontSizeLarge : Theme.fontSizeMedium - opacity: (GreeterState.showPasswordInput ? GreeterState.passwordBuffer.length > 0 : GreeterState.usernameInput.length > 0) ? 1 : 0 - clip: true - elide: Text.ElideNone - horizontalAlignment: implicitWidth > width ? Text.AlignRight : Text.AlignLeft - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - } - - DankActionButton { - id: revealButton - - anchors.right: externalAuthButton.visible ? externalAuthButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)) - anchors.rightMargin: 0 - anchors.verticalCenter: parent.verticalCenter - iconName: parent.showPassword ? "visibility_off" : "visibility" - buttonSize: 32 - visible: GreeterState.showPasswordInput && GreeterState.passwordBuffer.length > 0 && (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: visible - onClicked: parent.showPassword = !parent.showPassword - } - DankActionButton { - id: externalAuthButton - - anchors.right: virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right) - anchors.rightMargin: 0 - anchors.verticalCenter: parent.verticalCenter - iconName: root.greeterPamHasFprint ? "fingerprint" : "key" - buttonSize: 32 - visible: GreeterState.showPasswordInput && root.greeterExternalAuthAvailable && GreeterState.passwordBuffer.length === 0 && (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: visible - onClicked: root.startAuthSession(false) - } - DankActionButton { - id: virtualKeyboardButton - - anchors.right: enterButton.visible ? enterButton.left : parent.right - anchors.rightMargin: enterButton.visible ? 0 : Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "keyboard" - buttonSize: 32 - visible: (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: visible - onClicked: { - if (keyboard_controller.isKeyboardActive) { - keyboard_controller.hide(); - } else { - keyboard_controller.show(); - } - } - } - - DankActionButton { - id: enterButton - - anchors.right: parent.right - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - iconName: "keyboard_return" - buttonSize: 36 - visible: (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: true - onClicked: { - if (GreeterState.showPasswordInput) { - root.startAuthSession(true); - } else { - if (inputField.text.trim()) { - root.submitUsername(inputField.text); - inputField.text = ""; - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - StyledText { - Layout.fillWidth: true - Layout.preferredHeight: 38 - Layout.topMargin: -Theme.spacingS - Layout.bottomMargin: -Theme.spacingS - text: root.authFeedbackMessage - color: Theme.error - font.pixelSize: Theme.fontSizeSmall - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - maximumLineCount: 2 - opacity: root.authFeedbackMessage !== "" ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: 0 - Layout.preferredWidth: switchUserRow.width + Theme.spacingL * 2 - Layout.preferredHeight: 40 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - opacity: GreeterState.showPasswordInput ? 1 : 0 - enabled: GreeterState.showPasswordInput - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Row { - id: switchUserRow - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "people" - size: Theme.iconSize - 4 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Switch User") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - StateLayer { - stateColor: Theme.primary - cornerRadius: parent.radius - enabled: !GreeterState.unlocking && Greetd.state === GreetdState.Inactive && GreeterState.showPasswordInput - onClicked: { - GreeterState.reset(); - root.externalAuthAutoStartedForUser = ""; - inputField.text = ""; - PortalService.profileImage = ""; - } - } - } - } - } - - Row { - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: Theme.spacingXL - spacing: Theme.spacingL - - Item { - width: keyboardLayoutRow.width - height: keyboardLayoutRow.height - anchors.verticalCenter: parent.verticalCenter - visible: { - if (CompositorService.isNiri) { - return NiriService.keyboardLayoutNames.length > 1; - } else if (CompositorService.isHyprland) { - return hyprlandLayoutCount > 1; - } - return false; - } - - Row { - id: keyboardLayoutRow - spacing: 4 - - Item { - width: Theme.iconSize - height: Theme.iconSize - - DankIcon { - name: "keyboard" - size: Theme.iconSize - color: "white" - anchors.centerIn: parent - } - } - - Item { - width: childrenRect.width - height: Theme.iconSize - - StyledText { - text: { - if (CompositorService.isNiri) { - const layout = NiriService.getCurrentKeyboardLayoutName(); - if (!layout) - return ""; - const parts = layout.split(" "); - if (parts.length > 0) { - return parts[0].substring(0, 2).toUpperCase(); - } - return layout.substring(0, 2).toUpperCase(); - } else if (CompositorService.isHyprland) { - return hyprlandCurrentLayout; - } - return ""; - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - - MouseArea { - id: keyboardLayoutArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (CompositorService.isNiri) { - NiriService.cycleKeyboardLayout(); - } else if (CompositorService.isHyprland) { - Quickshell.execDetached(["hyprctl", "switchxkblayout", hyprlandKeyboard, "next"]); - updateHyprlandLayout(); - } - } - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: { - const keyboardVisible = (CompositorService.isNiri && NiriService.keyboardLayoutNames.length > 1) || (CompositorService.isHyprland && hyprlandLayoutCount > 1); - return keyboardVisible && GreetdSettings.weatherEnabled && WeatherService.weather.available; - } - } - - Row { - spacing: 6 - visible: GreetdSettings.weatherEnabled && WeatherService.weather.available - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.iconSize - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: (GreetdSettings.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: GreetdSettings.weatherEnabled && WeatherService.weather.available && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio) || BatteryService.batteryAvailable) - } - - Row { - spacing: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.networkStatus !== "disconnected" || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio) - - DankIcon { - name: NetworkService.networkStatus === "ethernet" ? "lan" : NetworkService.wifiSignalIcon - size: Theme.iconSize - 2 - color: NetworkService.networkStatus !== "disconnected" ? "white" : Qt.rgba(255, 255, 255, 0.5) - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.networkStatus !== "disconnected" - } - - DankIcon { - name: "bluetooth" - size: Theme.iconSize - 2 - color: "white" - anchors.verticalCenter: parent.verticalCenter - visible: BluetoothService.available && BluetoothService.enabled - } - - DankIcon { - name: { - if (!AudioService.sink?.audio) { - return "volume_up"; - } - if (AudioService.sink.audio.muted) - return "volume_off"; - if (AudioService.sink.audio.volume === 0) - return "volume_mute"; - if (AudioService.sink.audio.volume * 100 < 33) { - return "volume_down"; - } - return "volume_up"; - } - size: Theme.iconSize - 2 - color: (AudioService.sink && AudioService.sink.audio && (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0)) ? Qt.rgba(255, 255, 255, 0.5) : "white" - anchors.verticalCenter: parent.verticalCenter - visible: AudioService.sink && AudioService.sink.audio - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio)) - } - - Row { - spacing: 4 - visible: BatteryService.batteryAvailable - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: { - if (BatteryService.isCharging) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - - return "battery_charging_20"; - } - if (BatteryService.isPluggedIn) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - - return "battery_charging_20"; - } - if (BatteryService.batteryLevel >= 95) { - return "battery_full"; - } - - if (BatteryService.batteryLevel >= 85) { - return "battery_6_bar"; - } - - if (BatteryService.batteryLevel >= 70) { - return "battery_5_bar"; - } - - if (BatteryService.batteryLevel >= 55) { - return "battery_4_bar"; - } - - if (BatteryService.batteryLevel >= 40) { - return "battery_3_bar"; - } - - if (BatteryService.batteryLevel >= 25) { - return "battery_2_bar"; - } - - return "battery_1_bar"; - } - size: Theme.iconSize - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - - if (BatteryService.isCharging || BatteryService.isPluggedIn) { - return Theme.primary; - } - - return "white"; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: BatteryService.batteryLevel + "%" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - - DankActionButton { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.margins: Theme.spacingXL - visible: GreetdSettings.lockScreenShowPowerActions - iconName: "power_settings_new" - iconColor: Theme.error - buttonSize: 40 - onClicked: powerMenu.show() - } - - Item { - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.margins: Theme.spacingXL - width: Math.max(200, currentSessionMetrics.width + 80) - height: 60 - - StyledTextMetrics { - id: currentSessionMetrics - text: root.currentSessionName - } - - property real longestSessionWidth: { - let maxWidth = 0; - for (var i = 0; i < sessionMetricsRepeater.count; i++) { - const item = sessionMetricsRepeater.itemAt(i); - if (item && item.width > maxWidth) { - maxWidth = item.width; - } - } - return maxWidth; - } - - Repeater { - id: sessionMetricsRepeater - model: GreeterState.sessionList - delegate: StyledTextMetrics { - text: modelData - } - } - - DankDropdown { - id: sessionDropdown - anchors.fill: parent - text: "" - description: "" - currentValue: root.currentSessionName - options: GreeterState.sessionList - enableFuzzySearch: GreeterState.sessionList.length > 5 - popupWidthOffset: 0 - popupWidth: Math.max(250, parent.longestSessionWidth + 100) - openUpwards: true - alignPopupRight: true - onValueChanged: value => { - const idx = GreeterState.sessionList.indexOf(value); - if (idx < 0) - return; - GreeterState.currentSessionIndex = idx; - GreeterState.selectedSession = GreeterState.sessionExecs[idx]; - GreeterState.selectedSessionPath = GreeterState.sessionPaths[idx]; - } - } - } - } - - property string currentSessionName: GreeterState.sessionList[GreeterState.currentSessionIndex] || "" - - function finalizeSessionSelection() { - if (GreeterState.sessionList.length === 0) - return; - if (!GreetdMemory.memoryReady) - return; - if (!GreetdSettings.settingsLoaded) - return; - - const savedSession = GreetdSettings.rememberLastSession ? GreetdMemory.lastSessionId : ""; - if (savedSession && GreetdSettings.rememberLastSession) { - for (var i = 0; i < GreeterState.sessionPaths.length; i++) { - if (GreeterState.sessionPaths[i] === savedSession) { - GreeterState.currentSessionIndex = i; - GreeterState.selectedSession = GreeterState.sessionExecs[i] || ""; - GreeterState.selectedSessionPath = GreeterState.sessionPaths[i]; - return; - } - } - } - - GreeterState.currentSessionIndex = 0; - GreeterState.selectedSession = GreeterState.sessionExecs[0] || ""; - GreeterState.selectedSessionPath = GreeterState.sessionPaths[0] || ""; - } - - property var sessionDirs: { - const homeDir = Quickshell.env("HOME") || ""; - const dirs = ["/usr/share/wayland-sessions", "/usr/share/xsessions", "/usr/local/share/wayland-sessions", "/usr/local/share/xsessions"]; - - if (homeDir) { - dirs.push(homeDir + "/.local/share/wayland-sessions"); - dirs.push(homeDir + "/.local/share/xsessions"); - } - - if (xdgDataDirs) { - xdgDataDirs.split(":").forEach(dir => { - if (dir) { - dirs.push(dir + "/wayland-sessions"); - dirs.push(dir + "/xsessions"); - } - }); - } - return dirs; - } - - property var _pendingFiles: ({}) - property int _pendingCount: 0 - - function _addSession(path, name, exec) { - if (!name || !exec || GreeterState.sessionList.includes(name)) - return; - GreeterState.sessionList = GreeterState.sessionList.concat([name]); - GreeterState.sessionExecs = GreeterState.sessionExecs.concat([exec]); - GreeterState.sessionPaths = GreeterState.sessionPaths.concat([path]); - } - - function _parseDesktopFile(content, path) { - let name = ""; - let exec = ""; - const lines = content.split("\n"); - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (!name && line.startsWith("Name=")) - name = line.substring(5).trim(); - else if (!exec && line.startsWith("Exec=")) - exec = line.substring(5).trim(); - if (name && exec) - break; - } - _addSession(path, name, exec); - } - - function _loadDesktopFile(filePath) { - if (_pendingFiles[filePath]) - return; - _pendingFiles[filePath] = true; - _pendingCount++; - - const loader = desktopFileLoader.createObject(root, { - "filePath": filePath - }); - } - - function _onFileLoaded(filePath) { - _pendingCount--; - if (_pendingCount === 0) - Qt.callLater(finalizeSessionSelection); - } - - Component { - id: desktopFileLoader - - FileView { - id: fv - property string filePath: "" - path: filePath - - onLoaded: { - root._parseDesktopFile(text(), filePath); - root._onFileLoaded(filePath); - fv.destroy(); - } - - onLoadFailed: { - root._onFileLoaded(filePath); - fv.destroy(); - } - } - } - - Repeater { - model: isPrimaryScreen ? sessionDirs : [] - - Item { - required property string modelData - - FolderListModel { - folder: encodeFileUrl(modelData) - nameFilters: ["*.desktop"] - showDirs: false - showDotAndDotDot: false - - onStatusChanged: { - if (status !== FolderListModel.Ready) - return; - for (let i = 0; i < count; i++) { - let fp = get(i, "filePath"); - if (fp.startsWith("file://")) - fp = fp.substring(7); - root._loadDesktopFile(fp); - } - } - } - } - } - - Connections { - target: Greetd - enabled: isPrimaryScreen - - function onAuthMessage(message, error, responseRequired, echoResponse) { - if (responseRequired) { - cancelingExternalAuthForPassword = false; - passwordSessionTransitionRetryCount = 0; - awaitingExternalAuth = false; - pendingPasswordResponse = true; - const hasPasswordBuffer = GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0; - if (!passwordSubmitRequested && hasPasswordBuffer) - passwordSubmitRequested = true; - if (passwordSubmitRequested && !root.submitBufferedPassword()) - passwordSubmitRequested = false; - if (passwordSubmitRequested || hasPasswordBuffer) { - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.restart(); - } else { - authTimeout.stop(); - } - return; - } - pendingPasswordResponse = false; - const externalPrompt = root.isExternalAuthPrompt(message, responseRequired); - if (!passwordSubmitRequested) - awaitingExternalAuth = root.greeterExternalAuthAvailable && externalPrompt; - if (awaitingExternalAuth || (passwordSubmitRequested && externalPrompt && root.greeterPamHasExternalAuth)) - authTimeout.interval = externalAuthTimeoutMs; - else - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.restart(); - Greetd.respond(""); - } - - function onStateChanged() { - if (Greetd.state === GreetdState.Inactive) { - const resumePasswordSubmit = cancelingExternalAuthForPassword && passwordSubmitRequested; - awaitingExternalAuth = false; - pendingPasswordResponse = false; - cancelingExternalAuthForPassword = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - if (resumePasswordSubmit) { - Qt.callLater(function() { - root.startAuthSession(true); - }); - return; - } - resetPasswordSessionTransition(true); - } - } - - function onReadyToLaunch() { - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - passwordFailureCount = 0; - clearAuthFeedback(); - const sessionCmd = GreeterState.selectedSession || GreeterState.sessionExecs[GreeterState.currentSessionIndex]; - const sessionPath = GreeterState.selectedSessionPath || GreeterState.sessionPaths[GreeterState.currentSessionIndex]; - if (!sessionCmd) { - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - placeholderDelay.restart(); - return; - } - - GreeterState.unlocking = true; - launchTimeout.restart(); - if (GreetdSettings.rememberLastSession) { - GreetdMemory.setLastSessionId(sessionPath); - } else if (GreetdMemory.lastSessionId) { - GreetdMemory.setLastSessionId(""); - } - if (GreetdSettings.rememberLastUser) { - GreetdMemory.setLastSuccessfulUser(GreeterState.username); - } else if (GreetdMemory.lastSuccessfulUser) { - GreetdMemory.setLastSuccessfulUser(""); - } - pendingLaunchCommand = sessionCmd; - pendingLaunchEnv = ["XDG_SESSION_TYPE=wayland"]; - memoryFlushTimer.restart(); - } - - function onAuthFailure(message) { - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - launchTimeout.stop(); - GreeterState.unlocking = false; - if (isLikelyLockoutMessage(message)) { - GreeterState.pamState = "max"; - } else { - GreeterState.pamState = "fail"; - passwordFailureCount = passwordFailureCount + 1; - } - authFeedbackMessage = currentAuthMessage(); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - placeholderDelay.restart(); - Greetd.cancelSession(); - } - - function onError(error) { - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - launchTimeout.stop(); - GreeterState.unlocking = false; - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - placeholderDelay.restart(); - Greetd.cancelSession(); - } - } - - Timer { - id: memoryFlushTimer - interval: memoryFlushDelayMs - onTriggered: { - if (!pendingLaunchCommand) - return; - const sessionCommand = pendingLaunchCommand; - const launchEnv = pendingLaunchEnv; - pendingLaunchCommand = ""; - pendingLaunchEnv = []; - Greetd.launch(sessionCommand.split(" "), launchEnv); - } - } - - Timer { - id: authTimeout - interval: defaultAuthTimeoutMs - onTriggered: { - if (GreeterState.unlocking || Greetd.state === GreetdState.Inactive) - return; - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - placeholderDelay.restart(); - Greetd.cancelSession(); - } - } - - Timer { - id: launchTimeout - interval: 8000 - onTriggered: { - if (!GreeterState.unlocking) - return; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - GreeterState.unlocking = false; - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - placeholderDelay.restart(); - Greetd.cancelSession(); - } - } - - Timer { - id: placeholderDelay - interval: 4000 - onTriggered: clearAuthFeedback() - } - - LockPowerMenu { - id: powerMenu - showLogout: false - powerActionConfirmOverride: GreetdSettings.powerActionConfirm - powerActionHoldDurationOverride: GreetdSettings.powerActionHoldDuration - powerMenuActionsOverride: GreetdSettings.powerMenuActions - powerMenuDefaultActionOverride: GreetdSettings.powerMenuDefaultAction - powerMenuGridLayoutOverride: GreetdSettings.powerMenuGridLayout - requiredActions: ["poweroff"] - onClosed: { - if (isPrimaryScreen && inputField && inputField.forceActiveFocus) { - Qt.callLater(() => inputField.forceActiveFocus()); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterState.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterState.qml deleted file mode 100644 index ac57de7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterState.qml +++ /dev/null @@ -1,30 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound -import QtQuick -import Quickshell - -Singleton { - id: root - - property string passwordBuffer: "" - property string username: "" - property string usernameInput: "" - property bool showPasswordInput: false - property string selectedSession: "" - property string selectedSessionPath: "" - property string pamState: "" - property bool unlocking: false - - property var sessionList: [] - property var sessionExecs: [] - property var sessionPaths: [] - property int currentSessionIndex: 0 - - function reset() { - showPasswordInput = false; - username = ""; - usernameInput = ""; - passwordBuffer = ""; - pamState = ""; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterSurface.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterSurface.qml deleted file mode 100644 index a8af5df..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterSurface.qml +++ /dev/null @@ -1,34 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Wayland -import Quickshell.Services.Greetd -import qs.Common - -Variants { - model: Quickshell.screens - - PanelWindow { - id: root - - property var modelData - - screen: modelData - anchors { - left: true - right: true - top: true - bottom: true - } - exclusionMode: ExclusionMode.Normal - WlrLayershell.layer: WlrLayer.Overlay - WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive - color: "transparent" - - GreeterContent { - anchors.fill: parent - screenName: root.screen?.name ?? "" - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/README.md deleted file mode 100644 index 4ac5a77..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/README.md +++ /dev/null @@ -1,277 +0,0 @@ -# Dank (dms) Greeter - -A greeter for [greetd](https://github.com/kennylevinsen/greetd) that follows the aesthetics of the dms lock screen. - -## Features - -- **Multi user**: Login with any system user -- **dms sync**: Sync settings with dms for consistent styling between shell and greeter -- **Multiple compositors**: The `dms-greeter` wrapper supports niri, Hyprland, sway, scroll, miracle-wm, labwc, and mangowc. -- **Custom PAM**: Supports custom PAM configuration in `/etc/pam.d/greetd` -- **Session Memory**: Remembers last selected session and user - - Can be disabled via `settings.json` keys: `greeterRememberLastSession` and `greeterRememberLastUser` - -## Installation - -### Arch Linux - -Arch linux users can install [greetd-dms-greeter-git](https://aur.archlinux.org/packages/greetd-dms-greeter-git) from the AUR. - -```bash -paru -S greetd-dms-greeter-git -# Or with yay -yay -S greetd-dms-greeter-git -``` - -### Debian / openSUSE - -Official packages are available from the [DankLinux OBS repository](https://software.opensuse.org/download/package?package=dms-greeter&project=home%3AAvengeMedia%3Adanklinux). Add the repo for your distribution and install: - -```bash -# Debian 13 -sudo apt install dms-greeter # after adding the repo - -# openSUSE Tumbleweed -zypper install dms-greeter # after adding the repo -``` - -See the [Installation guide](https://danklinux.com/docs/dankgreeter/installation) for full repository setup. - -If you previously installed manually, remove legacy files first: - -```bash -sudo rm -f /usr/local/bin/dms-greeter -sudo rm -rf /etc/xdg/quickshell/dms-greeter -``` - -Then complete setup: - -```bash -dms greeter enable -dms greeter sync -``` - -#### Syncing themes (Optional) - -To sync your wallpaper and theme with the greeter login screen, follow the manual setup below: - -
-Manual theme syncing - -```bash -# Add yourself to greeter group -sudo usermod -aG greeter - -# Set ACLs to allow greeter to traverse your directories -setfacl -m u:greeter:x ~ ~/.config ~/.local ~/.cache ~/.local/state - -# Set group ownership on config directories -sudo chgrp -R greeter ~/.config/DankMaterialShell -sudo chgrp -R greeter ~/.local/state/DankMaterialShell -sudo chgrp -R greeter ~/.cache/DankMaterialShell -sudo chmod -R g+rX ~/.config/DankMaterialShell ~/.cache/DankMaterialShell ~/.cache/quickshell - -# Create symlinks -sudo ln -sf ~/.config/DankMaterialShell/settings.json /var/cache/dms-greeter/settings.json -sudo ln -sf ~/.local/state/DankMaterialShell/session.json /var/cache/dms-greeter/session.json -sudo ln -sf ~/.cache/DankMaterialShell/dms-colors.json /var/cache/dms-greeter/colors.json - -# Logout and login for group membership to take effect -``` - -
- -### Fedora / RHEL / Rocky / Alma - -Install from COPR or build the RPM: - -```bash -# From COPR (when available) -sudo dnf copr enable avenge/dms -sudo dnf install dms-greeter - -# Or build locally -cd /path/to/DankMaterialShell -rpkg local -sudo rpm -ivh x86_64/dms-greeter-*.rpm -``` - -The package automatically: -- Creates the greeter user -- Sets up directories and permissions -- Configures greetd with auto-detected compositor -- Applies SELinux contexts - -Then complete setup: - -```bash -dms greeter enable -dms greeter sync -``` - -#### Syncing themes (Optional) - -Run: - -```bash -dms greeter sync -``` - -Then logout/login to see your wallpaper on the greeter. - -### Automatic - -The easiest thing is to run `dms greeter install` or `dms` for interactive installation. -On Debian/openSUSE, this now prefers the `dms-greeter` package when the OBS repo is configured. - -### Manual (fallback only) - -Use this only if no package is available for your distro. - -1. Install `greetd` (in most distro's standard repositories) and `quickshell` - -2. Create the greeter user (if not already created by greetd): -```bash -sudo groupadd -r greeter -sudo useradd -r -g greeter -d /var/lib/greeter -s /bin/bash -c "System Greeter" greeter -sudo mkdir -p /var/lib/greeter -sudo chown greeter:greeter /var/lib/greeter -``` - -3. Clone the dms project to `/etc/xdg/quickshell/dms-greeter`: -```bash -sudo git clone https://github.com/AvengeMedia/DankMaterialShell.git /etc/xdg/quickshell/dms-greeter -``` - -4. Copy `Modules/Greetd/assets/dms-greeter` to `/usr/local/bin/dms-greeter`: -```bash -sudo cp /etc/xdg/quickshell/dms-greeter/Modules/Greetd/assets/dms-greeter /usr/local/bin/dms-greeter -sudo chmod +x /usr/local/bin/dms-greeter -``` - -5. Create greeter cache directory with proper permissions: -```bash -sudo mkdir -p /var/cache/dms-greeter -sudo chown : /var/cache/dms-greeter -sudo chmod 2770 /var/cache/dms-greeter -``` - -6. Edit or create `/etc/greetd/config.toml`: -```toml -[terminal] -vt = 1 - -[default_session] -user = "greeter" -# Change compositor to another wrapper-supported compositor if preferred -command = "/usr/local/bin/dms-greeter --command niri" -``` - -7. Disable existing display manager and enable greetd: -```bash -sudo systemctl disable gdm sddm lightdm -sudo systemctl enable greetd -``` - -8. (Optional) Set up theme syncing using the manual ACL method described in the Configuration → Personalization section below - -#### Legacy installation (deprecated) - -If you prefer the old method with separate shell scripts and config files: -1. Copy `assets/dms-niri.kdl` or `assets/dms-hypr.conf` to `/etc/greetd` -2. Copy `assets/greet-niri.sh` or `assets/greet-hyprland.sh` to `/usr/local/bin/start-dms-greetd.sh` -3. Edit the config file and replace `_DMS_PATH_` with your DMS installation path -4. Configure greetd to use `/usr/local/bin/start-dms-greetd.sh` - -### NixOS - -To install the greeter on NixOS add the repo to your flake inputs as described in the readme. Then somewhere in your NixOS config add this to imports: -```nix -imports = [ - inputs.dank-material-shell.nixosModules.greeter -] -``` - -Enable the greeter with this in your NixOS config: -```nix -programs.dank-material-shell.greeter = { - enable = true; - compositor.name = "niri"; # or set to hyprland - configHome = "/home/user"; # optionally copyies that users DMS settings (and wallpaper if set) to the greeters data directory as root before greeter starts -}; -``` - -## Usage - -### Using dms-greeter wrapper (recommended) - -The `dms-greeter` wrapper simplifies running the greeter with any compositor: - -```bash -dms-greeter --command niri -dms-greeter --command hyprland -dms-greeter --command sway -dms-greeter --command mangowc -dms-greeter --command niri -C /path/to/custom-niri.kdl -dms-greeter --command niri --remember-last-user false --remember-last-session false -``` - -Configure greetd to use it in `/etc/greetd/config.toml`: -```toml -[terminal] -vt = 1 - -[default_session] -user = "greeter" -command = "/usr/bin/dms-greeter --command niri" -``` - -### Manual usage - -To run dms in greeter mode you can also manually set environment variables: - -```bash -DMS_RUN_GREETER=1 qs -p /path/to/dms -``` - -### Configuration - -#### Compositor - -For current wrapper-based installs, the `dms-greeter` wrapper supports niri, hyprland, sway, scroll, miracle-wm, labwc, and mangowc. - -Only niri currently has a generated greeter config path managed by `dms greeter sync`. - -- niri: `dms greeter sync` writes the generated greeter config to `/etc/greetd/niri/config.kdl`. Add local manual tweaks in `/etc/greetd/niri_overrides.kdl`. -- Other wrapper-supported compositors use the wrapper-generated config by default. If you need a custom compositor config, add `-C /path/to/config` to the `dms-greeter` command in `/etc/greetd/config.toml`. - -#### Personalization - -The greeter can be personalized with wallpapers, themes, weather, clock formats, and more - configured exactly the same as dms. - -**Easiest method:** Run `dms greeter sync` to automatically sync your DMS theme with the greeter. - -**Manual method:** You can manually synchronize configurations if you want greeter settings to always mirror your shell: - -```bash -# Add yourself to the greeter group -sudo usermod -aG greeter $USER - -# Set ACLs to allow greeter user to traverse your home directory -setfacl -m u:greeter:x ~ ~/.config ~/.local ~/.cache ~/.local/state - -# Set group permissions on DMS directories -sudo chgrp -R greeter ~/.config/DankMaterialShell ~/.local/state/DankMaterialShell ~/.cache/quickshell -sudo chmod -R g+rX ~/.config/DankMaterialShell ~/.local/state/DankMaterialShell ~/.cache/quickshell - -# Create symlinks for theme files -sudo ln -sf ~/.config/DankMaterialShell/settings.json /var/cache/dms-greeter/settings.json -sudo ln -sf ~/.local/state/DankMaterialShell/session.json /var/cache/dms-greeter/session.json -sudo ln -sf ~/.cache/DankMaterialShell/dms-colors.json /var/cache/dms-greeter/colors.json - -# Logout and login for group membership to take effect -``` - -**Advanced:** You can override the configuration path with the `DMS_GREET_CFG_DIR` environment variable or the `--cache-dir` flag when using `dms-greeter`. The default is `/var/cache/dms-greeter`. - -The cache directory should be owned by `:` with `2770` permissions. If the greeter user is not available yet, DMS falls back to `root:`. diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-greeter b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-greeter deleted file mode 100755 index 5d3419c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-greeter +++ /dev/null @@ -1,424 +0,0 @@ -#!/bin/bash - -set -e - -COMPOSITOR="" -COMPOSITOR_CONFIG="" -DMS_PATH="dms-greeter" -CACHE_DIR="/var/cache/dms-greeter" -REMEMBER_LAST_SESSION="" -REMEMBER_LAST_USER="" -DEBUG_MODE=0 - -show_help() { - cat << EOF -dms-greeter - DankMaterialShell greeter launcher - -Usage: dms-greeter --command COMPOSITOR [OPTIONS] - -Required: - --command COMPOSITOR Compositor to use (niri, hyprland, sway, scroll, miracle, mango, or labwc) - -Options: - -C, --config PATH Custom compositor config file - -p, --path PATH DMS path (config name or absolute path) - (default: dms-greeter) - --cache-dir PATH Cache directory for greeter data - (default: /var/cache/dms-greeter) - --remember-last-session BOOL - Persist selected session to greeter memory - (BOOL: true/false, default: from settings.json) - --remember-last-user BOOL - Persist last successful username to greeter memory - (BOOL: true/false, default: from settings.json) - --no-save-session Alias for --remember-last-session false - --no-save-username Alias for --remember-last-user false - --debug Enable verbose startup logging to stderr - -h, --help Show this help message - -Examples: - dms-greeter --command niri - dms-greeter --command hyprland -C /etc/greetd/custom-hypr.conf - dms-greeter --command sway -p /home/user/.config/quickshell/custom-dms - dms-greeter --command scroll -p /home/user/.config/quickshell/custom-dms - dms-greeter --command niri --cache-dir /tmp/dmsgreeter - dms-greeter --command niri --no-save-session --no-save-username - dms-greeter --command mango - dms-greeter --command labwc -EOF -} - -require_command() { - local cmd="$1" - if ! command -v "$cmd" >/dev/null 2>&1; then - echo "Error: required command '$cmd' was not found in PATH" >&2 - exit 1 - fi -} - -normalize_bool_flag() { - local flag_name="$1" - local value="$2" - local normalized="${value,,}" - - case "$normalized" in - 1|true|yes|on) - echo "1" - ;; - 0|false|no|off) - echo "0" - ;; - *) - echo "Error: $flag_name must be true/false (or 1/0, yes/no, on/off)" >&2 - exit 1 - ;; - esac -} - -exec_compositor() { - local log_tag="$1" - shift - - if [[ "$DEBUG_MODE" == "1" ]]; then - exec "$@" - fi - - if command -v systemd-cat >/dev/null 2>&1; then - exec "$@" > >(systemd-cat -t "dms-greeter/$log_tag" -p info) 2>&1 - fi - - exec "$@" -} - -while [[ $# -gt 0 ]]; do - case $1 in - --command) - COMPOSITOR="$2" - shift 2 - ;; - -C|--config) - COMPOSITOR_CONFIG="$2" - shift 2 - ;; - -p|--path) - DMS_PATH="$2" - shift 2 - ;; - --cache-dir) - CACHE_DIR="$2" - shift 2 - ;; - --remember-last-session) - REMEMBER_LAST_SESSION="$2" - shift 2 - ;; - --remember-last-user) - REMEMBER_LAST_USER="$2" - shift 2 - ;; - --no-save-session) - REMEMBER_LAST_SESSION="0" - shift - ;; - --no-save-username) - REMEMBER_LAST_USER="0" - shift - ;; - --debug) - DEBUG_MODE=1 - shift - ;; - -h|--help) - show_help - exit 0 - ;; - *) - echo "Unknown option: $1" >&2 - show_help - exit 1 - ;; - esac -done - -if [[ -z "$COMPOSITOR" ]]; then - echo "Error: --command COMPOSITOR is required" >&2 - show_help - exit 1 -fi - -locate_dms_config() { - local config_name="$1" - local search_paths=() - - local config_home="${XDG_CONFIG_HOME:-$HOME/.config}" - search_paths+=("$config_home/quickshell/$config_name") - - search_paths+=("/usr/share/quickshell/$config_name") - - local config_dirs="${XDG_CONFIG_DIRS:-/etc/xdg}" - IFS=':' read -ra dirs <<< "$config_dirs" - for dir in "${dirs[@]}"; do - if [[ -n "$dir" ]]; then - search_paths+=("$dir/quickshell/$config_name") - fi - done - - for path in "${search_paths[@]}"; do - if [[ -f "$path/shell.qml" ]]; then - echo "$path" - return 0 - fi - done - - return 1 -} - -export XDG_SESSION_TYPE=wayland -export QT_QPA_PLATFORM=wayland -export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 -export EGL_PLATFORM=gbm -export DMS_RUN_GREETER=1 - -if [[ ! -d "$CACHE_DIR" ]]; then - echo "Error: cache directory '$CACHE_DIR' does not exist." >&2 - echo " Run 'dms greeter sync' to initialize it, or pass --cache-dir to an existing directory." >&2 - exit 1 -fi - -export DMS_GREET_CFG_DIR="$CACHE_DIR" - -if [[ -n "$REMEMBER_LAST_SESSION" ]]; then - DMS_GREET_REMEMBER_LAST_SESSION=$(normalize_bool_flag "--remember-last-session" "$REMEMBER_LAST_SESSION") - export DMS_GREET_REMEMBER_LAST_SESSION - if [[ "$DMS_GREET_REMEMBER_LAST_SESSION" == "1" ]]; then - DMS_SAVE_SESSION=true - else - DMS_SAVE_SESSION=false - fi - export DMS_SAVE_SESSION -fi - -if [[ -n "$REMEMBER_LAST_USER" ]]; then - DMS_GREET_REMEMBER_LAST_USER=$(normalize_bool_flag "--remember-last-user" "$REMEMBER_LAST_USER") - export DMS_GREET_REMEMBER_LAST_USER - if [[ "$DMS_GREET_REMEMBER_LAST_USER" == "1" ]]; then - DMS_SAVE_USERNAME=true - else - DMS_SAVE_USERNAME=false - fi - export DMS_SAVE_USERNAME -fi - -export HOME="$CACHE_DIR" -export XDG_STATE_HOME="$CACHE_DIR/.local/state" -export XDG_DATA_HOME="$CACHE_DIR/.local/share" -export XDG_CACHE_HOME="$CACHE_DIR/.cache" - - -# Keep greeter VT clean by default; callers can override via env or --debug. -if [[ -z "${RUST_LOG:-}" ]]; then - export RUST_LOG=warn -fi -if [[ -z "${NIRI_LOG:-}" ]]; then - export NIRI_LOG=warn -fi - -if command -v qs >/dev/null 2>&1; then - QS_BIN="qs" -elif command -v quickshell >/dev/null 2>&1; then - QS_BIN="quickshell" -else - echo "Error: neither 'qs' nor 'quickshell' was found in PATH" >&2 - exit 1 -fi - -QS_CMD="$QS_BIN" -if [[ "$DMS_PATH" == /* ]]; then - QS_CMD="$QS_BIN -p $DMS_PATH" -else - RESOLVED_PATH=$(locate_dms_config "$DMS_PATH") - if [[ $? -eq 0 && -n "$RESOLVED_PATH" ]]; then - if [[ "$DEBUG_MODE" == "1" ]]; then - echo "Located DMS config at: $RESOLVED_PATH" >&2 - fi - QS_CMD="$QS_BIN -p $RESOLVED_PATH" - else - echo "Error: Could not find DMS config '$DMS_PATH' (shell.qml) in any valid config path" >&2 - exit 1 - fi -fi - -case "$COMPOSITOR" in - niri) - require_command "niri" - if [[ -z "$COMPOSITOR_CONFIG" ]]; then - TEMP_CONFIG=$(mktemp) - # base/default config - cat > "$TEMP_CONFIG" << NIRI_EOF -hotkey-overlay { - skip-at-startup -} - -environment { - DMS_RUN_GREETER "1" -} - -debug { - keep-max-bpc-unchanged -} - -gestures { - hot-corners { - off - } -} - -layout { - background-color "#000000" -} -NIRI_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - else - TEMP_CONFIG=$(mktemp) - cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG" - fi - # Append includes if override_files exist - OVERRIDE_FILES=( - /usr/share/greetd/niri_overrides.kdl # for building into a system image - /etc/greetd/niri_overrides.kdl # for local overrides - ) - for override_file in "${OVERRIDE_FILES[@]}"; do - if [[ -e "$override_file" ]]; then - # TODO: maybe move to optional=true when Niri Next drops, so we can avoid these checks ;-) - cat >> "$TEMP_CONFIG" << NIRI_EOF - -include "$override_file" -NIRI_EOF - fi - done - # Append spawn command - cat >> "$TEMP_CONFIG" << NIRI_EOF - -spawn-at-startup "sh" "-c" "$QS_CMD; niri msg action quit --skip-confirmation" -NIRI_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - exec_compositor "niri" niri -c "$COMPOSITOR_CONFIG" - ;; - - hyprland) - if ! command -v start-hyprland >/dev/null 2>&1 && ! command -v Hyprland >/dev/null 2>&1; then - echo "Error: neither 'start-hyprland' nor 'Hyprland' was found in PATH" >&2 - exit 1 - fi - if [[ -z "$COMPOSITOR_CONFIG" ]]; then - TEMP_CONFIG=$(mktemp) - cat > "$TEMP_CONFIG" << HYPRLAND_EOF -env = DMS_RUN_GREETER,1 - -misc { - disable_hyprland_logo = true -} - -exec-once = sh -c "$QS_CMD; hyprctl dispatch exit" -HYPRLAND_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - else - TEMP_CONFIG=$(mktemp) - cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG" - cat >> "$TEMP_CONFIG" << HYPRLAND_EOF - -exec-once = sh -c "$QS_CMD; hyprctl dispatch exit" -HYPRLAND_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - fi - if command -v start-hyprland >/dev/null 2>&1; then - exec_compositor "hyprland" start-hyprland -- --config "$COMPOSITOR_CONFIG" - else - exec_compositor "hyprland" Hyprland -c "$COMPOSITOR_CONFIG" - fi - ;; - - sway) - require_command "sway" - if [[ -z "$COMPOSITOR_CONFIG" ]]; then - TEMP_CONFIG=$(mktemp) - cat > "$TEMP_CONFIG" << SWAY_EOF -exec "$QS_CMD; swaymsg exit" -SWAY_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - else - TEMP_CONFIG=$(mktemp) - cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG" - cat >> "$TEMP_CONFIG" << SWAY_EOF - -exec "$QS_CMD; swaymsg exit" -SWAY_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - fi - exec_compositor "sway" sway --unsupported-gpu -c "$COMPOSITOR_CONFIG" - ;; - - scroll) - require_command "scroll" - if [[ -z "$COMPOSITOR_CONFIG" ]]; then - TEMP_CONFIG=$(mktemp) - cat > "$TEMP_CONFIG" << SCROLL_EOF -exec "$QS_CMD; scrollmsg exit" -SCROLL_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - else - TEMP_CONFIG=$(mktemp) - cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG" - cat >> "$TEMP_CONFIG" << SCROLL_EOF - -exec "$QS_CMD; scrollmsg exit" -SCROLL_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - fi - exec_compositor "scroll" scroll -c "$COMPOSITOR_CONFIG" - ;; - - miracle|miracle-wm) - require_command "miracle-wm" - if [[ -z "$COMPOSITOR_CONFIG" ]]; then - TEMP_CONFIG=$(mktemp) - cat > "$TEMP_CONFIG" << MIRACLE_EOF -exec "$QS_CMD; miraclemsg exit" -MIRACLE_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - else - TEMP_CONFIG=$(mktemp) - cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG" - cat >> "$TEMP_CONFIG" << MIRACLE_EOF - -exec "$QS_CMD; miraclemsg exit" -MIRACLE_EOF - COMPOSITOR_CONFIG="$TEMP_CONFIG" - fi - exec_compositor "miracle" miracle-wm -c "$COMPOSITOR_CONFIG" - ;; - - labwc) - require_command "labwc" - if [[ -n "$COMPOSITOR_CONFIG" ]]; then - exec_compositor "labwc" labwc --config "$COMPOSITOR_CONFIG" --session "$QS_CMD" - else - exec_compositor "labwc" labwc --session "$QS_CMD" - fi - ;; - - mango|mangowc) - require_command "mango" - if [[ -n "$COMPOSITOR_CONFIG" ]]; then - exec_compositor "mango" mango -c "$COMPOSITOR_CONFIG" -s "$QS_CMD && mmsg -d quit" - else - exec_compositor "mango" mango -s "$QS_CMD && mmsg -d quit" - fi - ;; - - *) - echo "Error: Unsupported compositor: $COMPOSITOR" >&2 - echo "Supported compositors: niri, hyprland, sway, scroll, miracle, mango, labwc" >&2 - exit 1 - ;; -esac diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-hypr.conf b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-hypr.conf deleted file mode 100644 index 33eefcd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-hypr.conf +++ /dev/null @@ -1,3 +0,0 @@ -env = DMS_RUN_GREETER,1 - -exec = sh -c "qs -p _DMS_PATH_; hyprctl dispatch exit" diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-niri.kdl b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-niri.kdl deleted file mode 100644 index dfc4703..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/dms-niri.kdl +++ /dev/null @@ -1,23 +0,0 @@ -hotkey-overlay { - skip-at-startup -} - -environment { - DMS_RUN_GREETER "1" -} - -spawn-at-startup "sh" "-c" "qs -p _DMS_PATH_; niri msg action quit --skip-confirmation" - -debug { - keep-max-bpc-unchanged -} - -gestures { - hot-corners { - off - } -} - -layout { - background-color "#000000" -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-hyprland.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-hyprland.sh deleted file mode 100755 index c23b479..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-hyprland.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -export XDG_SESSION_TYPE=wayland -export QT_QPA_PLATFORM=wayland -export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 -export EGL_PLATFORM=gbm -if command -v start-hyprland >/dev/null 2>&1; then - exec start-hyprland -- -c /etc/greetd/dms-hypr.conf -else - exec Hyprland -c /etc/greetd/dms-hypr.conf -fi diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-niri.sh b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-niri.sh deleted file mode 100755 index d31db65..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Greetd/assets/greet-niri.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -export XDG_SESSION_TYPE=wayland -export QT_QPA_PLATFORM=wayland -export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 -export EGL_PLATFORM=gbm - -exec niri -c /etc/greetd/dms-niri.kdl diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/CustomButtonKeyboard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/CustomButtonKeyboard.qml deleted file mode 100644 index 639389c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/CustomButtonKeyboard.qml +++ /dev/null @@ -1,41 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankActionButton { - id: customButtonKeyboard - circular: false - property string text: "" - width: 40 - height: 40 - property bool isShift: false - color: Theme.surface - - property bool isIcon: text === "keyboard_hide" || text === "Backspace" || text === "Enter" - - DankIcon { - anchors.centerIn: parent - name: { - if (parent.text === "keyboard_hide") return "keyboard_hide" - if (parent.text === "Backspace") return "backspace" - if (parent.text === "Enter") return "keyboard_return" - return "" - } - size: 20 - color: Theme.surfaceText - visible: parent.isIcon - } - - StyledText { - id: contentItem - anchors.centerIn: parent - text: parent.text - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeXLarge - font.weight: Font.Normal - visible: !parent.isIcon - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToDpmsWindow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToDpmsWindow.qml deleted file mode 100644 index 0486890..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToDpmsWindow.qml +++ /dev/null @@ -1,102 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common - -PanelWindow { - id: root - - property bool active: false - - signal fadeCompleted - signal fadeCancelled - - visible: active - color: "transparent" - - WlrLayershell.namespace: "dms:fade-to-dpms" - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: active ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None - - anchors { - left: true - right: true - top: true - bottom: true - } - - Rectangle { - id: fadeOverlay - anchors.fill: parent - color: "black" - opacity: 0 - - onOpacityChanged: { - if (opacity >= 0.99 && root.active) { - root.fadeCompleted(); - } - } - } - - SequentialAnimation { - id: fadeSeq - running: false - - NumberAnimation { - target: fadeOverlay - property: "opacity" - from: 0.0 - to: 1.0 - duration: SettingsData.fadeToDpmsGracePeriod * 1000 - easing.type: Easing.OutCubic - } - } - - function startFade() { - if (!SettingsData.fadeToDpmsEnabled) - return; - active = true; - fadeOverlay.opacity = 0.0; - fadeSeq.stop(); - fadeSeq.start(); - } - - function cancelFade() { - fadeSeq.stop(); - fadeOverlay.opacity = 0.0; - active = false; - fadeCancelled(); - } - - MouseArea { - anchors.fill: parent - enabled: root.active - onClicked: root.cancelFade() - onPressed: root.cancelFade() - } - - FocusScope { - anchors.fill: parent - focus: root.active - - Keys.onPressed: event => { - root.cancelFade(); - event.accepted = true; - } - } - - Component.onCompleted: { - if (active) { - forceActiveFocus(); - } - } - - onActiveChanged: { - if (active) { - forceActiveFocus(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToLockWindow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToLockWindow.qml deleted file mode 100644 index c73a59a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/FadeToLockWindow.qml +++ /dev/null @@ -1,102 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common - -PanelWindow { - id: root - - property bool active: false - - signal fadeCompleted - signal fadeCancelled - - visible: active - color: "transparent" - - WlrLayershell.namespace: "dms:fade-to-lock" - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: active ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None - - anchors { - left: true - right: true - top: true - bottom: true - } - - Rectangle { - id: fadeOverlay - anchors.fill: parent - color: "black" - opacity: 0 - - onOpacityChanged: { - if (opacity >= 0.99 && root.active) { - root.fadeCompleted(); - } - } - } - - SequentialAnimation { - id: fadeSeq - running: false - - NumberAnimation { - target: fadeOverlay - property: "opacity" - from: 0.0 - to: 1.0 - duration: SettingsData.fadeToLockGracePeriod * 1000 - easing.type: Easing.OutCubic - } - } - - function startFade() { - if (!SettingsData.fadeToLockEnabled) - return; - active = true; - fadeOverlay.opacity = 0.0; - fadeSeq.stop(); - fadeSeq.start(); - } - - function cancelFade() { - fadeSeq.stop(); - fadeOverlay.opacity = 0.0; - active = false; - fadeCancelled(); - } - - MouseArea { - anchors.fill: parent - enabled: root.active - onClicked: root.cancelFade() - onPressed: root.cancelFade() - } - - FocusScope { - anchors.fill: parent - focus: root.active - - Keys.onPressed: event => { - root.cancelFade(); - event.accepted = true; - } - } - - Component.onCompleted: { - if (active) { - forceActiveFocus(); - } - } - - onActiveChanged: { - if (active) { - forceActiveFocus(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Keyboard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Keyboard.qml deleted file mode 100644 index cfc0c61..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Keyboard.qml +++ /dev/null @@ -1,344 +0,0 @@ -import QtQuick -import qs.Common - -Rectangle { - id: root - property Item target - height: 60 * 5 - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - color: Theme.surfaceContainerHigh - - signal dismissed - - property double rowSpacing: 0.01 * width // horizontal spacing between keyboard - property double columnSpacing: 0.02 * height // vertical spacing between keyboard - property bool shift: false //Boolean for the shift state - property bool symbols: false //Boolean for the symbol state - property double columns: 10 // Number of column - property double rows: 4 // Number of row - - property string strShift: '\u2191' - property string strBackspace: "Backspace" - property string strEnter: "Enter" - property string strClose: "keyboard_hide" - - property var modelKeyboard: { - "row_1": [{ - "text": 'q', - "symbol": '1', - "width": 1 - }, { - "text": 'w', - "symbol": '2', - "width": 1 - }, { - "text": 'e', - "symbol": '3', - "width": 1 - }, { - "text": 'r', - "symbol": '4', - "width": 1 - }, { - "text": 't', - "symbol": '5', - "width": 1 - }, { - "text": 'y', - "symbol": '6', - "width": 1 - }, { - "text": 'u', - "symbol": '7', - "width": 1 - }, { - "text": 'i', - "symbol": '8', - "width": 1 - }, { - "text": 'o', - "symbol": '9', - "width": 1 - }, { - "text": 'p', - "symbol": '0', - "width": 1 - }], - "row_2": [{ - "text": 'a', - "symbol": '-', - "width": 1 - }, { - "text": 's', - "symbol": '/', - "width": 1 - }, { - "text": 'd', - "symbol": ':', - "width": 1 - }, { - "text": 'f', - "symbol": ';', - "width": 1 - }, { - "text": 'g', - "symbol": '(', - "width": 1 - }, { - "text": 'h', - "symbol": ')', - "width": 1 - }, { - "text": 'j', - "symbol": '€', - "width": 1 - }, { - "text": 'k', - "symbol": '&', - "width": 1 - }, { - "text": 'l', - "symbol": '@', - "width": 1 - }], - "row_3": [{ - "text": strShift, - "symbol": strShift, - "width": 1.5 - }, { - "text": 'z', - "symbol": '.', - "width": 1 - }, { - "text": 'x', - "symbol": ',', - "width": 1 - }, { - "text": 'c', - "symbol": '?', - "width": 1 - }, { - "text": 'v', - "symbol": '!', - "width": 1 - }, { - "text": 'b', - "symbol": "'", - "width": 1 - }, { - "text": 'n', - "symbol": "%", - "width": 1 - }, { - "text": 'm', - "symbol": '"', - "width": 1 - }, { - "text": strBackspace, - "symbol": strBackspace, - "width": 1.5 - }], - "row_4": [{ - "text": strClose, - "symbol": strClose, - "width": 1.5 - }, { - "text": "123", - "symbol": 'ABC', - "width": 1.5 - }, { - "text": ' ', - "symbol": ' ', - "width": 4.5 - }, { - "text": '.', - "symbol": '.', - "width": 1 - }, { - "text": strEnter, - "symbol": strEnter, - "width": 1.5 - }] - } - - //Here is the corresponding table between the ascii and the key event - property var tableKeyEvent: { - "_0": Qt.Key_0, - "_1": Qt.Key_1, - "_2": Qt.Key_2, - "_3": Qt.Key_3, - "_4": Qt.Key_4, - "_5": Qt.Key_5, - "_6": Qt.Key_6, - "_7": Qt.Key_7, - "_8": Qt.Key_8, - "_9": Qt.Key_9, - "_a": Qt.Key_A, - "_b": Qt.Key_B, - "_c": Qt.Key_C, - "_d": Qt.Key_D, - "_e": Qt.Key_E, - "_f": Qt.Key_F, - "_g": Qt.Key_G, - "_h": Qt.Key_H, - "_i": Qt.Key_I, - "_j": Qt.Key_J, - "_k": Qt.Key_K, - "_l": Qt.Key_L, - "_m": Qt.Key_M, - "_n": Qt.Key_N, - "_o": Qt.Key_O, - "_p": Qt.Key_P, - "_q": Qt.Key_Q, - "_r": Qt.Key_R, - "_s": Qt.Key_S, - "_t": Qt.Key_T, - "_u": Qt.Key_U, - "_v": Qt.Key_V, - "_w": Qt.Key_W, - "_x": Qt.Key_X, - "_y": Qt.Key_Y, - "_z": Qt.Key_Z, - "_←": Qt.Key_Backspace, - "_return": Qt.Key_Return, - "_ ": Qt.Key_Space, - "_-": Qt.Key_Minus, - "_/": Qt.Key_Slash, - "_:": Qt.Key_Colon, - "_;": Qt.Key_Semicolon, - "_(": Qt.Key_BracketLeft, - "_)": Qt.Key_BracketRight, - "_€": parseInt( - "20ac", - 16) // I didn't find the appropriate Qt event so I used the hex format - , - "_&": Qt.Key_Ampersand, - "_@": Qt.Key_At, - '_"': Qt.Key_QuoteDbl, - "_.": Qt.Key_Period, - "_,": Qt.Key_Comma, - "_?": Qt.Key_Question, - "_!": Qt.Key_Exclam, - "_'": Qt.Key_Apostrophe, - "_%": Qt.Key_Percent, - "_*": Qt.Key_Asterisk -} - -Item { -id: keyboard_container -anchors.left: parent.left -anchors.leftMargin: 5 -anchors.right: parent.right -anchors.top: parent.top -anchors.topMargin: 5 -anchors.bottom: parent.bottom -anchors.bottomMargin: 5 - -//One column which contains 5 rows -Column { -spacing: columnSpacing - -Row { -id: row_1 -spacing: rowSpacing -Repeater { -model: modelKeyboard["row_1"] -delegate: CustomButtonKeyboard { -text: symbols ? modelData.symbol : shift ? modelData.text.toUpperCase -() : modelData.text -width: modelData.width * keyboard_container.width / columns - rowSpacing -height: keyboard_container.height / rows - columnSpacing - -onClicked: root.clicked(text) -} -} -} -Row { -id: row_2 -spacing: rowSpacing -Repeater { -model: modelKeyboard["row_2"] -delegate: CustomButtonKeyboard { -text: symbols ? modelData.symbol : shift ? modelData.text.toUpperCase -() : modelData.text -width: modelData.width * keyboard_container.width / columns - rowSpacing -height: keyboard_container.height / rows - columnSpacing - -onClicked: root.clicked(text) -} -} -} -Row { -id: row_3 -spacing: rowSpacing -Repeater { -model: modelKeyboard["row_3"] -delegate: CustomButtonKeyboard { -text: symbols ? modelData.symbol : shift ? modelData.text.toUpperCase -() : modelData.text -width: modelData.width * keyboard_container.width / columns - rowSpacing -height: keyboard_container.height / rows - columnSpacing -isShift: shift && text === strShift - -onClicked: root.clicked(text) -} -} -} -Row { -id: row_4 -spacing: rowSpacing -Repeater { -model: modelKeyboard["row_4"] -delegate: CustomButtonKeyboard { -text: symbols ? modelData.symbol : shift ? modelData.text.toUpperCase -() : modelData.text -width: modelData.width * keyboard_container.width / columns - rowSpacing -height: keyboard_container.height / rows - columnSpacing - -onClicked: root.clicked(text) -} -} -} -} -} -signal clicked(string text) - -Connections { -target: root -function onClicked(text) { -if (!keyboard_controller.target) -return -if (text === strShift) { -root.shift = !root.shift -} else if (text === '123') { -root.symbols = true -} else if (text === 'ABC') { -root.symbols = false -} else if (text === strEnter) { -if (keyboard_controller.target.accepted) { -keyboard_controller.target.accepted() -} -} else if (text === strClose) { -root.dismissed() -} else { -if (text === strBackspace) { -var current = keyboard_controller.target.text -keyboard_controller.target.text = current.slice(0, current.length - 1) -} else { -var charToInsert = root.symbols ? text : (root.shift ? text.toUpperCase -() : text) -var current = keyboard_controller.target.text -var cursorPos = keyboard_controller.target.cursorPosition -keyboard_controller.target.text = current.slice(0, -cursorPos) + charToInsert + current.slice(cursorPos) -keyboard_controller.target.cursorPosition = cursorPos + 1 -} - -if (root.shift && text !== strShift) -root.shift = false -} -} -} -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/KeyboardController.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/KeyboardController.qml deleted file mode 100644 index 09d77a5..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/KeyboardController.qml +++ /dev/null @@ -1,40 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick - -Item { - id: keyboard_controller - - // reference on the TextInput - property Item target - //Booléan on the state of the keyboard - property bool isKeyboardActive: false - - property var rootObject - - function show() { - if (!isKeyboardActive && keyboard === null) { - keyboard = keyboardComponent.createObject( - keyboard_controller.rootObject) - keyboard.target = keyboard_controller.target - keyboard.dismissed.connect(hide) - isKeyboardActive = true - } else - console.log("The keyboard is already shown") - } - - function hide() { - if (isKeyboardActive && keyboard !== null) { - keyboard.destroy() - isKeyboardActive = false - } else - console.log("The keyboard is already hidden") - } - - // private - property Item keyboard: null - Component { - id: keyboardComponent - Keyboard {} - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Lock.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Lock.qml deleted file mode 100644 index 9a5a00f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Lock.qml +++ /dev/null @@ -1,296 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Wayland -import qs.Common -import qs.Services - -Scope { - id: root - - property string sharedPasswordBuffer: "" - property bool shouldLock: false - - onShouldLockChanged: { - IdleService.isShellLocked = shouldLock; - if (shouldLock && lockPowerOffArmed) { - lockStateCheck.restart(); - } - } - - Timer { - id: lockStateCheck - interval: 100 - repeat: false - onTriggered: { - if (sessionLock.locked && lockPowerOffArmed) { - pendingLock = false; - IdleService.monitorsOff = true; - CompositorService.powerOffMonitors(); - lockWakeAllowed = false; - lockWakeDebounce.restart(); - lockPowerOffArmed = false; - dpmsReapplyTimer.start(); - } - } - } - - property bool lockInitiatedLocally: false - property bool pendingLock: false - property bool lockPowerOffArmed: false - property bool lockWakeAllowed: false - - Component.onCompleted: { - IdleService.lockComponent = this; - if (SettingsData.lockAtStartup) - lock(); - } - - function notifyLoginctl(lockAction: bool) { - if (!SettingsData.loginctlLockIntegration || !DMSService.isConnected) - return; - if (lockAction) - DMSService.lockSession(() => {}); - else - DMSService.unlockSession(() => {}); - } - - function lock() { - if (SettingsData.customPowerActionLock?.length > 0) { - Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLock]); - return; - } - if (shouldLock || pendingLock) - return; - - lockInitiatedLocally = true; - lockPowerOffArmed = SettingsData.lockScreenPowerOffMonitorsOnLock; - - if (!SessionService.active && SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration) { - pendingLock = true; - notifyLoginctl(true); - return; - } - - shouldLock = true; - notifyLoginctl(true); - } - - function unlock() { - if (!shouldLock) - return; - lockInitiatedLocally = false; - notifyLoginctl(false); - shouldLock = false; - } - - function forceReset() { - lockInitiatedLocally = false; - pendingLock = false; - shouldLock = false; - } - - function activate() { - lock(); - } - - Connections { - target: SessionService - - function onSessionLocked() { - if (shouldLock || pendingLock) - return; - if (!SessionService.active && SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration) { - pendingLock = true; - lockInitiatedLocally = false; - return; - } - lockInitiatedLocally = false; - lockPowerOffArmed = SettingsData.lockScreenPowerOffMonitorsOnLock; - shouldLock = true; - } - - function onSessionUnlocked() { - if (pendingLock) { - pendingLock = false; - lockInitiatedLocally = false; - return; - } - if (!shouldLock || lockInitiatedLocally) - return; - shouldLock = false; - } - - function onLoginctlStateChanged() { - if (SessionService.active && pendingLock) { - pendingLock = false; - lockInitiatedLocally = true; - lockPowerOffArmed = SettingsData.lockScreenPowerOffMonitorsOnLock; - shouldLock = true; - return; - } - if (SessionService.locked && !shouldLock && !pendingLock) { - lockInitiatedLocally = false; - lockPowerOffArmed = SettingsData.lockScreenPowerOffMonitorsOnLock; - shouldLock = true; - } - } - } - - Connections { - target: IdleService - - function onLockRequested() { - lock(); - } - } - - WlSessionLock { - id: sessionLock - - locked: shouldLock - - WlSessionLockSurface { - id: lockSurface - - property string currentScreenName: screen?.name ?? "" - property bool isActiveScreen: { - if (Quickshell.screens.length <= 1) - return true; - if (SettingsData.lockScreenActiveMonitor === "all") - return true; - return currentScreenName === SettingsData.lockScreenActiveMonitor; - } - - color: isActiveScreen ? "transparent" : SettingsData.lockScreenInactiveColor - - LockSurface { - anchors.fill: parent - visible: lockSurface.isActiveScreen - lock: sessionLock - sharedPasswordBuffer: root.sharedPasswordBuffer - screenName: lockSurface.currentScreenName - isLocked: shouldLock - onUnlockRequested: root.unlock() - onPasswordChanged: newPassword => { - root.sharedPasswordBuffer = newPassword; - } - } - } - } - - Connections { - target: sessionLock - - function onLockedChanged() { - if (sessionLock.locked) { - pendingLock = false; - if (lockPowerOffArmed && SettingsData.lockScreenPowerOffMonitorsOnLock) { - IdleService.monitorsOff = true; - CompositorService.powerOffMonitors(); - lockWakeAllowed = false; - lockWakeDebounce.restart(); - } - lockPowerOffArmed = false; - dpmsReapplyTimer.start(); - return; - } - - lockWakeAllowed = false; - if (IdleService.monitorsOff && SettingsData.lockScreenPowerOffMonitorsOnLock) { - IdleService.monitorsOff = false; - CompositorService.powerOnMonitors(); - } - } - } - - LockScreenDemo { - id: demoWindow - } - - IpcHandler { - target: "lock" - - function lock() { - root.lock(); - } - - function unlock() { - root.unlock(); - } - - function forceReset() { - root.forceReset(); - } - - function demo() { - demoWindow.showDemo(); - } - - function isLocked(): bool { - return sessionLock.locked; - } - - function status(): string { - return JSON.stringify({ - shouldLock: root.shouldLock, - sessionLockLocked: sessionLock.locked, - lockInitiatedLocally: root.lockInitiatedLocally, - pendingLock: root.pendingLock, - loginctlLocked: SessionService.locked, - loginctlActive: SessionService.active - }); - } - } - - Timer { - id: dpmsReapplyTimer - interval: 100 - repeat: false - onTriggered: IdleService.reapplyDpmsIfNeeded() - } - - Timer { - id: lockWakeDebounce - interval: 200 - repeat: false - onTriggered: { - if (!sessionLock.locked) - return; - if (!SettingsData.lockScreenPowerOffMonitorsOnLock) - return; - if (!IdleService.monitorsOff) { - lockWakeAllowed = true; - return; - } - if (lockWakeAllowed) { - IdleService.monitorsOff = false; - CompositorService.powerOnMonitors(); - } else { - lockWakeAllowed = true; - } - } - } - - MouseArea { - anchors.fill: parent - enabled: sessionLock.locked - hoverEnabled: enabled - onPressed: lockWakeDebounce.restart() - onPositionChanged: lockWakeDebounce.restart() - onWheel: lockWakeDebounce.restart() - } - - FocusScope { - anchors.fill: parent - focus: sessionLock.locked - - Keys.onPressed: event => { - if (!sessionLock.locked) - return; - lockWakeDebounce.restart(); - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockPowerMenu.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockPowerMenu.qml deleted file mode 100644 index 0a0ee84..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockPowerMenu.qml +++ /dev/null @@ -1,820 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Effects -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - property bool isVisible: false - property bool showLogout: true - property int selectedIndex: 0 - property int selectedRow: 0 - property int selectedCol: 0 - property var visibleActions: [] - property int gridColumns: 3 - property int gridRows: 2 - property bool useGridLayout: false - - property string holdAction: "" - property int holdActionIndex: -1 - property real holdProgress: 0 - property bool showHoldHint: false - - property var powerActionConfirmOverride: undefined - property var powerActionHoldDurationOverride: undefined - property var powerMenuActionsOverride: undefined - property var powerMenuDefaultActionOverride: undefined - property var powerMenuGridLayoutOverride: undefined - property var requiredActions: [] - - readonly property bool needsConfirmation: powerActionConfirmOverride !== undefined ? powerActionConfirmOverride : SettingsData.powerActionConfirm - readonly property int holdDurationMs: (powerActionHoldDurationOverride !== undefined ? powerActionHoldDurationOverride : SettingsData.powerActionHoldDuration) * 1000 - - signal closed - - function updateVisibleActions() { - const allActions = powerMenuActionsOverride !== undefined ? powerMenuActionsOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuActions) ? SettingsData.powerMenuActions : ["logout", "suspend", "hibernate", "reboot", "poweroff"]); - const hibernateSupported = (typeof SessionService !== "undefined" && SessionService.hibernateSupported) || false; - let filtered = allActions.filter(action => { - if (action === "hibernate" && !hibernateSupported) - return false; - if (action === "lock") - return false; - if (action === "restart") - return false; - if (action === "logout" && !showLogout) - return false; - return true; - }); - - for (const action of requiredActions) { - if (!filtered.includes(action)) - filtered.push(action); - } - - visibleActions = filtered; - - useGridLayout = powerMenuGridLayoutOverride !== undefined ? powerMenuGridLayoutOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuGridLayout !== undefined) ? SettingsData.powerMenuGridLayout : false); - if (!useGridLayout) - return; - const count = visibleActions.length; - if (count === 0) { - gridColumns = 1; - gridRows = 1; - return; - } - - if (count <= 3) { - gridColumns = 1; - gridRows = count; - return; - } - - if (count === 4) { - gridColumns = 2; - gridRows = 2; - return; - } - - gridColumns = 3; - gridRows = Math.ceil(count / 3); - } - - function getDefaultActionIndex() { - const defaultAction = powerMenuDefaultActionOverride !== undefined ? powerMenuDefaultActionOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuDefaultAction) ? SettingsData.powerMenuDefaultAction : "suspend"); - const index = visibleActions.indexOf(defaultAction); - return index >= 0 ? index : 0; - } - - function getActionAtIndex(index) { - if (index < 0 || index >= visibleActions.length) - return ""; - return visibleActions[index]; - } - - function getActionData(action) { - switch (action) { - case "reboot": - return { - "icon": "restart_alt", - "label": I18n.tr("Reboot"), - "key": "R" - }; - case "logout": - return { - "icon": "logout", - "label": I18n.tr("Log Out"), - "key": "X" - }; - case "poweroff": - return { - "icon": "power_settings_new", - "label": I18n.tr("Power Off"), - "key": "P" - }; - case "suspend": - return { - "icon": "bedtime", - "label": I18n.tr("Suspend"), - "key": "S" - }; - case "hibernate": - return { - "icon": "ac_unit", - "label": I18n.tr("Hibernate"), - "key": "H" - }; - default: - return { - "icon": "help", - "label": action, - "key": "?" - }; - } - } - - function actionNeedsConfirm(action) { - return action !== "lock" && action !== "restart"; - } - - function startHold(action, actionIndex) { - if (!needsConfirmation || !actionNeedsConfirm(action)) { - executeAction(action); - return; - } - holdAction = action; - holdActionIndex = actionIndex; - holdProgress = 0; - showHoldHint = false; - holdTimer.start(); - } - - function cancelHold() { - if (holdAction === "") - return; - const wasHolding = holdProgress > 0; - holdTimer.stop(); - if (wasHolding && holdProgress < 1) { - showHoldHint = true; - hintTimer.restart(); - } - holdAction = ""; - holdActionIndex = -1; - holdProgress = 0; - } - - function completeHold() { - if (holdProgress < 1) { - cancelHold(); - return; - } - const action = holdAction; - holdTimer.stop(); - holdAction = ""; - holdActionIndex = -1; - holdProgress = 0; - executeAction(action); - } - - function executeAction(action) { - if (!action) - return; - if (typeof SessionService === "undefined") - return; - hide(); - switch (action) { - case "logout": - SessionService.logout(); - break; - case "suspend": - SessionService.suspend(); - break; - case "hibernate": - SessionService.hibernate(); - break; - case "reboot": - SessionService.reboot(); - break; - case "poweroff": - SessionService.poweroff(); - break; - } - } - - function selectOption(action, actionIndex) { - startHold(action, actionIndex !== undefined ? actionIndex : -1); - } - - function show() { - holdAction = ""; - holdActionIndex = -1; - holdProgress = 0; - showHoldHint = false; - updateVisibleActions(); - const defaultIndex = getDefaultActionIndex(); - if (useGridLayout) { - selectedRow = Math.floor(defaultIndex / gridColumns); - selectedCol = defaultIndex % gridColumns; - selectedIndex = defaultIndex; - } else { - selectedIndex = defaultIndex; - } - isVisible = true; - Qt.callLater(() => powerMenuFocusScope.forceActiveFocus()); - } - - function hide() { - cancelHold(); - isVisible = false; - closed(); - } - - function handleListNavigation(event, isPressed) { - if (!isPressed) { - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_R || event.key === Qt.Key_X || event.key === Qt.Key_S || event.key === Qt.Key_H || (event.key === Qt.Key_P && !(event.modifiers & Qt.ControlModifier))) { - cancelHold(); - event.accepted = true; - } - return; - } - - switch (event.key) { - case Qt.Key_Up: - case Qt.Key_Backtab: - selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length; - event.accepted = true; - break; - case Qt.Key_Down: - case Qt.Key_Tab: - selectedIndex = (selectedIndex + 1) % visibleActions.length; - event.accepted = true; - break; - case Qt.Key_Return: - case Qt.Key_Enter: - startHold(getActionAtIndex(selectedIndex), selectedIndex); - event.accepted = true; - break; - case Qt.Key_N: - if (event.modifiers & Qt.ControlModifier) { - selectedIndex = (selectedIndex + 1) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_P: - if (!(event.modifiers & Qt.ControlModifier)) { - const idx = visibleActions.indexOf("poweroff"); - startHold("poweroff", idx); - event.accepted = true; - } else { - selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_J: - if (event.modifiers & Qt.ControlModifier) { - selectedIndex = (selectedIndex + 1) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_K: - if (event.modifiers & Qt.ControlModifier) { - selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length; - event.accepted = true; - } - break; - case Qt.Key_R: - startHold("reboot", visibleActions.indexOf("reboot")); - event.accepted = true; - break; - case Qt.Key_X: - startHold("logout", visibleActions.indexOf("logout")); - event.accepted = true; - break; - case Qt.Key_S: - startHold("suspend", visibleActions.indexOf("suspend")); - event.accepted = true; - break; - case Qt.Key_H: - startHold("hibernate", visibleActions.indexOf("hibernate")); - event.accepted = true; - break; - } - } - - function handleGridNavigation(event, isPressed) { - if (!isPressed) { - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_R || event.key === Qt.Key_X || event.key === Qt.Key_S || event.key === Qt.Key_H || (event.key === Qt.Key_P && !(event.modifiers & Qt.ControlModifier))) { - cancelHold(); - event.accepted = true; - } - return; - } - - switch (event.key) { - case Qt.Key_Left: - selectedCol = (selectedCol - 1 + gridColumns) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Right: - selectedCol = (selectedCol + 1) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Up: - case Qt.Key_Backtab: - selectedRow = (selectedRow - 1 + gridRows) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Down: - case Qt.Key_Tab: - selectedRow = (selectedRow + 1) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - break; - case Qt.Key_Return: - case Qt.Key_Enter: - startHold(getActionAtIndex(selectedIndex), selectedIndex); - event.accepted = true; - break; - case Qt.Key_N: - if (event.modifiers & Qt.ControlModifier) { - selectedCol = (selectedCol + 1) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_P: - if (!(event.modifiers & Qt.ControlModifier)) { - const idx = visibleActions.indexOf("poweroff"); - startHold("poweroff", idx); - event.accepted = true; - } else { - selectedCol = (selectedCol - 1 + gridColumns) % gridColumns; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_J: - if (event.modifiers & Qt.ControlModifier) { - selectedRow = (selectedRow + 1) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_K: - if (event.modifiers & Qt.ControlModifier) { - selectedRow = (selectedRow - 1 + gridRows) % gridRows; - selectedIndex = selectedRow * gridColumns + selectedCol; - event.accepted = true; - } - break; - case Qt.Key_R: - startHold("reboot", visibleActions.indexOf("reboot")); - event.accepted = true; - break; - case Qt.Key_X: - startHold("logout", visibleActions.indexOf("logout")); - event.accepted = true; - break; - case Qt.Key_S: - startHold("suspend", visibleActions.indexOf("suspend")); - event.accepted = true; - break; - case Qt.Key_H: - startHold("hibernate", visibleActions.indexOf("hibernate")); - event.accepted = true; - break; - } - } - - anchors.fill: parent - color: Qt.rgba(0, 0, 0, 0.5) - visible: isVisible - z: 1000 - - MouseArea { - anchors.fill: parent - onClicked: root.hide() - } - - Timer { - id: holdTimer - interval: 16 - repeat: true - onTriggered: { - root.holdProgress = Math.min(1, root.holdProgress + (interval / root.holdDurationMs)); - if (root.holdProgress >= 1) { - stop(); - root.completeHold(); - } - } - } - - Timer { - id: hintTimer - interval: 2000 - onTriggered: root.showHoldHint = false - } - - FocusScope { - id: powerMenuFocusScope - anchors.fill: parent - focus: root.isVisible - - onVisibleChanged: { - if (visible) - Qt.callLater(() => forceActiveFocus()); - } - - Keys.onEscapePressed: root.hide() - Keys.onPressed: event => { - if (event.isAutoRepeat) { - event.accepted = true; - return; - } - if (useGridLayout) { - handleGridNavigation(event, true); - } else { - handleListNavigation(event, true); - } - } - Keys.onReleased: event => { - if (event.isAutoRepeat) { - event.accepted = true; - return; - } - if (useGridLayout) { - handleGridNavigation(event, false); - } else { - handleListNavigation(event, false); - } - } - - Rectangle { - anchors.centerIn: parent - width: useGridLayout ? Math.min(550, gridColumns * 180 + Theme.spacingS * (gridColumns - 1) + Theme.spacingL * 2) : 320 - height: contentItem.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - border.color: Theme.outlineMedium - border.width: 1 - - Item { - id: contentItem - anchors.fill: parent - anchors.margins: Theme.spacingL - implicitHeight: headerRow.height + Theme.spacingM + (useGridLayout ? buttonGrid.implicitHeight : buttonColumn.implicitHeight) + (root.needsConfirmation ? hintRow.height + Theme.spacingM : 0) - - Row { - id: headerRow - width: parent.width - height: 30 - - StyledText { - text: I18n.tr("Power Options") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - 150 - height: 1 - } - - DankActionButton { - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.hide() - } - } - - Grid { - id: buttonGrid - visible: useGridLayout - anchors.top: headerRow.bottom - anchors.topMargin: Theme.spacingM - anchors.horizontalCenter: parent.horizontalCenter - columns: root.gridColumns - columnSpacing: Theme.spacingS - rowSpacing: Theme.spacingS - width: parent.width - - Repeater { - model: root.visibleActions - - Rectangle { - id: gridButtonRect - required property int index - required property string modelData - - readonly property var actionData: root.getActionData(modelData) - readonly property bool isSelected: root.selectedIndex === index - readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff" - readonly property bool isHolding: root.holdActionIndex === index && root.holdProgress > 0 - - width: (contentItem.width - Theme.spacingS * (root.gridColumns - 1)) / root.gridColumns - height: 100 - radius: Theme.cornerRadius - color: { - if (isSelected) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12); - if (mouseArea.containsMouse) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08); - return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08); - } - border.color: isSelected ? Theme.primary : "transparent" - border.width: isSelected ? 2 : 0 - - Rectangle { - id: gridProgressMask - anchors.fill: parent - radius: parent.radius - visible: false - layer.enabled: true - } - - Item { - anchors.fill: parent - visible: gridButtonRect.isHolding - layer.enabled: gridButtonRect.isHolding - layer.effect: MultiEffect { - maskEnabled: true - maskSource: gridProgressMask - maskSpreadAtMin: 1 - maskThresholdMin: 0.5 - } - - Rectangle { - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - width: parent.width * root.holdProgress - color: { - if (gridButtonRect.modelData === "poweroff") - return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3); - if (gridButtonRect.modelData === "reboot") - return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3); - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - } - } - } - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: gridButtonRect.actionData.icon - size: Theme.iconSize + 8 - color: { - if (gridButtonRect.showWarning && (mouseArea.containsMouse || gridButtonRect.isHolding)) { - return gridButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: gridButtonRect.actionData.label - font.pixelSize: Theme.fontSizeMedium - color: { - if (gridButtonRect.showWarning && (mouseArea.containsMouse || gridButtonRect.isHolding)) { - return gridButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Rectangle { - width: 20 - height: 16 - radius: 4 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: gridButtonRect.actionData.key - font.pixelSize: Theme.fontSizeSmall - 1 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - anchors.centerIn: parent - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - root.selectedRow = Math.floor(index / root.gridColumns); - root.selectedCol = index % root.gridColumns; - root.selectedIndex = index; - root.startHold(modelData, index); - } - onReleased: root.cancelHold() - onCanceled: root.cancelHold() - } - } - } - } - - Column { - id: buttonColumn - visible: !useGridLayout - anchors.top: headerRow.bottom - anchors.topMargin: Theme.spacingM - anchors.left: parent.left - anchors.right: parent.right - spacing: Theme.spacingS - - Repeater { - model: root.visibleActions - - Rectangle { - id: listButtonRect - required property int index - required property string modelData - - readonly property var actionData: root.getActionData(modelData) - readonly property bool isSelected: root.selectedIndex === index - readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff" - readonly property bool isHolding: root.holdActionIndex === index && root.holdProgress > 0 - - width: parent.width - height: 50 - radius: Theme.cornerRadius - color: { - if (isSelected) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12); - if (listMouseArea.containsMouse) - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08); - return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08); - } - border.color: isSelected ? Theme.primary : "transparent" - border.width: isSelected ? 2 : 0 - - Rectangle { - id: listProgressMask - anchors.fill: parent - radius: parent.radius - visible: false - layer.enabled: true - } - - Item { - anchors.fill: parent - visible: listButtonRect.isHolding - layer.enabled: listButtonRect.isHolding - layer.effect: MultiEffect { - maskEnabled: true - maskSource: listProgressMask - maskSpreadAtMin: 1 - maskThresholdMin: 0.5 - } - - Rectangle { - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - width: parent.width * root.holdProgress - color: { - if (listButtonRect.modelData === "poweroff") - return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3); - if (listButtonRect.modelData === "reboot") - return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3); - return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3); - } - } - } - - Row { - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: listButtonRect.actionData.icon - size: Theme.iconSize + 4 - color: { - if (listButtonRect.showWarning && (listMouseArea.containsMouse || listButtonRect.isHolding)) { - return listButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: listButtonRect.actionData.label - font.pixelSize: Theme.fontSizeMedium - color: { - if (listButtonRect.showWarning && (listMouseArea.containsMouse || listButtonRect.isHolding)) { - return listButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning; - } - return Theme.surfaceText; - } - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - width: 28 - height: 20 - radius: 4 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.1) - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: listButtonRect.actionData.key - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - font.weight: Font.Medium - anchors.centerIn: parent - } - } - - MouseArea { - id: listMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - root.selectedIndex = index; - root.startHold(modelData, index); - } - onReleased: root.cancelHold() - onCanceled: root.cancelHold() - } - } - } - } - - Row { - id: hintRow - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.spacingS - spacing: Theme.spacingXS - visible: root.needsConfirmation - opacity: root.showHoldHint ? 1 : 0.5 - - Behavior on opacity { - NumberAnimation { - duration: 150 - } - } - - DankIcon { - name: root.showHoldHint ? "warning" : "touch_app" - size: Theme.fontSizeSmall - color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - readonly property real totalMs: root.holdDurationMs - readonly property int remainingMs: Math.ceil(totalMs * (1 - root.holdProgress)) - readonly property real durationSec: root.holdDurationMs / 1000 - text: { - if (root.showHoldHint) - return I18n.tr("Hold longer to confirm"); - if (root.holdProgress > 0) { - if (totalMs < 1000) - return I18n.tr("Hold to confirm (%1 ms)").arg(remainingMs); - return I18n.tr("Hold to confirm (%1s)").arg(Math.ceil(remainingMs / 1000)); - } - if (totalMs < 1000) - return I18n.tr("Hold to confirm (%1 ms)").arg(totalMs); - return I18n.tr("Hold to confirm (%1s)").arg(durationSec); - } - font.pixelSize: Theme.fontSizeSmall - color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - Component.onCompleted: updateVisibleActions() -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenContent.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenContent.qml deleted file mode 100644 index b296e98..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenContent.qml +++ /dev/null @@ -1,1707 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import QtQuick.Window -import Quickshell -import Quickshell.Hyprland -import Quickshell.Io -import Quickshell.Services.Mpris -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - function encodeFileUrl(path) { - if (!path) - return ""; - return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/'); - } - - property string passwordBuffer: "" - property bool demoMode: false - property string screenName: "" - property bool unlocking: false - property string pamState: "" - property string hyprlandCurrentLayout: "" - property string hyprlandKeyboard: "" - property int hyprlandLayoutCount: 0 - property bool lockerReadySent: false - property bool lockerReadyArmed: false - - signal unlockRequested - - function resetLockState() { - lockerReadySent = false; - lockerReadyArmed = true; - unlocking = false; - pamState = ""; - if (pam) - pam.lockMessage = ""; - } - - function currentAuthFeedbackText() { - if (!pam) - return ""; - if (pam.u2fState === "insert" && !pam.u2fPending) - return I18n.tr("Insert your security key..."); - if (pam.u2fState === "waiting" && !pam.u2fPending) - return I18n.tr("Touch your security key..."); - if (pam.lockMessage && pam.lockMessage.length > 0) - return pam.lockMessage; - if (root.pamState === "error") - return I18n.tr("Authentication error - try again"); - if (root.pamState === "max") - return I18n.tr("Too many attempts - locked out"); - if (root.pamState === "fail") - return I18n.tr("Incorrect password - try again"); - if (pam.fprintState === "error") { - const detail = (pam.fprint.message || "").trim(); - return detail.length > 0 ? I18n.tr("Fingerprint error: %1").arg(detail) : I18n.tr("Fingerprint error"); - } - if (pam.fprintState === "max") - return I18n.tr("Maximum fingerprint attempts reached. Please use password."); - if (pam.fprintState === "fail") - return I18n.tr("Fingerprint not recognized (%1/%2). Please try again or use password.").arg(pam.fprint.tries).arg(SettingsData.maxFprintTries); - return ""; - } - - function authFeedbackIsHint() { - return pam && (pam.u2fState === "waiting" || pam.u2fState === "insert") && !pam.u2fPending; - } - - Component.onCompleted: { - WeatherService.addRef(); - UserInfoService.getUserInfo(); - - if (CompositorService.isHyprland) - updateHyprlandLayout(); - - lockerReadyArmed = true; - } - - Component.onDestruction: { - WeatherService.removeRef(); - } - - function sendLockerReadyOnce() { - if (lockerReadySent) - return; - if (root.unlocking) - return; - lockerReadySent = true; - if (SessionService.loginctlAvailable && DMSService.apiVersion >= 2) { - DMSService.sendRequest("loginctl.lockerReady", null, resp => { - if (resp?.error) - console.warn("lockerReady failed:", resp.error); - else - console.log("lockerReady sent (afterAnimating/afterRendering)"); - }); - } - } - - function maybeSend() { - if (!lockerReadyArmed) - return; - if (root.unlocking) - return; - if (!root.visible || root.opacity <= 0) - return; - Qt.callLater(() => { - if (root.visible && root.opacity > 0 && !root.unlocking) - sendLockerReadyOnce(); - }); - } - - Connections { - target: root.Window.window - enabled: target !== null - - function onAfterAnimating() { - maybeSend(); - } - function onAfterRendering() { - maybeSend(); - } - } - - onVisibleChanged: maybeSend() - onOpacityChanged: maybeSend() - - function updateHyprlandLayout() { - if (CompositorService.isHyprland) { - hyprlandLayoutProcess.running = true; - } - } - - Process { - id: hyprlandLayoutProcess - running: false - command: ["hyprctl", "-j", "devices"] - stdout: StdioCollector { - onStreamFinished: { - try { - const data = JSON.parse(text); - const mainKeyboard = data.keyboards.find(kb => kb.main === true); - if (!mainKeyboard) { - hyprlandCurrentLayout = ""; - hyprlandLayoutCount = 0; - return; - } - hyprlandKeyboard = mainKeyboard.name; - if (mainKeyboard.active_keymap) { - const parts = mainKeyboard.active_keymap.split(" "); - hyprlandCurrentLayout = parts[0].substring(0, 2).toUpperCase(); - } else { - hyprlandCurrentLayout = ""; - } - hyprlandLayoutCount = mainKeyboard.layout ? mainKeyboard.layout.split(",").length : 0; - } catch (e) { - hyprlandCurrentLayout = ""; - hyprlandLayoutCount = 0; - } - } - } - } - - Connections { - target: CompositorService.isHyprland ? Hyprland : null - enabled: CompositorService.isHyprland - - function onRawEvent(event) { - if (event.name === "activelayout") - updateHyprlandLayout(); - } - } - - Loader { - anchors.fill: parent - active: { - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - return !currentWallpaper || (currentWallpaper && currentWallpaper.startsWith("#")); - } - asynchronous: true - - sourceComponent: DankBackdrop { - screenName: root.screenName - } - } - - Image { - id: wallpaperBackground - - anchors.fill: parent - source: { - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - return (currentWallpaper && !currentWallpaper.startsWith("#")) ? encodeFileUrl(currentWallpaper) : ""; - } - fillMode: Theme.getFillMode(SessionData.getMonitorWallpaperFillMode(screenName)) - smooth: true - asynchronous: false - cache: true - visible: source !== "" - layer.enabled: true - - layer.effect: MultiEffect { - autoPaddingEnabled: false - blurEnabled: true - blur: 0.8 - blurMax: 32 - blurMultiplier: 1 - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - anchors.fill: parent - color: "black" - opacity: 0.4 - } - - SystemClock { - id: systemClock - - precision: SystemClock.Seconds - } - - Rectangle { - anchors.fill: parent - color: "transparent" - - Item { - id: clockContainer - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.verticalCenter - anchors.bottomMargin: 60 - width: parent.width - height: clockText.implicitHeight - visible: SettingsData.lockScreenShowTime - - Row { - id: clockText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - spacing: 0 - - property string fullTimeStr: { - const format = SettingsData.getEffectiveTimeFormat(); - return systemClock.date.toLocaleTimeString(Qt.locale(), format); - } - property var timeParts: fullTimeStr.split(':') - property string hours: timeParts[0] || "" - property string minutes: timeParts[1] || "" - property string secondsWithAmPm: timeParts.length > 2 ? timeParts[2] : "" - property string seconds: secondsWithAmPm.replace(/\s*(AM|PM|am|pm)$/i, '') - property string ampm: { - const match = fullTimeStr.match(/\s*(AM|PM|am|pm)$/i); - return match ? match[0].trim() : ""; - } - property bool hasSeconds: timeParts.length > 2 - - StyledText { - width: 75 - text: clockText.hours.length > 1 ? clockText.hours[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - width: 75 - text: clockText.hours.length > 1 ? clockText.hours[1] : clockText.hours.length > 0 ? clockText.hours[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: ":" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - } - - StyledText { - width: 75 - text: clockText.minutes.length > 0 ? clockText.minutes[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - width: 75 - text: clockText.minutes.length > 1 ? clockText.minutes[1] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: clockText.hasSeconds ? ":" : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.hasSeconds - } - - StyledText { - width: 75 - text: clockText.hasSeconds && clockText.seconds.length > 0 ? clockText.seconds[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - visible: clockText.hasSeconds - } - - StyledText { - width: 75 - text: clockText.hasSeconds && clockText.seconds.length > 1 ? clockText.seconds[1] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - visible: clockText.hasSeconds - } - - StyledText { - width: 20 - text: " " - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.ampm !== "" - } - - StyledText { - text: clockText.ampm - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.ampm !== "" - } - } - } - - StyledText { - id: dateText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: clockContainer.bottom - anchors.topMargin: 4 - visible: SettingsData.lockScreenShowDate - text: { - if (SettingsData.lockDateFormat && SettingsData.lockDateFormat.length > 0) { - return systemClock.date.toLocaleDateString(I18n.locale(), SettingsData.lockDateFormat); - } - return systemClock.date.toLocaleDateString(I18n.locale(), Locale.LongFormat); - } - font.pixelSize: Theme.fontSizeXLarge - color: "white" - opacity: 0.9 - } - - Item { - id: lockNotificationPanel - - readonly property int notificationMode: SettingsData.lockScreenNotificationMode - readonly property var notifications: NotificationService.groupedNotifications - readonly property int totalCount: { - let count = 0; - for (const group of notifications) { - count += group.count || 0; - } - return count; - } - readonly property bool hasNotifications: totalCount > 0 - readonly property var appNameGroups: { - const groups = {}; - for (const group of notifications) { - const appName = (group.appName || "Unknown").toLowerCase(); - if (!groups[appName]) { - groups[appName] = { - appName: group.appName || I18n.tr("Unknown"), - count: 0, - latestNotification: group.latestNotification - }; - } - groups[appName].count += group.count || 0; - if (group.latestNotification && (!groups[appName].latestNotification || group.latestNotification.time > groups[appName].latestNotification.time)) { - groups[appName].latestNotification = group.latestNotification; - } - } - return Object.values(groups).sort((a, b) => b.count - a.count); - } - - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: dateText.visible ? dateText.bottom : clockContainer.bottom - anchors.topMargin: Theme.spacingM - width: Math.min(380, parent.width - Theme.spacingXL * 2) - height: notificationMode === 0 || !hasNotifications ? 0 : contentLoader.height - visible: notificationMode > 0 && hasNotifications - clip: true - - Behavior on height { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Loader { - id: contentLoader - anchors.left: parent.left - anchors.right: parent.right - active: lockNotificationPanel.notificationMode > 0 && lockNotificationPanel.hasNotifications - sourceComponent: { - switch (lockNotificationPanel.notificationMode) { - case 1: - return countOnlyComponent; - case 2: - return appNamesComponent; - case 3: - return fullContentComponent; - default: - return null; - } - } - } - - Component { - id: countOnlyComponent - - Rectangle { - width: parent.width - height: 44 - radius: Theme.cornerRadius - color: Qt.rgba(0, 0, 0, 0.3) - border.color: Qt.rgba(1, 1, 1, 0.1) - border.width: 1 - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "notifications" - size: Theme.iconSize - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: lockNotificationPanel.totalCount === 1 ? I18n.tr("1 notification") : I18n.tr("%1 notifications").arg(lockNotificationPanel.totalCount) - font.pixelSize: Theme.fontSizeMedium - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - - Component { - id: appNamesComponent - - Rectangle { - width: parent.width - height: Math.min(appNamesColumn.implicitHeight + Theme.spacingM * 2, 200) - radius: Theme.cornerRadius - color: Qt.rgba(0, 0, 0, 0.3) - border.color: Qt.rgba(1, 1, 1, 0.1) - border.width: 1 - clip: true - - Flickable { - anchors.fill: parent - anchors.margins: Theme.spacingM - contentHeight: appNamesColumn.implicitHeight - clip: true - boundsBehavior: Flickable.StopAtBounds - - Column { - id: appNamesColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: lockNotificationPanel.appNameGroups.slice(0, 5) - - Row { - required property var modelData - width: parent.width - spacing: Theme.spacingS - - DankIcon { - name: "notifications" - size: Theme.iconSize - 4 - color: "white" - opacity: 0.8 - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.appName || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: "white" - elide: Text.ElideRight - width: parent.width - Theme.iconSize - countBadge.width - Theme.spacingS * 2 - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - id: countBadge - width: countText.implicitWidth + Theme.spacingS * 2 - height: 20 - radius: 10 - color: Qt.rgba(1, 1, 1, 0.2) - visible: modelData.count > 1 - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: countText - anchors.centerIn: parent - text: modelData.count > 99 ? "99+" : modelData.count.toString() - font.pixelSize: Theme.fontSizeSmall - color: "white" - } - } - } - } - - StyledText { - visible: lockNotificationPanel.appNameGroups.length > 5 - text: I18n.tr("+ %1 more").arg(lockNotificationPanel.appNameGroups.length - 5) - font.pixelSize: Theme.fontSizeSmall - color: "white" - opacity: 0.7 - } - } - } - } - } - - Component { - id: fullContentComponent - - Rectangle { - width: parent.width - height: Math.min(fullContentColumn.implicitHeight + Theme.spacingM * 2, 280) - radius: Theme.cornerRadius - color: Qt.rgba(0, 0, 0, 0.3) - border.color: Qt.rgba(1, 1, 1, 0.1) - border.width: 1 - clip: true - - Flickable { - anchors.fill: parent - anchors.margins: Theme.spacingM - contentHeight: fullContentColumn.implicitHeight - clip: true - boundsBehavior: Flickable.StopAtBounds - - Column { - id: fullContentColumn - width: parent.width - spacing: Theme.spacingM - - Repeater { - model: { - const items = []; - for (const group of lockNotificationPanel.appNameGroups) { - if (group.latestNotification && items.length < 5) { - items.push(group.latestNotification); - } - } - return items; - } - - Rectangle { - required property var modelData - required property int index - width: parent.width - height: notifContent.implicitHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - 4 - color: Qt.rgba(1, 1, 1, 0.05) - - Column { - id: notifContent - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingS - spacing: 2 - - Row { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: modelData.appName || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: "white" - opacity: 0.7 - elide: Text.ElideRight - width: parent.width - timeText.implicitWidth - Theme.spacingXS - } - - StyledText { - id: timeText - text: modelData.timeStr || "" - font.pixelSize: Theme.fontSizeSmall - color: "white" - opacity: 0.5 - } - } - - StyledText { - width: parent.width - text: modelData.summary || "" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: "white" - elide: Text.ElideRight - maximumLineCount: 1 - visible: text.length > 0 - } - - StyledText { - width: parent.width - text: { - const body = modelData.body || ""; - return body.replace(/<[^>]*>/g, '').replace(/\n/g, ' '); - } - font.pixelSize: Theme.fontSizeSmall - color: "white" - opacity: 0.8 - elide: Text.ElideRight - maximumLineCount: 2 - wrapMode: Text.WordWrap - visible: text.length > 0 - } - } - } - } - - StyledText { - visible: lockNotificationPanel.appNameGroups.length > 5 - text: I18n.tr("+ %1 more").arg(lockNotificationPanel.appNameGroups.length - 5) - font.pixelSize: Theme.fontSizeSmall - color: "white" - opacity: 0.7 - } - } - } - } - } - } - - ColumnLayout { - id: passwordLayout - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: lockNotificationPanel.visible ? lockNotificationPanel.bottom : (dateText.visible ? dateText.bottom : clockContainer.bottom) - anchors.topMargin: Theme.spacingL - spacing: Theme.spacingM - width: 380 - - RowLayout { - spacing: Theme.spacingL - Layout.fillWidth: true - - DankCircularImage { - Layout.preferredWidth: 60 - Layout.preferredHeight: 60 - imageSource: { - if (PortalService.profileImage === "") - return ""; - if (PortalService.profileImage.startsWith("/")) - return encodeFileUrl(PortalService.profileImage); - return PortalService.profileImage; - } - fallbackIcon: "person" - visible: SettingsData.lockScreenShowProfileImage - } - - Rectangle { - property bool showPassword: false - - Layout.fillWidth: true - Layout.preferredHeight: 60 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) - border.color: passwordField.activeFocus ? Theme.primary : Qt.rgba(1, 1, 1, 0.3) - border.width: passwordField.activeFocus ? 2 : 1 - visible: SettingsData.lockScreenShowPasswordField || root.passwordBuffer.length > 0 - - Item { - id: lockIconContainer - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: 20 - height: 20 - - DankIcon { - id: lockIcon - - anchors.centerIn: parent - name: { - if (pam.u2fPending) - return "passkey"; - if (pam.fprint.tries >= SettingsData.maxFprintTries) - return "fingerprint_off"; - if (pam.fprint.active) - return "fingerprint"; - if (pam.u2f.active) - return "passkey"; - return "lock"; - } - size: 20 - color: { - if (pam.fprint.tries >= SettingsData.maxFprintTries) - return Theme.error; - if (pam.u2fState !== "") - return Theme.tertiary; - return passwordField.activeFocus ? Theme.primary : Theme.surfaceVariantText; - } - opacity: pam.passwd.active ? 0 : 1 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - TextInput { - id: passwordField - - anchors.fill: parent - anchors.leftMargin: lockIconContainer.width + Theme.spacingM * 2 - anchors.rightMargin: { - let margin = Theme.spacingM; - if (loadingSpinner.visible) { - margin += loadingSpinner.width; - } - if (enterButton.visible) { - margin += enterButton.width + 2; - } - if (virtualKeyboardButton.visible) { - margin += virtualKeyboardButton.width; - } - if (revealButton.visible) { - margin += revealButton.width; - } - return margin; - } - opacity: 0 - focus: true - enabled: !demoMode - activeFocusOnTab: !demoMode - echoMode: parent.showPassword ? TextInput.Normal : TextInput.Password - onTextChanged: { - if (!demoMode) { - root.passwordBuffer = text; - } - } - onAccepted: { - if (!demoMode && !root.unlocking && !pam.passwd.active && !pam.u2fPending) { - pam.passwd.start(); - } - } - Keys.onPressed: event => { - if (demoMode) { - return; - } - - if (root.unlocking) { - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Escape) { - if (pam.u2fPending) { - pam.cancelU2fPending(); - event.accepted = true; - return; - } - clear(); - } - - if (pam.passwd.active) { - console.log("PAM is active, ignoring input"); - event.accepted = true; - return; - } - } - - Component.onCompleted: { - if (!demoMode) { - forceActiveFocus(); - } - } - - onVisibleChanged: { - if (visible && !demoMode) { - forceActiveFocus(); - } - } - - onActiveFocusChanged: { - if (!activeFocus && !demoMode && visible && passwordField && !powerMenu.isVisible) { - Qt.callLater(() => { - if (passwordField && passwordField.forceActiveFocus) { - passwordField.forceActiveFocus(); - } - }); - } - } - - onEnabledChanged: { - if (enabled && !demoMode && visible && passwordField && !powerMenu.isVisible) { - Qt.callLater(() => { - if (passwordField && passwordField.forceActiveFocus) { - passwordField.forceActiveFocus(); - } - }); - } - } - } - - KeyboardController { - id: keyboardController - target: passwordField - rootObject: root - } - - StyledText { - id: placeholder - - anchors.left: lockIconContainer.right - anchors.leftMargin: Theme.spacingM - anchors.right: (revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right)))) - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - text: { - if (demoMode) { - return ""; - } - if (root.unlocking) { - return "Unlocking..."; - } - if (pam.u2fPending) { - if (pam.u2fState === "insert") - return "Insert your security key..."; - return "Touch your security key..."; - } - if (pam.passwd.active) { - return "Authenticating..."; - } - return "Password..."; - } - color: root.unlocking ? Theme.primary : (pam.passwd.active ? Theme.primary : Theme.outline) - font.pixelSize: Theme.fontSizeMedium - opacity: (demoMode || root.passwordBuffer.length === 0) ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - StyledText { - anchors.left: lockIconContainer.right - anchors.leftMargin: Theme.spacingM - anchors.right: (revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right)))) - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - text: { - if (demoMode) { - return "••••••••"; - } - if (parent.showPassword) { - return root.passwordBuffer; - } - return "•".repeat(root.passwordBuffer.length); - } - color: Theme.surfaceText - font.pixelSize: parent.showPassword ? Theme.fontSizeMedium : Theme.fontSizeLarge - opacity: (demoMode || root.passwordBuffer.length > 0) ? 1 : 0 - clip: true - elide: Text.ElideNone - horizontalAlignment: implicitWidth > width ? Text.AlignRight : Text.AlignLeft - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - } - - DankActionButton { - id: revealButton - - anchors.right: virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right)) - anchors.rightMargin: 0 - anchors.verticalCenter: parent.verticalCenter - iconName: parent.showPassword ? "visibility_off" : "visibility" - buttonSize: 32 - visible: !demoMode && root.passwordBuffer.length > 0 && !pam.passwd.active && !root.unlocking - enabled: visible - onClicked: parent.showPassword = !parent.showPassword - } - DankActionButton { - id: virtualKeyboardButton - - anchors.right: enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right) - anchors.rightMargin: enterButton.visible ? 0 : Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "keyboard" - buttonSize: 32 - visible: !demoMode && !pam.passwd.active && !root.unlocking && !pam.u2fPending - enabled: visible - onClicked: { - if (keyboardController.isKeyboardActive) { - keyboardController.hide(); - } else { - keyboardController.show(); - } - } - } - - Rectangle { - id: loadingSpinner - - anchors.right: enterButton.visible ? enterButton.left : parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - width: 24 - height: 24 - radius: 12 - color: "transparent" - visible: !demoMode && (pam.passwd.active || root.unlocking) - - DankIcon { - anchors.centerIn: parent - name: "check_circle" - size: 20 - color: Theme.primary - visible: root.unlocking - - SequentialAnimation on scale { - running: root.unlocking - - NumberAnimation { - from: 0 - to: 1.2 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedDecel - } - - NumberAnimation { - from: 1.2 - to: 1 - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.emphasizedAccel - } - } - } - - Item { - anchors.fill: parent - visible: pam.passwd.active && !root.unlocking - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.centerIn: parent - color: "transparent" - border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) - border.width: 2 - } - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.centerIn: parent - color: "transparent" - border.color: Theme.primary - border.width: 2 - - Rectangle { - width: parent.width - height: parent.height / 2 - anchors.top: parent.top - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) - } - - RotationAnimation on rotation { - running: pam.passwd.active && !root.unlocking - loops: Animation.Infinite - duration: Anims.durLong - from: 0 - to: 360 - } - } - } - } - - DankActionButton { - id: enterButton - - anchors.right: parent.right - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - iconName: "keyboard_return" - buttonSize: 36 - visible: (demoMode || (!pam.passwd.active && !root.unlocking && !pam.u2fPending)) - enabled: !demoMode - onClicked: { - if (!demoMode && !root.unlocking && !pam.u2fPending) { - pam.passwd.start(); - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - StyledText { - id: authFeedbackText - - Layout.fillWidth: true - Layout.preferredHeight: text.length > 0 ? Math.min(implicitHeight, Math.ceil(Theme.fontSizeSmall * 4.5)) : 0 - text: root.currentAuthFeedbackText() - color: root.authFeedbackIsHint() ? Theme.outline : Theme.error - font.pixelSize: Theme.fontSizeSmall - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - maximumLineCount: 3 - elide: Text.ElideRight - opacity: text.length > 0 ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - Row { - anchors.top: passwordLayout.bottom - anchors.topMargin: Theme.spacingS - anchors.horizontalCenter: passwordLayout.horizontalCenter - spacing: 4 - opacity: DMSService.capsLockState ? 1 : 0 - - DankIcon { - name: "shift_lock" - size: 14 - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Caps Lock is on") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - StyledText { - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: Theme.spacingXL - text: I18n.tr("DEMO MODE - Click anywhere to exit") - font.pixelSize: Theme.fontSizeSmall - color: "white" - opacity: 0.7 - visible: demoMode - } - - Row { - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: Theme.spacingXL - spacing: Theme.spacingL - visible: SettingsData.lockScreenShowSystemIcons - - Item { - width: keyboardLayoutRow.width - height: keyboardLayoutRow.height - anchors.verticalCenter: parent.verticalCenter - visible: { - if (CompositorService.isNiri) { - return NiriService.keyboardLayoutNames.length > 1; - } else if (CompositorService.isHyprland) { - return hyprlandLayoutCount > 1; - } - return false; - } - - Row { - id: keyboardLayoutRow - spacing: 4 - - Item { - width: Theme.iconSize - height: Theme.iconSize - - DankIcon { - name: "keyboard" - size: Theme.iconSize - color: "white" - anchors.centerIn: parent - } - } - - Item { - width: childrenRect.width - height: Theme.iconSize - - StyledText { - text: { - if (CompositorService.isNiri) { - const layout = NiriService.getCurrentKeyboardLayoutName(); - if (!layout) - return ""; - const parts = layout.split(" "); - if (parts.length > 0) { - return parts[0].substring(0, 2).toUpperCase(); - } - return layout.substring(0, 2).toUpperCase(); - } else if (CompositorService.isHyprland) { - return hyprlandCurrentLayout; - } - return ""; - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - - MouseArea { - id: keyboardLayoutArea - anchors.fill: parent - enabled: !demoMode - hoverEnabled: enabled - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: { - if (CompositorService.isNiri) { - NiriService.cycleKeyboardLayout(); - } else if (CompositorService.isHyprland) { - Quickshell.execDetached(["hyprctl", "switchxkblayout", hyprlandKeyboard, "next"]); - updateHyprlandLayout(); - } - } - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: MprisController.activePlayer && SettingsData.lockScreenShowMediaPlayer - } - - Row { - spacing: Theme.spacingS - visible: MprisController.activePlayer && SettingsData.lockScreenShowMediaPlayer - anchors.verticalCenter: parent.verticalCenter - - Item { - width: 20 - height: Theme.iconSize - anchors.verticalCenter: parent.verticalCenter - - Loader { - active: MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing - - sourceComponent: Component { - Ref { - service: CavaService - } - } - } - - Timer { - running: !CavaService.cavaAvailable && MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing - interval: 256 - repeat: true - onTriggered: { - CavaService.values = [Math.random() * 40 + 10, Math.random() * 60 + 20, Math.random() * 50 + 15, Math.random() * 35 + 20, Math.random() * 45 + 15, Math.random() * 55 + 25]; - } - } - - Row { - anchors.centerIn: parent - spacing: 1.5 - - Repeater { - model: 6 - delegate: Rectangle { - required property int index - - width: 2 - height: { - if (MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing && CavaService.values.length > index) { - const rawLevel = CavaService.values[index] || 0; - const scaledLevel = Math.sqrt(Math.min(Math.max(rawLevel, 0), 100) / 100) * 100; - const maxHeight = Theme.iconSize - 2; - const minHeight = 3; - return minHeight + (scaledLevel / 100) * (maxHeight - minHeight); - } - return 3; - } - radius: 1.5 - color: "white" - anchors.verticalCenter: parent.verticalCenter - - Behavior on height { - NumberAnimation { - duration: Anims.durShort - easing.type: Easing.BezierSpline - easing.bezierCurve: Anims.standardDecel - } - } - } - } - } - } - - StyledText { - text: { - const player = MprisController.activePlayer; - if (!player?.trackTitle) - return ""; - const title = player.trackTitle; - const artist = player.trackArtist || ""; - return artist ? title + " • " + artist : title; - } - font.pixelSize: Theme.fontSizeLarge - color: "white" - opacity: 0.9 - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - width: Math.min(implicitWidth, 400) - wrapMode: Text.NoWrap - maximumLineCount: 1 - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.verticalCenter: parent.verticalCenter - color: prevArea.containsMouse ? Qt.rgba(255, 255, 255, 0.2) : "transparent" - visible: MprisController.activePlayer - opacity: (MprisController.activePlayer?.canGoPrevious ?? false) ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: "skip_previous" - size: 12 - color: "white" - } - - MouseArea { - id: prevArea - anchors.fill: parent - enabled: MprisController.activePlayer?.canGoPrevious ?? false - hoverEnabled: enabled - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: MprisController.previousOrRewind() - } - } - - Rectangle { - width: 24 - height: 24 - radius: 12 - anchors.verticalCenter: parent.verticalCenter - color: MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing ? Qt.rgba(255, 255, 255, 0.9) : Qt.rgba(255, 255, 255, 0.2) - visible: MprisController.activePlayer - - DankIcon { - anchors.centerIn: parent - name: MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow" - size: 14 - color: MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing ? "black" : "white" - } - - MouseArea { - anchors.fill: parent - enabled: MprisController.activePlayer - hoverEnabled: enabled - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: MprisController.activePlayer?.togglePlaying() - } - } - - Rectangle { - width: 20 - height: 20 - radius: 10 - anchors.verticalCenter: parent.verticalCenter - color: nextArea.containsMouse ? Qt.rgba(255, 255, 255, 0.2) : "transparent" - visible: MprisController.activePlayer - opacity: (MprisController.activePlayer?.canGoNext ?? false) ? 1 : 0.3 - - DankIcon { - anchors.centerIn: parent - name: "skip_next" - size: 12 - color: "white" - } - - MouseArea { - id: nextArea - anchors.fill: parent - enabled: MprisController.activePlayer?.canGoNext ?? false - hoverEnabled: enabled - cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: MprisController.activePlayer?.next() - } - } - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: MprisController.activePlayer && SettingsData.lockScreenShowMediaPlayer && WeatherService.weather.available - } - - Row { - spacing: 6 - visible: WeatherService.weather.available - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.iconSize - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: (SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: WeatherService.weather.available && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio) || BatteryService.batteryAvailable) - } - - Row { - spacing: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.networkAvailable || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio) - - DankIcon { - name: "screen_record" - size: Theme.iconSize - 2 - color: NiriService.hasActiveCast ? "white" : Qt.rgba(255, 255, 255, 0.5) - anchors.verticalCenter: parent.verticalCenter - visible: NiriService.hasCasts - } - - DankIcon { - name: { - if (NetworkService.wifiToggling) - return "sync"; - switch (NetworkService.networkStatus) { - case "ethernet": - return "lan"; - case "vpn": - return NetworkService.ethernetConnected ? "lan" : NetworkService.wifiSignalIcon; - default: - return NetworkService.wifiSignalIcon; - } - } - size: Theme.iconSize - 2 - color: NetworkService.networkStatus !== "disconnected" ? "white" : Qt.rgba(255, 255, 255, 0.5) - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.networkAvailable - } - - DankIcon { - name: "vpn_lock" - size: Theme.iconSize - 2 - color: "white" - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.vpnAvailable && NetworkService.vpnConnected - } - - DankIcon { - name: "bluetooth" - size: Theme.iconSize - 2 - color: "white" - anchors.verticalCenter: parent.verticalCenter - visible: BluetoothService.available && BluetoothService.enabled - } - - DankIcon { - name: { - if (!AudioService.sink?.audio) { - return "volume_up"; - } - if (AudioService.sink.audio.muted) - return "volume_off"; - if (AudioService.sink.audio.volume === 0) - return "volume_mute"; - if (AudioService.sink.audio.volume * 100 < 33) { - return "volume_down"; - } - return "volume_up"; - } - size: Theme.iconSize - 2 - color: (AudioService.sink && AudioService.sink.audio && (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0)) ? Qt.rgba(255, 255, 255, 0.5) : "white" - anchors.verticalCenter: parent.verticalCenter - visible: AudioService.sink && AudioService.sink.audio - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio)) - } - - Row { - spacing: 4 - visible: BatteryService.batteryAvailable - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: { - if (BatteryService.isCharging) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - - return "battery_charging_20"; - } - if (BatteryService.isPluggedIn) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - - return "battery_charging_20"; - } - if (BatteryService.batteryLevel >= 95) { - return "battery_full"; - } - - if (BatteryService.batteryLevel >= 85) { - return "battery_6_bar"; - } - - if (BatteryService.batteryLevel >= 70) { - return "battery_5_bar"; - } - - if (BatteryService.batteryLevel >= 55) { - return "battery_4_bar"; - } - - if (BatteryService.batteryLevel >= 40) { - return "battery_3_bar"; - } - - if (BatteryService.batteryLevel >= 25) { - return "battery_2_bar"; - } - - return "battery_1_bar"; - } - size: Theme.iconSize - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - - if (BatteryService.isCharging || BatteryService.isPluggedIn) { - return Theme.primary; - } - - return "white"; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: BatteryService.batteryLevel + "%" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - - DankActionButton { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.margins: Theme.spacingXL - visible: SettingsData.lockScreenShowPowerActions - iconName: "power_settings_new" - iconColor: Theme.error - buttonSize: 40 - onClicked: { - if (demoMode) { - console.log("Demo: Power Menu"); - } else { - powerMenu.show(); - } - } - } - } - - Pam { - id: pam - lockSecured: !demoMode - onUnlockRequested: { - root.unlocking = true; - lockerReadyArmed = false; - passwordField.text = ""; - root.passwordBuffer = ""; - root.unlockRequested(); - } - onStateChanged: { - root.pamState = state; - if (state !== "") { - root.unlocking = false; - placeholderDelay.restart(); - passwordField.text = ""; - root.passwordBuffer = ""; - } - } - onU2fPendingChanged: { - if (u2fPending) { - passwordField.text = ""; - root.passwordBuffer = ""; - if (keyboardController.isKeyboardActive) - keyboardController.hide(); - } - } - } - - Connections { - target: pam - - function onUnlockInProgressChanged() { - if (!pam.unlockInProgress && root.unlocking) - root.unlocking = false; - } - } - - Binding { - target: pam - property: "buffer" - value: root.passwordBuffer - } - - Timer { - id: placeholderDelay - - interval: 4000 - onTriggered: root.pamState = "" - } - - MouseArea { - anchors.fill: parent - enabled: demoMode - onClicked: root.unlockRequested() - } - - LockPowerMenu { - id: powerMenu - showLogout: true - onClosed: { - if (!demoMode && passwordField && passwordField.forceActiveFocus) { - Qt.callLater(() => passwordField.forceActiveFocus()); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenDemo.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenDemo.qml deleted file mode 100644 index e13eac9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockScreenDemo.qml +++ /dev/null @@ -1,46 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Wayland - -PanelWindow { - id: root - - property bool demoActive: false - - visible: demoActive - - anchors { - top: true - bottom: true - left: true - right: true - } - - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive - - color: "transparent" - - function showDemo(): void { - console.log("Showing lock screen demo"); - demoActive = true; - } - - function hideDemo(): void { - console.log("Hiding lock screen demo"); - demoActive = false; - } - - Loader { - anchors.fill: parent - active: demoActive - sourceComponent: LockScreenContent { - demoMode: true - screenName: root.screen?.name ?? "" - onUnlockRequested: root.hideDemo() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockSurface.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockSurface.qml deleted file mode 100644 index 9d1beae..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/LockSurface.qml +++ /dev/null @@ -1,73 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell.Wayland -import qs.Common - -FocusScope { - id: root - - required property WlSessionLock lock - required property string sharedPasswordBuffer - required property string screenName - required property bool isLocked - - signal passwordChanged(string newPassword) - signal unlockRequested - - Keys.onPressed: event => { - if (videoScreensaver.active && videoScreensaver.inputEnabled) { - videoScreensaver.dismiss(); - event.accepted = true; - } - } - - Rectangle { - anchors.fill: parent - color: "transparent" - } - - LockScreenContent { - id: lockContent - - anchors.fill: parent - demoMode: false - passwordBuffer: root.sharedPasswordBuffer - screenName: root.screenName - enabled: !videoScreensaver.active - focus: !videoScreensaver.active - opacity: videoScreensaver.active ? 0 : 1 - onUnlockRequested: root.unlockRequested() - onPasswordBufferChanged: { - if (root.sharedPasswordBuffer !== passwordBuffer) { - root.passwordChanged(passwordBuffer); - } - } - - Behavior on opacity { - NumberAnimation { - duration: 200 - } - } - } - - VideoScreensaver { - id: videoScreensaver - anchors.fill: parent - screenName: root.screenName - } - - Component.onCompleted: forceActiveFocus() - - onIsLockedChanged: { - if (isLocked) { - forceActiveFocus(); - lockContent.resetLockState(); - if (SettingsData.lockScreenVideoEnabled) { - videoScreensaver.start(); - } - return; - } - lockContent.unlocking = false; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Pam.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Pam.qml deleted file mode 100644 index f5e7859..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/Pam.qml +++ /dev/null @@ -1,405 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Services.Pam -import qs.Common - -Scope { - id: root - - property bool lockSecured: false - property bool unlockInProgress: false - - readonly property alias passwd: passwd - readonly property alias fprint: fprint - readonly property alias u2f: u2f - property string lockMessage - property string state - property string fprintState - property string u2fState - property bool u2fPending: false - property string buffer - - signal flashMsg - signal unlockRequested - - function resetAuthFlows(): void { - passwd.abort(); - fprint.abort(); - u2f.abort(); - errorRetry.running = false; - u2fErrorRetry.running = false; - u2fPendingTimeout.running = false; - passwdActiveTimeout.running = false; - unlockRequestTimeout.running = false; - root.u2fPending = false; - root.u2fState = ""; - root.unlockInProgress = false; - } - - function recoverFromAuthStall(newState: string): void { - resetAuthFlows(); - root.state = newState; - flashMsg(); - stateReset.restart(); - fprint.checkAvail(); - u2f.checkAvail(); - } - - function completeUnlock(): void { - if (!root.unlockInProgress) { - root.unlockInProgress = true; - passwd.abort(); - fprint.abort(); - u2f.abort(); - errorRetry.running = false; - u2fErrorRetry.running = false; - u2fPendingTimeout.running = false; - root.u2fPending = false; - root.u2fState = ""; - unlockRequestTimeout.restart(); - unlockRequested(); - } - } - - function proceedAfterPrimaryAuth(): void { - if (SettingsData.enableU2f && SettingsData.u2fMode === "and" && u2f.available) { - u2f.startForSecondFactor(); - } else { - completeUnlock(); - } - } - - function cancelU2fPending(): void { - if (!root.u2fPending) - return; - u2f.abort(); - u2fErrorRetry.running = false; - u2fPendingTimeout.running = false; - root.u2fPending = false; - root.u2fState = ""; - fprint.checkAvail(); - } - - FileView { - id: dankshellConfigWatcher - - path: "/etc/pam.d/dankshell" - printErrors: false - } - - FileView { - id: nixosMarker - - path: "/etc/NIXOS" - printErrors: false - } - - FileView { - id: u2fConfigWatcher - - path: "/etc/pam.d/dankshell-u2f" - printErrors: false - } - - // Detects Nix-installed DMS on non-NixOS systems - readonly property bool runningFromNixStore: Quickshell.shellDir.startsWith("/nix/store/") - - PamContext { - id: passwd - - config: dankshellConfigWatcher.loaded ? "dankshell" : "login" - configDirectory: (dankshellConfigWatcher.loaded || nixosMarker.loaded || root.runningFromNixStore) ? "/etc/pam.d" : Quickshell.shellDir + "/assets/pam" - - onMessageChanged: { - if (message.startsWith("The account is locked")) { - root.lockMessage = message; - } else if (root.lockMessage && message.endsWith(" left to unlock)")) { - root.lockMessage += "\n" + message; - } else if (root.lockMessage && message && message.length > 0) { - root.lockMessage = ""; - } - } - - onResponseRequiredChanged: { - if (!responseRequired) - return; - - respond(root.buffer); - } - - onCompleted: res => { - if (res === PamResult.Success) { - if (!root.unlockInProgress) { - fprint.abort(); - root.proceedAfterPrimaryAuth(); - } - return; - } - - unlockRequestTimeout.running = false; - root.unlockInProgress = false; - root.u2fPending = false; - root.u2fState = ""; - u2fPendingTimeout.running = false; - u2f.abort(); - - if (res === PamResult.Error) - root.state = "error"; - else if (res === PamResult.MaxTries) - root.state = "max"; - else if (res === PamResult.Failed) - root.state = "fail"; - - root.flashMsg(); - stateReset.restart(); - } - } - - Connections { - target: passwd - - function onActiveChanged() { - if (passwd.active) { - passwdActiveTimeout.restart(); - } else { - passwdActiveTimeout.running = false; - } - } - } - - PamContext { - id: fprint - - property bool available: SettingsData.lockFingerprintReady - property int tries - property int errorTries - - function checkAvail(): void { - if (!available || !SettingsData.enableFprint || !root.lockSecured) { - abort(); - return; - } - - tries = 0; - errorTries = 0; - start(); - } - - config: "fprint" - configDirectory: Quickshell.shellDir + "/assets/pam" - - onCompleted: res => { - if (!available) - return; - - if (res === PamResult.Success) { - if (!root.unlockInProgress) { - passwd.abort(); - root.proceedAfterPrimaryAuth(); - } - return; - } - - if (res === PamResult.Error) { - root.fprintState = "error"; - errorTries++; - if (errorTries < 5) { - abort(); - errorRetry.restart(); - } - } else if (res === PamResult.MaxTries) { - tries++; - if (tries < SettingsData.maxFprintTries) { - root.fprintState = "fail"; - start(); - } else { - root.fprintState = "max"; - abort(); - } - } - - root.flashMsg(); - fprintStateReset.start(); - } - } - - PamContext { - id: u2f - - property bool available: SettingsData.lockU2fReady - - function checkAvail(): void { - if (!available || !SettingsData.enableU2f || !root.lockSecured) { - abort(); - return; - } - - if (SettingsData.u2fMode === "or") { - start(); - } - } - - function startForSecondFactor(): void { - if (!available || !SettingsData.enableU2f) { - root.completeUnlock(); - return; - } - abort(); - root.u2fPending = true; - root.u2fState = ""; - u2fPendingTimeout.restart(); - start(); - } - - config: u2fConfigWatcher.loaded ? "dankshell-u2f" : "u2f" - configDirectory: u2fConfigWatcher.loaded ? "/etc/pam.d" : Quickshell.shellDir + "/assets/pam" - - onMessageChanged: { - if (message.toLowerCase().includes("touch")) - root.u2fState = "waiting"; - } - - onCompleted: res => { - if (!available || root.unlockInProgress) - return; - - if (res === PamResult.Success) { - root.completeUnlock(); - return; - } - - if (res === PamResult.Error || res === PamResult.MaxTries || res === PamResult.Failed) { - abort(); - - if (root.u2fPending) { - if (root.u2fState === "waiting") { - // AND mode: device was found but auth failed → back to password - root.u2fPending = false; - root.u2fState = ""; - fprint.checkAvail(); - } else { - // AND mode: no device found → keep pending, show "Insert...", retry - root.u2fState = "insert"; - u2fErrorRetry.restart(); - } - } else { - // OR mode: prompt to insert key, silently retry - root.u2fState = "insert"; - u2fErrorRetry.restart(); - } - } - } - } - - Timer { - id: errorRetry - - interval: 800 - onTriggered: fprint.start() - } - - Timer { - id: u2fErrorRetry - - interval: 800 - onTriggered: u2f.start() - } - - Timer { - id: u2fPendingTimeout - - interval: 30000 - onTriggered: root.cancelU2fPending() - } - - Timer { - id: passwdActiveTimeout - - interval: 15000 - onTriggered: { - if (passwd.active) - root.recoverFromAuthStall("error"); - } - } - - Timer { - id: unlockRequestTimeout - - interval: 8000 - onTriggered: { - if (root.unlockInProgress) - root.recoverFromAuthStall("error"); - } - } - - Timer { - id: stateReset - - interval: 4000 - onTriggered: { - if (root.state !== "max") - root.state = ""; - } - } - - Timer { - id: fprintStateReset - - interval: 4000 - onTriggered: { - root.fprintState = ""; - fprint.errorTries = 0; - } - } - - onLockSecuredChanged: { - if (lockSecured) { - SettingsData.refreshAuthAvailability(); - root.state = ""; - root.fprintState = ""; - root.u2fState = ""; - root.u2fPending = false; - root.lockMessage = ""; - root.resetAuthFlows(); - fprint.checkAvail(); - u2f.checkAvail(); - } else { - root.resetAuthFlows(); - } - } - - Connections { - target: SettingsData - - function onEnableFprintChanged(): void { - fprint.checkAvail(); - } - - function onLockFingerprintReadyChanged(): void { - fprint.checkAvail(); - } - - function onEnableU2fChanged(): void { - u2f.checkAvail(); - } - - function onLockU2fReadyChanged(): void { - u2f.checkAvail(); - } - - function onU2fModeChanged(): void { - if (root.lockSecured) { - u2f.abort(); - u2fErrorRetry.running = false; - u2fPendingTimeout.running = false; - unlockRequestTimeout.running = false; - root.u2fPending = false; - root.u2fState = ""; - u2f.checkAvail(); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/VideoScreensaver.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/VideoScreensaver.qml deleted file mode 100644 index 129f507..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Lock/VideoScreensaver.qml +++ /dev/null @@ -1,200 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell.Io -import qs.Common -import qs.Services - -Item { - id: root - - required property string screenName - property bool active: false - property string videoSource: "" - property bool inputEnabled: false - property point lastMousePos: Qt.point(-1, -1) - property bool mouseInitialized: false - property var videoPlayer: null - - signal dismissed - - visible: active - z: 1000 - - Rectangle { - id: background - anchors.fill: parent - color: "black" - visible: root.active - } - - Timer { - id: inputEnableTimer - interval: 500 - onTriggered: root.inputEnabled = true - } - - Process { - id: videoPicker - property string result: "" - property string folder: "" - - command: ["sh", "-c", "find '" + folder + "' -maxdepth 1 -type f \\( " + "-iname '*.mp4' -o -iname '*.mkv' -o -iname '*.webm' -o " + "-iname '*.mov' -o -iname '*.avi' -o -iname '*.m4v' " + "\\) 2>/dev/null | shuf -n1"] - - stdout: SplitParser { - onRead: data => { - const path = data.trim(); - if (path) { - videoPicker.result = path; - root.videoSource = "file://" + path; - } - } - } - - onExited: exitCode => { - if (exitCode !== 0 || !videoPicker.result) { - console.warn("VideoScreensaver: no video found in folder"); - ToastService.showError(I18n.tr("Video Screensaver"), I18n.tr("No video found in folder")); - root.dismiss(); - } - } - } - - Process { - id: fileChecker - command: ["test", "-d", SettingsData.lockScreenVideoPath] - - onExited: exitCode => { - const isDir = exitCode === 0; - const videoPath = SettingsData.lockScreenVideoPath; - - if (isDir) { - videoPicker.folder = videoPath; - videoPicker.running = true; - } else if (SettingsData.lockScreenVideoCycling) { - const parentFolder = videoPath.substring(0, videoPath.lastIndexOf('/')); - videoPicker.folder = parentFolder; - videoPicker.running = true; - } else { - root.videoSource = "file://" + videoPath; - } - } - } - - function createVideoPlayer() { - if (videoPlayer) - return true; - - try { - videoPlayer = Qt.createQmlObject(` - import QtQuick - import QtMultimedia - Video { - anchors.fill: parent - fillMode: VideoOutput.PreserveAspectCrop - loops: MediaPlayer.Infinite - volume: 0 - } - `, background, "VideoScreensaver.VideoPlayer"); - - videoPlayer.errorOccurred.connect((error, errorString) => { - console.warn("VideoScreensaver: playback error:", errorString); - ToastService.showError(I18n.tr("Video Screensaver"), I18n.tr("Playback error: ") + errorString); - root.dismiss(); - }); - - return true; - } catch (e) { - console.warn("VideoScreensaver: Failed to create video player:", e); - return false; - } - } - - function destroyVideoPlayer() { - if (videoPlayer) { - videoPlayer.stop(); - videoPlayer.destroy(); - videoPlayer = null; - } - } - - function start() { - if (!SettingsData.lockScreenVideoEnabled || !SettingsData.lockScreenVideoPath) - return; - - if (!MultimediaService.available) { - ToastService.showError(I18n.tr("Video Screensaver"), I18n.tr("QtMultimedia is not available")); - return; - } - - if (!createVideoPlayer()) - return; - - videoPicker.result = ""; - videoPicker.folder = ""; - inputEnabled = false; - mouseInitialized = false; - lastMousePos = Qt.point(-1, -1); - active = true; - inputEnableTimer.start(); - fileChecker.running = true; - } - - function dismiss() { - if (!active) - return; - destroyVideoPlayer(); - inputEnabled = false; - active = false; - videoSource = ""; - dismissed(); - } - - onVideoSourceChanged: { - if (videoSource && active && videoPlayer) { - videoPlayer.source = videoSource; - videoPlayer.play(); - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - enabled: root.active && root.inputEnabled - hoverEnabled: true - propagateComposedEvents: false - - onPositionChanged: mouse => { - if (!root.mouseInitialized) { - root.lastMousePos = Qt.point(mouse.x, mouse.y); - root.mouseInitialized = true; - return; - } - var dx = Math.abs(mouse.x - root.lastMousePos.x); - var dy = Math.abs(mouse.y - root.lastMousePos.y); - if (dx > 5 || dy > 5) { - root.dismiss(); - } - } - onClicked: root.dismiss() - onPressed: root.dismiss() - onWheel: root.dismiss() - } - - Connections { - target: IdleService - - function onLockRequested() { - if (SettingsData.lockScreenVideoEnabled && !root.active) { - root.start(); - } - } - - function onFadeToLockRequested() { - if (SettingsData.lockScreenVideoEnabled && !root.active) { - IdleService.cancelFadeToLock(); - root.start(); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/Notepad.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/Notepad.qml deleted file mode 100644 index e294695..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/Notepad.qml +++ /dev/null @@ -1,531 +0,0 @@ -pragma ComponentBehavior: Bound -import QtQuick -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Modals.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets - -Item { - id: root - - property bool fileDialogOpen: false - property string currentFileName: "" - property url currentFileUrl - property bool confirmationDialogOpen: false - property string pendingAction: "" - property url pendingFileUrl - property string lastSavedFileContent: "" - property var currentTab: NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null - property bool showSettingsMenu: false - property string pendingSaveContent: "" - property var slideout: null - - signal hideRequested - signal previewRequested(string content) - - Ref { - service: NotepadStorageService - } - - Connections { - target: slideout - enabled: slideout !== null - function onAboutToHide() { - textEditor.autoSaveToSession() - } - } - - function hasUnsavedChanges() { - return textEditor.hasUnsavedChanges(); - } - - function hasUnsavedTemporaryContent() { - return hasUnsavedChanges(); - } - - function createNewTab() { - performCreateNewTab(); - } - - function performCreateNewTab() { - NotepadStorageService.createNewTab(); - textEditor.text = ""; - textEditor.lastSavedContent = ""; - textEditor.contentLoaded = true; - textEditor.textArea.forceActiveFocus(); - } - - function closeTab(tabIndex) { - if (tabIndex === NotepadStorageService.currentTabIndex && hasUnsavedChanges()) { - root.pendingAction = "close_tab_" + tabIndex; - root.confirmationDialogOpen = true; - confirmationDialogLoader.active = true; - if (confirmationDialogLoader.item) - confirmationDialogLoader.item.open(); - } else { - performCloseTab(tabIndex); - } - } - - function performCloseTab(tabIndex) { - NotepadStorageService.closeTab(tabIndex); - Qt.callLater(() => { - textEditor.loadCurrentTabContent(); - }); - } - - function switchToTab(tabIndex) { - if (tabIndex < 0 || tabIndex >= NotepadStorageService.tabs.length) - return; - if (textEditor.contentLoaded) { - textEditor.autoSaveToSession(); - } - - NotepadStorageService.switchToTab(tabIndex); - Qt.callLater(() => { - textEditor.loadCurrentTabContent(); - if (currentTab) { - root.currentFileName = currentTab.fileName || ""; - root.currentFileUrl = currentTab.fileUrl || ""; - } - }); - } - - function saveToFile(fileUrl) { - if (!currentTab) - return; - var content = textEditor.text; - var filePath = fileUrl.toString().replace(/^file:\/\//, ''); - - saveFileView.path = ""; - pendingSaveContent = content; - saveFileView.path = filePath; - - Qt.callLater(() => { - saveFileView.setText(pendingSaveContent); - }); - } - - function loadFromFile(fileUrl) { - if (hasUnsavedTemporaryContent()) { - root.pendingFileUrl = fileUrl; - root.pendingAction = "load_file"; - root.confirmationDialogOpen = true; - confirmationDialogLoader.active = true; - if (confirmationDialogLoader.item) - confirmationDialogLoader.item.open(); - } else { - performLoadFromFile(fileUrl); - } - } - - function performLoadFromFile(fileUrl) { - const filePath = fileUrl.toString().replace(/^file:\/\//, ''); - const fileName = filePath.split('/').pop(); - - loadFileView.path = ""; - loadFileView.path = filePath; - - if (loadFileView.waitForJob()) { - Qt.callLater(() => { - var content = loadFileView.text(); - if (currentTab && content !== undefined && content !== null) { - textEditor.text = content; - textEditor.lastSavedContent = content; - textEditor.contentLoaded = true; - root.lastSavedFileContent = content; - - NotepadStorageService.updateTabMetadata(NotepadStorageService.currentTabIndex, { - title: fileName, - filePath: filePath, - isTemporary: false - }); - - root.currentFileName = fileName; - root.currentFileUrl = fileUrl; - textEditor.saveCurrentTabContent(); - } - }); - } - } - - Column { - anchors.fill: parent - spacing: Theme.spacingM - - NotepadTabs { - id: tabBar - width: parent.width - contentLoaded: textEditor.contentLoaded - - onTabSwitched: tabIndex => { - switchToTab(tabIndex); - } - - onTabClosed: tabIndex => { - closeTab(tabIndex); - } - - onNewTabRequested: { - createNewTab(); - } - } - - NotepadTextEditor { - id: textEditor - width: parent.width - height: parent.height - tabBar.height - Theme.spacingM * 2 - - onSaveRequested: { - if (currentTab && !currentTab.isTemporary && currentTab.filePath) { - var fileUrl = "file://" + currentTab.filePath; - saveToFile(fileUrl); - } else { - root.fileDialogOpen = true; - saveBrowserLoader.active = true; - if (saveBrowserLoader.item) - saveBrowserLoader.item.open(); - } - } - - onOpenRequested: { - textEditor.autoSaveToSession(); - if (textEditor.text.length > 0) { - createNewTab(); - } - - root.fileDialogOpen = true; - loadBrowserLoader.active = true; - if (loadBrowserLoader.item) - loadBrowserLoader.item.open(); - } - - onNewRequested: { - textEditor.autoSaveToSession(); - createNewTab(); - } - - onPreviewRequested: { - textEditor.togglePreview(); - } - - onEscapePressed: { - textEditor.autoSaveToSession() - root.hideRequested() - } - - onSettingsRequested: { - showSettingsMenu = !showSettingsMenu; - } - } - } - - NotepadSettings { - id: notepadSettings - anchors.fill: parent - isVisible: showSettingsMenu - onSettingsRequested: showSettingsMenu = !showSettingsMenu - onFindRequested: { - showSettingsMenu = false; - textEditor.showSearch(); - } - } - - FileView { - id: saveFileView - blockWrites: true - preload: false - atomicWrites: true - printErrors: true - - onSaved: { - if (currentTab && saveFileView.path && pendingSaveContent) { - NotepadStorageService.updateTabMetadata(NotepadStorageService.currentTabIndex, { - hasUnsavedChanges: false, - lastSavedContent: pendingSaveContent - }); - root.lastSavedFileContent = pendingSaveContent; - pendingSaveContent = ""; - } - } - - onSaveFailed: error => { - pendingSaveContent = ""; - } - } - - FileView { - id: loadFileView - blockLoading: true - preload: true - atomicWrites: true - printErrors: true - - onLoadFailed: error => {} - } - - LazyLoader { - id: saveBrowserLoader - active: false - - FileBrowserSurfaceModal { - id: saveBrowser - - browserTitle: I18n.tr("Save Notepad File") - browserIcon: "save" - browserType: "notepad_save" - fileExtensions: ["*.txt", "*.md", "*.*"] - allowStacking: true - saveMode: true - defaultFileName: { - if (currentTab && currentTab.title && currentTab.title !== "Untitled") { - return currentTab.title; - } else if (currentTab && !currentTab.isTemporary && currentTab.filePath) { - return currentTab.filePath.split('/').pop(); - } else { - return "note.txt"; - } - } - - onFileSelected: path => { - root.fileDialogOpen = false; - const cleanPath = decodeURI(path.toString().replace(/^file:\/\//, '')); - const fileName = cleanPath.split('/').pop(); - const fileUrl = "file://" + cleanPath; - - root.currentFileName = fileName; - root.currentFileUrl = fileUrl; - - if (currentTab) { - NotepadStorageService.saveTabAs(NotepadStorageService.currentTabIndex, cleanPath); - } - - saveToFile(fileUrl); - - if (root.pendingAction === "new") { - Qt.callLater(() => { - createNewTab(); - }); - } else if (root.pendingAction === "open") { - Qt.callLater(() => { - root.fileDialogOpen = true; - loadBrowserLoader.active = true; - if (loadBrowserLoader.item) - loadBrowserLoader.item.open(); - }); - } else if (root.pendingAction.startsWith("close_tab_")) { - Qt.callLater(() => { - var tabIndex = parseInt(root.pendingAction.split("_")[2]); - performCloseTab(tabIndex); - }); - } - root.pendingAction = ""; - - close(); - } - - onDialogClosed: { - root.fileDialogOpen = false; - } - } - } - - LazyLoader { - id: loadBrowserLoader - active: false - - FileBrowserSurfaceModal { - id: loadBrowser - - browserTitle: I18n.tr("Open Notepad File") - browserIcon: "folder_open" - browserType: "notepad_load" - fileExtensions: ["*.txt", "*.md", "*.*"] - allowStacking: true - - onFileSelected: path => { - root.fileDialogOpen = false; - const cleanPath = path.toString().replace(/^file:\/\//, ''); - const fileName = cleanPath.split('/').pop(); - const fileUrl = "file://" + cleanPath; - - root.currentFileName = fileName; - root.currentFileUrl = fileUrl; - - loadFromFile(fileUrl); - close(); - } - - onDialogClosed: { - root.fileDialogOpen = false; - } - } - } - - LazyLoader { - id: confirmationDialogLoader - active: false - - DankModal { - id: confirmationDialog - - modalWidth: 400 - modalHeight: contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 180 - shouldBeVisible: false - allowStacking: true - - onBackgroundClicked: { - close(); - root.confirmationDialogOpen = false; - } - - content: Component { - FocusScope { - anchors.fill: parent - focus: true - implicitHeight: contentColumn.implicitHeight - - Keys.onEscapePressed: event => { - confirmationDialog.close(); - root.confirmationDialogOpen = false; - event.accepted = true; - } - - Column { - id: contentColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Unsaved Changes") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: root.pendingAction === "new" ? I18n.tr("You have unsaved changes. Save before creating a new file?") : root.pendingAction.startsWith("close_tab_") ? I18n.tr("You have unsaved changes. Save before closing this tab?") : root.pendingAction === "load_file" || root.pendingAction === "open" ? I18n.tr("You have unsaved changes. Save before opening a file?") : I18n.tr("You have unsaved changes. Save before continuing?") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - width: parent.width - wrapMode: Text.Wrap - } - - Item { - width: parent.width - height: 36 - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Rectangle { - width: Math.max(80, discardText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: discardArea.containsMouse ? Theme.surfaceTextHover : "transparent" - border.color: Theme.surfaceVariantAlpha - border.width: 1 - - StyledText { - id: discardText - anchors.centerIn: parent - text: I18n.tr("Don't Save") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - MouseArea { - id: discardArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - confirmationDialog.close(); - root.confirmationDialogOpen = false; - if (root.pendingAction === "new") { - createNewTab(); - } else if (root.pendingAction === "open") { - root.fileDialogOpen = true; - loadBrowserLoader.active = true; - if (loadBrowserLoader.item) - loadBrowserLoader.item.open(); - } else if (root.pendingAction === "load_file") { - performLoadFromFile(root.pendingFileUrl); - } else if (root.pendingAction.startsWith("close_tab_")) { - var tabIndex = parseInt(root.pendingAction.split("_")[2]); - performCloseTab(tabIndex); - } - root.pendingAction = ""; - root.pendingFileUrl = ""; - } - } - } - - Rectangle { - width: Math.max(70, saveAsText.contentWidth + Theme.spacingM * 2) - height: 36 - radius: Theme.cornerRadius - color: saveAsArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary - - StyledText { - id: saveAsText - anchors.centerIn: parent - text: I18n.tr("Save") - font.pixelSize: Theme.fontSizeMedium - color: Theme.background - font.weight: Font.Medium - } - - MouseArea { - id: saveAsArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - confirmationDialog.close(); - root.confirmationDialogOpen = false; - root.fileDialogOpen = true; - saveBrowserLoader.active = true; - if (saveBrowserLoader.item) - saveBrowserLoader.item.open(); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - - DankActionButton { - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: { - confirmationDialog.close(); - root.confirmationDialogOpen = false; - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadSettings.qml deleted file mode 100644 index 9265ddf..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadSettings.qml +++ /dev/null @@ -1,367 +0,0 @@ -pragma ComponentBehavior: Bound -import QtQuick -import qs.Common -import qs.Widgets - -Item { - id: root - - property bool isVisible: false - property var cachedFontFamilies: [] - property var cachedMonoFamilies: [] - property bool fontsEnumerated: false - - signal settingsRequested - signal findRequested - - function enumerateFonts() { - var fonts = ["Default"]; - var availableFonts = Qt.fontFamilies(); - var rootFamilies = []; - var seenFamilies = new Set(); - for (var i = 0; i < availableFonts.length; i++) { - var fontName = availableFonts[i]; - if (fontName.startsWith(".")) - continue; - if (fontName === Theme.defaultFontFamily) - continue; - var rootName = fontName.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").replace(/ (UI|Display|Text|Mono|Sans|Serif)$/i, function (match, suffix) { - return match; - }).trim(); - if (!seenFamilies.has(rootName) && rootName !== "") { - seenFamilies.add(rootName); - rootFamilies.push(rootName); - } - } - cachedFontFamilies = fonts.concat(rootFamilies.sort()); - var monoFonts = ["Default"]; - var monoFamilies = []; - var seenMonoFamilies = new Set(); - for (var j = 0; j < availableFonts.length; j++) { - var fontName2 = availableFonts[j]; - if (fontName2.startsWith(".")) - continue; - if (fontName2 === SettingsData.defaultMonoFontFamily) - continue; - var lowerName = fontName2.toLowerCase(); - if (lowerName.includes("mono") || lowerName.includes("code") || lowerName.includes("console") || lowerName.includes("terminal") || lowerName.includes("courier") || lowerName.includes("dejavu sans mono") || lowerName.includes("jetbrains") || lowerName.includes("fira") || lowerName.includes("hack") || lowerName.includes("source code") || lowerName.includes("ubuntu mono") || lowerName.includes("cascadia")) { - var rootName2 = fontName2.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").trim(); - if (!seenMonoFamilies.has(rootName2) && rootName2 !== "") { - seenMonoFamilies.add(rootName2); - monoFamilies.push(rootName2); - } - } - } - cachedMonoFamilies = monoFonts.concat(monoFamilies.sort()); - fontsEnumerated = true; - } - - Component.onCompleted: { - if (!fontsEnumerated) { - enumerateFonts(); - } - } - - MouseArea { - anchors.fill: parent - visible: root.isVisible - onClicked: root.settingsRequested() - z: 50 - } - - Rectangle { - id: settingsMenu - visible: root.isVisible - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - width: 360 - height: settingsColumn.implicitHeight + Theme.spacingXL * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, Theme.notepadTransparency) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 1 - z: 100 - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: parent.z - 1 - } - - Column { - id: settingsColumn - width: parent.width - Theme.spacingXL * 2 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: Theme.spacingXL - spacing: Theme.spacingS - - Rectangle { - width: parent.width - height: 36 - color: "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Notepad Font Settings") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - } - - DankToggle { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - text: I18n.tr("Use Monospace Font") - description: "Toggle fonts" - checked: SettingsData.notepadUseMonospace - onToggled: checked => { - SettingsData.notepadUseMonospace = checked; - } - } - - DankToggle { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - text: I18n.tr("Show Line Numbers") - description: "Display line numbers in editor" - checked: SettingsData.notepadShowLineNumbers - onToggled: checked => { - SettingsData.notepadShowLineNumbers = checked; - } - } - - StyledRect { - width: parent.width - height: 60 - radius: Theme.cornerRadius - color: "transparent" - - StateLayer { - anchors.fill: parent - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - stateColor: Theme.primary - cornerRadius: parent.radius - onClicked: root.findRequested() - } - - Row { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "search" - size: Theme.iconSize - 2 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Find in Text") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Open search bar to find text") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - Rectangle { - width: parent.width - height: visible ? (fontDropdown.height + Theme.spacingS) : 0 - color: "transparent" - visible: !SettingsData.notepadUseMonospace - - DankDropdown { - id: fontDropdown - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - text: I18n.tr("Font Family") - options: cachedFontFamilies - currentValue: { - if (!SettingsData.notepadFontFamily || SettingsData.notepadFontFamily === "") - return "Default (Global)"; - else - return SettingsData.notepadFontFamily; - } - enableFuzzySearch: true - onValueChanged: value => { - if (value && (value.startsWith("Default") || value === "Default (Global)")) { - SettingsData.notepadFontFamily = ""; - } else { - SettingsData.notepadFontFamily = value; - } - } - } - } - - Rectangle { - width: parent.width - height: fontSizeRow.height + Theme.spacingS - color: "transparent" - - Row { - id: fontSizeRow - width: parent.width - spacing: Theme.spacingS - - Column { - width: parent.width - fontSizeControls.width - Theme.spacingM - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Font Size") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: SettingsData.notepadFontSize + "px" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - } - } - - Row { - id: fontSizeControls - spacing: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 32 - iconName: "remove" - iconSize: Theme.iconSizeSmall - enabled: SettingsData.notepadFontSize > 8 - backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5) - iconColor: Theme.surfaceText - onClicked: { - var newSize = Math.max(8, SettingsData.notepadFontSize - 1); - SettingsData.notepadFontSize = newSize; - } - } - - Rectangle { - width: 60 - height: 32 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 1 - - StyledText { - anchors.centerIn: parent - text: SettingsData.notepadFontSize + "px" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - } - - DankActionButton { - buttonSize: 32 - iconName: "add" - iconSize: Theme.iconSizeSmall - enabled: SettingsData.notepadFontSize < 48 - backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5) - iconColor: Theme.surfaceText - onClicked: { - var newSize = Math.min(48, SettingsData.notepadFontSize + 1); - SettingsData.notepadFontSize = newSize; - } - } - } - } - } - - Rectangle { - width: parent.width - height: transparencySliderColumn.height + Theme.spacingS - color: "transparent" - - Column { - id: transparencySliderColumn - width: parent.width - spacing: Theme.spacingS - - DankToggle { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - text: I18n.tr("Custom Transparency") - description: "Override global transparency for Notepad" - checked: SettingsData.notepadTransparencyOverride >= 0 - onToggled: checked => { - if (checked) { - SettingsData.notepadTransparencyOverride = SettingsData.notepadLastCustomTransparency; - } else { - SettingsData.notepadTransparencyOverride = -1; - } - } - } - - DankSlider { - anchors.left: parent.left - anchors.leftMargin: -Theme.spacingM - width: parent.width + Theme.spacingM - height: 24 - visible: SettingsData.notepadTransparencyOverride >= 0 - value: Math.round((SettingsData.notepadTransparencyOverride >= 0 ? SettingsData.notepadTransparencyOverride : SettingsData.popupTransparency) * 100) - minimum: 0 - maximum: 100 - unit: "" - showValue: true - wheelEnabled: false - onSliderValueChanged: newValue => { - if (SettingsData.notepadTransparencyOverride >= 0) { - SettingsData.notepadTransparencyOverride = newValue / 100; - } - } - } - } - } - - StyledText { - width: parent.width - text: SettingsData.notepadUseMonospace ? "Using global monospace font from Settings → Personalization" : "Global fonts can be configured in Settings → Personalization" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceTextMedium - wrapMode: Text.WordWrap - opacity: 0.8 - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml deleted file mode 100644 index 05a21d1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTabs.qml +++ /dev/null @@ -1,285 +0,0 @@ -pragma ComponentBehavior: Bound -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Services -import qs.Widgets - -Column { - id: root - - property var currentTab: NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null - property bool contentLoaded: false - property int draggedIndex: -1 - property int dropTargetIndex: -1 - property bool suppressShiftAnimation: false - readonly property real tabItemSize: 128 + Theme.spacingXS - - signal tabSwitched(int tabIndex) - signal tabClosed(int tabIndex) - signal newTabRequested - - function hasUnsavedChangesForTab(tab) { - if (!tab) - return false; - - if (tab.id === currentTab?.id) { - return root.parent?.hasUnsavedChanges ? root.parent.hasUnsavedChanges() : false; - } - return false; - } - - spacing: Theme.spacingXS - - Row { - width: parent.width - height: 36 - spacing: Theme.spacingXS - - ScrollView { - width: parent.width - newTabButton.width - Theme.spacingXS - height: parent.height - clip: true - - ScrollBar.horizontal.visible: false - ScrollBar.vertical.visible: false - - Row { - spacing: Theme.spacingXS - - Repeater { - model: NotepadStorageService.tabs - - delegate: Item { - id: delegateItem - required property int index - required property var modelData - - readonly property bool isActive: NotepadStorageService.currentTabIndex === index - readonly property bool isHovered: tabMouseArea.containsMouse && !closeMouseArea.containsMouse - readonly property real tabWidth: 128 - property bool longPressing: false - property bool dragging: false - property point dragStartPos: Qt.point(0, 0) - property int targetIndex: -1 - property int originalIndex: -1 - property real dragAxisOffset: 0 - - Timer { - id: longPressTimer - interval: 200 - repeat: false - onTriggered: { - if (NotepadStorageService.tabs.length > 1) { - delegateItem.longPressing = true - } - } - } - - readonly property real shiftOffset: { - if (root.draggedIndex < 0) - return 0 - if (index === root.draggedIndex) - return 0 - var dragIdx = root.draggedIndex - var dropIdx = root.dropTargetIndex - var myIdx = index - var shiftAmount = root.tabItemSize - if (dropIdx < 0) - return 0 - if (dragIdx < dropIdx && myIdx > dragIdx && myIdx <= dropIdx) - return -shiftAmount - if (dragIdx > dropIdx && myIdx >= dropIdx && myIdx < dragIdx) - return shiftAmount - return 0 - } - - width: tabWidth - height: 32 - z: dragging ? 100 : 0 - - transform: Translate { - x: shiftOffset - Behavior on x { - enabled: !root.suppressShiftAnimation - NumberAnimation { - duration: 150 - easing.type: Easing.OutCubic - } - } - } - - Item { - id: tabVisual - anchors.fill: parent - z: 1 - layer.enabled: dragging - layer.smooth: true - - transform: Translate { - x: dragging ? dragAxisOffset : 0 - } - - Rectangle { - id: tabRect - anchors.fill: parent - radius: Theme.cornerRadius - color: isActive ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryPressed, 0) - border.width: isActive || dragging ? 0 : 1 - border.color: dragging ? Theme.primary : Theme.outlineMedium - clip: true - - Row { - id: tabContent - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingXS - - StyledText { - id: tabText - width: parent.width - (tabCloseButton.visible ? tabCloseButton.width + Theme.spacingXS : 0) - text: { - var prefix = "" - if (hasUnsavedChangesForTab(modelData)) { - prefix = "● " - } - return prefix + (modelData.title || "Untitled") - } - font.pixelSize: Theme.fontSizeSmall - color: isActive ? Theme.primary : Theme.surfaceText - font.weight: isActive ? Font.Medium : Font.Normal - elide: Text.ElideMiddle - maximumLineCount: 1 - wrapMode: Text.NoWrap - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - id: tabCloseButton - width: 20 - height: 20 - radius: Theme.cornerRadius - color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0) - visible: NotepadStorageService.tabs.length > 1 - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: "close" - size: 14 - color: Theme.surfaceTextMedium - anchors.centerIn: parent - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - z: 100 - - onClicked: root.tabClosed(index) - } - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - MouseArea { - id: tabMouseArea - anchors.fill: parent - hoverEnabled: true - preventStealing: dragging || longPressing - cursorShape: dragging || longPressing ? Qt.ClosedHandCursor : Qt.PointingHandCursor - acceptedButtons: Qt.LeftButton - - onPressed: mouse => { - if (mouse.button === Qt.LeftButton && NotepadStorageService.tabs.length > 1) { - delegateItem.dragStartPos = Qt.point(mouse.x, mouse.y) - longPressTimer.start() - } - } - - onReleased: mouse => { - longPressTimer.stop() - var wasDragging = delegateItem.dragging - var didReorder = wasDragging && delegateItem.targetIndex >= 0 && delegateItem.targetIndex !== delegateItem.originalIndex - - if (didReorder) { - root.suppressShiftAnimation = true - NotepadStorageService.reorderTab(delegateItem.originalIndex, delegateItem.targetIndex) - } - - delegateItem.longPressing = false - delegateItem.dragging = false - delegateItem.dragAxisOffset = 0 - delegateItem.targetIndex = -1 - delegateItem.originalIndex = -1 - root.draggedIndex = -1 - root.dropTargetIndex = -1 - if (didReorder) { - Qt.callLater(() => { - root.suppressShiftAnimation = false - }) - } - - if (wasDragging || mouse.button !== Qt.LeftButton) - return - root.tabSwitched(index) - } - - onPositionChanged: mouse => { - if (delegateItem.longPressing && !delegateItem.dragging) { - var distance = Math.sqrt(Math.pow(mouse.x - delegateItem.dragStartPos.x, 2) + Math.pow(mouse.y - delegateItem.dragStartPos.y, 2)) - if (distance > 5) { - delegateItem.dragging = true - delegateItem.targetIndex = index - delegateItem.originalIndex = index - root.draggedIndex = index - root.dropTargetIndex = index - } - } - - if (!delegateItem.dragging) - return - - var axisOffset = mouse.x - delegateItem.dragStartPos.x - delegateItem.dragAxisOffset = axisOffset - - var itemSize = root.tabItemSize - var rawSlot = axisOffset / itemSize - var slotOffset = rawSlot >= 0 - ? Math.floor(rawSlot + 0.4) - : Math.ceil(rawSlot - 0.4) - var tabCount = NotepadStorageService.tabs.length - var newTargetIndex = Math.max(0, Math.min(tabCount - 1, delegateItem.originalIndex + slotOffset)) - - if (newTargetIndex !== delegateItem.targetIndex) { - delegateItem.targetIndex = newTargetIndex - root.dropTargetIndex = newTargetIndex - } - } - } - } - } - } - } - - DankActionButton { - id: newTabButton - width: 32 - height: 32 - iconName: "add" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.newTabRequested() - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTextEditor.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTextEditor.qml deleted file mode 100644 index 7ea0b27..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Notepad/NotepadTextEditor.qml +++ /dev/null @@ -1,924 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Quickshell.Io -import qs.Common -import qs.Services -import qs.Widgets - -pragma ComponentBehavior: Bound - -Column { - id: root - - Component.onCompleted: { - if (PluginService.isPluginLoaded("dankNotepadModule")) { - pluginHighlightedHtml = SettingsData.getBuiltInPluginSetting("dankNotepadModule", "highlightedHtml", "") - } - } - - property alias text: textArea.text - property alias textArea: textArea - property bool contentLoaded: false - property string lastSavedContent: "" - property var currentTab: NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null - property bool searchVisible: false - property string searchQuery: "" - property var searchMatches: [] - property int currentMatchIndex: -1 - property int matchCount: 0 - property bool inlinePreviewVisible: false - property string previewMode: "split" // split | full - property string pluginHighlightedHtml: "" - property string lastPluginContent: "" - property int loadRequestId: 0 - - signal saveRequested() - signal openRequested() - signal newRequested() - signal previewRequested() - signal escapePressed() - signal contentChanged() - signal settingsRequested() - - function hasUnsavedChanges() { - if (!currentTab || !contentLoaded) { - return false - } - - if (currentTab.isTemporary) { - return textArea.text.length > 0 - } - return textArea.text !== lastSavedContent - } - - function loadCurrentTabContent() { - if (!currentTab) return - - const requestedTabId = currentTab.id - const requestId = ++loadRequestId - contentLoaded = false - NotepadStorageService.loadTabContent( - NotepadStorageService.currentTabIndex, - (content) => { - const activeTab = NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex - ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] - : null - if (requestId !== loadRequestId || !activeTab || activeTab.id !== requestedTabId) - return - - lastSavedContent = content - textArea.text = content - contentLoaded = true - syncContentToPlugin() - } - ) - } - - function saveCurrentTabContent() { - if (!currentTab || !contentLoaded) return - - NotepadStorageService.saveTabContent( - NotepadStorageService.currentTabIndex, - textArea.text - ) - lastSavedContent = textArea.text - } - - function autoSaveToSession() { - if (!currentTab || !contentLoaded) return - saveCurrentTabContent() - } - - function setTextDocumentLineHeight() { - return - } - - property string lastTextForLineModel: "" - property var lineModel: [] - - function updateLineModel() { - if (!SettingsData.notepadShowLineNumbers) { - lineModel = [] - lastTextForLineModel = "" - return - } - - if (textArea.text !== lastTextForLineModel || lineModel.length === 0) { - lastTextForLineModel = textArea.text - lineModel = textArea.text.split('\n') - } - } - - function performSearch() { - let matches = [] - currentMatchIndex = -1 - - if (!searchQuery || searchQuery.length === 0) { - searchMatches = [] - matchCount = 0 - textArea.select(0, 0) - return - } - - const text = textArea.text - const query = searchQuery.toLowerCase() - let index = 0 - - while (index < text.length) { - const foundIndex = text.toLowerCase().indexOf(query, index) - if (foundIndex === -1) break - - matches.push({ - start: foundIndex, - end: foundIndex + searchQuery.length - }) - index = foundIndex + 1 - } - - searchMatches = matches - matchCount = matches.length - - if (matchCount > 0) { - currentMatchIndex = 0 - highlightCurrentMatch() - } else { - textArea.select(0, 0) - } - } - - function highlightCurrentMatch() { - if (currentMatchIndex >= 0 && currentMatchIndex < searchMatches.length) { - const match = searchMatches[currentMatchIndex] - - textArea.cursorPosition = match.start - textArea.moveCursorSelection(match.end, TextEdit.SelectCharacters) - - const flickable = textArea.parent - if (flickable && flickable.contentY !== undefined) { - const lineHeight = textArea.font.pixelSize * 1.5 - const approxLine = textArea.text.substring(0, match.start).split('\n').length - const targetY = approxLine * lineHeight - flickable.height / 2 - flickable.contentY = Math.max(0, Math.min(targetY, flickable.contentHeight - flickable.height)) - } - } - } - - function findNext() { - if (matchCount === 0 || searchMatches.length === 0) return - - currentMatchIndex = (currentMatchIndex + 1) % matchCount - highlightCurrentMatch() - } - - function findPrevious() { - if (matchCount === 0 || searchMatches.length === 0) return - - currentMatchIndex = currentMatchIndex <= 0 ? matchCount - 1 : currentMatchIndex - 1 - highlightCurrentMatch() - } - - function showSearch() { - searchVisible = true - Qt.callLater(() => { - searchField.forceActiveFocus() - }) - } - - function togglePreview() { - if (!inlinePreviewVisible) { - inlinePreviewVisible = true - previewMode = "split" - } else if (previewMode === "split") { - previewMode = "full" - } else { - inlinePreviewVisible = false - previewMode = "split" - } - syncContentToPlugin() - } - - function renderPreviewHtml() { - if (!inlinePreviewVisible) return "" - return pluginHighlightedHtml.length > 0 ? pluginHighlightedHtml : "

Rendering preview…

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

It is built with Quickshell, a QT6 framework for building desktop shells, and Go, a statically typed, compiled programming language.').arg(Theme.primary) - textFormat: Text.RichText - font.pixelSize: Theme.fontSizeMedium - linkColor: Theme.primary - onLinkActivated: url => Qt.openUrlExternally(url) - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - } - } - } - } - - StyledRect { - visible: DMSService.isConnected - width: parent.width - height: backendSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: backendSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "dns" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Backend") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingL - - Column { - spacing: 2 - - StyledText { - text: I18n.tr("Version") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: DMSService.cliVersion || "—" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignLeft - } - } - - Rectangle { - width: 1 - height: 32 - color: Theme.outlineVariant - } - - Column { - spacing: 2 - - StyledText { - text: I18n.tr("API") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: `v${DMSService.apiVersion}` - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignLeft - } - } - - Rectangle { - width: 1 - height: 32 - color: Theme.outlineVariant - } - - Column { - spacing: 2 - - StyledText { - text: I18n.tr("Status") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: 4 - - Rectangle { - width: 8 - height: 8 - radius: 4 - color: Theme.success - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Connected") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignLeft - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: DMSService.capabilities.length > 0 - - StyledText { - text: I18n.tr("Capabilities") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Flow { - width: parent.width - spacing: 6 - - Repeater { - model: DMSService.capabilities - - Rectangle { - width: capText.implicitWidth + 16 - height: 26 - radius: 13 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) - - StyledText { - id: capText - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - } - } - } - } - } - } - } - - StyledRect { - width: parent.width - height: toolsSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: toolsSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "build" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Tools") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingS - - DankButton { - text: I18n.tr("Show Welcome") - iconName: "waving_hand" - backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) - textColor: Theme.surfaceText - onClicked: FirstLaunchService.showWelcome() - } - - DankButton { - text: I18n.tr("System Check") - iconName: "vital_signs" - backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) - textColor: Theme.surfaceText - onClicked: FirstLaunchService.showDoctor() - } - } - } - } - - StyledText { - anchors.horizontalCenter: parent.horizontalCenter - text: I18n.tr('MIT License').arg(Theme.surfaceVariantText) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - textFormat: Text.RichText - wrapMode: Text.NoWrap - onLinkActivated: url => Qt.openUrlExternally(url) - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - } - } - } - } - - // Community tooltip - positioned absolutely above everything - Rectangle { - id: communityTooltip - parent: aboutTab - z: 1000 - - property var hoveredButton: { - if (compositorButton.hovered) - return compositorButton; - if (matrixButton.visible && matrixButton.hovered) - return matrixButton; - if (ircButton.visible && ircButton.hovered) - return ircButton; - if (dmsDiscordButton.hovered) - return dmsDiscordButton; - if (compositorDiscordButton.visible && compositorDiscordButton.hovered) - return compositorDiscordButton; - if (redditButton.visible && redditButton.hovered) - return redditButton; - return null; - } - - property string tooltipText: hoveredButton ? hoveredButton.tooltipText : "" - - visible: hoveredButton !== null && tooltipText !== "" - width: tooltipLabel.implicitWidth + 24 - height: tooltipLabel.implicitHeight + 12 - - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.width: 0 - border.color: Theme.outlineMedium - - x: hoveredButton ? hoveredButton.mapToItem(aboutTab, hoveredButton.width / 2, 0).x - width / 2 : 0 - y: hoveredButton ? communityIcons.mapToItem(aboutTab, 0, 0).y - height - 8 : 0 - - ElevationShadow { - anchors.fill: parent - z: -1 - level: Theme.elevationLevel1 - fallbackOffset: 1 - targetRadius: communityTooltip.radius - targetColor: communityTooltip.color - borderColor: communityTooltip.border.color - borderWidth: communityTooltip.border.width - shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2 - shadowEnabled: Theme.elevationEnabled - } - - StyledText { - id: tooltipLabel - anchors.centerIn: parent - text: communityTooltip.tooltipText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AudioTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AudioTab.qml deleted file mode 100644 index c054791..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/AudioTab.qml +++ /dev/null @@ -1,747 +0,0 @@ -import QtQuick -import Quickshell.Services.Pipewire -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var outputDevices: [] - property var inputDevices: [] - property bool showEditDialog: false - property var editingDevice: null - property string editingDeviceType: "" - property string newDeviceName: "" - property bool isReloadingAudio: false - property var hiddenOutputDeviceNames: SessionData.hiddenOutputDeviceNames ?? [] - property var hiddenInputDeviceNames: SessionData.hiddenInputDeviceNames ?? [] - property bool showHiddenOutputDevices: false - property bool showHiddenInputDevices: false - - function persistHiddenOutputDeviceNames(deviceNames) { - const uniqueNames = [...new Set(deviceNames)]; - hiddenOutputDeviceNames = uniqueNames; - SessionData.setHiddenOutputDeviceNames(uniqueNames); - } - - function persistHiddenInputDeviceNames(deviceNames) { - const uniqueNames = [...new Set(deviceNames)]; - hiddenInputDeviceNames = uniqueNames; - SessionData.setHiddenInputDeviceNames(uniqueNames); - } - - function updateDeviceList() { - const allNodes = Pipewire.nodes.values; - - // Sort devices: active first, then alphabetically by name - const sortDevices = (a, b) => { - if (a === AudioService.sink && b !== AudioService.sink) - return -1; - if (b === AudioService.sink && a !== AudioService.sink) - return 1; - const nameA = AudioService.displayName(a).toLowerCase(); - const nameB = AudioService.displayName(b).toLowerCase(); - return nameA.localeCompare(nameB); - }; - - const outputs = allNodes.filter(node => { - return node.audio && node.isSink && !node.isStream; - }); - outputDevices = outputs.sort(sortDevices); - - const inputs = allNodes.filter(node => { - return node.audio && !node.isSink && !node.isStream; - }); - - const sortInputs = (a, b) => { - if (a === AudioService.source && b !== AudioService.source) - return -1; - if (b === AudioService.source && a !== AudioService.source) - return 1; - const nameA = AudioService.displayName(a).toLowerCase(); - const nameB = AudioService.displayName(b).toLowerCase(); - return nameA.localeCompare(nameB); - }; - - inputDevices = inputs.sort(sortInputs); - } - - Component.onCompleted: { - hiddenOutputDeviceNames = SessionData.hiddenOutputDeviceNames ?? []; - hiddenInputDeviceNames = SessionData.hiddenInputDeviceNames ?? []; - updateDeviceList(); - } - - Connections { - target: Pipewire.nodes - function onValuesChanged() { - root.updateDeviceList(); - } - } - - Connections { - target: AudioService - function onWireplumberReloadStarted() { - root.isReloadingAudio = true; - } - function onWireplumberReloadCompleted(success) { - Qt.callLater(() => { - delayTimer.start(); - }); - } - function onDeviceAliasChanged(nodeName, newAlias) { - root.updateDeviceList(); - } - } - - Timer { - id: delayTimer - interval: 2000 - repeat: false - onTriggered: { - root.isReloadingAudio = false; - root.updateDeviceList(); - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "audio" - tags: ["audio", "device", "output", "speaker"] - title: I18n.tr("Output Devices", "Audio settings: speaker/headphone devices") - settingKey: "audioOutputDevices" - iconName: "volume_up" - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Set custom names for your audio output devices", "Audio settings description") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - } - - Repeater { - model: root.outputDevices.filter(d => !root.hiddenOutputDeviceNames.includes(d.name)) - - delegate: Column { - required property var modelData - width: parent?.width ?? 0 - spacing: 0 - - DeviceAliasRow { - deviceNode: modelData - deviceType: "output" - showHideButton: true - - onEditRequested: device => { - root.editingDevice = device; - root.editingDeviceType = "output"; - root.newDeviceName = AudioService.displayName(device); - root.showEditDialog = true; - } - - onResetRequested: device => { - AudioService.removeDeviceAlias(device.name); - } - - onHideRequested: device => { - root.persistHiddenOutputDeviceNames([...root.hiddenOutputDeviceNames, device.name]); - } - } - - Item { - width: parent.width - height: 36 - - StyledText { - id: maxVolLabel - text: I18n.tr("Max Volume", "Audio settings: maximum volume limit per device") + " · " + maxVolSlider.value + "%" - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM + Theme.iconSize + Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - DankSlider { - id: maxVolSlider - anchors.left: maxVolLabel.right - anchors.leftMargin: Theme.spacingS - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - height: 36 - minimum: 100 - maximum: 200 - step: 5 - showValue: true - wheelEnabled: false - centerMinimum: true - unit: "%" - onSliderValueChanged: newValue => { - SessionData.setDeviceMaxVolume(modelData.name, newValue); - } - } - - Binding { - target: maxVolSlider - property: "value" - value: SessionData.deviceMaxVolumes[modelData.name] ?? 100 - when: !maxVolSlider.isDragging - } - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No output devices found", "Audio settings empty state") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: root.outputDevices.filter(d => !root.hiddenOutputDeviceNames.includes(d.name)).length === 0 && root.hiddenOutputDeviceNames.length === 0 - topPadding: Theme.spacingM - } - - Column { - width: parent.width - spacing: 0 - visible: root.hiddenOutputDeviceNames.length > 0 - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Item { - width: parent.width - height: 36 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "visibility_off" - size: Theme.iconSize - 4 - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Hidden (%1)", "count of hidden audio devices").arg(root.hiddenOutputDeviceNames.length) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankIcon { - name: root.showHiddenOutputDevices ? "expand_less" : "expand_more" - size: Theme.iconSize - 4 - color: Theme.surfaceVariantText - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.showHiddenOutputDevices = !root.showHiddenOutputDevices - } - } - - Column { - width: parent.width - spacing: 0 - visible: root.showHiddenOutputDevices - - Repeater { - model: root.outputDevices.filter(d => root.hiddenOutputDeviceNames.includes(d.name)) - - delegate: DeviceAliasRow { - required property var modelData - deviceNode: modelData - deviceType: "output" - isHidden: true - showHideButton: true - - onHideRequested: device => { - root.persistHiddenOutputDeviceNames(root.hiddenOutputDeviceNames.filter(n => n !== device.name)); - } - - onResetRequested: device => { - AudioService.removeDeviceAlias(device.name); - } - } - } - } - } - } - } - - SettingsCard { - tab: "audio" - tags: ["audio", "device", "input", "microphone"] - title: I18n.tr("Input Devices") - settingKey: "audioInputDevices" - iconName: "mic" - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Set custom names for your audio input devices", "Audio settings description") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - } - - Repeater { - model: root.inputDevices.filter(d => !root.hiddenInputDeviceNames.includes(d.name)) - - delegate: DeviceAliasRow { - required property var modelData - - deviceNode: modelData - deviceType: "input" - showHideButton: true - - onEditRequested: device => { - root.editingDevice = device; - root.editingDeviceType = "input"; - root.newDeviceName = AudioService.displayName(device); - root.showEditDialog = true; - } - - onResetRequested: device => { - AudioService.removeDeviceAlias(device.name); - } - - onHideRequested: device => { - root.persistHiddenInputDeviceNames([...root.hiddenInputDeviceNames, device.name]); - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No input devices found", "Audio settings empty state") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: root.inputDevices.filter(d => !root.hiddenInputDeviceNames.includes(d.name)).length === 0 && root.hiddenInputDeviceNames.length === 0 - topPadding: Theme.spacingM - } - - Column { - width: parent.width - spacing: 0 - visible: root.hiddenInputDeviceNames.length > 0 - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Item { - width: parent.width - height: 36 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "visibility_off" - size: Theme.iconSize - 4 - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Hidden (%1)", "count of hidden audio devices").arg(root.hiddenInputDeviceNames.length) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankIcon { - name: root.showHiddenInputDevices ? "expand_less" : "expand_more" - size: Theme.iconSize - 4 - color: Theme.surfaceVariantText - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.showHiddenInputDevices = !root.showHiddenInputDevices - } - } - - Column { - width: parent.width - spacing: 0 - visible: root.showHiddenInputDevices - - Repeater { - model: root.inputDevices.filter(d => root.hiddenInputDeviceNames.includes(d.name)) - - delegate: DeviceAliasRow { - required property var modelData - deviceNode: modelData - deviceType: "input" - isHidden: true - showHideButton: true - - onHideRequested: device => { - root.persistHiddenInputDeviceNames(root.hiddenInputDeviceNames.filter(n => n !== device.name)); - } - - onResetRequested: device => { - AudioService.removeDeviceAlias(device.name); - } - } - } - } - } - } - } - } - } - - Rectangle { - id: loadingOverlay - anchors.fill: parent - color: Theme.withAlpha(Theme.surface, 0.9) - visible: root.isReloadingAudio - z: 100 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingL - - Rectangle { - width: 80 - height: 80 - radius: 40 - color: Theme.primaryContainer - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - id: spinningIcon - name: "refresh" - size: 40 - color: Theme.primary - anchors.centerIn: parent - - RotationAnimator { - target: spinningIcon - from: 0 - to: 360 - duration: 1500 - loops: Animation.Infinite - running: loadingOverlay.visible - } - } - } - - Column { - spacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: I18n.tr("Restarting audio system...", "Loading overlay while WirePlumber restarts") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("This may take a few seconds", "Loading overlay subtitle") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - id: dialogOverlay - anchors.fill: parent - visible: root.showEditDialog - color: Theme.withAlpha(Theme.surface, 0.8) - z: 1000 - - MouseArea { - anchors.fill: parent - onClicked: { - root.showEditDialog = false; - } - } - - Rectangle { - id: editDialog - anchors.centerIn: parent - width: Math.min(500, parent.width - Theme.spacingL * 4) - height: dialogContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 1 - border.color: Theme.outlineMedium - - MouseArea { - anchors.fill: parent - onClicked: {} - } - - Column { - id: dialogContent - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: root.editingDeviceType === "input" ? "mic" : "speaker" - size: Theme.iconSize + 8 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - 8 - spacing: 4 - - StyledText { - text: I18n.tr("Set Custom Device Name", "Audio device rename dialog title") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Bold - color: Theme.surfaceText - width: parent.width - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: root.editingDevice?.name ?? "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - } - - StyledText { - visible: AudioService.hasDeviceAlias(root.editingDevice?.name ?? "") - text: I18n.tr("Original: %1", "Shows the original device name before renaming").arg(AudioService.originalName(root.editingDevice)) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - elide: Text.ElideRight - opacity: 0.7 - horizontalAlignment: Text.AlignLeft - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Custom Name", "Audio device rename dialog field label") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - DankTextField { - id: nameInput - width: parent.width - placeholderText: I18n.tr("Enter device name...", "Audio device rename dialog placeholder") - text: root.newDeviceName - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - showClearButton: true - - onTextChanged: { - root.newDeviceName = text; - } - - Keys.onReturnPressed: { - if (text.trim() !== "") { - saveButtonMouseArea.clicked(null); - } - } - - Keys.onEscapePressed: { - root.showEditDialog = false; - } - - Component.onCompleted: { - Qt.callLater(() => { - forceActiveFocus(); - selectAll(); - }); - } - } - - StyledText { - width: parent.width - text: I18n.tr("Press Enter and the audio system will restart to apply the change", "Audio device rename dialog hint") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - } - - Row { - LayoutMirroring.enabled: false - width: parent.width - spacing: Theme.spacingM - layoutDirection: Qt.RightToLeft - - Rectangle { - id: saveButton - width: saveButtonContent.width + Theme.spacingL * 2 - height: Theme.buttonHeight - radius: Theme.cornerRadius - color: saveButtonMouseArea.containsMouse ? Theme.primaryContainer : Theme.primary - enabled: root.newDeviceName.trim() !== "" - opacity: enabled ? 1.0 : 0.5 - - Row { - id: saveButtonContent - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "check" - size: Theme.iconSize - 4 - color: Theme.onPrimary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Save") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.onPrimary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: saveButtonMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: parent.enabled - onClicked: { - if (root.editingDevice && root.newDeviceName.trim() !== "") { - AudioService.setDeviceAlias(root.editingDevice.name, root.newDeviceName); - root.showEditDialog = false; - } - } - } - } - - Rectangle { - width: cancelButtonText.width + Theme.spacingL * 2 - height: Theme.buttonHeight - radius: Theme.cornerRadius - color: cancelButtonMouseArea.containsMouse ? Theme.surfaceHover : "transparent" - border.width: 1 - border.color: Theme.outline - - StyledText { - id: cancelButtonText - text: I18n.tr("Cancel") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.centerIn: parent - } - - MouseArea { - id: cancelButtonMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.showEditDialog = false; - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ClipboardTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ClipboardTab.qml deleted file mode 100644 index d477bb9..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ClipboardTab.qml +++ /dev/null @@ -1,463 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - property var config: ({}) - property bool configLoaded: false - property bool configError: false - property bool saving: false - - readonly property var maxHistoryOptions: [ - { - text: "25", - value: 25 - }, - { - text: "50", - value: 50 - }, - { - text: "100", - value: 100 - }, - { - text: "200", - value: 200 - }, - { - text: "500", - value: 500 - }, - { - text: "1,000", - value: 1000 - }, - { - text: "10,000", - value: 10000 - }, - { - text: "15,000", - value: 15000 - }, - { - text: "20,000", - value: 20000 - }, - { - text: "30,000", - value: 30000 - }, - { - text: "50,000", - value: 50000 - }, - { - text: "100,000", - value: 100000 - }, - { - text: "∞", - value: -1 - } - ] - - readonly property var maxEntrySizeOptions: [ - { - text: "1 MB", - value: 1048576 - }, - { - text: "2 MB", - value: 2097152 - }, - { - text: "5 MB", - value: 5242880 - }, - { - text: "10 MB", - value: 10485760 - }, - { - text: "20 MB", - value: 20971520 - }, - { - text: "50 MB", - value: 52428800 - } - ] - - readonly property var autoClearOptions: [ - { - text: I18n.tr("Never"), - value: 0 - }, - { - text: I18n.tr("1 day"), - value: 1 - }, - { - text: I18n.tr("3 days"), - value: 3 - }, - { - text: I18n.tr("7 days"), - value: 7 - }, - { - text: I18n.tr("14 days"), - value: 14 - }, - { - text: I18n.tr("30 days"), - value: 30 - }, - { - text: I18n.tr("90 days"), - value: 90 - } - ] - - readonly property var maxPinnedOptions: [ - { - text: "5", - value: 5 - }, - { - text: "10", - value: 10 - }, - { - text: "15", - value: 15 - }, - { - text: "25", - value: 25 - }, - { - text: "50", - value: 50 - }, - { - text: "100", - value: 100 - } - ] - - function getMaxHistoryText(value) { - if (value <= 0) - return "∞"; - for (let opt of maxHistoryOptions) { - if (opt.value === value) - return opt.text; - } - return value.toLocaleString(); - } - - function getMaxEntrySizeText(value) { - for (let opt of maxEntrySizeOptions) { - if (opt.value === value) - return opt.text; - } - const mb = Math.round(value / 1048576); - return mb + " MB"; - } - - function getAutoClearText(value) { - for (let opt of autoClearOptions) { - if (opt.value === value) - return opt.text; - } - return value + " " + I18n.tr("days"); - } - - function getMaxPinnedText(value) { - for (let opt of maxPinnedOptions) { - if (opt.value === value) - return opt.text; - } - return value.toString(); - } - - function loadConfig() { - configLoaded = false; - configError = false; - DMSService.sendRequest("clipboard.getConfig", null, response => { - if (response.error) { - configError = true; - return; - } - config = response.result || {}; - configLoaded = true; - }); - } - - function saveConfig(key, value) { - const params = {}; - params[key] = value; - saving = true; - DMSService.sendRequest("clipboard.setConfig", params, response => { - saving = false; - if (response.error) { - ToastService.showError(I18n.tr("Failed to save clipboard setting"), response.error); - return; - } - const updated = JSON.parse(JSON.stringify(config)); - updated[key] = value; - config = updated; - }); - } - - Component.onCompleted: { - if (DMSService.isConnected) - loadConfig(); - } - - Connections { - target: DMSService - function onIsConnectedChanged() { - if (DMSService.isConnected) - loadConfig(); - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - Rectangle { - width: parent.width - height: warningContent.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12) - visible: !DMSService.isConnected || configError - - Row { - id: warningContent - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "info" - size: Theme.iconSizeSmall - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - font.pixelSize: Theme.fontSizeSmall - text: !DMSService.isConnected ? I18n.tr("DMS service is not connected. Clipboard settings are unavailable.") : I18n.tr("Failed to load clipboard configuration.") - wrapMode: Text.WordWrap - width: parent.width - Theme.iconSizeSmall - Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - } - } - } - - SettingsCard { - tab: "clipboard" - tags: ["clipboard", "history", "limit"] - title: I18n.tr("History Settings") - iconName: "history" - visible: configLoaded - - SettingsDropdownRow { - id: maxHistoryDropdown - tab: "clipboard" - tags: ["clipboard", "history", "max", "limit"] - settingKey: "maxHistory" - text: I18n.tr("Maximum History") - description: I18n.tr("Maximum number of clipboard entries to keep") - options: root.maxHistoryOptions.map(opt => opt.text) - - Component.onCompleted: { - currentValue = root.getMaxHistoryText(root.config.maxHistory ?? 100); - } - - onValueChanged: value => { - for (let opt of root.maxHistoryOptions) { - if (opt.text === value) { - root.saveConfig("maxHistory", opt.value); - return; - } - } - } - - Connections { - target: root - function onConfigChanged() { - maxHistoryDropdown.currentValue = root.getMaxHistoryText(root.config.maxHistory ?? 100); - } - } - } - - SettingsDropdownRow { - id: maxEntrySizeDropdown - tab: "clipboard" - tags: ["clipboard", "entry", "size", "limit"] - settingKey: "maxEntrySize" - text: I18n.tr("Maximum Entry Size") - description: I18n.tr("Maximum size per clipboard entry") - options: root.maxEntrySizeOptions.map(opt => opt.text) - - Component.onCompleted: { - currentValue = root.getMaxEntrySizeText(root.config.maxEntrySize ?? 5242880); - } - - onValueChanged: value => { - for (let opt of root.maxEntrySizeOptions) { - if (opt.text === value) { - root.saveConfig("maxEntrySize", opt.value); - return; - } - } - } - - Connections { - target: root - function onConfigChanged() { - maxEntrySizeDropdown.currentValue = root.getMaxEntrySizeText(root.config.maxEntrySize ?? 5242880); - } - } - } - - SettingsDropdownRow { - id: autoClearDaysDropdown - tab: "clipboard" - tags: ["clipboard", "auto", "clear", "days"] - settingKey: "autoClearDays" - text: I18n.tr("Auto-Clear After") - description: I18n.tr("Automatically delete entries older than this") - options: root.autoClearOptions.map(opt => opt.text) - - Component.onCompleted: { - currentValue = root.getAutoClearText(root.config.autoClearDays ?? 0); - } - - onValueChanged: value => { - for (let opt of root.autoClearOptions) { - if (opt.text === value) { - root.saveConfig("autoClearDays", opt.value); - return; - } - } - } - - Connections { - target: root - function onConfigChanged() { - autoClearDaysDropdown.currentValue = root.getAutoClearText(root.config.autoClearDays ?? 0); - } - } - } - - SettingsDropdownRow { - id: maxPinnedDropdown - tab: "clipboard" - tags: ["clipboard", "pinned", "max", "limit"] - settingKey: "maxPinned" - text: I18n.tr("Maximum Pinned Entries") - description: I18n.tr("Maximum number of entries that can be saved") - options: root.maxPinnedOptions.map(opt => opt.text) - - function updateValue() { - if (root.configLoaded) { - currentValue = root.getMaxPinnedText(root.config.maxPinned ?? 25); - } - } - - Component.onCompleted: { - updateValue(); - } - - onValueChanged: value => { - for (let opt of root.maxPinnedOptions) { - if (opt.text === value) { - root.saveConfig("maxPinned", opt.value); - return; - } - } - } - - Connections { - target: root - function onConfigLoadedChanged() { - if (root.configLoaded) { - maxPinnedDropdown.updateValue(); - } - } - function onConfigChanged() { - maxPinnedDropdown.updateValue(); - } - } - } - } - - SettingsCard { - tab: "clipboard" - tags: ["clipboard", "behavior"] - title: I18n.tr("Behavior") - iconName: "settings" - visible: configLoaded - - SettingsToggleRow { - tab: "clipboard" - tags: ["clipboard", "clear", "startup"] - settingKey: "clearAtStartup" - text: I18n.tr("Clear at Startup") - description: I18n.tr("Clear all history when server starts") - checked: root.config.clearAtStartup ?? false - onToggled: checked => root.saveConfig("clearAtStartup", checked) - } - - SettingsToggleRow { - tab: "clipboard" - tags: ["clipboard", "enter", "paste", "behavior"] - settingKey: "clipboardEnterToPaste" - text: I18n.tr("Enter to Paste") - description: I18n.tr("Press Enter to paste, Shift+Enter to copy", "Clipboard behavior setting description") - checked: SettingsData.clipboardEnterToPaste - onToggled: checked => SettingsData.set("clipboardEnterToPaste", checked) - } - } - - SettingsCard { - tab: "clipboard" - tags: ["clipboard", "advanced", "disable"] - title: I18n.tr("Advanced") - iconName: "tune" - collapsible: true - expanded: false - visible: configLoaded - - SettingsToggleRow { - tab: "clipboard" - tags: ["clipboard", "disable", "history"] - settingKey: "disabled" - text: I18n.tr("Disable History Persistence") - description: I18n.tr("Clipboard works but nothing saved to disk") - checked: root.config.disabled ?? false - onToggled: checked => root.saveConfig("disabled", checked) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DankBarTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DankBarTab.qml deleted file mode 100644 index a4bd87d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DankBarTab.qml +++ /dev/null @@ -1,1563 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: dankBarTab - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var parentModal: null - property string selectedBarId: "default" - - property var selectedBarConfig: { - selectedBarId; - SettingsData.barConfigs; - const index = SettingsData.barConfigs.findIndex(cfg => cfg.id === selectedBarId); - return index !== -1 ? SettingsData.barConfigs[index] : SettingsData.barConfigs[0]; - } - - property bool selectedBarIsVertical: { - selectedBarId; - const pos = selectedBarConfig?.position ?? SettingsData.Position.Top; - return pos === SettingsData.Position.Left || pos === SettingsData.Position.Right; - } - - Timer { - id: horizontalBarChangeDebounce - interval: 500 - repeat: false - onTriggered: { - const verticalBars = SettingsData.barConfigs.filter(cfg => { - const pos = cfg.position ?? SettingsData.Position.Top; - return pos === SettingsData.Position.Left || pos === SettingsData.Position.Right; - }); - - verticalBars.forEach(bar => { - if (!bar.enabled) - return; - SettingsData.updateBarConfig(bar.id, { - enabled: false - }); - Qt.callLater(() => SettingsData.updateBarConfig(bar.id, { - enabled: true - })); - }); - } - } - - function _isBarActive(c) { - if (!c.enabled) - return false; - const prefs = c.screenPreferences || ["all"]; - if (prefs.length > 0) - return true; - return (c.showOnLastDisplay ?? true) && Quickshell.screens.length === 1; - } - - function notifyHorizontalBarChange() { - const configs = SettingsData.barConfigs; - if (configs.length < 2) - return; - - const hasHorizontal = configs.some(c => { - if (!_isBarActive(c)) - return false; - const p = c.position ?? SettingsData.Position.Top; - return p === SettingsData.Position.Top || p === SettingsData.Position.Bottom; - }); - if (!hasHorizontal) - return; - - const hasVertical = configs.some(c => { - if (!_isBarActive(c)) - return false; - const p = c.position ?? SettingsData.Position.Top; - return p === SettingsData.Position.Left || p === SettingsData.Position.Right; - }); - if (!hasVertical) - return; - - horizontalBarChangeDebounce.restart(); - } - - function createNewBar() { - if (SettingsData.barConfigs.length >= 4) - return; - const defaultBar = SettingsData.getBarConfig("default"); - if (!defaultBar) - return; - const newId = "bar" + Date.now(); - const newBar = { - id: newId, - name: "Bar " + (SettingsData.barConfigs.length + 1), - enabled: true, - position: defaultBar.position ?? 0, - screenPreferences: [], - showOnLastDisplay: false, - leftWidgets: defaultBar.leftWidgets || [], - centerWidgets: defaultBar.centerWidgets || [], - rightWidgets: defaultBar.rightWidgets || [], - spacing: defaultBar.spacing ?? 4, - innerPadding: defaultBar.innerPadding ?? 4, - bottomGap: defaultBar.bottomGap ?? 0, - transparency: defaultBar.transparency ?? 1.0, - widgetTransparency: defaultBar.widgetTransparency ?? 1.0, - squareCorners: defaultBar.squareCorners ?? false, - noBackground: defaultBar.noBackground ?? false, - gothCornersEnabled: defaultBar.gothCornersEnabled ?? false, - gothCornerRadiusOverride: defaultBar.gothCornerRadiusOverride ?? false, - gothCornerRadiusValue: defaultBar.gothCornerRadiusValue ?? 12, - borderEnabled: defaultBar.borderEnabled ?? false, - borderColor: defaultBar.borderColor || "surfaceText", - borderOpacity: defaultBar.borderOpacity ?? 1.0, - borderThickness: defaultBar.borderThickness ?? 1, - widgetOutlineEnabled: defaultBar.widgetOutlineEnabled ?? false, - widgetOutlineColor: defaultBar.widgetOutlineColor || "primary", - widgetOutlineOpacity: defaultBar.widgetOutlineOpacity ?? 1.0, - widgetOutlineThickness: defaultBar.widgetOutlineThickness ?? 1, - widgetPadding: defaultBar.widgetPadding ?? 8, - maximizeWidgetIcons: defaultBar.maximizeWidgetIcons ?? false, - maximizeWidgetText: defaultBar.maximizeWidgetText ?? false, - removeWidgetPadding: defaultBar.removeWidgetPadding ?? false, - fontScale: defaultBar.fontScale ?? 1.0, - iconScale: defaultBar.iconScale ?? 1.0, - autoHide: defaultBar.autoHide ?? false, - autoHideDelay: defaultBar.autoHideDelay ?? 250, - showOnWindowsOpen: defaultBar.showOnWindowsOpen ?? false, - openOnOverview: defaultBar.openOnOverview ?? false, - visible: defaultBar.visible ?? true, - popupGapsAuto: defaultBar.popupGapsAuto ?? true, - popupGapsManual: defaultBar.popupGapsManual ?? 4, - maximizeDetection: defaultBar.maximizeDetection ?? true, - scrollEnabled: defaultBar.scrollEnabled ?? true, - scrollXBehavior: defaultBar.scrollXBehavior ?? "column", - scrollYBehavior: defaultBar.scrollYBehavior ?? "workspace", - shadowIntensity: defaultBar.shadowIntensity ?? 0, - shadowOpacity: defaultBar.shadowOpacity ?? 60, - shadowDirectionMode: defaultBar.shadowDirectionMode ?? "inherit", - shadowDirection: defaultBar.shadowDirection ?? "top", - shadowColorMode: defaultBar.shadowColorMode ?? "default", - shadowCustomColor: defaultBar.shadowCustomColor ?? "#000000" - }; - SettingsData.addBarConfig(newBar); - selectedBarId = newId; - } - - function deleteBar(barId) { - if (barId === "default") - return; - if (SettingsData.barConfigs.length <= 1) - return; - SettingsData.deleteBarConfig(barId); - selectedBarId = "default"; - } - - function toggleBarEnabled(barId) { - if (barId === "default") - return; - const config = SettingsData.getBarConfig(barId); - if (!config) - return; - SettingsData.updateBarConfig(barId, { - enabled: !config.enabled - }); - } - - function getBarScreenPreferences(barId) { - const config = SettingsData.getBarConfig(barId); - return config?.screenPreferences || ["all"]; - } - - function setBarScreenPreferences(barId, prefs) { - SettingsData.updateBarConfig(barId, { - screenPreferences: prefs - }); - notifyHorizontalBarChange(); - } - - function getBarShowOnLastDisplay(barId) { - const config = SettingsData.getBarConfig(barId); - return config?.showOnLastDisplay ?? true; - } - - function setBarShowOnLastDisplay(barId, value) { - SettingsData.updateBarConfig(barId, { - showOnLastDisplay: value - }); - if (Quickshell.screens.length === 1) - notifyHorizontalBarChange(); - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - iconName: "dashboard" - title: I18n.tr("Bar Configurations") - settingKey: "barConfigurations" - - RowLayout { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - Layout.fillWidth: true - } - - DankButton { - text: I18n.tr("Add Bar") - iconName: "add" - buttonHeight: 32 - visible: SettingsData.barConfigs.length < 4 - onClicked: dankBarTab.createNewBar() - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: SettingsData.barConfigs - - Rectangle { - id: barCard - required property var modelData - required property int index - - width: parent.width - height: barCardContent.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: dankBarTab.selectedBarId === modelData.id ? Theme.withAlpha(Theme.primary, 0.15) : Theme.surfaceVariant - border.width: dankBarTab.selectedBarId === modelData.id ? 2 : 0 - border.color: Theme.primary - - Row { - id: barCardContent - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Column { - width: parent.width - deleteBtn.width - Theme.spacingM - spacing: Theme.spacingXS / 2 - - StyledText { - text: barCard.modelData.name || "Bar " + (barCard.index + 1) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: { - SettingsData.barConfigs; - const cfg = SettingsData.getBarConfig(barCard.modelData.id); - switch (cfg?.position ?? SettingsData.Position.Top) { - case SettingsData.Position.Top: - return I18n.tr("Top"); - case SettingsData.Position.Bottom: - return I18n.tr("Bottom"); - case SettingsData.Position.Left: - return I18n.tr("Left"); - case SettingsData.Position.Right: - return I18n.tr("Right"); - default: - return I18n.tr("Top"); - } - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - SettingsData.barConfigs; - const cfg = SettingsData.getBarConfig(barCard.modelData.id); - const prefs = cfg?.screenPreferences || ["all"]; - if (prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")) - return I18n.tr("All displays"); - return prefs.length === 1 - ? I18n.tr("%1 display").arg(prefs.length) - : I18n.tr("%1 displays").arg(prefs.length); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - SettingsData.barConfigs; - const cfg = SettingsData.getBarConfig(barCard.modelData.id); - const left = cfg?.leftWidgets?.length || 0; - const center = cfg?.centerWidgets?.length || 0; - const right = cfg?.rightWidgets?.length || 0; - return I18n.tr("%1 widgets").replace("%1", left + center + right); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignLeft - visible: { - SettingsData.barConfigs; - const cfg = SettingsData.getBarConfig(barCard.modelData.id); - return !cfg?.enabled && barCard.modelData.id !== "default"; - } - } - - StyledText { - text: I18n.tr("Disabled") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - horizontalAlignment: Text.AlignLeft - visible: { - SettingsData.barConfigs; - const cfg = SettingsData.getBarConfig(barCard.modelData.id); - return !cfg?.enabled && barCard.modelData.id !== "default"; - } - } - } - } - - DankActionButton { - id: deleteBtn - buttonSize: 32 - iconName: "delete" - iconSize: 16 - backgroundColor: Theme.withAlpha(Theme.error, 0.15) - iconColor: Theme.error - visible: barCard.modelData.id !== "default" - enabled: SettingsData.barConfigs.length > 1 - anchors.verticalCenter: parent.verticalCenter - onClicked: dankBarTab.deleteBar(barCard.modelData.id) - } - } - - MouseArea { - anchors.fill: parent - z: -1 - cursorShape: Qt.PointingHandCursor - onClicked: dankBarTab.selectedBarId = barCard.modelData.id - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on border.width { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - - SettingsCard { - iconName: selectedBarConfig?.enabled ? "visibility" : "visibility_off" - title: I18n.tr("Enable Bar") - visible: selectedBarId !== "default" - - SettingsToggleRow { - text: I18n.tr("Toggle visibility of this bar configuration") - checked: { - selectedBarId; - return selectedBarConfig?.enabled ?? false; - } - onToggled: toggled => dankBarTab.toggleBarEnabled(selectedBarId) - } - } - - SettingsCard { - iconName: "display_settings" - title: I18n.tr("Display Assignment") - settingKey: "barDisplay" - visible: selectedBarConfig?.enabled - - StyledText { - width: parent.width - text: I18n.tr("Configure which displays show \"%1\"").replace("%1", selectedBarConfig?.name || "this bar") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Column { - id: displayAssignmentColumn - width: parent.width - spacing: Theme.spacingS - - property bool showingAll: { - const prefs = selectedBarConfig?.screenPreferences || ["all"]; - return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all"); - } - - SettingsToggleRow { - text: I18n.tr("All displays") - checked: displayAssignmentColumn.showingAll - onToggled: checked => { - if (checked) { - dankBarTab.setBarScreenPreferences(selectedBarId, ["all"]); - } else { - dankBarTab.setBarScreenPreferences(selectedBarId, []); - } - } - } - - SettingsToggleRow { - text: I18n.tr("Show on Last Display") - checked: selectedBarConfig?.showOnLastDisplay ?? true - visible: !displayAssignmentColumn.showingAll - onToggled: checked => dankBarTab.setBarShowOnLastDisplay(selectedBarId, checked) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: !displayAssignmentColumn.showingAll - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: !displayAssignmentColumn.showingAll - - Repeater { - model: Quickshell.screens - - delegate: SettingsToggleRow { - id: screenToggle - required property var modelData - - text: SettingsData.getScreenDisplayName(modelData) - description: modelData.width + "×" + modelData.height + " • " + (SettingsData.displayNameMode === "system" ? (modelData.model || "Unknown Model") : modelData.name) - checked: { - const prefs = selectedBarConfig?.screenPreferences || []; - if (typeof prefs[0] === "string" && prefs[0] === "all") - return false; - return SettingsData.isScreenInPreferences(modelData, prefs); - } - onToggled: checked => { - let currentPrefs = selectedBarConfig?.screenPreferences || []; - if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") - currentPrefs = []; - - const screenModelIndex = SettingsData.getScreenModelIndex(modelData); - - let newPrefs = currentPrefs.filter(pref => { - if (typeof pref === "string") - return false; - if (pref.modelIndex !== undefined && screenModelIndex >= 0) - return !(pref.model === modelData.model && pref.modelIndex === screenModelIndex); - return pref.name !== modelData.name || pref.model !== modelData.model; - }); - - if (checked) { - const prefObj = { - name: modelData.name, - model: modelData.model || "" - }; - if (screenModelIndex >= 0) - prefObj.modelIndex = screenModelIndex; - newPrefs.push(prefObj); - } - - dankBarTab.setBarScreenPreferences(selectedBarId, newPrefs); - } - } - } - } - } - } - - SettingsCard { - iconName: "vertical_align_center" - title: I18n.tr("Position") - settingKey: "barPosition" - visible: selectedBarConfig?.enabled - - Item { - width: parent.width - height: positionButtonGroup.height - - DankButtonGroup { - id: positionButtonGroup - anchors.horizontalCenter: parent.horizontalCenter - model: [I18n.tr("Top"), I18n.tr("Bottom"), I18n.tr("Left"), I18n.tr("Right")] - currentIndex: { - selectedBarId; - const config = SettingsData.getBarConfig(selectedBarId); - const pos = config?.position ?? 0; - switch (pos) { - case SettingsData.Position.Top: - return 0; - case SettingsData.Position.Bottom: - return 1; - case SettingsData.Position.Left: - return 2; - case SettingsData.Position.Right: - return 3; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let newPos = 0; - switch (index) { - case 0: - newPos = SettingsData.Position.Top; - break; - case 1: - newPos = SettingsData.Position.Bottom; - break; - case 2: - newPos = SettingsData.Position.Left; - break; - case 3: - newPos = SettingsData.Position.Right; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - position: newPos - }); - notifyHorizontalBarChange(); - } - } - } - } - - SettingsCard { - iconName: "visibility_off" - title: I18n.tr("Visibility") - settingKey: "barVisibility" - visible: selectedBarConfig?.enabled - - SettingsToggleRow { - text: I18n.tr("Auto-hide") - checked: selectedBarConfig?.autoHide ?? false - onToggled: toggled => { - SettingsData.updateBarConfig(selectedBarId, { - autoHide: toggled - }); - notifyHorizontalBarChange(); - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: selectedBarConfig?.autoHide ?? false - leftPadding: Theme.spacingM - - Rectangle { - width: parent.width - parent.leftPadding - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsSliderRow { - id: hideDelaySlider - width: parent.width - parent.parent.leftPadding - text: I18n.tr("Hide Delay") - value: selectedBarConfig?.autoHideDelay ?? 250 - minimum: 0 - maximum: 2000 - unit: "ms" - defaultValue: 250 - onSliderValueChanged: newValue => { - SettingsData.updateBarConfig(selectedBarId, { - autoHideDelay: newValue - }); - } - - Binding { - target: hideDelaySlider - property: "value" - value: selectedBarConfig?.autoHideDelay ?? 250 - restoreMode: Binding.RestoreBinding - } - } - - SettingsToggleRow { - width: parent.width - parent.leftPadding - visible: CompositorService.isNiri || CompositorService.isHyprland - text: I18n.tr("Hide When Windows Open") - checked: selectedBarConfig?.showOnWindowsOpen ?? false - onToggled: toggled => { - SettingsData.updateBarConfig(selectedBarId, { - showOnWindowsOpen: toggled - }); - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - text: I18n.tr("Manual Show/Hide") - checked: selectedBarConfig?.visible ?? true - onToggled: toggled => { - SettingsData.updateBarConfig(selectedBarId, { - visible: toggled - }); - notifyHorizontalBarChange(); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - text: I18n.tr("Click Through") - checked: selectedBarConfig?.clickThrough ?? false - onToggled: toggled => SettingsData.updateBarConfig(selectedBarId, { - clickThrough: toggled - }) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: CompositorService.isNiri - } - - SettingsToggleRow { - visible: CompositorService.isNiri - text: I18n.tr("Show on Overview") - checked: selectedBarConfig?.openOnOverview ?? false - onToggled: toggled => { - SettingsData.updateBarConfig(selectedBarId, { - openOnOverview: toggled - }); - } - } - } - - SettingsToggleCard { - iconName: "fit_screen" - title: I18n.tr("Maximize Detection") - description: I18n.tr("Remove gaps and border when windows are maximized") - visible: selectedBarConfig?.enabled && (CompositorService.isNiri || CompositorService.isHyprland) - checked: selectedBarConfig?.maximizeDetection ?? true - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - maximizeDetection: checked - }) - } - - SettingsToggleCard { - iconName: "mouse" - title: I18n.tr("Scroll Wheel") - description: I18n.tr("Control workspaces and columns by scrolling on the bar") - visible: selectedBarConfig?.enabled - checked: selectedBarConfig?.scrollEnabled ?? true - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - scrollEnabled: checked - }) - - SettingsButtonGroupRow { - text: I18n.tr("Y Axis") - model: CompositorService.isNiri ? [I18n.tr("None"), I18n.tr("Workspace"), I18n.tr("Column")] : [I18n.tr("None"), I18n.tr("Workspace")] - currentIndex: { - switch (selectedBarConfig?.scrollYBehavior || "workspace") { - case "none": - return 0; - case "workspace": - return 1; - case "column": - return 2; - default: - return 1; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let behavior = "workspace"; - switch (index) { - case 0: - behavior = "none"; - break; - case 1: - behavior = "workspace"; - break; - case 2: - behavior = "column"; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - scrollYBehavior: behavior - }); - } - } - - SettingsButtonGroupRow { - text: I18n.tr("X Axis") - visible: CompositorService.isNiri - model: [I18n.tr("None"), I18n.tr("Workspace"), I18n.tr("Column")] - currentIndex: { - switch (selectedBarConfig?.scrollXBehavior || "column") { - case "none": - return 0; - case "workspace": - return 1; - case "column": - return 2; - default: - return 2; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let behavior = "column"; - switch (index) { - case 0: - behavior = "none"; - break; - case 1: - behavior = "workspace"; - break; - case 2: - behavior = "column"; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - scrollXBehavior: behavior - }); - } - } - } - - SettingsCard { - iconName: "space_bar" - title: I18n.tr("Spacing") - settingKey: "barSpacing" - visible: selectedBarConfig?.enabled - - SettingsSliderRow { - id: edgeSpacingSlider - text: I18n.tr("Edge Spacing") - value: selectedBarConfig?.spacing ?? 4 - minimum: 0 - maximum: 32 - defaultValue: 4 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - spacing: finalValue - }); - } - - Binding { - target: edgeSpacingSlider - property: "value" - value: selectedBarConfig?.spacing ?? 4 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: exclusiveZoneSlider - text: I18n.tr("Exclusive Zone Offset") - value: selectedBarConfig?.bottomGap ?? 0 - minimum: -50 - maximum: 50 - defaultValue: 0 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - bottomGap: finalValue - }); - } - - Binding { - target: exclusiveZoneSlider - property: "value" - value: selectedBarConfig?.bottomGap ?? 0 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: sizeSlider - text: I18n.tr("Size") - value: selectedBarConfig?.innerPadding ?? 4 - minimum: -8 - maximum: 24 - defaultValue: 4 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - innerPadding: finalValue - }); - } - - Binding { - target: sizeSlider - property: "value" - value: selectedBarConfig?.innerPadding ?? 4 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: widgetPaddingSlider - text: I18n.tr("Padding") - value: selectedBarConfig?.widgetPadding ?? 8 - minimum: 0 - maximum: 32 - unit: "px" - defaultValue: 8 - opacity: (selectedBarConfig?.removeWidgetPadding ?? false) ? 0.5 : 1.0 - enabled: !(selectedBarConfig?.removeWidgetPadding ?? false) - onSliderValueChanged: newValue => { - SettingsData.updateBarConfig(selectedBarId, { - widgetPadding: newValue - }); - } - - Binding { - target: widgetPaddingSlider - property: "value" - value: selectedBarConfig?.widgetPadding ?? 12 - restoreMode: Binding.RestoreBinding - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - text: I18n.tr("Auto Popup Gaps") - checked: selectedBarConfig?.popupGapsAuto ?? true - onToggled: checked => { - SettingsData.updateBarConfig(selectedBarId, { - popupGapsAuto: checked - }); - } - } - - Column { - width: parent.width - leftPadding: Theme.spacingM - spacing: Theme.spacingM - visible: !(selectedBarConfig?.popupGapsAuto ?? true) - - Rectangle { - width: parent.width - parent.leftPadding - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsSliderRow { - id: popupGapsManualSlider - width: parent.width - parent.parent.leftPadding - text: I18n.tr("Manual Gap Size") - value: selectedBarConfig?.popupGapsManual ?? 4 - minimum: 0 - maximum: 50 - defaultValue: 4 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - popupGapsManual: finalValue - }); - } - - Binding { - target: popupGapsManualSlider - property: "value" - value: selectedBarConfig?.popupGapsManual ?? 4 - restoreMode: Binding.RestoreBinding - } - } - } - } - - SettingsSliderCard { - id: fontScaleSliderCard - iconName: "text_fields" - title: I18n.tr("Font Scale") - description: I18n.tr("Scale DankBar font sizes independently") - visible: selectedBarConfig?.enabled - minimum: 50 - maximum: 200 - value: Math.round((selectedBarConfig?.fontScale ?? 1.0) * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => { - SettingsData.updateBarConfig(selectedBarId, { - fontScale: newValue / 100 - }); - } - - Binding { - target: fontScaleSliderCard - property: "value" - value: Math.round((selectedBarConfig?.fontScale ?? 1.0) * 100) - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderCard { - id: iconScaleSliderCard - iconName: "interests" - title: I18n.tr("Icon Scale") - description: I18n.tr("Scale DankBar icon sizes independently") - visible: selectedBarConfig?.enabled - minimum: 50 - maximum: 200 - value: Math.round((selectedBarConfig?.iconScale ?? 1.0) * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => { - SettingsData.updateBarConfig(selectedBarId, { - iconScale: newValue / 100 - }); - } - - Binding { - target: iconScaleSliderCard - property: "value" - value: Math.round((selectedBarConfig?.iconScale ?? 1.0) * 100) - restoreMode: Binding.RestoreBinding - } - } - - SettingsCard { - iconName: "opacity" - title: I18n.tr("Transparency") - settingKey: "barTransparency" - visible: selectedBarConfig?.enabled - - SettingsSliderRow { - id: barTransparencySlider - text: I18n.tr("Bar Transparency") - value: (selectedBarConfig?.transparency ?? 1.0) * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - transparency: finalValue / 100 - }); - } - - Binding { - target: barTransparencySlider - property: "value" - value: (selectedBarConfig?.transparency ?? 1.0) * 100 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: widgetTransparencySlider - text: I18n.tr("Widget Transparency") - value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - widgetTransparency: finalValue / 100 - }); - } - - Binding { - target: widgetTransparencySlider - property: "value" - value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100 - restoreMode: Binding.RestoreBinding - } - } - } - - SettingsCard { - id: shadowCard - iconName: "layers" - title: I18n.tr("Shadow Override", "bar shadow settings card") - settingKey: "barShadow" - collapsible: true - expanded: true - visible: selectedBarConfig?.enabled - - readonly property bool shadowActive: (selectedBarConfig?.shadowIntensity ?? 0) > 0 - readonly property bool isCustomColor: (selectedBarConfig?.shadowColorMode ?? "default") === "custom" - readonly property string directionSource: selectedBarConfig?.shadowDirectionMode ?? "inherit" - - StyledText { - width: parent.width - text: I18n.tr("Enable a custom override below to set per-bar shadow intensity, opacity, and color.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - SettingsToggleRow { - text: I18n.tr("Custom Shadow Override") - description: I18n.tr("Override the global shadow with per-bar settings") - checked: shadowCard.shadowActive - onToggled: checked => { - if (checked) { - SettingsData.updateBarConfig(selectedBarId, { - shadowIntensity: 12, - shadowOpacity: 60 - }); - } else { - SettingsData.updateBarConfig(selectedBarId, { - shadowIntensity: 0 - }); - } - } - } - - SettingsSliderRow { - visible: shadowCard.shadowActive - text: I18n.tr("Intensity", "shadow intensity slider") - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: 12 - value: selectedBarConfig?.shadowIntensity ?? 0 - onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, { - shadowIntensity: newValue - }) - } - - SettingsSliderRow { - visible: shadowCard.shadowActive - text: I18n.tr("Opacity") - minimum: 10 - maximum: 100 - unit: "%" - defaultValue: 60 - value: selectedBarConfig?.shadowOpacity ?? 60 - onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, { - shadowOpacity: newValue - }) - } - - SettingsDropdownRow { - visible: shadowCard.shadowActive - text: I18n.tr("Direction Source", "bar shadow direction source") - description: I18n.tr("Choose how this bar resolves shadow direction") - settingKey: "barShadowDirectionSource" - options: [I18n.tr("Inherit Global (Default)", "bar shadow direction source option"), I18n.tr("Auto (Bar-aware)", "bar shadow direction source option"), I18n.tr("Manual", "bar shadow direction source option")] - currentValue: { - switch (shadowCard.directionSource) { - case "autoBar": - return I18n.tr("Auto (Bar-aware)", "bar shadow direction source option"); - case "manual": - return I18n.tr("Manual", "bar shadow direction source option"); - default: - return I18n.tr("Inherit Global (Default)", "bar shadow direction source option"); - } - } - onValueChanged: value => { - if (value === I18n.tr("Auto (Bar-aware)", "bar shadow direction source option")) { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirectionMode: "autoBar" - }); - } else if (value === I18n.tr("Manual", "bar shadow direction source option")) { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirectionMode: "manual" - }); - } else { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirectionMode: "inherit" - }); - } - } - } - - SettingsDropdownRow { - visible: shadowCard.shadowActive && shadowCard.directionSource === "manual" - text: I18n.tr("Manual Direction", "bar manual shadow direction") - description: I18n.tr("Use a fixed shadow direction for this bar") - settingKey: "barShadowDirectionManual" - options: [I18n.tr("Top", "shadow direction option"), I18n.tr("Top Left", "shadow direction option"), I18n.tr("Top Right", "shadow direction option"), I18n.tr("Bottom", "shadow direction option")] - currentValue: { - switch (selectedBarConfig?.shadowDirection) { - case "topLeft": - return I18n.tr("Top Left", "shadow direction option"); - case "topRight": - return I18n.tr("Top Right", "shadow direction option"); - case "bottom": - return I18n.tr("Bottom", "shadow direction option"); - default: - return I18n.tr("Top", "shadow direction option"); - } - } - onValueChanged: value => { - if (value === I18n.tr("Top Left", "shadow direction option")) { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirection: "topLeft" - }); - } else if (value === I18n.tr("Top Right", "shadow direction option")) { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirection: "topRight" - }); - } else if (value === I18n.tr("Bottom", "shadow direction option")) { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirection: "bottom" - }); - } else { - SettingsData.updateBarConfig(selectedBarId, { - shadowDirection: "top" - }); - } - } - } - - Column { - visible: shadowCard.shadowActive - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Color") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - horizontalAlignment: Text.AlignLeft - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - } - - Item { - width: parent.width - height: shadowColorGroup.implicitHeight - - DankButtonGroup { - id: shadowColorGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 420 ? Theme.spacingXS : Theme.spacingS - minButtonWidth: parent.width < 420 ? 36 : 56 - textSize: parent.width < 420 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("Default (Black)"), I18n.tr("Surface", "shadow color option"), I18n.tr("Primary"), I18n.tr("Secondary"), I18n.tr("Custom")] - selectionMode: "single" - currentIndex: { - switch (selectedBarConfig?.shadowColorMode || "default") { - case "surface": - return 1; - case "primary": - return 2; - case "secondary": - return 3; - case "custom": - return 4; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let mode = "default"; - switch (index) { - case 1: - mode = "surface"; - break; - case 2: - mode = "primary"; - break; - case 3: - mode = "secondary"; - break; - case 4: - mode = "custom"; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - shadowColorMode: mode - }); - } - } - } - - Rectangle { - visible: selectedBarConfig?.shadowColorMode === "custom" - width: 32 - height: 32 - radius: 16 - color: selectedBarConfig?.shadowCustomColor ?? "#000000" - border.color: Theme.outline - border.width: 1 - anchors.horizontalCenter: parent.horizontalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - PopoutService.colorPickerModal.selectedColor = selectedBarConfig?.shadowCustomColor ?? "#000000"; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (color) { - SettingsData.updateBarConfig(selectedBarId, { - shadowCustomColor: color.toString() - }); - }; - PopoutService.colorPickerModal.show(); - } - } - } - } - } - - SettingsCard { - iconName: "rounded_corner" - title: I18n.tr("Corners & Background") - settingKey: "barCorners" - collapsible: true - expanded: false - visible: selectedBarConfig?.enabled - - SettingsToggleRow { - text: I18n.tr("Square Corners") - checked: selectedBarConfig?.squareCorners ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - squareCorners: checked - }) - } - - SettingsToggleRow { - text: I18n.tr("No Background") - checked: selectedBarConfig?.noBackground ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - noBackground: checked - }) - } - - SettingsToggleRow { - text: I18n.tr("Maximize Widget Icons") - checked: selectedBarConfig?.maximizeWidgetIcons ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - maximizeWidgetIcons: checked - }) - } - - SettingsToggleRow { - text: I18n.tr("Maximize Widget Text") - checked: selectedBarConfig?.maximizeWidgetText ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - maximizeWidgetText: checked - }) - } - - SettingsToggleRow { - text: I18n.tr("Remove Widget Padding") - checked: selectedBarConfig?.removeWidgetPadding ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - removeWidgetPadding: checked - }) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - text: I18n.tr("Goth Corners") - checked: selectedBarConfig?.gothCornersEnabled ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - gothCornersEnabled: checked - }) - } - - SettingsToggleRow { - text: I18n.tr("Corner Radius Override") - checked: selectedBarConfig?.gothCornerRadiusOverride ?? false - visible: selectedBarConfig?.gothCornersEnabled ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - gothCornerRadiusOverride: checked - }) - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: (selectedBarConfig?.gothCornersEnabled ?? false) && (selectedBarConfig?.gothCornerRadiusOverride ?? false) - leftPadding: Theme.spacingM - - SettingsSliderRow { - id: gothCornerRadiusSlider - width: parent.width - parent.leftPadding - text: I18n.tr("Goth Corner Radius") - value: selectedBarConfig?.gothCornerRadiusValue ?? 12 - minimum: 0 - maximum: 64 - defaultValue: 12 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - gothCornerRadiusValue: finalValue - }); - } - - Binding { - target: gothCornerRadiusSlider - property: "value" - value: selectedBarConfig?.gothCornerRadiusValue ?? 12 - restoreMode: Binding.RestoreBinding - } - } - } - } - - SettingsToggleCard { - iconName: "border_style" - title: I18n.tr("Border") - visible: selectedBarConfig?.enabled - checked: selectedBarConfig?.borderEnabled ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - borderEnabled: checked - }) - - SettingsButtonGroupRow { - text: I18n.tr("Color") - model: ["Surface", "Secondary", "Primary"] - currentIndex: { - switch (selectedBarConfig?.borderColor || "surfaceText") { - case "surfaceText": - return 0; - case "secondary": - return 1; - case "primary": - return 2; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let newColor = "surfaceText"; - switch (index) { - case 0: - newColor = "surfaceText"; - break; - case 1: - newColor = "secondary"; - break; - case 2: - newColor = "primary"; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - borderColor: newColor - }); - } - } - - SettingsSliderRow { - id: borderOpacitySlider - text: I18n.tr("Opacity") - value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - borderOpacity: finalValue / 100 - }); - } - - Binding { - target: borderOpacitySlider - property: "value" - value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: borderThicknessSlider - text: I18n.tr("Thickness") - value: selectedBarConfig?.borderThickness ?? 1 - minimum: 1 - maximum: 10 - unit: "px" - defaultValue: 1 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - borderThickness: finalValue - }); - } - - Binding { - target: borderThicknessSlider - property: "value" - value: selectedBarConfig?.borderThickness ?? 1 - restoreMode: Binding.RestoreBinding - } - } - } - - SettingsToggleCard { - iconName: "highlight" - title: I18n.tr("Widget Outline") - visible: selectedBarConfig?.enabled - checked: selectedBarConfig?.widgetOutlineEnabled ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - widgetOutlineEnabled: checked - }) - - SettingsButtonGroupRow { - text: I18n.tr("Color") - model: ["Surface", "Secondary", "Primary"] - currentIndex: { - switch (selectedBarConfig?.widgetOutlineColor || "primary") { - case "surfaceText": - return 0; - case "secondary": - return 1; - case "primary": - return 2; - default: - return 2; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let newColor = "primary"; - switch (index) { - case 0: - newColor = "surfaceText"; - break; - case 1: - newColor = "secondary"; - break; - case 2: - newColor = "primary"; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - widgetOutlineColor: newColor - }); - } - } - - SettingsSliderRow { - id: widgetOutlineOpacitySlider - text: I18n.tr("Opacity") - value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - widgetOutlineOpacity: finalValue / 100 - }); - } - - Binding { - target: widgetOutlineOpacitySlider - property: "value" - value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100 - restoreMode: Binding.RestoreBinding - } - } - - SettingsSliderRow { - id: widgetOutlineThicknessSlider - text: I18n.tr("Thickness") - value: selectedBarConfig?.widgetOutlineThickness ?? 1 - minimum: 1 - maximum: 10 - unit: "px" - defaultValue: 1 - onSliderDragFinished: finalValue => { - SettingsData.updateBarConfig(selectedBarId, { - widgetOutlineThickness: finalValue - }); - } - - Binding { - target: widgetOutlineThicknessSlider - property: "value" - value: selectedBarConfig?.widgetOutlineThickness ?? 1 - restoreMode: Binding.RestoreBinding - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetBrowser.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetBrowser.qml deleted file mode 100644 index 4c23596..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetBrowser.qml +++ /dev/null @@ -1,477 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property string searchQuery: "" - property var filteredWidgets: [] - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - property var parentModal: null - - signal widgetAdded(string widgetType) - - function updateFilteredWidgets() { - const allWidgets = DesktopWidgetRegistry.registeredWidgetsList || []; - var filtered = []; - - if (!searchQuery || searchQuery.length === 0) { - filtered = allWidgets.slice(); - } else { - var query = searchQuery.toLowerCase(); - for (var i = 0; i < allWidgets.length; i++) { - var widget = allWidgets[i]; - var name = widget.name ? widget.name.toLowerCase() : ""; - var description = widget.description ? widget.description.toLowerCase() : ""; - var id = widget.id ? widget.id.toLowerCase() : ""; - - if (name.indexOf(query) !== -1 || description.indexOf(query) !== -1 || id.indexOf(query) !== -1) - filtered.push(widget); - } - } - - filtered.sort((a, b) => { - if (a.featured !== b.featured) - return a.featured ? -1 : 1; - return 0; - }); - - filteredWidgets = filtered; - selectedIndex = -1; - keyboardNavigationActive = false; - } - - function selectNext() { - if (filteredWidgets.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.min(selectedIndex + 1, filteredWidgets.length - 1); - } - - function selectPrevious() { - if (filteredWidgets.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.max(selectedIndex - 1, -1); - if (selectedIndex === -1) - keyboardNavigationActive = false; - } - - function selectWidget() { - if (selectedIndex < 0 || selectedIndex >= filteredWidgets.length) - return; - var widget = filteredWidgets[selectedIndex]; - addWidget(widget); - } - - function addWidget(widget) { - const widgetType = widget.id; - const defaultConfig = DesktopWidgetRegistry.getDefaultConfig(widgetType); - const name = widget.name || widgetType; - SettingsData.createDesktopWidgetInstance(widgetType, name, defaultConfig); - root.widgetAdded(widgetType); - root.hide(); - } - - function show() { - updateFilteredWidgets(); - if (parentModal) - parentModal.shouldHaveFocus = false; - visible = true; - Qt.callLater(() => { - searchField.forceActiveFocus(); - }); - } - - function hide() { - visible = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal && parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - objectName: "desktopWidgetBrowser" - title: I18n.tr("Add Desktop Widget") - minimumSize: Qt.size(400, 350) - implicitWidth: 500 - implicitHeight: 550 - color: Theme.surfaceContainer - visible: false - - onVisibleChanged: { - if (visible) { - updateFilteredWidgets(); - Qt.callLater(() => { - searchField.forceActiveFocus(); - }); - return; - } - searchQuery = ""; - filteredWidgets = []; - selectedIndex = -1; - keyboardNavigationActive = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal && parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - Connections { - target: DesktopWidgetRegistry - function onRegistryChanged() { - if (root.visible) - root.updateFilteredWidgets(); - } - } - - FocusScope { - id: widgetKeyHandler - - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Escape: - root.hide(); - event.accepted = true; - return; - case Qt.Key_Down: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_Up: - root.selectPrevious(); - event.accepted = true; - return; - case Qt.Key_Return: - case Qt.Key_Enter: - if (root.keyboardNavigationActive) { - root.selectWidget(); - } else if (root.filteredWidgets.length > 0) { - root.addWidget(root.filteredWidgets[0]); - } - event.accepted = true; - return; - } - if (event.modifiers & Qt.ControlModifier) { - switch (event.key) { - case Qt.Key_N: - case Qt.Key_J: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_P: - case Qt.Key_K: - root.selectPrevious(); - event.accepted = true; - return; - } - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - id: titleBar - width: parent.width - height: 48 - - MouseArea { - anchors.fill: parent - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - Rectangle { - anchors.fill: parent - color: Theme.withAlpha(Theme.surfaceContainer, 0.5) - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "add_circle" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Add Desktop Widget") - font.pixelSize: Theme.fontSizeXLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - visible: windowControls.supported - circular: false - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - circular: false - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.hide() - } - } - } - - Item { - width: parent.width - height: parent.height - titleBar.height - - Column { - id: contentColumn - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Select a widget to add to your desktop. Each widget is a separate instance with its own settings.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - width: parent.width - wrapMode: Text.WordWrap - } - - DankTextField { - id: searchField - width: parent.width - height: 48 - cornerRadius: Theme.cornerRadius - backgroundColor: Theme.surfaceContainerHigh - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: "search" - leftIconSize: Theme.iconSize - leftIconColor: Theme.surfaceVariantText - leftIconFocusedColor: Theme.primary - showClearButton: true - textColor: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - placeholderText: I18n.tr("Search widgets...") - text: root.searchQuery - focus: true - ignoreLeftRightKeys: true - keyForwardTargets: [widgetKeyHandler] - onTextEdited: { - root.searchQuery = text; - root.updateFilteredWidgets(); - } - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - root.hide(); - event.accepted = true; - return; - } - if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) - event.accepted = false; - } - } - - DankListView { - id: widgetList - - width: parent.width - height: parent.height - y - spacing: Theme.spacingS - model: root.filteredWidgets - clip: true - - delegate: Rectangle { - id: delegateRoot - - required property var modelData - required property int index - - width: widgetList.width - height: 72 - radius: Theme.cornerRadius - property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex - color: isSelected ? Theme.primarySelected : widgetArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.surfaceVariant, 0.3) - border.color: isSelected ? Theme.primary : Theme.withAlpha(Theme.outline, 0.2) - border.width: isSelected ? 2 : 1 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Rectangle { - width: 44 - height: 44 - radius: Theme.cornerRadius - color: Theme.primarySelected - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: delegateRoot.modelData.icon || "widgets" - size: Theme.iconSize - color: Theme.primary - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - 44 - Theme.iconSize - Theme.spacingM * 3 - - Row { - spacing: Theme.spacingS - - StyledText { - text: delegateRoot.modelData.name || delegateRoot.modelData.id - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - Rectangle { - visible: delegateRoot.modelData.featured || false - width: featuredWidgetRow.implicitWidth + Theme.spacingXS * 2 - height: 18 - radius: 9 - color: Theme.withAlpha(Theme.secondary, 0.15) - border.color: Theme.withAlpha(Theme.secondary, 0.4) - border.width: 1 - anchors.verticalCenter: parent.verticalCenter - - Row { - id: featuredWidgetRow - anchors.centerIn: parent - spacing: 2 - - DankIcon { - name: "star" - size: 10 - color: Theme.secondary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("featured") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.secondary - font.weight: Font.Medium - } - } - } - - Rectangle { - visible: delegateRoot.modelData.type === "plugin" - width: pluginLabel.implicitWidth + Theme.spacingXS * 2 - height: 18 - radius: 9 - color: Theme.withAlpha(Theme.secondary, 0.15) - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: pluginLabel - anchors.centerIn: parent - text: I18n.tr("Plugin") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.secondary - } - } - } - - StyledText { - text: delegateRoot.modelData.description || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - elide: Text.ElideRight - width: parent.width - wrapMode: Text.WordWrap - maximumLineCount: 2 - visible: text !== "" - } - } - - DankIcon { - name: "add" - size: Theme.iconSize - 4 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: widgetArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.addWidget(delegateRoot.modelData) - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - footer: Item { - width: widgetList.width - height: emptyText.visible ? 60 : 0 - - StyledText { - id: emptyText - visible: root.filteredWidgets.length === 0 - text: root.searchQuery.length > 0 ? I18n.tr("No widgets match your search") : I18n.tr("No widgets available") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignHCenter - anchors.centerIn: parent - } - } - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetInstanceCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetInstanceCard.qml deleted file mode 100644 index 4852d6b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetInstanceCard.qml +++ /dev/null @@ -1,460 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Controls -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets -import qs.Modules.Settings.DesktopWidgetSettings as DWS - -SettingsCard { - id: root - - required property var instanceData - property bool isExpanded: false - property bool confirmingDelete: false - - readonly property string instanceId: instanceData?.id ?? "" - readonly property string widgetType: instanceData?.widgetType ?? "" - readonly property var widgetDef: DesktopWidgetRegistry.getWidget(widgetType) - readonly property string widgetName: instanceData?.name ?? widgetDef?.name ?? widgetType - - signal deleteRequested - signal duplicateRequested - - property Component clockSettingsComponent: Component { - DWS.ClockSettings {} - } - - property Component systemMonitorSettingsComponent: Component { - DWS.SystemMonitorSettings {} - } - - property Component pluginSettingsComponent: Component { - DWS.PluginDesktopWidgetSettings { - instanceId: root.instanceId - instanceData: root.instanceData - widgetType: root.widgetType - widgetDef: root.widgetDef - } - } - - width: parent?.width ?? 400 - iconName: widgetDef?.icon ?? "widgets" - title: widgetName - collapsible: true - expanded: isExpanded - - onExpandedChanged: isExpanded = expanded - - headerActions: [ - DankToggle { - checked: instanceData?.enabled ?? true - onToggled: isChecked => { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - enabled: isChecked - }); - } - }, - DankActionButton { - id: menuButton - iconName: "more_vert" - onClicked: { - if (actionsMenu.opened) { - actionsMenu.close(); - return; - } - actionsMenu.open(); - } - - Popup { - id: actionsMenu - x: -width + parent.width - y: parent.height + Theme.spacingXS - width: 160 - padding: Theme.spacingXS - modal: false - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - onClosed: root.confirmingDelete = false - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Theme.outlineLight - border.width: 1 - } - - contentItem: Column { - spacing: 2 - - Rectangle { - width: parent.width - height: Theme.iconSizeLarge - radius: Theme.cornerRadius - color: duplicateArea.containsMouse ? Theme.primaryHover : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "content_copy" - size: Theme.iconSizeSmall - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Duplicate") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - - MouseArea { - id: duplicateArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - actionsMenu.close(); - root.duplicateRequested(); - } - } - } - - Rectangle { - width: parent.width - height: Theme.iconSizeLarge - radius: Theme.cornerRadius - color: deleteArea.containsMouse ? Theme.errorHover : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: root.confirmingDelete ? "warning" : "delete" - size: Theme.iconSizeSmall - color: Theme.error - } - - StyledText { - text: root.confirmingDelete ? I18n.tr("Confirm Delete") : I18n.tr("Delete") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - } - } - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (root.confirmingDelete) { - actionsMenu.close(); - root.deleteRequested(); - return; - } - root.confirmingDelete = true; - } - } - } - } - } - } - ] - - Column { - width: parent.width - spacing: 0 - visible: root.isExpanded - opacity: visible ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Item { - width: parent.width - height: nameRow.height + Theme.spacingM * 2 - - Row { - id: nameRow - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - - StyledText { - text: I18n.tr("Name") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 80 - horizontalAlignment: Text.AlignLeft - } - - DankTextField { - width: parent.width - 80 - Theme.spacingM - text: root.widgetName - onEditingFinished: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - name: text - }); - } - } - } - } - - SettingsDivider {} - - Item { - width: parent.width - height: groupRow.height + Theme.spacingM * 2 - visible: (SettingsData.desktopWidgetGroups || []).length > 0 - - Row { - id: groupRow - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - - StyledText { - text: I18n.tr("Group") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 80 - horizontalAlignment: Text.AlignLeft - } - - DankDropdown { - id: groupDropdown - width: parent.width - 80 - Theme.spacingM - compactMode: true - - property var groupsData: { - const groups = SettingsData.desktopWidgetGroups || []; - const items = [ - { - value: "", - label: I18n.tr("None") - } - ]; - for (const g of groups) { - items.push({ - value: g.id, - label: g.name - }); - } - return items; - } - - options: groupsData.map(g => g.label) - currentValue: { - const currentGroup = root.instanceData?.group ?? ""; - const item = groupsData.find(g => g.value === currentGroup); - return item?.label ?? I18n.tr("None"); - } - - onValueChanged: value => { - if (!root.instanceId) - return; - const item = groupsData.find(g => g.label === value); - const groupId = item?.value ?? ""; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - group: groupId || null - }); - } - } - } - } - - SettingsDivider { - visible: (SettingsData.desktopWidgetGroups || []).length > 0 - } - - SettingsToggleRow { - text: I18n.tr("Show on Overlay") - checked: instanceData?.config?.showOnOverlay ?? false - onToggled: isChecked => { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, { - showOnOverlay: isChecked - }); - } - } - - SettingsDivider { - visible: CompositorService.isNiri - } - - SettingsToggleRow { - visible: CompositorService.isNiri - text: I18n.tr("Show on Overview") - checked: instanceData?.config?.showOnOverview ?? false - onToggled: isChecked => { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, { - showOnOverview: isChecked - }); - } - } - - SettingsDivider { - visible: CompositorService.isNiri - } - - SettingsToggleRow { - visible: CompositorService.isNiri - text: I18n.tr("Show on Overview Only") - checked: instanceData?.config?.showOnOverviewOnly ?? false - onToggled: isChecked => { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, { - showOnOverviewOnly: isChecked - }); - } - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Click Through") - description: I18n.tr("Allow clicks to pass through the widget") - checked: instanceData?.config?.clickThrough ?? false - onToggled: isChecked => { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, { - clickThrough: isChecked - }); - } - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Sync Position Across Screens") - description: I18n.tr("Use the same position and size on all displays") - checked: instanceData?.config?.syncPositionAcrossScreens ?? false - onToggled: isChecked => { - if (!root.instanceId) - return; - if (isChecked) - SettingsData.syncDesktopWidgetPositionToAllScreens(root.instanceId); - SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, { - syncPositionAcrossScreens: isChecked - }); - } - } - - SettingsDivider {} - - Item { - width: parent.width - height: ipcColumn.height + Theme.spacingM * 2 - - Column { - id: ipcColumn - x: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Command") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Rectangle { - width: parent.width - height: ipcText.height + Theme.spacingS * 2 - radius: Theme.cornerRadius / 2 - color: Theme.surfaceHover - - Row { - x: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - width: parent.width - Theme.spacingS * 2 - - StyledText { - id: ipcText - text: "dms ipc call desktopWidget toggleOverlay " + root.instanceId - font.pixelSize: Theme.fontSizeSmall - font.family: Theme.monoFontFamily - color: Theme.surfaceVariantText - width: parent.width - copyBtn.width - Theme.spacingS - elide: Text.ElideMiddle - anchors.verticalCenter: parent.verticalCenter - } - - DankButton { - id: copyBtn - iconName: "content_copy" - backgroundColor: "transparent" - textColor: Theme.surfaceText - buttonHeight: 28 - horizontalPadding: 4 - anchors.verticalCenter: parent.verticalCenter - onClicked: { - Quickshell.execDetached(["dms", "cl", "copy", "dms ipc call desktopWidget toggleOverlay " + root.instanceId]); - ToastService.showInfo(I18n.tr("Copied to clipboard")); - } - } - } - } - } - } - - SettingsDivider {} - - Loader { - id: settingsLoader - width: parent.width - active: root.isExpanded && root.widgetType !== "" - - sourceComponent: { - switch (root.widgetType) { - case "desktopClock": - return clockSettingsComponent; - case "systemMonitor": - return systemMonitorSettingsComponent; - default: - return pluginSettingsComponent; - } - } - - onLoaded: { - if (!item) - return; - item.instanceId = root.instanceId; - item.instanceData = Qt.binding(() => root.instanceData); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/ClockSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/ClockSettings.qml deleted file mode 100644 index 7bd02b4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/ClockSettings.qml +++ /dev/null @@ -1,163 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Column { - id: root - - property string instanceId: "" - property var instanceData: null - - readonly property var cfg: instanceData?.config ?? {} - - function updateConfig(key, value) { - if (!instanceId) - return; - var updates = {}; - updates[key] = value; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, updates); - } - - width: parent?.width ?? 400 - spacing: 0 - - SettingsDropdownRow { - text: I18n.tr("Clock Style") - options: [I18n.tr("Digital"), I18n.tr("Analog"), I18n.tr("Stacked")] - currentValue: { - switch (cfg.style) { - case "analog": - return I18n.tr("Analog"); - case "stacked": - return I18n.tr("Stacked"); - default: - return I18n.tr("Digital"); - } - } - onValueChanged: value => { - switch (value) { - case I18n.tr("Analog"): - root.updateConfig("style", "analog"); - return; - case I18n.tr("Stacked"): - root.updateConfig("style", "stacked"); - return; - default: - root.updateConfig("style", "digital"); - } - } - } - - SettingsDivider { - visible: cfg.style === "analog" - } - - SettingsToggleRow { - visible: cfg.style === "analog" - text: I18n.tr("Show Hour Numbers") - checked: cfg.showAnalogNumbers ?? false - onToggled: checked => root.updateConfig("showAnalogNumbers", checked) - } - - SettingsDivider { - visible: cfg.style === "analog" - } - - SettingsToggleRow { - visible: cfg.style === "analog" - text: I18n.tr("Show Seconds") - checked: cfg.showAnalogSeconds ?? true - onToggled: checked => root.updateConfig("showAnalogSeconds", checked) - } - - SettingsDivider { - visible: cfg.style === "digital" || cfg.style === "stacked" - } - - SettingsToggleRow { - visible: cfg.style === "digital" || cfg.style === "stacked" - text: I18n.tr("Show Seconds") - checked: cfg.showDigitalSeconds ?? false - onToggled: checked => root.updateConfig("showDigitalSeconds", checked) - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Show Date") - checked: cfg.showDate ?? true - onToggled: checked => root.updateConfig("showDate", checked) - } - - SettingsDivider {} - - SettingsSliderRow { - text: I18n.tr("Transparency") - minimum: 0 - maximum: 100 - value: Math.round((cfg.transparency ?? 0.8) * 100) - unit: "%" - onSliderValueChanged: newValue => root.updateConfig("transparency", newValue / 100) - } - - SettingsDivider {} - - SettingsColorPicker { - colorMode: cfg.colorMode ?? "primary" - customColor: cfg.customColor ?? "#ffffff" - onColorModeSelected: mode => root.updateConfig("colorMode", mode) - onCustomColorSelected: selectedColor => root.updateConfig("customColor", selectedColor.toString()) - } - - SettingsDivider {} - - SettingsDisplayPicker { - displayPreferences: cfg.displayPreferences ?? ["all"] - onPreferencesChanged: prefs => root.updateConfig("displayPreferences", prefs) - } - - SettingsDivider {} - - Item { - width: parent.width - height: resetRow.height + Theme.spacingM * 2 - - Row { - id: resetRow - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Reset Position") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - - DankButton { - text: I18n.tr("Reset Size") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/PluginDesktopWidgetSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/PluginDesktopWidgetSettings.qml deleted file mode 100644 index 949e33f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/PluginDesktopWidgetSettings.qml +++ /dev/null @@ -1,137 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Column { - id: root - - property string instanceId: "" - property var instanceData: null - property string widgetType: "" - property var widgetDef: null - - readonly property var cfg: instanceData?.config ?? {} - readonly property string settingsPath: widgetDef?.settingsComponent ?? "" - - function updateConfig(key, value) { - if (!instanceId) - return; - var updates = {}; - updates[key] = value; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, updates); - } - - QtObject { - id: instanceScopedPluginService - - readonly property var availablePlugins: PluginService.availablePlugins - readonly property var loadedPlugins: PluginService.loadedPlugins - readonly property var pluginDesktopComponents: PluginService.pluginDesktopComponents - - signal pluginDataChanged(string pluginId) - signal pluginLoaded(string pluginId) - signal pluginUnloaded(string pluginId) - - function loadPluginData(pluginId, key, defaultValue) { - const cfg = root.instanceData?.config; - if (cfg && key in cfg) - return cfg[key]; - return SettingsData.getPluginSetting(root.widgetType, key, defaultValue); - } - - function savePluginData(pluginId, key, value) { - root.updateConfig(key, value); - Qt.callLater(() => pluginDataChanged(root.widgetType)); - return true; - } - - function getPluginVariants(pluginId) { - return PluginService.getPluginVariants(pluginId); - } - - function isPluginLoaded(pluginId) { - return PluginService.isPluginLoaded(pluginId); - } - } - - width: parent?.width ?? 400 - spacing: 0 - - Loader { - id: pluginSettingsLoader - width: parent.width - active: root.settingsPath !== "" - - source: root.settingsPath - - onLoaded: { - if (!item) - return; - if (item.instanceId !== undefined) - item.instanceId = root.instanceId; - if (item.instanceData !== undefined) - item.instanceData = Qt.binding(() => root.instanceData); - if (item.pluginService !== undefined) - item.pluginService = instanceScopedPluginService; - if (item.reloadChildValues) - Qt.callLater(item.reloadChildValues); - } - } - - Column { - width: parent.width - spacing: 0 - visible: root.settingsPath === "" - - SettingsDisplayPicker { - displayPreferences: cfg.displayPreferences ?? ["all"] - onPreferencesChanged: prefs => root.updateConfig("displayPreferences", prefs) - } - - SettingsDivider {} - - Item { - width: parent.width - height: resetRow.height + Theme.spacingM * 2 - - Row { - id: resetRow - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Reset Position") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - - DankButton { - text: I18n.tr("Reset Size") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml deleted file mode 100644 index 5ff156f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetSettings/SystemMonitorSettings.qml +++ /dev/null @@ -1,444 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Column { - id: root - - property string instanceId: "" - property var instanceData: null - - readonly property var cfg: instanceData?.config ?? {} - - function updateConfig(key, value) { - if (!instanceId) - return; - var updates = {}; - updates[key] = value; - SettingsData.updateDesktopWidgetInstanceConfig(instanceId, updates); - } - - width: parent?.width ?? 400 - spacing: 0 - - SettingsToggleRow { - text: I18n.tr("Show Header") - checked: cfg.showHeader ?? true - onToggled: checked => root.updateConfig("showHeader", checked) - } - - SettingsDivider {} - - Item { - width: parent.width - height: graphIntervalColumn.height + Theme.spacingM * 2 - - Column { - id: graphIntervalColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Graph Time Range") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - DankButtonGroup { - model: ["1m", "5m", "10m", "30m"] - currentIndex: { - switch (cfg.graphInterval ?? 60) { - case 60: - return 0; - case 300: - return 1; - case 600: - return 2; - case 1800: - return 3; - default: - return 0; - } - } - buttonHeight: 32 - minButtonWidth: 48 - textSize: Theme.fontSizeSmall - checkEnabled: false - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const values = [60, 300, 600, 1800]; - root.updateConfig("graphInterval", values[index]); - } - } - } - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("CPU") - checked: cfg.showCpu ?? true - onToggled: checked => root.updateConfig("showCpu", checked) - } - - SettingsDivider { - visible: cfg.showCpu ?? true - } - - SettingsToggleRow { - visible: cfg.showCpu ?? true - text: I18n.tr("CPU Graph") - checked: cfg.showCpuGraph ?? true - onToggled: checked => root.updateConfig("showCpuGraph", checked) - } - - SettingsDivider { - visible: cfg.showCpu ?? true - } - - SettingsToggleRow { - visible: cfg.showCpu ?? true - text: I18n.tr("CPU Temperature") - checked: cfg.showCpuTemp ?? true - onToggled: checked => root.updateConfig("showCpuTemp", checked) - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("GPU Temperature") - checked: cfg.showGpuTemp ?? false - onToggled: checked => root.updateConfig("showGpuTemp", checked) - } - - SettingsDivider { - visible: (cfg.showGpuTemp ?? false) && DgopService.availableGpus.length > 0 - } - - Item { - width: parent.width - height: gpuSelectColumn.height + Theme.spacingM * 2 - visible: (cfg.showGpuTemp ?? false) && DgopService.availableGpus.length > 0 - - Column { - id: gpuSelectColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("GPU") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - Repeater { - model: DgopService.availableGpus - - Rectangle { - required property var modelData - - readonly property bool isSelected: (cfg.gpuPciId ?? "") === modelData.pciId - - width: parent.width - height: 44 - radius: Theme.cornerRadius - color: isSelected ? Theme.primarySelected : Theme.surfaceHover - border.color: isSelected ? Theme.primary : "transparent" - border.width: 2 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: "videocam" - size: Theme.iconSizeSmall - color: isSelected ? Theme.primary : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSizeSmall - Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: 0 - - StyledText { - text: modelData.displayName || "Unknown GPU" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - elide: Text.ElideRight - } - - StyledText { - text: modelData.driver || "" - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.surfaceVariantText - visible: text !== "" - } - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.updateConfig("gpuPciId", modelData.pciId) - } - } - } - } - } - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Memory") - checked: cfg.showMemory ?? true - onToggled: checked => root.updateConfig("showMemory", checked) - } - - SettingsDivider { - visible: cfg.showMemory ?? true - } - - SettingsToggleRow { - visible: cfg.showMemory ?? true - text: I18n.tr("Memory Graph") - checked: cfg.showMemoryGraph ?? true - onToggled: checked => root.updateConfig("showMemoryGraph", checked) - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Network") - checked: cfg.showNetwork ?? true - onToggled: checked => root.updateConfig("showNetwork", checked) - } - - SettingsDivider { - visible: cfg.showNetwork ?? true - } - - SettingsToggleRow { - visible: cfg.showNetwork ?? true - text: I18n.tr("Network Graph") - checked: cfg.showNetworkGraph ?? true - onToggled: checked => root.updateConfig("showNetworkGraph", checked) - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Disk") - checked: cfg.showDisk ?? true - onToggled: checked => root.updateConfig("showDisk", checked) - } - - SettingsDivider {} - - SettingsToggleRow { - text: I18n.tr("Top Processes") - checked: cfg.showTopProcesses ?? false - onToggled: checked => root.updateConfig("showTopProcesses", checked) - } - - SettingsDivider { - visible: cfg.showTopProcesses ?? false - } - - Item { - width: parent.width - height: topProcessesColumn.height + Theme.spacingM * 2 - visible: cfg.showTopProcesses ?? false - - Column { - id: topProcessesColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - width: parent.width - processCountButtons.width - Theme.spacingM - text: I18n.tr("Process Count") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankButtonGroup { - id: processCountButtons - model: ["3", "5", "10"] - currentIndex: { - switch (cfg.topProcessCount ?? 3) { - case 3: - return 0; - case 5: - return 1; - case 10: - return 2; - default: - return 0; - } - } - buttonHeight: 32 - minButtonWidth: 36 - textSize: Theme.fontSizeSmall - checkEnabled: false - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const values = [3, 5, 10]; - root.updateConfig("topProcessCount", values[index]); - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - width: parent.width - sortByButtons.width - Theme.spacingM - text: I18n.tr("Sort By") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankButtonGroup { - id: sortByButtons - model: ["CPU", "MEM"] - currentIndex: (cfg.topProcessSortBy ?? "cpu") === "cpu" ? 0 : 1 - buttonHeight: 32 - minButtonWidth: 48 - textSize: Theme.fontSizeSmall - checkEnabled: false - onSelectionChanged: (index, selected) => { - if (!selected) - return; - root.updateConfig("topProcessSortBy", index === 0 ? "cpu" : "memory"); - } - } - } - } - } - - SettingsDivider {} - - SettingsDropdownRow { - text: I18n.tr("Layout") - options: [I18n.tr("Auto"), I18n.tr("Grid"), I18n.tr("List")] - currentValue: { - switch (cfg.layoutMode ?? "auto") { - case "grid": - return I18n.tr("Grid"); - case "list": - return I18n.tr("List"); - default: - return I18n.tr("Auto"); - } - } - onValueChanged: value => { - switch (value) { - case I18n.tr("Grid"): - root.updateConfig("layoutMode", "grid"); - return; - case I18n.tr("List"): - root.updateConfig("layoutMode", "list"); - return; - default: - root.updateConfig("layoutMode", "auto"); - } - } - } - - SettingsDivider {} - - SettingsSliderRow { - text: I18n.tr("Transparency") - minimum: 0 - maximum: 100 - value: Math.round((cfg.transparency ?? 0.8) * 100) - unit: "%" - onSliderValueChanged: newValue => root.updateConfig("transparency", newValue / 100) - } - - SettingsDivider {} - - SettingsColorPicker { - colorMode: cfg.colorMode ?? "primary" - customColor: cfg.customColor ?? "#ffffff" - onColorModeSelected: mode => root.updateConfig("colorMode", mode) - onCustomColorSelected: selectedColor => root.updateConfig("customColor", selectedColor.toString()) - } - - SettingsDivider {} - - SettingsDisplayPicker { - displayPreferences: cfg.displayPreferences ?? ["all"] - onPreferencesChanged: prefs => root.updateConfig("displayPreferences", prefs) - } - - SettingsDivider {} - - Item { - width: parent.width - height: resetRow.height + Theme.spacingM * 2 - - Row { - id: resetRow - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Reset Position") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - - DankButton { - text: I18n.tr("Reset Size") - backgroundColor: Theme.surfaceHover - textColor: Theme.surfaceText - buttonHeight: 36 - onClicked: { - if (!root.instanceId) - return; - SettingsData.updateDesktopWidgetInstance(root.instanceId, { - positions: {} - }); - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetsTab.qml deleted file mode 100644 index 5fb2794..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DesktopWidgetsTab.qml +++ /dev/null @@ -1,708 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var expandedStates: ({}) - property var groupCollapsedStates: ({}) - property var parentModal: null - property string editingGroupId: "" - property string newGroupName: "" - - readonly property var allInstances: SettingsData.desktopWidgetInstances || [] - readonly property var allGroups: SettingsData.desktopWidgetGroups || [] - - function showWidgetBrowser() { - widgetBrowserLoader.active = true; - if (widgetBrowserLoader.item) - widgetBrowserLoader.item.show(); - } - - function showDesktopPluginBrowser() { - desktopPluginBrowserLoader.active = true; - if (desktopPluginBrowserLoader.item) - desktopPluginBrowserLoader.item.show(); - } - - LazyLoader { - id: widgetBrowserLoader - active: false - - DesktopWidgetBrowser { - parentModal: root.parentModal - onWidgetAdded: widgetType => { - ToastService.showInfo(I18n.tr("Widget added")); - } - } - } - - LazyLoader { - id: desktopPluginBrowserLoader - active: false - - PluginBrowser { - parentModal: root.parentModal - typeFilter: "desktop-widget" - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "widgets" - title: I18n.tr("Desktop Widgets") - - Column { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - spacing: Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Add and configure widgets that appear on your desktop") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Add Widget") - iconName: "add" - onClicked: root.showWidgetBrowser() - } - - DankButton { - text: I18n.tr("Browse Plugins") - iconName: "store" - onClicked: root.showDesktopPluginBrowser() - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "folder" - title: I18n.tr("Groups") - collapsible: true - expanded: root.allGroups.length > 0 - - Column { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - spacing: Theme.spacingM - - StyledText { - width: parent.width - text: I18n.tr("Organize widgets into collapsible groups") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: Theme.spacingS - width: parent.width - - DankTextField { - id: newGroupField - width: parent.width - addGroupBtn.width - Theme.spacingS - placeholderText: I18n.tr("New group name...") - text: root.newGroupName - onTextChanged: root.newGroupName = text - onAccepted: { - if (!text.trim()) - return; - SettingsData.createDesktopWidgetGroup(text.trim()); - root.newGroupName = ""; - text = ""; - } - } - - DankButton { - id: addGroupBtn - iconName: "add" - text: I18n.tr("Add") - enabled: root.newGroupName.trim().length > 0 - onClicked: { - SettingsData.createDesktopWidgetGroup(root.newGroupName.trim()); - root.newGroupName = ""; - newGroupField.text = ""; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: root.allGroups.length > 0 - - Repeater { - model: root.allGroups - - Rectangle { - id: groupItem - required property var modelData - required property int index - - width: parent.width - height: 40 - radius: Theme.cornerRadius - color: groupMouseArea.containsMouse ? Theme.surfaceHover : Theme.surfaceContainer - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: "folder" - size: Theme.iconSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Loader { - active: root.editingGroupId === groupItem.modelData.id - width: active ? parent.width - Theme.iconSizeSmall - deleteGroupBtn.width - Theme.spacingS * 3 : 0 - height: active ? 32 : 0 - anchors.verticalCenter: parent.verticalCenter - - sourceComponent: DankTextField { - text: groupItem.modelData.name - onAccepted: { - if (!text.trim()) - return; - SettingsData.updateDesktopWidgetGroup(groupItem.modelData.id, { - name: text.trim() - }); - root.editingGroupId = ""; - } - onEditingFinished: { - if (!text.trim()) - return; - SettingsData.updateDesktopWidgetGroup(groupItem.modelData.id, { - name: text.trim() - }); - root.editingGroupId = ""; - } - Component.onCompleted: forceActiveFocus() - } - } - - StyledText { - visible: root.editingGroupId !== groupItem.modelData.id - text: groupItem.modelData.name - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - width: parent.width - Theme.iconSizeSmall - deleteGroupBtn.width - Theme.spacingS * 3 - } - - DankActionButton { - id: deleteGroupBtn - iconName: "delete" - anchors.verticalCenter: parent.verticalCenter - onClicked: { - SettingsData.removeDesktopWidgetGroup(groupItem.modelData.id); - ToastService.showInfo(I18n.tr("Group removed")); - } - } - } - - MouseArea { - id: groupMouseArea - anchors.fill: parent - hoverEnabled: true - onDoubleClicked: root.editingGroupId = groupItem.modelData.id - } - } - } - } - } - } - - Repeater { - model: root.allGroups - - Column { - id: groupSection - required property var modelData - required property int index - - readonly property string groupId: modelData.id - readonly property var groupInstances: root.allInstances.filter(inst => inst.group === groupId) - - width: mainColumn.width - spacing: Theme.spacingM - visible: groupInstances.length > 0 - - Rectangle { - width: parent.width - height: 44 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: (root.groupCollapsedStates[groupSection.groupId] ?? false) ? "expand_more" : "expand_less" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - name: "folder" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: groupSection.modelData.name - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "(" + groupSection.groupInstances.length + ")" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - var states = Object.assign({}, root.groupCollapsedStates); - states[groupSection.groupId] = !(states[groupSection.groupId] ?? false); - root.groupCollapsedStates = states; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: !(root.groupCollapsedStates[groupSection.groupId] ?? false) - leftPadding: Theme.spacingM - - Repeater { - model: ScriptModel { - objectProp: "id" - values: groupSection.groupInstances - } - - Item { - id: groupDelegateItem - required property var modelData - required property int index - - property bool held: groupDragArea.pressed - property real originalY: y - - readonly property string instanceIdRef: modelData.id - readonly property var liveInstanceData: { - const instances = root.allInstances; - return instances.find(inst => inst.id === instanceIdRef) ?? modelData; - } - - width: groupSection.width - Theme.spacingM - height: groupCard.height - z: held ? 2 : 1 - - DesktopWidgetInstanceCard { - id: groupCard - width: parent.width - headerLeftPadding: 20 - instanceData: groupDelegateItem.liveInstanceData - isExpanded: root.expandedStates[groupDelegateItem.instanceIdRef] ?? false - - onExpandedChanged: { - if (expanded === (root.expandedStates[groupDelegateItem.instanceIdRef] ?? false)) - return; - var states = Object.assign({}, root.expandedStates); - states[groupDelegateItem.instanceIdRef] = expanded; - root.expandedStates = states; - } - - onDuplicateRequested: SettingsData.duplicateDesktopWidgetInstance(groupDelegateItem.instanceIdRef) - - onDeleteRequested: { - SettingsData.removeDesktopWidgetInstance(groupDelegateItem.instanceIdRef); - ToastService.showInfo(I18n.tr("Widget removed")); - } - } - - MouseArea { - id: groupDragArea - anchors.left: parent.left - anchors.top: parent.top - width: 40 - height: 50 - hoverEnabled: true - cursorShape: Qt.SizeVerCursor - drag.target: groupDelegateItem.held ? groupDelegateItem : undefined - drag.axis: Drag.YAxis - preventStealing: true - - onPressed: { - groupDelegateItem.z = 2; - groupDelegateItem.originalY = groupDelegateItem.y; - } - onReleased: { - groupDelegateItem.z = 1; - if (!drag.active) { - groupDelegateItem.y = groupDelegateItem.originalY; - return; - } - const spacing = Theme.spacingM; - const itemH = groupDelegateItem.height + spacing; - var newIndex = Math.round(groupDelegateItem.y / itemH); - newIndex = Math.max(0, Math.min(newIndex, groupSection.groupInstances.length - 1)); - if (newIndex !== groupDelegateItem.index) - SettingsData.reorderDesktopWidgetInstanceInGroup(groupDelegateItem.instanceIdRef, groupSection.groupId, newIndex); - groupDelegateItem.y = groupDelegateItem.originalY; - } - } - - DankIcon { - x: Theme.spacingL - 2 - y: Theme.spacingL + (Theme.iconSize / 2) - (size / 2) - name: "drag_indicator" - size: 18 - color: Theme.outline - opacity: groupDragArea.containsMouse || groupDragArea.pressed ? 1 : 0.5 - } - - Behavior on y { - enabled: !groupDragArea.pressed && !groupDragArea.drag.active - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } - - Column { - id: ungroupedSection - width: parent.width - spacing: Theme.spacingM - visible: ungroupedInstances.length > 0 - - readonly property var ungroupedInstances: root.allInstances.filter(inst => { - if (!inst.group) - return true; - return !root.allGroups.some(g => g.id === inst.group); - }) - - Rectangle { - width: parent.width - height: 44 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - visible: root.allGroups.length > 0 - - Row { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingS - - DankIcon { - name: (root.groupCollapsedStates["_ungrouped"] ?? false) ? "expand_more" : "expand_less" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - name: "widgets" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Ungrouped") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "(" + ungroupedSection.ungroupedInstances.length + ")" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - var states = Object.assign({}, root.groupCollapsedStates); - states["_ungrouped"] = !(states["_ungrouped"] ?? false); - root.groupCollapsedStates = states; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: !(root.groupCollapsedStates["_ungrouped"] ?? false) - leftPadding: root.allGroups.length > 0 ? Theme.spacingM : 0 - - Repeater { - model: ScriptModel { - objectProp: "id" - values: ungroupedSection.ungroupedInstances - } - - Item { - id: ungroupedDelegateItem - required property var modelData - required property int index - - property bool held: ungroupedDragArea.pressed - property real originalY: y - - readonly property string instanceIdRef: modelData.id - readonly property var liveInstanceData: { - const instances = root.allInstances; - return instances.find(inst => inst.id === instanceIdRef) ?? modelData; - } - - width: ungroupedSection.width - (root.allGroups.length > 0 ? Theme.spacingM : 0) - height: ungroupedCard.height - z: held ? 2 : 1 - - DesktopWidgetInstanceCard { - id: ungroupedCard - width: parent.width - headerLeftPadding: 20 - instanceData: ungroupedDelegateItem.liveInstanceData - isExpanded: root.expandedStates[ungroupedDelegateItem.instanceIdRef] ?? false - - onExpandedChanged: { - if (expanded === (root.expandedStates[ungroupedDelegateItem.instanceIdRef] ?? false)) - return; - var states = Object.assign({}, root.expandedStates); - states[ungroupedDelegateItem.instanceIdRef] = expanded; - root.expandedStates = states; - } - - onDuplicateRequested: SettingsData.duplicateDesktopWidgetInstance(ungroupedDelegateItem.instanceIdRef) - - onDeleteRequested: { - SettingsData.removeDesktopWidgetInstance(ungroupedDelegateItem.instanceIdRef); - ToastService.showInfo(I18n.tr("Widget removed")); - } - } - - MouseArea { - id: ungroupedDragArea - anchors.left: parent.left - anchors.top: parent.top - width: 40 - height: 50 - hoverEnabled: true - cursorShape: Qt.SizeVerCursor - drag.target: ungroupedDelegateItem.held ? ungroupedDelegateItem : undefined - drag.axis: Drag.YAxis - preventStealing: true - - onPressed: { - ungroupedDelegateItem.z = 2; - ungroupedDelegateItem.originalY = ungroupedDelegateItem.y; - } - onReleased: { - ungroupedDelegateItem.z = 1; - if (!drag.active) { - ungroupedDelegateItem.y = ungroupedDelegateItem.originalY; - return; - } - const spacing = Theme.spacingM; - const itemH = ungroupedDelegateItem.height + spacing; - var newIndex = Math.round(ungroupedDelegateItem.y / itemH); - newIndex = Math.max(0, Math.min(newIndex, ungroupedSection.ungroupedInstances.length - 1)); - if (newIndex !== ungroupedDelegateItem.index) - SettingsData.reorderDesktopWidgetInstanceInGroup(ungroupedDelegateItem.instanceIdRef, null, newIndex); - ungroupedDelegateItem.y = ungroupedDelegateItem.originalY; - } - } - - DankIcon { - x: Theme.spacingL - 2 - y: Theme.spacingL + (Theme.iconSize / 2) - (size / 2) - name: "drag_indicator" - size: 18 - color: Theme.outline - opacity: ungroupedDragArea.containsMouse || ungroupedDragArea.pressed ? 1 : 0.5 - } - - Behavior on y { - enabled: !ungroupedDragArea.pressed && !ungroupedDragArea.drag.active - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - - StyledText { - visible: root.allInstances.length === 0 - text: I18n.tr("No widgets added. Click \"Add Widget\" to get started.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - SettingsCard { - width: parent.width - iconName: "info" - title: I18n.tr("Help") - - Column { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - Rectangle { - width: 40 - height: 40 - radius: 20 - color: Theme.primarySelected - - DankIcon { - anchors.centerIn: parent - name: "drag_pan" - size: Theme.iconSize - color: Theme.primary - } - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 40 - Theme.spacingM - - StyledText { - text: I18n.tr("Move Widget") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Right-click and drag anywhere on the widget") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Rectangle { - width: 40 - height: 40 - radius: 20 - color: Theme.primarySelected - - DankIcon { - anchors.centerIn: parent - name: "open_in_full" - size: Theme.iconSize - color: Theme.primary - } - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 40 - Theme.spacingM - - StyledText { - text: I18n.tr("Resize Widget") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Right-click and drag the bottom-right corner") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml deleted file mode 100644 index b6e253b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml +++ /dev/null @@ -1,1837 +0,0 @@ -pragma Singleton -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import Quickshell -import qs.Common -import qs.Services - -Singleton { - id: root - - readonly property bool hasOutputBackend: WlrOutputService.wlrOutputAvailable - readonly property var wlrOutputs: WlrOutputService.outputs - property var outputs: ({}) - property var savedOutputs: ({}) - property var allOutputs: buildAllOutputsMap() - - property var includeStatus: ({ - "exists": false, - "included": false - }) - property bool checkingInclude: false - property bool fixingInclude: false - - property var pendingChanges: ({}) - property var pendingNiriChanges: ({}) - property var pendingHyprlandChanges: ({}) - property var originalNiriSettings: null - property var originalHyprlandSettings: null - property var originalOutputs: null - property string originalDisplayNameMode: "" - property bool formatChanged: originalDisplayNameMode !== "" && originalDisplayNameMode !== SettingsData.displayNameMode - property bool hasPendingChanges: Object.keys(pendingChanges).length > 0 || Object.keys(pendingNiriChanges).length > 0 || Object.keys(pendingHyprlandChanges).length > 0 || formatChanged - - property bool validatingConfig: false - property string validationError: "" - - property var currentOutputSet: [] - property string matchedProfile: "" - property bool profilesLoading: false - property var validatedProfiles: ({}) - property bool manualActivation: false - - signal changesApplied(var changeDescriptions) - signal changesConfirmed - signal changesReverted - signal profileActivated(string profileId, string profileName) - signal profileSaved(string profileId, string profileName) - signal profileDeleted(string profileId) - signal profileError(string message) - - function buildCurrentOutputSet() { - const connected = []; - for (const name in outputs) { - const output = outputs[name]; - connected.push(getOutputIdentifier(output, name)); - } - return connected.sort(); - } - - function getOutputIdentifier(output, outputName) { - if (SettingsData.displayNameMode === "model" && output?.make && output?.model) { - if (CompositorService.isNiri) { - const serial = output.serial || "Unknown"; - return output.make + " " + output.model + " " + serial; - } - return output.make + " " + output.model; - } - return outputName; - } - - function validateProfiles() { - const compositor = CompositorService.compositor; - const profiles = SettingsData.getDisplayProfiles(compositor); - const profilesDir = getProfilesDir(); - const ext = getProfileExtension(); - - if (!profilesDir) { - validatedProfiles = {}; - return; - } - - const profileIds = Object.keys(profiles); - if (profileIds.length === 0) { - validatedProfiles = {}; - return; - } - - const fileChecks = profileIds.map(id => profilesDir + "/" + id + ext).join(" "); - Proc.runCommand("validate-profiles", ["sh", "-c", `for f in ${fileChecks}; do [ -f "$f" ] && echo "$f"; done`], (output, exitCode) => { - const existingFiles = new Set(output.trim().split("\n").filter(f => f)); - const validated = {}; - for (const profileId of profileIds) { - const profileFile = profilesDir + "/" + profileId + ext; - if (existingFiles.has(profileFile)) - validated[profileId] = profiles[profileId]; - else - SettingsData.removeDisplayProfile(compositor, profileId); - } - validatedProfiles = validated; - matchedProfile = findMatchingProfile(); - }); - } - - function findMatchingProfile() { - const profiles = validatedProfiles; - - console.log("[Profile Match] Current outputs:", JSON.stringify(currentOutputSet)); - - let bestMatch = ""; - let bestScore = -1; - let bestUpdatedAt = 0; - - for (const profileId in profiles) { - const profile = profiles[profileId]; - const profileSet = new Set(profile.outputSet); - - console.log("[Profile Match] Checking", profile.name, "outputSet:", JSON.stringify(profile.outputSet)); - - let allCurrentPresent = true; - for (const output of currentOutputSet) { - if (!profileSet.has(output)) { - console.log("[Profile Match] - Missing output:", output); - allCurrentPresent = false; - break; - } - } - if (!allCurrentPresent) { - console.log("[Profile Match] - SKIP: not all current outputs present"); - continue; - } - - const disconnectedCount = profile.outputSet.length - currentOutputSet.length; - const score = currentOutputSet.length * 100 - disconnectedCount; - const updatedAt = profile.updatedAt || profile.createdAt || 0; - console.log("[Profile Match] - MATCH score:", score, "(disconnected:", disconnectedCount, "updatedAt:", updatedAt + ")"); - - if (score > bestScore || (score === bestScore && updatedAt > bestUpdatedAt)) { - bestScore = score; - bestMatch = profileId; - bestUpdatedAt = updatedAt; - } - } - console.log("[Profile Match] Best match:", bestMatch, "score:", bestScore); - return bestMatch; - } - - function getProfilesDir() { - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - switch (CompositorService.compositor) { - case "niri": - return configDir + "/niri/dms/profiles"; - case "hyprland": - return configDir + "/hypr/dms/profiles"; - case "dwl": - return configDir + "/mango/dms/profiles"; - default: - return ""; - } - } - - function getProfileExtension() { - return CompositorService.compositor === "niri" ? ".kdl" : ".conf"; - } - - function createProfile(name) { - const compositor = CompositorService.compositor; - const profileId = "profile_" + Date.now() + "_" + Math.random().toString(36).substr(2, 6); - const outputSet = buildCurrentOutputSet(); - const now = Date.now(); - - const profileData = { - "id": profileId, - "name": name, - "outputSet": outputSet, - "createdAt": now, - "updatedAt": now - }; - - const profilesDir = getProfilesDir(); - const profileFile = profilesDir + "/" + profileId + getProfileExtension(); - const paths = getConfigPaths(); - if (!paths) { - profileError(I18n.tr("Compositor not supported")); - return; - } - - profilesLoading = true; - Proc.runCommand("create-profile-dir", ["mkdir", "-p", profilesDir], (output, exitCode) => { - if (exitCode !== 0) { - profilesLoading = false; - profileError(I18n.tr("Failed to create profiles directory")); - return; - } - Proc.runCommand("copy-profile", ["cp", "-L", paths.outputsFile, profileFile], (output2, exitCode2) => { - if (exitCode2 !== 0) { - profilesLoading = false; - profileError(I18n.tr("Failed to save profile file")); - return; - } - SettingsData.setDisplayProfile(compositor, profileId, profileData); - SettingsData.setActiveDisplayProfile(compositor, profileId); - const updated = JSON.parse(JSON.stringify(validatedProfiles)); - updated[profileId] = profileData; - validatedProfiles = updated; - Proc.runCommand("link-new-profile", ["ln", "-sf", profileFile, paths.outputsFile], () => { - profilesLoading = false; - currentOutputSet = outputSet; - matchedProfile = profileId; - profileSaved(profileId, name); - }); - }); - }); - } - - function renameProfile(profileId, newName) { - const compositor = CompositorService.compositor; - const profiles = SettingsData.getDisplayProfiles(compositor); - const profile = profiles[profileId]; - if (!profile) { - profileError(I18n.tr("Profile not found")); - return; - } - profile.name = newName; - profile.updatedAt = Date.now(); - SettingsData.setDisplayProfile(compositor, profileId, profile); - } - - function deleteProfile(profileId) { - const compositor = CompositorService.compositor; - const profilesDir = getProfilesDir(); - const profileFile = profilesDir + "/" + profileId + getProfileExtension(); - const isActive = SettingsData.getActiveDisplayProfile(compositor) === profileId; - - profilesLoading = true; - Proc.runCommand("delete-profile", ["rm", "-f", profileFile], (output, exitCode) => { - profilesLoading = false; - SettingsData.removeDisplayProfile(compositor, profileId); - if (isActive) { - SettingsData.setActiveDisplayProfile(compositor, ""); - backendWriteOutputsConfig(allOutputs); - } - const updated = JSON.parse(JSON.stringify(validatedProfiles)); - delete updated[profileId]; - validatedProfiles = updated; - matchedProfile = findMatchingProfile(); - profileDeleted(profileId); - }); - } - - function activateProfile(profileId) { - const compositor = CompositorService.compositor; - const profiles = SettingsData.getDisplayProfiles(compositor); - const profile = profiles[profileId]; - if (!profile) { - profileError(I18n.tr("Profile not found")); - return; - } - - const profilesDir = getProfilesDir(); - const profileFile = profilesDir + "/" + profileId + getProfileExtension(); - const paths = getConfigPaths(); - if (!paths) - return; - - manualActivation = true; - profilesLoading = true; - Proc.runCommand("activate-profile", ["ln", "-sf", profileFile, paths.outputsFile], (output, exitCode) => { - if (exitCode !== 0) { - profilesLoading = false; - manualActivation = false; - profileError(I18n.tr("Failed to activate profile - file not found")); - return; - } - SettingsData.setActiveDisplayProfile(compositor, profileId); - - const reloadCmd = CompositorService.isNiri ? ["niri", "msg", "action", "reload-config-or-panic"] : CompositorService.isHyprland ? ["hyprctl", "reload"] : []; - if (reloadCmd.length > 0) { - Proc.runCommand("reload-compositor", reloadCmd, (output2, exitCode2) => { - profilesLoading = false; - WlrOutputService.requestState(); - profileActivated(profileId, profile.name); - manualActivationTimer.restart(); - }); - } else { - profilesLoading = false; - profileActivated(profileId, profile.name); - manualActivationTimer.restart(); - } - }); - } - - Timer { - id: manualActivationTimer - interval: 2000 - onTriggered: root.manualActivation = false - } - - Timer { - id: autoSelectDebounceTimer - interval: 800 - onTriggered: root.doAutoSelectProfile() - } - - // ! TODO - auto profile switching is buggy on niri and other compositors, might need a longer debounce before updating output configuration idk - function autoSelectProfile() { - return; // disabled - autoSelectDebounceTimer.restart(); - } - - function doAutoSelectProfile() { - return; // disabled - if (!SettingsData.displayProfileAutoSelect || manualActivation) - return; - currentOutputSet = buildCurrentOutputSet(); - const matched = findMatchingProfile(); - matchedProfile = matched; - if (matched && matched !== SettingsData.getActiveDisplayProfile(CompositorService.compositor)) - activateProfile(matched); - } - - function deleteDisconnectedOutput(outputName) { - if (outputs[outputName]?.connected) - return; - - const updated = JSON.parse(JSON.stringify(savedOutputs)); - delete updated[outputName]; - savedOutputs = updated; - - const mergedOutputs = {}; - for (const name in outputs) - mergedOutputs[name] = outputs[name]; - for (const name in updated) - mergedOutputs[name] = updated[name]; - - backendWriteOutputsConfig(mergedOutputs); - } - - function buildAllOutputsMap() { - const result = {}; - for (const name in savedOutputs) { - result[name] = Object.assign({}, savedOutputs[name], { - "connected": false - }); - } - for (const name in outputs) { - result[name] = Object.assign({}, outputs[name], { - "connected": true - }); - } - return result; - } - - onOutputsChanged: { - allOutputs = buildAllOutputsMap(); - currentOutputSet = buildCurrentOutputSet(); - matchedProfile = findMatchingProfile(); - // ! TODO - auto profile switching disabled for now - // if (SettingsData.displayProfileAutoSelect) - // Qt.callLater(autoSelectProfile); - } - onSavedOutputsChanged: allOutputs = buildAllOutputsMap() - - Connections { - target: WlrOutputService - function onStateChanged() { - root.outputs = root.buildOutputsMap(); - root.reloadSavedOutputs(); - } - } - - Component.onCompleted: { - outputs = buildOutputsMap(); - reloadSavedOutputs(); - checkIncludeStatus(); - currentOutputSet = buildCurrentOutputSet(); - validateProfiles(); - } - - function reloadSavedOutputs() { - const paths = getConfigPaths(); - if (!paths) { - savedOutputs = {}; - return; - } - - Proc.runCommand("load-saved-outputs", ["cat", paths.outputsFile], (content, exitCode) => { - if (exitCode !== 0 || !content.trim()) { - savedOutputs = {}; - return; - } - const parsed = parseOutputsConfig(content); - const filtered = filterDisconnectedOnly(parsed); - savedOutputs = filtered; - - if (CompositorService.isHyprland) { - initHyprlandSettingsFromConfig(parsed); - syncHyprlandVrrFromConfig(parsed); - } - if (CompositorService.isNiri) - syncNiriVrrFromConfig(parsed); - }); - } - - function initHyprlandSettingsFromConfig(parsedOutputs) { - const current = JSON.parse(JSON.stringify(SettingsData.hyprlandOutputSettings)); - let changed = false; - - for (const outputName in parsedOutputs) { - const output = parsedOutputs[outputName]; - const settings = output.hyprlandSettings; - if (!settings) - continue; - - if (current[outputName]) - continue; - - const hasSettings = settings.colorManagement || settings.bitdepth || settings.sdrBrightness !== undefined || settings.sdrSaturation !== undefined; - if (!hasSettings) - continue; - - current[outputName] = {}; - if (settings.colorManagement) - current[outputName].colorManagement = settings.colorManagement; - if (settings.bitdepth) - current[outputName].bitdepth = settings.bitdepth; - if (settings.sdrBrightness !== undefined) - current[outputName].sdrBrightness = settings.sdrBrightness; - if (settings.sdrSaturation !== undefined) - current[outputName].sdrSaturation = settings.sdrSaturation; - changed = true; - } - - if (changed) { - SettingsData.hyprlandOutputSettings = current; - SettingsData.saveSettings(); - } - } - - function syncHyprlandVrrFromConfig(parsedOutputs) { - const current = JSON.parse(JSON.stringify(SettingsData.hyprlandOutputSettings)); - let changed = false; - for (const outputName in parsedOutputs) { - const settings = parsedOutputs[outputName]?.hyprlandSettings; - const fromConfig = settings?.vrrFullscreenOnly ?? false; - const stored = current[outputName]?.vrrFullscreenOnly ?? false; - if (fromConfig === stored) - continue; - if (!current[outputName]) - current[outputName] = {}; - if (fromConfig) - current[outputName].vrrFullscreenOnly = true; - else - delete current[outputName].vrrFullscreenOnly; - changed = true; - } - if (changed) { - SettingsData.hyprlandOutputSettings = current; - SettingsData.saveSettings(); - } - } - - function syncNiriVrrFromConfig(parsedOutputs) { - let changed = false; - for (const outputName in parsedOutputs) { - const output = parsedOutputs[outputName]; - const current = SettingsData.getNiriOutputSetting(outputName, "vrrOnDemand", false); - const fromConfig = output.vrr_on_demand ?? false; - if (current === fromConfig) - continue; - SettingsData.setNiriOutputSetting(outputName, "vrrOnDemand", fromConfig || undefined); - changed = true; - } - if (changed) - SettingsData.saveSettings(); - } - - function filterDisconnectedOnly(parsedOutputs) { - const result = {}; - const liveNames = Object.keys(outputs); - const liveByIdentifier = {}; - for (const name of liveNames) { - const o = outputs[name]; - if (o?.make && o?.model) { - const serial = o.serial || "Unknown"; - const id = (o.make + " " + o.model + " " + serial).trim(); - liveByIdentifier[id] = true; - liveByIdentifier[o.make + " " + o.model] = true; - } - liveByIdentifier[name] = true; - } - - for (const savedName in parsedOutputs) { - const trimmed = savedName.trim(); - if (!liveByIdentifier[trimmed]) - result[savedName] = parsedOutputs[savedName]; - } - return result; - } - - function parseOutputsConfig(content) { - switch (CompositorService.compositor) { - case "niri": - return parseNiriOutputs(content); - case "hyprland": - return parseHyprlandOutputs(content); - case "dwl": - return parseMangoOutputs(content); - default: - return {}; - } - } - - function parseNiriOutputs(content) { - const result = {}; - const outputRegex = /output\s+"([^"]+)"\s*\{([^}]*)\}/g; - let match; - while ((match = outputRegex.exec(content)) !== null) { - const name = match[1]; - const body = match[2]; - - const modeMatch = body.match(/mode\s+"(\d+)x(\d+)@([\d.]+)"/); - const posMatch = body.match(/position\s+x=(-?\d+)\s+y=(-?\d+)/); - const scaleMatch = body.match(/scale\s+([\d.]+)/); - const transformMatch = body.match(/transform\s+"([^"]+)"/); - const vrrMatch = body.match(/variable-refresh-rate/); - const vrrOnDemandMatch = body.match(/variable-refresh-rate\s+on-demand=true/); - - result[name] = { - "name": name, - "logical": { - "x": posMatch ? parseInt(posMatch[1]) : 0, - "y": posMatch ? parseInt(posMatch[2]) : 0, - "scale": scaleMatch ? parseFloat(scaleMatch[1]) : 1.0, - "transform": transformMatch ? transformMatch[1] : "Normal" - }, - "modes": modeMatch ? [ - { - "width": parseInt(modeMatch[1]), - "height": parseInt(modeMatch[2]), - "refresh_rate": Math.round(parseFloat(modeMatch[3]) * 1000) - } - ] : [], - "current_mode": 0, - "vrr_enabled": !!vrrMatch, - "vrr_on_demand": !!vrrOnDemandMatch, - "vrr_supported": true - }; - } - return result; - } - - function parseHyprlandOutputs(content) { - const result = {}; - const lines = content.split("\n"); - for (const line of lines) { - const disableMatch = line.match(/^\s*monitor\s*=\s*([^,]+),\s*disable\s*$/); - if (disableMatch) { - const name = disableMatch[1].trim(); - result[name] = { - "name": name, - "logical": { - "x": 0, - "y": 0, - "scale": 1.0, - "transform": "Normal" - }, - "modes": [], - "current_mode": -1, - "vrr_enabled": false, - "vrr_supported": false, - "hyprlandSettings": { - "disabled": true - } - }; - continue; - } - const match = line.match(/^\s*monitor\s*=\s*([^,]+),\s*(\d+)x(\d+)@([\d.]+),\s*(-?\d+)x(-?\d+),\s*([\d.]+)/); - if (!match) - continue; - const name = match[1].trim(); - const rest = line.substring(line.indexOf(match[7]) + match[7].length); - - let transform = 0, vrrMode = 0, bitdepth = undefined, cm = undefined; - let sdrBrightness = undefined, sdrSaturation = undefined; - - const transformMatch = rest.match(/,\s*transform,\s*(\d+)/); - if (transformMatch) - transform = parseInt(transformMatch[1]); - - const vrrMatch = rest.match(/,\s*vrr,\s*(\d+)/); - if (vrrMatch) - vrrMode = parseInt(vrrMatch[1]); - - const bitdepthMatch = rest.match(/,\s*bitdepth,\s*(\d+)/); - if (bitdepthMatch) - bitdepth = parseInt(bitdepthMatch[1]); - - const cmMatch = rest.match(/,\s*cm,\s*(\w+)/); - if (cmMatch) - cm = cmMatch[1]; - - const sdrBrightnessMatch = rest.match(/,\s*sdrbrightness,\s*([\d.]+)/); - if (sdrBrightnessMatch) - sdrBrightness = parseFloat(sdrBrightnessMatch[1]); - - const sdrSaturationMatch = rest.match(/,\s*sdrsaturation,\s*([\d.]+)/); - if (sdrSaturationMatch) - sdrSaturation = parseFloat(sdrSaturationMatch[1]); - - let mirror = ""; - const mirrorMatch = rest.match(/,\s*mirror,\s*([^,\s]+)/); - if (mirrorMatch) - mirror = mirrorMatch[1]; - - result[name] = { - "name": name, - "logical": { - "x": parseInt(match[5]), - "y": parseInt(match[6]), - "scale": parseFloat(match[7]), - "transform": hyprlandToTransform(transform) - }, - "modes": [ - { - "width": parseInt(match[2]), - "height": parseInt(match[3]), - "refresh_rate": Math.round(parseFloat(match[4]) * 1000) - } - ], - "current_mode": 0, - "vrr_enabled": vrrMode >= 1, - "vrr_supported": true, - "hyprlandSettings": { - "bitdepth": bitdepth, - "colorManagement": cm, - "sdrBrightness": sdrBrightness, - "sdrSaturation": sdrSaturation, - "vrrFullscreenOnly": vrrMode === 2 ? true : undefined - }, - "mirror": mirror - }; - } - return result; - } - - function hyprlandToTransform(value) { - switch (value) { - case 0: - return "Normal"; - case 1: - return "90"; - case 2: - return "180"; - case 3: - return "270"; - case 4: - return "Flipped"; - case 5: - return "Flipped90"; - case 6: - return "Flipped180"; - case 7: - return "Flipped270"; - default: - return "Normal"; - } - } - - function parseMangoOutputs(content) { - const result = {}; - const lines = content.split("\n"); - for (const line of lines) { - const trimmed = line.trim(); - if (!trimmed.startsWith("monitorrule=")) - continue; - - const params = {}; - for (const pair of trimmed.substring("monitorrule=".length).split(",")) { - const colonIdx = pair.indexOf(":"); - if (colonIdx < 0) - continue; - params[pair.substring(0, colonIdx).trim()] = pair.substring(colonIdx + 1).trim(); - } - - const name = params.name; - if (!name) - continue; - - result[name] = { - "name": name, - "logical": { - "x": parseInt(params.x || "0"), - "y": parseInt(params.y || "0"), - "scale": parseFloat(params.scale || "1"), - "transform": mangoToTransform(parseInt(params.rr || "0")) - }, - "modes": [ - { - "width": parseInt(params.width || "1920"), - "height": parseInt(params.height || "1080"), - "refresh_rate": parseFloat(params.refresh || "60") * 1000 - } - ], - "current_mode": 0, - "vrr_enabled": parseInt(params.vrr || "0") === 1, - "vrr_supported": true - }; - } - return result; - } - - function mangoToTransform(value) { - switch (value) { - case 0: - return "Normal"; - case 1: - return "90"; - case 2: - return "180"; - case 3: - return "270"; - case 4: - return "Flipped"; - case 5: - return "Flipped90"; - case 6: - return "Flipped180"; - case 7: - return "Flipped270"; - default: - return "Normal"; - } - } - - function getConfigPaths() { - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - switch (CompositorService.compositor) { - case "niri": - return { - "configFile": configDir + "/niri/config.kdl", - "outputsFile": configDir + "/niri/dms/outputs.kdl", - "grepPattern": 'include.*"dms/outputs.kdl"', - "includeLine": 'include "dms/outputs.kdl"' - }; - case "hyprland": - return { - "configFile": configDir + "/hypr/hyprland.conf", - "outputsFile": configDir + "/hypr/dms/outputs.conf", - "grepPattern": 'source.*dms/outputs.conf', - "includeLine": "source = ./dms/outputs.conf" - }; - case "dwl": - return { - "configFile": configDir + "/mango/config.conf", - "outputsFile": configDir + "/mango/dms/outputs.conf", - "grepPattern": 'source.*dms/outputs.conf', - "includeLine": "source=./dms/outputs.conf" - }; - default: - return null; - } - } - - function checkIncludeStatus() { - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland" && compositor !== "dwl") { - includeStatus = { - "exists": false, - "included": false - }; - return; - } - - const filename = (compositor === "niri") ? "outputs.kdl" : "outputs.conf"; - const compositorArg = (compositor === "dwl") ? "mangowc" : compositor; - - checkingInclude = true; - Proc.runCommand("check-outputs-include", ["dms", "config", "resolve-include", compositorArg, filename], (output, exitCode) => { - checkingInclude = false; - if (exitCode !== 0) { - includeStatus = { - "exists": false, - "included": false - }; - return; - } - try { - includeStatus = JSON.parse(output.trim()); - } catch (e) { - includeStatus = { - "exists": false, - "included": false - }; - } - }); - } - - function fixOutputsInclude() { - const paths = getConfigPaths(); - if (!paths) - return; - - fixingInclude = true; - const outputsDir = paths.outputsFile.substring(0, paths.outputsFile.lastIndexOf("/")); - const unixTime = Math.floor(Date.now() / 1000); - const backupFile = paths.configFile + ".backup" + unixTime; - - Proc.runCommand("fix-outputs-include", ["sh", "-c", `cp "${paths.configFile}" "${backupFile}" 2>/dev/null; ` + `mkdir -p "${outputsDir}" && ` + `touch "${paths.outputsFile}" && ` + `if ! grep -v '^[[:space:]]*\\(//\\|#\\)' "${paths.configFile}" 2>/dev/null | grep -q '${paths.grepPattern}'; then ` + `echo '' >> "${paths.configFile}" && ` + `echo '${paths.includeLine}' >> "${paths.configFile}"; fi`], (output, exitCode) => { - fixingInclude = false; - if (exitCode !== 0) - return; - checkIncludeStatus(); - WlrOutputService.requestState(); - }); - } - - function buildOutputsMap() { - const map = {}; - for (const output of wlrOutputs) { - const normalizedModes = (output.modes || []).map(m => ({ - "id": m.id, - "width": m.width, - "height": m.height, - "refresh_rate": m.refresh, - "preferred": m.preferred ?? false - })); - map[output.name] = { - "name": output.name, - "make": output.make || "", - "model": output.model || "", - "serial": output.serialNumber || "", - "modes": normalizedModes, - "current_mode": normalizedModes.findIndex(m => m.id === output.currentMode?.id), - "vrr_supported": output.adaptiveSyncSupported ?? false, - "vrr_enabled": output.adaptiveSync === 1, - "logical": { - "x": output.x ?? 0, - "y": output.y ?? 0, - "width": output.currentMode?.width ?? 1920, - "height": output.currentMode?.height ?? 1080, - "scale": output.scale ?? 1.0, - "transform": mapWlrTransform(output.transform) - } - }; - } - return map; - } - - function mapWlrTransform(wlrTransform) { - switch (wlrTransform) { - case 0: - return "Normal"; - case 1: - return "90"; - case 2: - return "180"; - case 3: - return "270"; - case 4: - return "Flipped"; - case 5: - return "Flipped90"; - case 6: - return "Flipped180"; - case 7: - return "Flipped270"; - default: - return "Normal"; - } - } - - function mapTransformToWlr(transform) { - switch (transform) { - case "Normal": - return 0; - case "90": - return 1; - case "180": - return 2; - case "270": - return 3; - case "Flipped": - return 4; - case "Flipped90": - return 5; - case "Flipped180": - return 6; - case "Flipped270": - return 7; - default: - return 0; - } - } - - function backendFetchOutputs() { - WlrOutputService.requestState(); - } - - function backendWriteOutputsConfig(outputsData) { - switch (CompositorService.compositor) { - case "niri": - NiriService.generateOutputsConfig(outputsData); - break; - case "hyprland": - HyprlandService.generateOutputsConfig(outputsData, buildMergedHyprlandSettings()); - break; - case "dwl": - DwlService.generateOutputsConfig(outputsData); - break; - default: - WlrOutputService.applyOutputsConfig(outputsData, outputs); - break; - } - } - - function normalizeOutputPositions(outputsData) { - const names = Object.keys(outputsData); - if (names.length === 0) - return outputsData; - - let minX = Infinity; - let minY = Infinity; - - for (const name of names) { - const output = outputsData[name]; - if (!output.logical) - continue; - minX = Math.min(minX, output.logical.x); - minY = Math.min(minY, output.logical.y); - } - - if (minX === Infinity || (minX === 0 && minY === 0)) - return outputsData; - - const normalized = JSON.parse(JSON.stringify(outputsData)); - for (const name of names) { - if (!normalized[name].logical) - continue; - normalized[name].logical.x -= minX; - normalized[name].logical.y -= minY; - } - - return normalized; - } - - function buildOutputsWithPendingChanges() { - const result = {}; - - for (const outputName in savedOutputs) { - if (!outputs[outputName]) - result[outputName] = JSON.parse(JSON.stringify(savedOutputs[outputName])); - } - - for (const outputName in outputs) { - result[outputName] = JSON.parse(JSON.stringify(outputs[outputName])); - } - - for (const outputName in pendingChanges) { - if (!result[outputName]) - continue; - const changes = pendingChanges[outputName]; - if (changes.position && result[outputName].logical) { - result[outputName].logical.x = changes.position.x; - result[outputName].logical.y = changes.position.y; - } - if (changes.mode !== undefined && result[outputName].modes) { - for (var i = 0; i < result[outputName].modes.length; i++) { - if (formatMode(result[outputName].modes[i]) === changes.mode) { - result[outputName].current_mode = i; - break; - } - } - } - if (changes.scale !== undefined && result[outputName].logical) - result[outputName].logical.scale = changes.scale; - if (changes.transform !== undefined && result[outputName].logical) - result[outputName].logical.transform = changes.transform; - if (changes.vrr !== undefined) - result[outputName].vrr_enabled = changes.vrr; - if (changes.mirror !== undefined) - result[outputName].mirror = changes.mirror; - } - return normalizeOutputPositions(result); - } - - function backendUpdateOutputPosition(outputName, x, y) { - if (!outputs || !outputs[outputName]) - return; - const updatedOutputs = {}; - for (const name in outputs) { - const output = outputs[name]; - if (name === outputName && output.logical) { - updatedOutputs[name] = JSON.parse(JSON.stringify(output)); - updatedOutputs[name].logical.x = x; - updatedOutputs[name].logical.y = y; - } else { - updatedOutputs[name] = output; - } - } - outputs = updatedOutputs; - } - - function backendUpdateOutputScale(outputName, scale) { - if (!outputs || !outputs[outputName]) - return; - const updatedOutputs = {}; - for (const name in outputs) { - const output = outputs[name]; - if (name === outputName && output.logical) { - updatedOutputs[name] = JSON.parse(JSON.stringify(output)); - updatedOutputs[name].logical.scale = scale; - } else { - updatedOutputs[name] = output; - } - } - outputs = updatedOutputs; - } - - function getOutputDisplayName(output, outputName) { - if (SettingsData.displayNameMode === "model" && output?.make && output?.model) { - if (CompositorService.isNiri) { - const serial = output.serial || "Unknown"; - return output.make + " " + output.model + " " + serial; - } - return output.make + " " + output.model; - } - return outputName; - } - - function getNiriOutputIdentifier(output, outputName) { - if (SettingsData.displayNameMode === "model" && output?.make && output?.model) { - const serial = output.serial || "Unknown"; - return output.make + " " + output.model + " " + serial; - } - return outputName; - } - - function getNiriSetting(output, outputName, key, defaultValue) { - if (!CompositorService.isNiri) - return defaultValue; - const identifier = getNiriOutputIdentifier(output, outputName); - const pending = pendingNiriChanges[identifier]; - if (pending && pending[key] !== undefined) - return pending[key]; - return SettingsData.getNiriOutputSetting(identifier, key, defaultValue); - } - - function setNiriSetting(output, outputName, key, value) { - if (!CompositorService.isNiri) - return; - initOriginalNiriSettings(); - const identifier = getNiriOutputIdentifier(output, outputName); - const newPending = JSON.parse(JSON.stringify(pendingNiriChanges)); - if (!newPending[identifier]) - newPending[identifier] = {}; - newPending[identifier][key] = value; - pendingNiriChanges = newPending; - } - - function initOriginalNiriSettings() { - if (originalNiriSettings) - return; - originalNiriSettings = JSON.parse(JSON.stringify(SettingsData.niriOutputSettings)); - } - - function getHyprlandOutputIdentifier(output, outputName) { - if (SettingsData.displayNameMode === "model" && output?.make && output?.model) - return "desc:" + output.make + " " + output.model + " " + (output?.serial || "Unknown"); - return outputName; - } - - function getHyprlandSetting(output, outputName, key, defaultValue) { - if (!CompositorService.isHyprland) - return defaultValue; - const identifier = getHyprlandOutputIdentifier(output, outputName); - const pending = pendingHyprlandChanges[identifier]; - if (pending && (key in pending)) { - const val = pending[key]; - return (val !== null && val !== undefined) ? val : defaultValue; - } - return SettingsData.getHyprlandOutputSetting(identifier, key, defaultValue); - } - - function setHyprlandSetting(output, outputName, key, value) { - if (!CompositorService.isHyprland) - return; - initOriginalHyprlandSettings(); - const identifier = getHyprlandOutputIdentifier(output, outputName); - const newPending = JSON.parse(JSON.stringify(pendingHyprlandChanges)); - if (!newPending[identifier]) - newPending[identifier] = {}; - newPending[identifier][key] = value; - pendingHyprlandChanges = newPending; - } - - function initOriginalHyprlandSettings() { - if (originalHyprlandSettings) - return; - originalHyprlandSettings = JSON.parse(JSON.stringify(SettingsData.hyprlandOutputSettings)); - } - - function initOriginalOutputs() { - if (!originalOutputs) - originalOutputs = JSON.parse(JSON.stringify(outputs)); - } - - function setPendingChange(outputName, key, value) { - initOriginalOutputs(); - const newPending = JSON.parse(JSON.stringify(pendingChanges)); - if (!newPending[outputName]) - newPending[outputName] = {}; - newPending[outputName][key] = value; - pendingChanges = newPending; - - if (key === "scale") { - recalculateAdjacentPositions(outputName, value); - backendUpdateOutputScale(outputName, value); - } - } - - function recalculateAdjacentPositions(changedOutput, newScale) { - const output = outputs[changedOutput]; - if (!output?.logical) - return; - const oldPhys = getPhysicalSize(output); - const oldLogicalW = Math.round(oldPhys.w / (output.logical.scale || 1.0)); - const newLogicalW = Math.round(oldPhys.w / newScale); - - const changedX = getPendingValue(changedOutput, "position")?.x ?? output.logical.x; - const changedY = getPendingValue(changedOutput, "position")?.y ?? output.logical.y; - - for (const name in outputs) { - if (name === changedOutput) - continue; - const other = outputs[name]; - if (!other?.logical) - continue; - const otherX = getPendingValue(name, "position")?.x ?? other.logical.x; - const otherY = getPendingValue(name, "position")?.y ?? other.logical.y; - const otherSize = getLogicalSize(other); - const otherRight = otherX + otherSize.w; - - if (Math.abs(changedX - otherRight) < 5) { - const newX = otherRight; - const newPending = JSON.parse(JSON.stringify(pendingChanges)); - if (!newPending[changedOutput]) - newPending[changedOutput] = {}; - newPending[changedOutput].position = { - "x": newX, - "y": changedY - }; - pendingChanges = newPending; - backendUpdateOutputPosition(changedOutput, newX, changedY); - return; - } - - const changedRight = changedX + oldLogicalW; - if (Math.abs(otherX - changedRight) < 5) { - const newOtherX = changedX + newLogicalW; - const newPending = JSON.parse(JSON.stringify(pendingChanges)); - if (!newPending[name]) - newPending[name] = {}; - newPending[name].position = { - "x": newOtherX, - "y": otherY - }; - pendingChanges = newPending; - backendUpdateOutputPosition(name, newOtherX, otherY); - } - } - } - - function getPendingValue(outputName, key) { - if (!pendingChanges[outputName]) - return undefined; - return pendingChanges[outputName][key]; - } - - function getEffectiveValue(outputName, key, originalValue) { - const pending = getPendingValue(outputName, key); - return pending !== undefined ? pending : originalValue; - } - - function clearPendingChanges() { - pendingChanges = {}; - pendingNiriChanges = {}; - pendingHyprlandChanges = {}; - originalOutputs = null; - originalNiriSettings = null; - originalHyprlandSettings = null; - originalDisplayNameMode = ""; - } - - function discardChanges() { - if (originalDisplayNameMode !== "") { - SettingsData.displayNameMode = originalDisplayNameMode; - SettingsData.saveSettings(); - } - backendFetchOutputs(); - clearPendingChanges(); - } - - function applyChanges() { - if (!hasPendingChanges) - return; - const changeDescriptions = []; - - if (formatChanged) { - const formatLabel = SettingsData.displayNameMode === "model" ? I18n.tr("Model") : I18n.tr("Name"); - changeDescriptions.push(I18n.tr("Config Format") + " → " + formatLabel); - } - - for (const outputName in pendingChanges) { - const changes = pendingChanges[outputName]; - if (changes.position) - changeDescriptions.push(outputName + ": " + I18n.tr("Position") + " → " + changes.position.x + ", " + changes.position.y); - if (changes.mode) - changeDescriptions.push(outputName + ": " + I18n.tr("Mode") + " → " + changes.mode); - if (changes.scale !== undefined) - changeDescriptions.push(outputName + ": " + I18n.tr("Scale") + " → " + changes.scale); - if (changes.transform) - changeDescriptions.push(outputName + ": " + I18n.tr("Transform") + " → " + getTransformLabel(changes.transform)); - if (changes.vrr !== undefined) - changeDescriptions.push(outputName + ": " + I18n.tr("VRR") + " → " + (changes.vrr ? I18n.tr("Enabled") : I18n.tr("Disabled"))); - } - - for (const outputId in pendingNiriChanges) { - const changes = pendingNiriChanges[outputId]; - if (changes.disabled !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Disabled") + " → " + (changes.disabled ? I18n.tr("Yes") : I18n.tr("No"))); - if (changes.vrrOnDemand !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("VRR On-Demand") + " → " + (changes.vrrOnDemand ? I18n.tr("Enabled") : I18n.tr("Disabled"))); - if (changes.focusAtStartup !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Focus at Startup") + " → " + (changes.focusAtStartup ? I18n.tr("Yes") : I18n.tr("No"))); - if (changes.hotCorners !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Hot Corners") + " → " + I18n.tr("Modified")); - if (changes.layout !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Layout") + " → " + I18n.tr("Modified")); - } - - for (const outputId in pendingHyprlandChanges) { - const changes = pendingHyprlandChanges[outputId]; - if (changes.disabled !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Disabled") + " → " + (changes.disabled ? I18n.tr("Yes") : I18n.tr("No"))); - if (changes.bitdepth !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Bit Depth") + " → " + changes.bitdepth); - if (changes.colorManagement !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Color Management") + " → " + changes.colorManagement); - if (changes.sdrBrightness !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("SDR Brightness") + " → " + changes.sdrBrightness); - if (changes.sdrSaturation !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("SDR Saturation") + " → " + changes.sdrSaturation); - if (changes.supportsHdr !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Force HDR") + " → " + (changes.supportsHdr ? I18n.tr("Yes") : I18n.tr("No"))); - if (changes.supportsWideColor !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("Force Wide Color") + " → " + (changes.supportsWideColor ? I18n.tr("Yes") : I18n.tr("No"))); - if (changes.vrrFullscreenOnly !== undefined) - changeDescriptions.push(outputId + ": " + I18n.tr("VRR Fullscreen Only") + " → " + (changes.vrrFullscreenOnly ? I18n.tr("Enabled") : I18n.tr("Disabled"))); - } - - if (CompositorService.isNiri) { - validateAndApplyNiriConfig(changeDescriptions); - return; - } - - changesApplied(changeDescriptions); - - if (formatChanged) - SettingsData.saveSettings(); - - if (CompositorService.isHyprland) - commitHyprlandSettingsChanges(); - - const mergedOutputs = buildOutputsWithPendingChanges(); - backendWriteOutputsConfig(mergedOutputs); - } - - function validateAndApplyNiriConfig(changeDescriptions) { - validatingConfig = true; - validationError = ""; - - const mergedOutputs = buildOutputsWithPendingChanges(); - const mergedNiriSettings = buildMergedNiriSettings(); - const configContent = generateNiriOutputsKdl(mergedOutputs, mergedNiriSettings); - - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - const tempFile = configDir + "/niri/dms/.outputs-validate-tmp.kdl"; - - Proc.runCommand("niri-validate-write-tmp", ["sh", "-c", `mkdir -p "$(dirname "${tempFile}")" && cat > "${tempFile}" << 'EOF'\n${configContent}EOF`], (output, writeExitCode) => { - if (writeExitCode !== 0) { - validatingConfig = false; - validationError = I18n.tr("Failed to write temp file for validation"); - ToastService.showError(I18n.tr("Config validation failed"), validationError, "", "display-config"); - return; - } - Proc.runCommand("niri-validate-config", ["sh", "-c", `niri validate -c "${tempFile}" 2>&1`], (validateOutput, validateExitCode) => { - validatingConfig = false; - Proc.runCommand("niri-validate-cleanup", ["rm", "-f", tempFile], () => {}); - if (validateExitCode !== 0) { - validationError = validateOutput.trim() || I18n.tr("Invalid configuration"); - ToastService.showError(I18n.tr("Config validation failed"), validationError, "", "display-config"); - return; - } - changesApplied(changeDescriptions); - if (formatChanged) - SettingsData.saveSettings(); - commitNiriSettingsChanges(); - backendWriteOutputsConfig(mergedOutputs); - }); - }); - } - - function buildMergedNiriSettings() { - const merged = JSON.parse(JSON.stringify(SettingsData.niriOutputSettings)); - for (const outputId in pendingNiriChanges) { - if (!merged[outputId]) - merged[outputId] = {}; - for (const key in pendingNiriChanges[outputId]) { - merged[outputId][key] = pendingNiriChanges[outputId][key]; - } - } - return merged; - } - - function commitNiriSettingsChanges() { - for (const outputId in pendingNiriChanges) { - for (const key in pendingNiriChanges[outputId]) { - SettingsData.setNiriOutputSetting(outputId, key, pendingNiriChanges[outputId][key]); - } - } - } - - function buildMergedHyprlandSettings() { - const merged = JSON.parse(JSON.stringify(SettingsData.hyprlandOutputSettings)); - for (const outputId in pendingHyprlandChanges) { - if (!merged[outputId]) - merged[outputId] = {}; - for (const key in pendingHyprlandChanges[outputId]) { - const val = pendingHyprlandChanges[outputId][key]; - if (val === null || val === undefined) - delete merged[outputId][key]; - else - merged[outputId][key] = val; - } - } - return merged; - } - - function commitHyprlandSettingsChanges() { - for (const outputId in pendingHyprlandChanges) { - for (const key in pendingHyprlandChanges[outputId]) { - const val = pendingHyprlandChanges[outputId][key]; - if (val === null || val === undefined) - SettingsData.removeHyprlandOutputSetting(outputId, key); - else - SettingsData.setHyprlandOutputSetting(outputId, key, val); - } - } - } - - function generateNiriOutputsKdl(outputsData, niriSettings) { - let kdlContent = `// Auto-generated by DMS - do not edit manually\n\n`; - const sortedNames = Object.keys(outputsData).sort((a, b) => { - const la = outputsData[a].logical || {}; - const lb = outputsData[b].logical || {}; - return (la.x ?? 0) - (lb.x ?? 0) || (la.y ?? 0) - (lb.y ?? 0); - }); - for (const outputName of sortedNames) { - const output = outputsData[outputName]; - const identifier = getNiriOutputIdentifier(output, outputName); - const settings = niriSettings[identifier] || {}; - kdlContent += `output "${identifier}" {\n`; - if (settings.disabled) { - kdlContent += ` off\n}\n\n`; - continue; - } - if (output.current_mode !== undefined && output.modes && output.modes[output.current_mode]) { - const mode = output.modes[output.current_mode]; - kdlContent += ` mode "${mode.width}x${mode.height}@${(mode.refresh_rate / 1000).toFixed(3)}"\n`; - } - if (output.logical) { - kdlContent += ` scale ${output.logical.scale ?? 1.0}\n`; - if (output.logical.transform && output.logical.transform !== "Normal") { - const transformMap = { - "Normal": "normal", - "90": "90", - "180": "180", - "270": "270", - "Flipped": "flipped", - "Flipped90": "flipped-90", - "Flipped180": "flipped-180", - "Flipped270": "flipped-270" - }; - kdlContent += ` transform "${transformMap[output.logical.transform] || "normal"}"\n`; - } - if (output.logical.x !== undefined && output.logical.y !== undefined) - kdlContent += ` position x=${output.logical.x} y=${output.logical.y}\n`; - } - if (settings.vrrOnDemand) { - kdlContent += ` variable-refresh-rate on-demand=true\n`; - } else if (output.vrr_enabled) { - kdlContent += ` variable-refresh-rate\n`; - } - if (settings.focusAtStartup) - kdlContent += ` focus-at-startup\n`; - if (settings.backdropColor) - kdlContent += ` backdrop-color "${settings.backdropColor}"\n`; - kdlContent += generateHotCornersBlock(settings); - kdlContent += generateLayoutBlock(settings); - kdlContent += `}\n\n`; - } - return kdlContent; - } - - function generateHotCornersBlock(settings) { - if (!settings.hotCorners) - return ""; - const hc = settings.hotCorners; - if (hc.off) - return ` hot-corners {\n off\n }\n`; - const corners = hc.corners || []; - if (corners.length === 0) - return ""; - let block = ` hot-corners {\n`; - for (const corner of corners) - block += ` ${corner}\n`; - block += ` }\n`; - return block; - } - - function generateLayoutBlock(settings) { - if (!settings.layout) - return ""; - const layout = settings.layout; - const hasSettings = layout.gaps !== undefined || layout.defaultColumnWidth || layout.presetColumnWidths || layout.alwaysCenterSingleColumn !== undefined; - if (!hasSettings) - return ""; - let block = ` layout {\n`; - if (layout.gaps !== undefined) - block += ` gaps ${layout.gaps}\n`; - if (layout.defaultColumnWidth?.type === "proportion") { - const val = layout.defaultColumnWidth.value; - const formatted = Number.isInteger(val) ? val.toFixed(1) : val.toString(); - block += ` default-column-width { proportion ${formatted}; }\n`; - } - if (layout.presetColumnWidths && layout.presetColumnWidths.length > 0) { - block += ` preset-column-widths {\n`; - for (const preset of layout.presetColumnWidths) { - if (preset.type === "proportion") { - const val = preset.value; - const formatted = Number.isInteger(val) ? val.toFixed(1) : val.toString(); - block += ` proportion ${formatted}\n`; - } - } - block += ` }\n`; - } - if (layout.alwaysCenterSingleColumn !== undefined) - block += layout.alwaysCenterSingleColumn ? ` always-center-single-column\n` : ` always-center-single-column false\n`; - block += ` }\n`; - return block; - } - - function confirmChanges() { - clearPendingChanges(); - changesConfirmed(); - } - - function revertChanges() { - const hadFormatChange = originalDisplayNameMode !== ""; - const hadNiriChanges = originalNiriSettings !== null; - const hadHyprlandChanges = originalHyprlandSettings !== null; - - if (hadFormatChange) { - SettingsData.displayNameMode = originalDisplayNameMode; - SettingsData.saveSettings(); - } - - if (hadNiriChanges) { - SettingsData.niriOutputSettings = JSON.parse(JSON.stringify(originalNiriSettings)); - SettingsData.saveSettings(); - } - - if (hadHyprlandChanges) { - SettingsData.hyprlandOutputSettings = JSON.parse(JSON.stringify(originalHyprlandSettings)); - SettingsData.saveSettings(); - } - - pendingHyprlandChanges = {}; - pendingNiriChanges = {}; - - if (!originalOutputs && !hadNiriChanges && !hadHyprlandChanges) { - if (hadFormatChange) - backendWriteOutputsConfig(buildOutputsWithPendingChanges()); - clearPendingChanges(); - changesReverted(); - return; - } - - const original = originalOutputs ? JSON.parse(JSON.stringify(originalOutputs)) : buildOutputsWithPendingChanges(); - for (const name in savedOutputs) { - if (!original[name]) - original[name] = JSON.parse(JSON.stringify(savedOutputs[name])); - } - backendWriteOutputsConfig(original); - clearPendingChanges(); - if (originalOutputs) - outputs = original; - changesReverted(); - } - - function getOutputBounds() { - if (!allOutputs || Object.keys(allOutputs).length === 0) - return { - "minX": 0, - "minY": 0, - "maxX": 1920, - "maxY": 1080, - "width": 1920, - "height": 1080 - }; - - let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; - - for (const name in allOutputs) { - const output = allOutputs[name]; - if (!output.logical) - continue; - const x = output.logical.x; - const y = output.logical.y; - const size = getLogicalSize(output); - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x + size.w); - maxY = Math.max(maxY, y + size.h); - } - - if (minX === Infinity) - return { - "minX": 0, - "minY": 0, - "maxX": 1920, - "maxY": 1080, - "width": 1920, - "height": 1080 - }; - return { - "minX": minX, - "minY": minY, - "maxX": maxX, - "maxY": maxY, - "width": maxX - minX, - "height": maxY - minY - }; - } - - function isRotated(transform) { - switch (transform) { - case "90": - case "270": - case "Flipped90": - case "Flipped270": - return true; - default: - return false; - } - } - - function getPhysicalSize(output) { - if (!output) - return { - "w": 1920, - "h": 1080 - }; - - let w = 1920, h = 1080; - if (output.modes && output.current_mode !== undefined) { - const mode = output.modes[output.current_mode]; - if (mode) { - w = mode.width || 1920; - h = mode.height || 1080; - } - } else if (output.logical) { - const scale = output.logical.scale || 1.0; - w = Math.round((output.logical.width || 1920) * scale); - h = Math.round((output.logical.height || 1080) * scale); - } - - if (output.logical && isRotated(output.logical.transform)) - return { - "w": h, - "h": w - }; - return { - "w": w, - "h": h - }; - } - - function getLogicalSize(output) { - if (!output) - return { - "w": 1920, - "h": 1080 - }; - - const phys = getPhysicalSize(output); - const scale = output.logical?.scale || 1.0; - - return { - "w": Math.round(phys.w / scale), - "h": Math.round(phys.h / scale) - }; - } - - function checkOverlap(testName, testX, testY, testW, testH) { - for (const name in outputs) { - if (name === testName) - continue; - const output = outputs[name]; - if (!output.logical) - continue; - const x = output.logical.x; - const y = output.logical.y; - const size = getLogicalSize(output); - if (!(testX + testW <= x || testX >= x + size.w || testY + testH <= y || testY >= y + size.h)) - return true; - } - return false; - } - - function snapToEdges(testName, posX, posY, testW, testH) { - const snapThreshold = 200; - let snappedX = posX; - let snappedY = posY; - let bestXDist = snapThreshold; - let bestYDist = snapThreshold; - - for (const name in outputs) { - if (name === testName) - continue; - const output = outputs[name]; - if (!output.logical) - continue; - const x = output.logical.x; - const y = output.logical.y; - const size = getLogicalSize(output); - - const rightEdge = x + size.w; - const bottomEdge = y + size.h; - const testRight = posX + testW; - const testBottom = posY + testH; - - const xSnaps = [ - { - "val": rightEdge, - "dist": Math.abs(posX - rightEdge) - }, - { - "val": x - testW, - "dist": Math.abs(testRight - x) - }, - { - "val": x, - "dist": Math.abs(posX - x) - }, - { - "val": rightEdge - testW, - "dist": Math.abs(testRight - rightEdge) - } - ]; - - const ySnaps = [ - { - "val": bottomEdge, - "dist": Math.abs(posY - bottomEdge) - }, - { - "val": y - testH, - "dist": Math.abs(testBottom - y) - }, - { - "val": y, - "dist": Math.abs(posY - y) - }, - { - "val": bottomEdge - testH, - "dist": Math.abs(testBottom - bottomEdge) - } - ]; - - for (const snap of xSnaps) { - if (snap.dist < bestXDist) { - bestXDist = snap.dist; - snappedX = snap.val; - } - } - - for (const snap of ySnaps) { - if (snap.dist < bestYDist) { - bestYDist = snap.dist; - snappedY = snap.val; - } - } - } - - if (checkOverlap(testName, snappedX, snappedY, testW, testH)) { - if (!checkOverlap(testName, snappedX, posY, testW, testH)) - return Qt.point(snappedX, posY); - if (!checkOverlap(testName, posX, snappedY, testW, testH)) - return Qt.point(posX, snappedY); - return Qt.point(posX, posY); - } - return Qt.point(snappedX, snappedY); - } - - function findBestSnapPosition(testName, posX, posY, testW, testH) { - const outputNames = Object.keys(outputs).filter(n => n !== testName); - - if (outputNames.length === 0) - return Qt.point(posX, posY); - - let bestPos = null; - let bestDist = Infinity; - - for (const name of outputNames) { - const output = outputs[name]; - if (!output.logical) - continue; - const x = output.logical.x; - const y = output.logical.y; - const size = getLogicalSize(output); - - const candidates = [ - { - "px": x + size.w, - "py": y - }, - { - "px": x - testW, - "py": y - }, - { - "px": x, - "py": y + size.h - }, - { - "px": x, - "py": y - testH - }, - { - "px": x + size.w, - "py": y + size.h - testH - }, - { - "px": x - testW, - "py": y + size.h - testH - }, - { - "px": x + size.w - testW, - "py": y + size.h - }, - { - "px": x + size.w - testW, - "py": y - testH - } - ]; - - for (const c of candidates) { - if (checkOverlap(testName, c.px, c.py, testW, testH)) - continue; - const dist = Math.hypot(c.px - posX, c.py - posY); - if (dist < bestDist) { - bestDist = dist; - bestPos = Qt.point(c.px, c.py); - } - } - } - - return bestPos || Qt.point(posX, posY); - } - - function formatMode(mode) { - if (!mode) - return ""; - return mode.width + "x" + mode.height + "@" + (mode.refresh_rate / 1000).toFixed(3); - } - - function getTransformLabel(transform) { - switch (transform) { - case "Normal": - return I18n.tr("Normal"); - case "90": - return I18n.tr("90°"); - case "180": - return I18n.tr("180°"); - case "270": - return I18n.tr("270°"); - case "Flipped": - return I18n.tr("Flipped"); - case "Flipped90": - return I18n.tr("Flipped 90°"); - case "Flipped180": - return I18n.tr("Flipped 180°"); - case "Flipped270": - return I18n.tr("Flipped 270°"); - default: - return I18n.tr("Normal"); - } - } - - function getTransformValue(label) { - if (label === I18n.tr("Normal")) - return "Normal"; - if (label === I18n.tr("90°")) - return "90"; - if (label === I18n.tr("180°")) - return "180"; - if (label === I18n.tr("270°")) - return "270"; - if (label === I18n.tr("Flipped")) - return "Flipped"; - if (label === I18n.tr("Flipped 90°")) - return "Flipped90"; - if (label === I18n.tr("Flipped 180°")) - return "Flipped180"; - if (label === I18n.tr("Flipped 270°")) - return "Flipped270"; - return "Normal"; - } - - function setOriginalDisplayNameMode(mode) { - if (originalDisplayNameMode === "") - originalDisplayNameMode = mode; - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml deleted file mode 100644 index 7c36e4b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/HyprlandOutputSettings.qml +++ /dev/null @@ -1,310 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Column { - id: root - - property string outputName: "" - property var outputData: null - property bool expanded: false - - width: parent.width - spacing: 0 - - Rectangle { - width: parent.width - height: headerRow.implicitHeight + Theme.spacingS * 2 - color: headerMouse.containsMouse ? Theme.withAlpha(Theme.primary, 0.1) : "transparent" - radius: Theme.cornerRadius / 2 - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: root.expanded ? "expand_more" : "chevron_right" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Compositor Settings") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: headerMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.expanded = !root.expanded - } - } - - Column { - id: settingsColumn - width: parent.width - spacing: Theme.spacingS - visible: root.expanded - topPadding: Theme.spacingS - - property int currentBitdepth: { - DisplayConfigState.pendingHyprlandChanges; - return DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "bitdepth", 8); - } - property bool is10Bit: currentBitdepth === 10 - - property string currentCm: { - DisplayConfigState.pendingHyprlandChanges; - return DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "colorManagement", "auto"); - } - property bool isHdrMode: currentCm === "hdr" || currentCm === "hdredid" - - DankToggle { - width: parent.width - text: I18n.tr("Disable Output") - checked: DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "disabled", false) - onToggled: checked => DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "disabled", checked) - } - - DankDropdown { - width: parent.width - text: I18n.tr("Mirror Display") - addHorizontalPadding: true - - property var otherOutputs: { - const list = [I18n.tr("None")]; - for (const name in DisplayConfigState.outputs) { - if (name !== root.outputName) - list.push(name); - } - return list; - } - options: otherOutputs - - currentValue: { - DisplayConfigState.pendingChanges; - const pending = DisplayConfigState.getPendingValue(root.outputName, "mirror"); - const val = pending !== undefined ? pending : (root.outputData.mirror || ""); - return val === "" ? I18n.tr("None") : val; - } - - onValueChanged: value => { - const realVal = value === I18n.tr("None") ? "" : value; - DisplayConfigState.setPendingChange(root.outputName, "mirror", realVal); - } - } - - DankToggle { - width: parent.width - text: I18n.tr("10-bit Color") - description: I18n.tr("Enable 10-bit color depth for wider color gamut and HDR support") - checked: settingsColumn.is10Bit - onToggled: checked => { - if (checked) { - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "bitdepth", 10); - } else { - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "bitdepth", null); - if (settingsColumn.isHdrMode) - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "colorManagement", "auto"); - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: settingsColumn.is10Bit - - Rectangle { - width: parent.width - height: 1 - color: Theme.withAlpha(Theme.outline, 0.15) - } - - DankDropdown { - width: parent.width - text: I18n.tr("Color Gamut") - addHorizontalPadding: true - currentValue: { - DisplayConfigState.pendingHyprlandChanges; - const val = DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "colorManagement", "auto"); - return cmLabelMap[val] || I18n.tr("Auto (Wide)"); - } - options: [I18n.tr("Auto (Wide)"), I18n.tr("Wide (BT2020)"), "DCI-P3", "Apple P3", "Adobe RGB", "EDID", "HDR", I18n.tr("HDR (EDID)")] - - property var cmValueMap: ({ - [I18n.tr("Auto (Wide)")]: "auto", - [I18n.tr("Wide (BT2020)")]: "wide", - "DCI-P3": "dcip3", - "Apple P3": "dp3", - "Adobe RGB": "adobe", - "EDID": "edid", - "HDR": "hdr", - [I18n.tr("HDR (EDID)")]: "hdredid" - }) - - property var cmLabelMap: ({ - "auto": I18n.tr("Auto (Wide)"), - "wide": I18n.tr("Wide (BT2020)"), - "dcip3": "DCI-P3", - "dp3": "Apple P3", - "adobe": "Adobe RGB", - "edid": "EDID", - "hdr": "HDR", - "hdredid": I18n.tr("HDR (EDID)") - }) - - onValueChanged: value => { - const cmValue = cmValueMap[value] || "auto"; - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "colorManagement", cmValue); - } - } - - Rectangle { - width: parent.width - Theme.spacingM * 2 - anchors.horizontalCenter: parent.horizontalCenter - height: warningColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius / 2 - color: Theme.withAlpha(Theme.warning, 0.15) - border.color: Theme.withAlpha(Theme.warning, 0.3) - border.width: 1 - visible: settingsColumn.isHdrMode - - Column { - id: warningColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - Row { - spacing: Theme.spacingS - DankIcon { - name: "warning" - size: Theme.iconSize - 4 - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - StyledText { - text: I18n.tr("Experimental Feature") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - } - StyledText { - text: I18n.tr("HDR mode is experimental. Verify your monitor supports HDR before enabling.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: settingsColumn.isHdrMode - - Rectangle { - width: parent.width - height: 1 - color: Theme.withAlpha(Theme.outline, 0.15) - } - - StyledText { - text: I18n.tr("HDR Tone Mapping") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - leftPadding: Theme.spacingM - } - - Row { - width: parent.width - Theme.spacingM * 2 - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("SDR Brightness") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - height: 40 - placeholderText: "1.0 - 2.0" - text: { - DisplayConfigState.pendingHyprlandChanges; - const val = DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "sdrBrightness", null); - return val !== null ? val.toString() : ""; - } - onEditingFinished: { - const trimmed = text.trim(); - if (!trimmed) { - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "sdrBrightness", null); - return; - } - const val = parseFloat(trimmed); - if (isNaN(val) || val < 0.1 || val > 5.0) - return; - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "sdrBrightness", parseFloat(val.toFixed(2))); - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("SDR Saturation") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - height: 40 - placeholderText: "0.5 - 1.5" - text: { - DisplayConfigState.pendingHyprlandChanges; - const val = DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "sdrSaturation", null); - return val !== null ? val.toString() : ""; - } - onEditingFinished: { - const trimmed = text.trim(); - if (!trimmed) { - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "sdrSaturation", null); - return; - } - const val = parseFloat(trimmed); - if (isNaN(val) || val < 0.0 || val > 3.0) - return; - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "sdrSaturation", parseFloat(val.toFixed(2))); - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml deleted file mode 100644 index f5f270b..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/IncludeWarningBox.qml +++ /dev/null @@ -1,94 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - width: parent.width - height: warningContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - - readonly property bool showError: DisplayConfigState.includeStatus.exists && !DisplayConfigState.includeStatus.included - readonly property bool showSetup: !DisplayConfigState.includeStatus.exists && !DisplayConfigState.includeStatus.included - - color: (showError || showSetup) ? Theme.withAlpha(Theme.primary, 0.15) : "transparent" - border.color: (showError || showSetup) ? Theme.withAlpha(Theme.primary, 0.3) : "transparent" - border.width: 1 - visible: (showError || showSetup) && DisplayConfigState.hasOutputBackend && !DisplayConfigState.checkingInclude - - Column { - id: warningContent - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - (fixButton.visible ? fixButton.width + Theme.spacingM : 0) - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: { - if (root.showSetup) - return I18n.tr("First Time Setup"); - if (root.showError) - return I18n.tr("Outputs Include Missing"); - return ""; - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.primary - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - if (root.showSetup) - return I18n.tr("Click 'Setup' to create the outputs config and add include to your compositor config."); - if (root.showError) - return I18n.tr("dms/outputs config exists but is not included in your compositor config. Display changes won't persist."); - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankButton { - id: fixButton - visible: root.showError || root.showSetup - text: { - if (DisplayConfigState.fixingInclude) - return I18n.tr("Fixing..."); - if (root.showSetup) - return I18n.tr("Setup"); - return I18n.tr("Fix Now"); - } - backgroundColor: Theme.primary - textColor: Theme.primaryText - enabled: !DisplayConfigState.fixingInclude - anchors.verticalCenter: parent.verticalCenter - onClicked: DisplayConfigState.fixOutputsInclude() - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorCanvas.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorCanvas.qml deleted file mode 100644 index accdfd7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorCanvas.qml +++ /dev/null @@ -1,82 +0,0 @@ -import QtQuick -import qs.Common - -Rectangle { - id: root - - property var filteredOutputs: { - const all = DisplayConfigState.allOutputs || {}; - const keys = Object.keys(all); - if (SettingsData.displayShowDisconnected) - return keys; - return keys.filter(k => all[k]?.connected); - } - - property var filteredBounds: { - const all = DisplayConfigState.allOutputs || {}; - let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; - for (const name of filteredOutputs) { - const output = all[name]; - if (!output?.logical) - continue; - const x = output.logical.x; - const y = output.logical.y; - const size = DisplayConfigState.getLogicalSize(output); - const w = size.w || 1920; - const h = size.h || 1080; - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x + w); - maxY = Math.max(maxY, y + h); - } - if (minX === Infinity) - return { - minX: 0, - minY: 0, - width: 1920, - height: 1080 - }; - return { - minX: minX, - minY: minY, - width: maxX - minX, - height: maxY - minY - }; - } - - width: parent.width - height: 280 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHighest - border.color: Theme.outline - border.width: 1 - - Item { - id: canvas - anchors.fill: parent - anchors.margins: Theme.spacingL - - property var bounds: root.filteredBounds - property real scaleFactor: { - if (bounds.width === 0 || bounds.height === 0) - return 0.1; - const padding = Theme.spacingL * 2; - const scaleX = (width - padding) / bounds.width; - const scaleY = (height - padding) / bounds.height; - return Math.min(scaleX, scaleY); - } - property point offset: Qt.point((width - bounds.width * scaleFactor) / 2 - bounds.minX * scaleFactor, (height - bounds.height * scaleFactor) / 2 - bounds.minY * scaleFactor) - - Repeater { - model: root.filteredOutputs - - delegate: MonitorRect { - required property string modelData - outputName: modelData - outputData: DisplayConfigState.allOutputs[modelData] - canvasScaleFactor: canvas.scaleFactor - canvasOffset: canvas.offset - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorRect.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorRect.qml deleted file mode 100644 index 0209e5f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/MonitorRect.qml +++ /dev/null @@ -1,159 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - required property string outputName - required property var outputData - required property real canvasScaleFactor - required property point canvasOffset - - property bool isConnected: outputData?.connected ?? false - property bool isDragging: false - property point originalLogical: Qt.point(0, 0) - property point snappedLogical: Qt.point(0, 0) - property bool isValidPosition: true - - property var physSize: DisplayConfigState.getPhysicalSize(outputData) - property var logicalSize: DisplayConfigState.getLogicalSize(outputData) - - x: isDragging ? x : (outputData?.logical?.x ?? 0) * canvasScaleFactor + canvasOffset.x - y: isDragging ? y : (outputData?.logical?.y ?? 0) * canvasScaleFactor + canvasOffset.y - width: logicalSize.w * canvasScaleFactor - height: logicalSize.h * canvasScaleFactor - radius: Theme.cornerRadius - opacity: isConnected ? 1.0 : 0.5 - - color: { - if (!isConnected) - return Theme.surfaceContainerHighest; - if (!isValidPosition) - return Theme.withAlpha(Theme.error, 0.3); - if (isDragging) - return Theme.withAlpha(Theme.primary, 0.4); - if (dragArea.containsMouse) - return Theme.withAlpha(Theme.primary, 0.2); - return Theme.surfaceContainerHigh; - } - - border.color: { - if (!isConnected) - return Theme.outline; - if (!isValidPosition) - return Theme.error; - if (isDragging) - return Theme.primary; - if (CompositorService.getFocusedScreen()?.name === outputName) - return Theme.primary; - return Theme.outline; - } - border.width: isDragging ? 3 : 2 - z: isDragging ? 100 : (isConnected ? 1 : 0) - - Rectangle { - id: snapPreview - visible: root.isDragging && root.isValidPosition && SettingsData.displaySnapToEdge - x: root.snappedLogical.x * root.canvasScaleFactor + root.canvasOffset.x - root.x - y: root.snappedLogical.y * root.canvasScaleFactor + root.canvasOffset.y - root.y - width: parent.width - height: parent.height - radius: Theme.cornerRadius - color: "transparent" - border.color: Theme.primary - border.width: 2 - opacity: 0.6 - } - - Column { - anchors.centerIn: parent - spacing: 2 - - DankIcon { - name: root.isConnected ? "desktop_windows" : "desktop_access_disabled" - size: Math.min(24, Math.min(root.width * 0.3, root.height * 0.25)) - color: root.isConnected ? (root.isValidPosition ? Theme.primary : Theme.error) : Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: DisplayConfigState.getOutputDisplayName(root.outputData, root.outputName) - font.pixelSize: Math.max(10, Math.min(14, root.width * 0.12)) - font.weight: Font.Medium - color: root.isConnected ? Theme.surfaceText : Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - elide: Text.ElideMiddle - width: Math.min(implicitWidth, root.width - 8) - } - - StyledText { - text: root.isConnected ? (root.physSize.w + "x" + root.physSize.h) : I18n.tr("Disconnected") - font.pixelSize: Math.max(8, Math.min(11, root.width * 0.09)) - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - MouseArea { - id: dragArea - anchors.fill: parent - hoverEnabled: true - enabled: root.isConnected - cursorShape: !root.isConnected ? Qt.ArrowCursor : (root.isDragging ? Qt.ClosedHandCursor : Qt.OpenHandCursor) - drag.target: root.isConnected ? root : null - drag.axis: Drag.XAndYAxis - drag.threshold: 0 - - onPressed: mouse => { - if (!root.isConnected) - return; - root.isDragging = true; - root.originalLogical = Qt.point(root.outputData?.logical?.x ?? 0, root.outputData?.logical?.y ?? 0); - root.snappedLogical = root.originalLogical; - root.isValidPosition = true; - } - - onPositionChanged: mouse => { - if (!root.isDragging || !root.isConnected) - return; - let posX = Math.round((root.x - root.canvasOffset.x) / root.canvasScaleFactor); - let posY = Math.round((root.y - root.canvasOffset.y) / root.canvasScaleFactor); - - const size = DisplayConfigState.getLogicalSize(root.outputData); - - const snapped = SettingsData.displaySnapToEdge ? DisplayConfigState.snapToEdges(root.outputName, posX, posY, size.w, size.h) : Qt.point(posX, posY); - root.snappedLogical = snapped; - root.isValidPosition = SettingsData.displaySnapToEdge ? !DisplayConfigState.checkOverlap(root.outputName, snapped.x, snapped.y, size.w, size.h) : true; - } - - onReleased: { - if (!root.isDragging || !root.isConnected) - return; - root.isDragging = false; - - const size = DisplayConfigState.getLogicalSize(root.outputData); - const finalX = root.snappedLogical.x; - const finalY = root.snappedLogical.y; - - if (SettingsData.displaySnapToEdge && DisplayConfigState.checkOverlap(root.outputName, finalX, finalY, size.w, size.h)) { - root.isValidPosition = true; - return; - } - - if (finalX === root.originalLogical.x && finalY === root.originalLogical.y) - return; - - DisplayConfigState.initOriginalOutputs(); - DisplayConfigState.backendUpdateOutputPosition(root.outputName, finalX, finalY); - DisplayConfigState.setPendingChange(root.outputName, "position", { - "x": finalX, - "y": finalY - }); - } - } - - Drag.active: dragArea.drag.active && root.isConnected -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NiriOutputSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NiriOutputSettings.qml deleted file mode 100644 index da9a4a7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NiriOutputSettings.qml +++ /dev/null @@ -1,368 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -Column { - id: root - - property string outputName: "" - property var outputData: null - property bool expanded: false - - width: parent.width - spacing: 0 - - Rectangle { - width: parent.width - height: headerRow.implicitHeight + Theme.spacingS * 2 - color: headerMouse.containsMouse ? Theme.withAlpha(Theme.primary, 0.1) : "transparent" - radius: Theme.cornerRadius / 2 - - Row { - id: headerRow - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: root.expanded ? "expand_more" : "chevron_right" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Compositor Settings") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: headerMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.expanded = !root.expanded - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: root.expanded - topPadding: Theme.spacingS - - DankToggle { - width: parent.width - text: I18n.tr("Disable Output") - checked: DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "disabled", false) - onToggled: checked => DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "disabled", checked) - } - - DankToggle { - width: parent.width - text: I18n.tr("Focus at Startup") - checked: DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "focusAtStartup", false) - onToggled: checked => DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "focusAtStartup", checked) - } - - DankDropdown { - width: parent.width - text: I18n.tr("Hot Corners") - addHorizontalPadding: true - - property var hotCornersData: { - void (DisplayConfigState.pendingNiriChanges); - return DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "hotCorners", null); - } - - currentValue: { - if (!hotCornersData) - return I18n.tr("Inherit"); - if (hotCornersData.off) - return I18n.tr("Off"); - const corners = hotCornersData.corners || []; - if (corners.length === 0) - return I18n.tr("Inherit"); - if (corners.length === 4) - return I18n.tr("All"); - return I18n.tr("Select..."); - } - options: [I18n.tr("Inherit"), I18n.tr("Off"), I18n.tr("All"), I18n.tr("Select...")] - - onValueChanged: value => { - switch (value) { - case I18n.tr("Inherit"): - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", null); - break; - case I18n.tr("Off"): - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", { - "off": true - }); - break; - case I18n.tr("All"): - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", { - "corners": ["top-left", "top-right", "bottom-left", "bottom-right"] - }); - break; - case I18n.tr("Select..."): - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", { - "corners": [] - }); - break; - } - } - } - - Item { - width: parent.width - height: hotCornersGroup.implicitHeight - clip: true - - property var hotCornersData: { - void (DisplayConfigState.pendingNiriChanges); - return DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "hotCorners", null); - } - - visible: hotCornersData && !hotCornersData.off && hotCornersData.corners !== undefined - - DankButtonGroup { - id: hotCornersGroup - anchors.horizontalCenter: parent.horizontalCenter - selectionMode: "multi" - checkEnabled: false - buttonHeight: 32 - buttonPadding: parent.width < 400 ? Theme.spacingXS : Theme.spacingM - minButtonWidth: parent.width < 400 ? 28 : 56 - textSize: parent.width < 400 ? 11 : Theme.fontSizeMedium - model: [I18n.tr("Top Left"), I18n.tr("Top Right"), I18n.tr("Bottom Left"), I18n.tr("Bottom Right")] - - property var cornerKeys: ["top-left", "top-right", "bottom-left", "bottom-right"] - - currentSelection: { - const hcData = parent.hotCornersData; - if (!hcData?.corners) - return []; - return hcData.corners.map(key => { - const idx = cornerKeys.indexOf(key); - return idx >= 0 ? model[idx] : null; - }).filter(v => v !== null); - } - - onSelectionChanged: (index, selected) => { - const corners = currentSelection.map(label => { - const idx = model.indexOf(label); - return idx >= 0 ? cornerKeys[idx] : null; - }).filter(v => v !== null); - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", { - "corners": corners - }); - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.withAlpha(Theme.outline, 0.15) - } - - Item { - width: parent.width - height: layoutColumn.implicitHeight - - Column { - id: layoutColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingS - - Column { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Layout Overrides") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceVariantText - } - - StyledText { - text: I18n.tr("Override global layout settings for this output") - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceVariantText, 0.7) - wrapMode: Text.WordWrap - width: parent.width - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Window Gaps (px)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - height: 40 - placeholderText: I18n.tr("Inherit") - text: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null); - if (layout?.gaps === undefined) - return ""; - return layout.gaps.toString(); - } - onEditingFinished: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {}; - const trimmed = text.trim(); - if (!trimmed) { - delete layout.gaps; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null); - return; - } - const val = parseInt(trimmed); - if (isNaN(val) || val < 0) - return; - layout.gaps = val; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", layout); - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Default Width (%)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - height: 40 - placeholderText: I18n.tr("Inherit") - text: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null); - if (!layout?.defaultColumnWidth) - return ""; - if (layout.defaultColumnWidth.type !== "proportion") - return ""; - const percent = layout.defaultColumnWidth.value * 100; - return parseFloat(percent.toFixed(4)).toString(); - } - onEditingFinished: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {}; - const trimmed = text.trim().replace("%", ""); - if (!trimmed) { - delete layout.defaultColumnWidth; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null); - return; - } - const val = parseFloat(trimmed); - if (isNaN(val) || val <= 0 || val > 100) - return; - layout.defaultColumnWidth = { - "type": "proportion", - "value": parseFloat((val / 100).toFixed(6)) - }; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", layout); - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Preset Widths (%)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "e.g. 33.33, 50, 66.67" - font.pixelSize: Theme.fontSizeSmall - color: Theme.withAlpha(Theme.surfaceVariantText, 0.7) - } - - DankTextField { - width: parent.width - height: 40 - placeholderText: I18n.tr("Inherit") - text: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null); - const presets = layout?.presetColumnWidths || []; - if (presets.length === 0) - return ""; - return presets.filter(p => p.type === "proportion").map(p => parseFloat((p.value * 100).toFixed(4))).join(", "); - } - onEditingFinished: { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {}; - const trimmed = text.trim(); - if (!trimmed) { - delete layout.presetColumnWidths; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null); - return; - } - const parts = trimmed.split(/[,\s]+/).filter(s => s); - const presets = []; - for (const part of parts) { - const val = parseFloat(part.replace("%", "")); - if (!isNaN(val) && val > 0 && val <= 100) - presets.push({ - "type": "proportion", - "value": parseFloat((val / 100).toFixed(6)) - }); - } - if (presets.length === 0) { - delete layout.presetColumnWidths; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null); - return; - } - presets.sort((a, b) => a.value - b.value); - layout.presetColumnWidths = presets; - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", layout); - } - } - } - } - } - - DankToggle { - width: parent.width - text: I18n.tr("Center Single Column") - property var layoutData: DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null) - checked: layoutData?.alwaysCenterSingleColumn ?? false - onToggled: checked => { - const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {}; - if (checked) { - layout.alwaysCenterSingleColumn = true; - } else { - delete layout.alwaysCenterSingleColumn; - } - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NoBackendMessage.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NoBackendMessage.qml deleted file mode 100644 index 93ab124..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/NoBackendMessage.qml +++ /dev/null @@ -1,60 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - width: parent.width - height: messageContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: messageContent - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "monitor" - size: Theme.iconSize - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Monitor Configuration") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Display configuration is not available. WLR output management protocol not supported.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/OutputCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/OutputCard.qml deleted file mode 100644 index 0da1175..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfig/OutputCard.qml +++ /dev/null @@ -1,352 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - required property string outputName - required property var outputData - property bool isConnected: outputData?.connected ?? false - - width: parent.width - height: settingsColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainerHigh, isConnected ? 0.5 : 0.3) - border.color: Theme.withAlpha(Theme.outline, 0.3) - border.width: 1 - opacity: isConnected ? 1.0 : 0.7 - - Column { - id: settingsColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: root.isConnected ? "desktop_windows" : "desktop_access_disabled" - size: Theme.iconSize - 4 - color: root.isConnected ? Theme.primary : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - (disconnectedBadge.visible ? disconnectedBadge.width + deleteButton.width + Theme.spacingS * 2 : 0) - spacing: 2 - - StyledText { - text: DisplayConfigState.getOutputDisplayName(root.outputData, root.outputName) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: root.isConnected ? Theme.surfaceText : Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: (root.outputData?.model ?? "") + (root.outputData?.make ? " - " + root.outputData.make : "") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Rectangle { - id: disconnectedBadge - visible: !root.isConnected - width: disconnectedText.implicitWidth + Theme.spacingM - height: disconnectedText.implicitHeight + Theme.spacingXS - radius: height / 2 - color: Theme.withAlpha(Theme.outline, 0.3) - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: disconnectedText - text: I18n.tr("Disconnected") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.centerIn: parent - } - } - - Rectangle { - id: deleteButton - visible: !root.isConnected - width: 28 - height: 28 - radius: Theme.cornerRadius - color: deleteArea.containsMouse ? Theme.errorHover : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: DisplayConfigState.deleteDisconnectedOutput(root.outputName) - } - } - } - - DankDropdown { - width: parent.width - text: I18n.tr("Resolution & Refresh") - visible: root.isConnected - currentValue: { - const pendingMode = DisplayConfigState.getPendingValue(root.outputName, "mode"); - if (pendingMode) - return pendingMode; - const data = DisplayConfigState.outputs[root.outputName]; - if (!data?.modes || data?.current_mode === undefined) - return "Auto"; - const mode = data.modes[data.current_mode]; - return mode ? DisplayConfigState.formatMode(mode) : "Auto"; - } - options: { - const data = DisplayConfigState.outputs[root.outputName]; - if (!data?.modes) - return ["Auto"]; - const opts = []; - for (var i = 0; i < data.modes.length; i++) { - opts.push(DisplayConfigState.formatMode(data.modes[i])); - } - return opts; - } - onValueChanged: value => DisplayConfigState.setPendingChange(root.outputName, "mode", value) - } - - StyledText { - visible: !root.isConnected - text: I18n.tr("Configuration will be preserved when this display reconnects") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: root.isConnected - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Scale") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Item { - id: scaleContainer - width: parent.width - height: scaleDropdown.visible ? scaleDropdown.height : scaleInput.height - - property bool customMode: false - property string currentScale: { - const pendingScale = DisplayConfigState.getPendingValue(root.outputName, "scale"); - if (pendingScale !== undefined) - return parseFloat(pendingScale.toFixed(2)).toString(); - const scale = DisplayConfigState.outputs[root.outputName]?.logical?.scale ?? 1.0; - return parseFloat(scale.toFixed(2)).toString(); - } - - DankDropdown { - id: scaleDropdown - width: parent.width - dropdownWidth: parent.width - visible: !scaleContainer.customMode - currentValue: scaleContainer.currentScale - options: { - const standard = ["0.5", "0.75", "1", "1.25", "1.5", "1.75", "2", "2.5", "3", I18n.tr("Custom...")]; - const current = scaleContainer.currentScale; - if (standard.slice(0, -1).includes(current)) - return standard; - const opts = [...standard.slice(0, -1), current, standard[standard.length - 1]]; - return opts.sort((a, b) => { - if (a === I18n.tr("Custom...")) - return 1; - if (b === I18n.tr("Custom...")) - return -1; - return parseFloat(a) - parseFloat(b); - }); - } - onValueChanged: value => { - if (value === I18n.tr("Custom...")) { - scaleContainer.customMode = true; - scaleInput.text = scaleContainer.currentScale; - scaleInput.forceActiveFocus(); - scaleInput.selectAll(); - return; - } - DisplayConfigState.setPendingChange(root.outputName, "scale", parseFloat(value)); - } - } - - DankTextField { - id: scaleInput - width: parent.width - height: 40 - visible: scaleContainer.customMode - placeholderText: "0.5 - 4.0" - - function applyValue() { - const val = parseFloat(text); - if (isNaN(val) || val < 0.25 || val > 4) { - text = scaleContainer.currentScale; - scaleContainer.customMode = false; - return; - } - DisplayConfigState.setPendingChange(root.outputName, "scale", parseFloat(val.toFixed(2))); - scaleContainer.customMode = false; - } - - onAccepted: applyValue() - onEditingFinished: applyValue() - Keys.onEscapePressed: { - text = scaleContainer.currentScale; - scaleContainer.customMode = false; - } - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Transform") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - DankDropdown { - width: parent.width - dropdownWidth: parent.width - currentValue: { - const pendingTransform = DisplayConfigState.getPendingValue(root.outputName, "transform"); - if (pendingTransform) - return DisplayConfigState.getTransformLabel(pendingTransform); - const data = DisplayConfigState.outputs[root.outputName]; - return DisplayConfigState.getTransformLabel(data?.logical?.transform ?? "Normal"); - } - options: [I18n.tr("Normal"), I18n.tr("90°"), I18n.tr("180°"), I18n.tr("270°"), I18n.tr("Flipped"), I18n.tr("Flipped 90°"), I18n.tr("Flipped 180°"), I18n.tr("Flipped 270°")] - onValueChanged: value => DisplayConfigState.setPendingChange(root.outputName, "transform", DisplayConfigState.getTransformValue(value)) - } - } - } - - DankToggle { - width: parent.width - text: I18n.tr("Variable Refresh Rate") - visible: root.isConnected && !CompositorService.isDwl && !CompositorService.isHyprland && !CompositorService.isNiri && (DisplayConfigState.outputs[root.outputName]?.vrr_supported ?? false) - checked: { - const pendingVrr = DisplayConfigState.getPendingValue(root.outputName, "vrr"); - if (pendingVrr !== undefined) - return pendingVrr; - return DisplayConfigState.outputs[root.outputName]?.vrr_enabled ?? false; - } - onToggled: checked => DisplayConfigState.setPendingChange(root.outputName, "vrr", checked) - } - - DankDropdown { - width: parent.width - text: I18n.tr("Variable Refresh Rate") - visible: root.isConnected && CompositorService.isHyprland && (DisplayConfigState.outputs[root.outputName]?.vrr_supported ?? false) - options: [I18n.tr("Off"), I18n.tr("On"), I18n.tr("Fullscreen Only")] - currentValue: { - DisplayConfigState.pendingHyprlandChanges; - if (DisplayConfigState.getHyprlandSetting(root.outputData, root.outputName, "vrrFullscreenOnly", false)) - return I18n.tr("Fullscreen Only"); - const pendingVrr = DisplayConfigState.getPendingValue(root.outputName, "vrr"); - const vrrEnabled = pendingVrr !== undefined ? pendingVrr : (DisplayConfigState.outputs[root.outputName]?.vrr_enabled ?? false); - if (vrrEnabled) - return I18n.tr("On"); - return I18n.tr("Off"); - } - onValueChanged: value => { - const off = I18n.tr("Off"); - const fullscreen = I18n.tr("Fullscreen Only"); - DisplayConfigState.setPendingChange(root.outputName, "vrr", value !== off); - DisplayConfigState.setHyprlandSetting(root.outputData, root.outputName, "vrrFullscreenOnly", value === fullscreen || null); - } - } - - DankDropdown { - width: parent.width - text: I18n.tr("Variable Refresh Rate") - visible: root.isConnected && CompositorService.isNiri && (DisplayConfigState.outputs[root.outputName]?.vrr_supported ?? false) - options: [I18n.tr("Off"), I18n.tr("On"), I18n.tr("On-Demand")] - currentValue: { - DisplayConfigState.pendingNiriChanges; - if (DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "vrrOnDemand", false)) - return I18n.tr("On-Demand"); - const pendingVrr = DisplayConfigState.getPendingValue(root.outputName, "vrr"); - const vrrEnabled = pendingVrr !== undefined ? pendingVrr : (DisplayConfigState.outputs[root.outputName]?.vrr_enabled ?? false); - if (!vrrEnabled) - return I18n.tr("Off"); - return I18n.tr("On"); - } - onValueChanged: value => { - const off = I18n.tr("Off"); - const onDemand = I18n.tr("On-Demand"); - DisplayConfigState.setPendingChange(root.outputName, "vrr", value !== off); - DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "vrrOnDemand", value === onDemand || null); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.withAlpha(Theme.outline, 0.2) - visible: compositorSettingsLoader.active - } - - Loader { - id: compositorSettingsLoader - width: parent.width - active: root.isConnected && compositorSettingsSource !== "" - source: compositorSettingsSource - - property string compositorSettingsSource: { - switch (CompositorService.compositor) { - case "niri": - return "NiriOutputSettings.qml"; - case "hyprland": - return "HyprlandOutputSettings.qml"; - default: - return ""; - } - } - - onLoaded: { - item.outputName = root.outputName; - item.outputData = root.outputData; - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfigTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfigTab.qml deleted file mode 100644 index 61b373d..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayConfigTab.qml +++ /dev/null @@ -1,540 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals -import qs.Services -import qs.Widgets -import qs.Modules.Settings.DisplayConfig - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string selectedProfileId: SettingsData.getActiveDisplayProfile(CompositorService.compositor) - property bool showNewProfileDialog: false - property bool showDeleteConfirmDialog: false - property bool showRenameDialog: false - property string newProfileName: "" - property string renameProfileName: "" - - function getProfileOptions() { - const profiles = DisplayConfigState.validatedProfiles; - const options = []; - for (const id in profiles) - options.push(profiles[id].name); - return options; - } - - function getProfileIds() { - return Object.keys(DisplayConfigState.validatedProfiles); - } - - function getProfileIdByName(name) { - const profiles = DisplayConfigState.validatedProfiles; - for (const id in profiles) { - if (profiles[id].name === name) - return id; - } - return ""; - } - - function getProfileNameById(id) { - const profiles = DisplayConfigState.validatedProfiles; - return profiles[id]?.name || ""; - } - - Connections { - target: DisplayConfigState - function onChangesApplied(changeDescriptions) { - confirmationModal.changes = changeDescriptions; - confirmationModal.open(); - } - function onChangesConfirmed() { - } - function onChangesReverted() { - } - function onProfileActivated(profileId, profileName) { - root.selectedProfileId = profileId; - ToastService.showInfo(I18n.tr("Profile activated: %1").arg(profileName)); - } - function onProfileSaved(profileId, profileName) { - root.selectedProfileId = profileId; - ToastService.showInfo(I18n.tr("Profile saved: %1").arg(profileName)); - } - function onProfileDeleted(profileId) { - root.selectedProfileId = SettingsData.getActiveDisplayProfile(CompositorService.compositor); - ToastService.showInfo(I18n.tr("Profile deleted")); - } - function onProfileError(message) { - ToastService.showError(I18n.tr("Profile error"), message); - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - IncludeWarningBox { - width: parent.width - } - - StyledRect { - width: parent.width - height: profileSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - visible: DisplayConfigState.hasOutputBackend - - Column { - id: profileSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "tune" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - autoSelectColumn.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Display Profiles") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Save and switch between display configurations") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - // ! TODO - auto profile switching is buggy on niri and other compositors - Column { - id: autoSelectColumn - visible: false // disabled for now - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Auto") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - - DankToggle { - id: autoSelectToggle - checked: false // disabled for now - enabled: false - onToggled: checked => { - // disabled for now - // SettingsData.displayProfileAutoSelect = checked; - // SettingsData.saveSettings(); - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: !root.showNewProfileDialog && !root.showDeleteConfirmDialog && !root.showRenameDialog - - DankDropdown { - id: profileDropdown - width: parent.width - newButton.width - deleteButton.width - Theme.spacingS * 2 - compactMode: true - dropdownWidth: width - options: root.getProfileOptions() - currentValue: root.getProfileNameById(root.selectedProfileId) - emptyText: I18n.tr("No profiles") - onValueChanged: value => { - const profileId = root.getProfileIdByName(value); - if (profileId && profileId !== root.selectedProfileId) - DisplayConfigState.activateProfile(profileId); - } - } - - DankButton { - id: newButton - iconName: "add" - text: "" - buttonHeight: 40 - horizontalPadding: Theme.spacingM - backgroundColor: Theme.surfaceContainer - textColor: Theme.surfaceText - onClicked: { - root.newProfileName = ""; - root.showNewProfileDialog = true; - } - } - - DankButton { - id: deleteButton - iconName: "delete" - text: "" - buttonHeight: 40 - horizontalPadding: Theme.spacingM - backgroundColor: Theme.surfaceContainer - textColor: Theme.error - enabled: root.selectedProfileId !== "" - onClicked: root.showDeleteConfirmDialog = true - } - } - - Rectangle { - width: parent.width - height: newProfileRow.height + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - visible: root.showNewProfileDialog - - Row { - id: newProfileRow - anchors.centerIn: parent - width: parent.width - Theme.spacingM * 2 - spacing: Theme.spacingS - - DankTextField { - id: newProfileField - width: parent.width - createButton.width - cancelNewButton.width - Theme.spacingS * 2 - placeholderText: I18n.tr("Profile name") - text: root.newProfileName - onTextChanged: root.newProfileName = text - onAccepted: { - if (text.trim()) - DisplayConfigState.createProfile(text.trim()); - root.showNewProfileDialog = false; - } - Component.onCompleted: forceActiveFocus() - } - - DankButton { - id: createButton - text: I18n.tr("Create") - enabled: root.newProfileName.trim() !== "" - onClicked: { - DisplayConfigState.createProfile(root.newProfileName.trim()); - root.showNewProfileDialog = false; - } - } - - DankButton { - id: cancelNewButton - text: I18n.tr("Cancel") - backgroundColor: "transparent" - textColor: Theme.surfaceText - onClicked: root.showNewProfileDialog = false - } - } - } - - Rectangle { - width: parent.width - height: deleteConfirmColumn.height + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - visible: root.showDeleteConfirmDialog - - Column { - id: deleteConfirmColumn - anchors.centerIn: parent - width: parent.width - Theme.spacingM * 2 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Delete profile \"%1\"?").arg(root.getProfileNameById(root.selectedProfileId)) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - } - - Row { - spacing: Theme.spacingS - anchors.right: parent.right - - DankButton { - text: I18n.tr("Delete") - backgroundColor: Theme.error - textColor: Theme.primaryText - onClicked: { - DisplayConfigState.deleteProfile(root.selectedProfileId); - root.showDeleteConfirmDialog = false; - } - } - - DankButton { - text: I18n.tr("Cancel") - backgroundColor: "transparent" - textColor: Theme.surfaceText - onClicked: root.showDeleteConfirmDialog = false - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: DisplayConfigState.matchedProfile !== "" - - DankIcon { - name: "check_circle" - size: 16 - color: Theme.success - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Matches profile: %1").arg(root.getProfileNameById(DisplayConfigState.matchedProfile)) - font.pixelSize: Theme.fontSizeSmall - color: Theme.success - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - - StyledRect { - width: parent.width - height: monitorConfigSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - visible: DisplayConfigState.hasOutputBackend - - Column { - id: monitorConfigSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "monitor" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - (displayFormatColumn.visible ? displayFormatColumn.width + Theme.spacingM : 0) - (snapColumn.visible ? snapColumn.width + Theme.spacingM : 0) - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Monitor Configuration") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Arrange displays and configure resolution, refresh rate, and VRR") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Column { - id: snapColumn - visible: true - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Snap") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - - DankToggle { - id: snapToggle - checked: SettingsData.displaySnapToEdge - onToggled: checked => { - SettingsData.displaySnapToEdge = checked; - SettingsData.saveSettings(); - } - } - } - - Column { - id: displayFormatColumn - visible: !CompositorService.isDwl - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Config Format") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - - DankButtonGroup { - id: displayFormatGroup - model: [I18n.tr("Name"), I18n.tr("Model")] - currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0 - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const newMode = index === 1 ? "model" : "system"; - DisplayConfigState.setOriginalDisplayNameMode(SettingsData.displayNameMode); - SettingsData.displayNameMode = newMode; - } - - Connections { - target: SettingsData - function onDisplayNameModeChanged() { - displayFormatGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0; - } - } - } - } - } - - MonitorCanvas { - width: parent.width - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingS - visible: { - const all = DisplayConfigState.allOutputs || {}; - const disconnected = Object.keys(all).filter(k => !all[k]?.connected); - return disconnected.length > 0; - } - - StyledText { - text: { - const all = DisplayConfigState.allOutputs || {}; - const disconnected = Object.keys(all).filter(k => !all[k]?.connected); - if (SettingsData.displayShowDisconnected) - return I18n.tr("%1 disconnected").arg(disconnected.length); - return I18n.tr("%1 disconnected (hidden)").arg(disconnected.length); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: SettingsData.displayShowDisconnected ? I18n.tr("Hide") : I18n.tr("Show") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - SettingsData.displayShowDisconnected = !SettingsData.displayShowDisconnected; - SettingsData.saveSettings(); - } - } - } - } - - Repeater { - model: { - const keys = Object.keys(DisplayConfigState.allOutputs || {}); - if (SettingsData.displayShowDisconnected) - return keys; - return keys.filter(k => DisplayConfigState.allOutputs[k]?.connected); - } - - delegate: OutputCard { - required property string modelData - outputName: modelData - outputData: DisplayConfigState.allOutputs[modelData] - } - } - } - - Row { - LayoutMirroring.enabled: false - width: parent.width - spacing: Theme.spacingS - visible: DisplayConfigState.hasPendingChanges - layoutDirection: Qt.RightToLeft - - DankButton { - text: I18n.tr("Apply Changes") - iconName: "check" - onClicked: DisplayConfigState.applyChanges() - } - - DankButton { - text: I18n.tr("Discard") - backgroundColor: "transparent" - textColor: Theme.surfaceText - onClicked: DisplayConfigState.discardChanges() - } - } - } - } - - NoBackendMessage { - width: parent.width - visible: !DisplayConfigState.hasOutputBackend - } - } - } - - DisplayConfirmationModal { - id: confirmationModal - onConfirmed: DisplayConfigState.confirmChanges() - onReverted: DisplayConfigState.revertChanges() - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayWidgetsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayWidgetsTab.qml deleted file mode 100644 index 59f6513..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DisplayWidgetsTab.qml +++ /dev/null @@ -1,522 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - function getBarComponentsFromSettings() { - const bars = SettingsData.barConfigs || []; - return bars.map(bar => ({ - "id": "bar:" + bar.id, - "name": bar.name || "Bar", - "description": I18n.tr("Individual bar configuration"), - "icon": "toolbar", - "barId": bar.id - })); - } - - property var variantComponents: getVariantComponentsList() - - function getVariantComponentsList() { - return [...getBarComponentsFromSettings(), - { - "id": "dock", - "name": I18n.tr("Application Dock"), - "description": I18n.tr("Bottom dock for pinned and running applications"), - "icon": "dock" - }, - { - "id": "notifications", - "name": I18n.tr("Notification Popups"), - "description": I18n.tr("Notification toast popups"), - "icon": "notifications" - }, - { - "id": "wallpaper", - "name": I18n.tr("Wallpaper"), - "description": I18n.tr("Desktop background images"), - "icon": "wallpaper" - }, - { - "id": "osd", - "name": I18n.tr("On-Screen Displays"), - "description": I18n.tr("Volume, brightness, and other system OSDs"), - "icon": "picture_in_picture" - }, - { - "id": "toast", - "name": I18n.tr("Toast Messages"), - "description": I18n.tr("System toast notifications"), - "icon": "campaign" - }, - { - "id": "notepad", - "name": I18n.tr("Notepad Slideout"), - "description": I18n.tr("Quick note-taking slideout panel"), - "icon": "sticky_note_2" - } - ]; - } - - Connections { - target: SettingsData - function onBarConfigsChanged() { - variantComponents = getVariantComponentsList(); - } - } - - function getScreenPreferences(componentId) { - if (componentId.startsWith("bar:")) { - const barId = componentId.substring(4); - const barConfig = SettingsData.getBarConfig(barId); - return barConfig?.screenPreferences || ["all"]; - } - return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"]; - } - - function setScreenPreferences(componentId, screenNames) { - if (componentId.startsWith("bar:")) { - const barId = componentId.substring(4); - SettingsData.updateBarConfig(barId, { - "screenPreferences": screenNames - }); - return; - } - var prefs = SettingsData.screenPreferences || {}; - var newPrefs = Object.assign({}, prefs); - newPrefs[componentId] = screenNames; - SettingsData.set("screenPreferences", newPrefs); - } - - function getShowOnLastDisplay(componentId) { - if (componentId.startsWith("bar:")) { - const barId = componentId.substring(4); - const barConfig = SettingsData.getBarConfig(barId); - return barConfig?.showOnLastDisplay ?? true; - } - return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false; - } - - function setShowOnLastDisplay(componentId, enabled) { - if (componentId.startsWith("bar:")) { - const barId = componentId.substring(4); - SettingsData.updateBarConfig(barId, { - "showOnLastDisplay": enabled - }); - return; - } - var prefs = SettingsData.showOnLastDisplay || {}; - var newPrefs = Object.assign({}, prefs); - newPrefs[componentId] = enabled; - SettingsData.set("showOnLastDisplay", newPrefs); - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - StyledRect { - width: parent.width - height: screensInfoSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: screensInfoSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "monitor" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Connected Displays") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Configure which displays show shell components") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Column { - width: parent.width - spacing: Theme.spacingXS - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Available Screens (%1)").arg(Quickshell.screens.length) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignLeft - } - - Item { - width: 1 - height: 1 - Layout.fillWidth: true - } - - Column { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Display Name Format") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - DankButtonGroup { - id: displayModeGroup - model: [I18n.tr("Name"), I18n.tr("Model")] - currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0 - onSelectionChanged: (index, selected) => { - if (!selected) - return; - SettingsData.displayNameMode = index === 1 ? "model" : "system"; - SettingsData.saveSettings(); - } - - Connections { - target: SettingsData - function onDisplayNameModeChanged() { - displayModeGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0; - } - } - } - } - } - } - - Repeater { - model: Quickshell.screens - - delegate: Rectangle { - width: parent.width - height: screenRow.implicitHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) - border.width: 0 - - Row { - id: screenRow - - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingM - - DankIcon { - name: "desktop_windows" - size: Theme.iconSize - 4 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM * 2 - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS / 2 - - StyledText { - text: SettingsData.getScreenDisplayName(modelData) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - width: parent.width - spacing: Theme.spacingS - - property var wlrOutput: WlrOutputService.wlrOutputAvailable ? WlrOutputService.getOutput(modelData.name) : null - property var currentMode: wlrOutput?.currentMode - - StyledText { - text: { - if (parent.currentMode) { - return parent.currentMode.width + "×" + parent.currentMode.height + "@" + Math.round(parent.currentMode.refresh / 1000) + "Hz"; - } - return modelData.width + "×" + modelData.height; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: SettingsData.displayNameMode === "system" ? (modelData.model || "Unknown Model") : modelData.name - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingL - - Repeater { - model: root.variantComponents - - delegate: StyledRect { - width: parent.width - height: componentSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: componentSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: modelData.icon - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: modelData.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Show on screens:") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Column { - property string componentId: modelData.id - - width: parent.width - spacing: Theme.spacingXS - - DankToggle { - width: parent.width - text: I18n.tr("All displays") - description: I18n.tr("Show on all connected displays") - checked: { - var prefs = root.getScreenPreferences(parent.componentId); - return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all"); - } - onToggled: checked => { - if (checked) { - root.setScreenPreferences(parent.componentId, ["all"]); - } else { - root.setScreenPreferences(parent.componentId, []); - const cid = parent.componentId; - if (["dankBar", "dock", "notifications", "osd", "toast"].includes(cid) || cid.startsWith("bar:")) { - root.setShowOnLastDisplay(cid, true); - } - } - } - } - - DankToggle { - width: parent.width - text: I18n.tr("Focused monitor only") - description: I18n.tr("Show notifications only on the currently focused monitor") - visible: parent.componentId === "notifications" - checked: SettingsData.notificationFocusedMonitor - onToggled: checked => SettingsData.set("notificationFocusedMonitor", checked) - } - - DankToggle { - width: parent.width - text: I18n.tr("Show on Last Display") - description: I18n.tr("Always show when there's only one connected display") - checked: root.getShowOnLastDisplay(parent.componentId) - visible: { - const prefs = root.getScreenPreferences(parent.componentId); - const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all"); - const cid = parent.componentId; - const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad"].includes(cid) || cid.startsWith("bar:"); - return !isAll && isRelevantComponent; - } - onToggled: checked => { - root.setShowOnLastDisplay(parent.componentId, checked); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: { - var prefs = root.getScreenPreferences(parent.componentId); - return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all"); - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: { - var prefs = root.getScreenPreferences(parent.componentId); - return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all"); - } - - Repeater { - model: Quickshell.screens - - delegate: DankToggle { - property var screenData: modelData - property string componentId: parent.parent.componentId - - width: parent.width - text: SettingsData.getScreenDisplayName(screenData) - description: screenData.width + "×" + screenData.height + " • " + (SettingsData.displayNameMode === "system" ? (screenData.model || "Unknown Model") : screenData.name) - checked: { - var prefs = root.getScreenPreferences(componentId); - if (typeof prefs[0] === "string" && prefs[0] === "all") - return false; - return SettingsData.isScreenInPreferences(screenData, prefs); - } - onToggled: checked => { - var currentPrefs = root.getScreenPreferences(componentId); - if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") { - currentPrefs = []; - } - - const screenModelIndex = SettingsData.getScreenModelIndex(screenData); - - var newPrefs = currentPrefs.filter(pref => { - if (typeof pref === "string") - return false; - if (pref.modelIndex !== undefined && screenModelIndex >= 0) { - return !(pref.model === screenData.model && pref.modelIndex === screenModelIndex); - } - return pref.name !== screenData.name || pref.model !== screenData.model; - }); - - if (checked) { - const prefObj = { - "name": screenData.name, - "model": screenData.model || "" - }; - if (screenModelIndex >= 0) { - prefObj.modelIndex = screenModelIndex; - } - newPrefs.push(prefObj); - } - - root.setScreenPreferences(componentId, newPrefs); - } - } - } - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DockTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DockTab.qml deleted file mode 100644 index 9b281a3..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/DockTab.qml +++ /dev/null @@ -1,657 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - FileBrowserModal { - id: dockLogoFileBrowser - browserTitle: I18n.tr("Select Dock Launcher Logo") - browserIcon: "image" - browserType: "generic" - filterExtensions: ["*.svg", "*.png", "*.jpg", "*.jpeg", "*.webp"] - onFileSelected: path => SettingsData.set("dockLauncherLogoCustomPath", path.replace("file://", "")) - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "dock_to_bottom" - title: I18n.tr("Dock Visibility") - settingKey: "dockVisibility" - - SettingsToggleRow { - settingKey: "showDock" - tags: ["dock", "show", "display", "enable"] - text: I18n.tr("Show Dock") - description: I18n.tr("Display a dock with pinned and running applications") - checked: SettingsData.showDock - onToggled: checked => SettingsData.setShowDock(checked) - } - - SettingsToggleRow { - settingKey: "dockAutoHide" - tags: ["dock", "autohide", "hide", "hover"] - text: I18n.tr("Auto-hide Dock") - description: I18n.tr("Always hide the dock and reveal it when hovering near the dock area") - checked: SettingsData.dockAutoHide - visible: SettingsData.showDock - onToggled: checked => { - if (checked && SettingsData.dockSmartAutoHide) { - SettingsData.set("dockSmartAutoHide", false); - } - SettingsData.set("dockAutoHide", checked); - } - } - - SettingsToggleRow { - settingKey: "dockSmartAutoHide" - tags: ["dock", "smart", "autohide", "windows", "overlap", "intelligent"] - text: I18n.tr("Intelligent Auto-hide") - description: I18n.tr("Show dock when floating windows don't overlap its area") - checked: SettingsData.dockSmartAutoHide - visible: SettingsData.showDock && (CompositorService.isNiri || CompositorService.isHyprland) - onToggled: checked => { - if (checked && SettingsData.dockAutoHide) { - SettingsData.set("dockAutoHide", false); - } - SettingsData.set("dockSmartAutoHide", checked); - } - } - - SettingsToggleRow { - settingKey: "dockOpenOnOverview" - tags: ["dock", "overview", "niri"] - text: I18n.tr("Show on Overview") - description: I18n.tr("Always show the dock when niri's overview is open") - checked: SettingsData.dockOpenOnOverview - visible: CompositorService.isNiri - onToggled: checked => SettingsData.set("dockOpenOnOverview", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "swap_vert" - title: I18n.tr("Position") - settingKey: "dockPosition" - - Item { - width: parent.width - height: dockPositionButtonGroup.height - - DankButtonGroup { - id: dockPositionButtonGroup - anchors.horizontalCenter: parent.horizontalCenter - model: [I18n.tr("Top"), I18n.tr("Bottom"), I18n.tr("Left"), I18n.tr("Right")] - currentIndex: { - switch (SettingsData.dockPosition) { - case SettingsData.Position.Top: - return 0; - case SettingsData.Position.Bottom: - return 1; - case SettingsData.Position.Left: - return 2; - case SettingsData.Position.Right: - return 3; - default: - return 1; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.setDockPosition(SettingsData.Position.Top); - break; - case 1: - SettingsData.setDockPosition(SettingsData.Position.Bottom); - break; - case 2: - SettingsData.setDockPosition(SettingsData.Position.Left); - break; - case 3: - SettingsData.setDockPosition(SettingsData.Position.Right); - break; - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "apps" - title: I18n.tr("Behavior") - settingKey: "dockBehavior" - - SettingsToggleRow { - settingKey: "dockIsolateDisplays" - tags: ["dock", "isolate", "monitor", "multi-monitor"] - text: I18n.tr("Isolate Displays") - description: I18n.tr("Only show windows from the current monitor on each dock") - checked: SettingsData.dockIsolateDisplays - onToggled: checked => SettingsData.set("dockIsolateDisplays", checked) - } - - SettingsToggleRow { - settingKey: "dockGroupByApp" - tags: ["dock", "group", "windows", "app"] - text: I18n.tr("Group by App") - description: I18n.tr("Group multiple windows of the same app together with a window count indicator") - checked: SettingsData.dockGroupByApp - onToggled: checked => SettingsData.set("dockGroupByApp", checked) - } - - SettingsToggleRow { - settingKey: "dockRestoreSpecialWorkspaceOnClick" - tags: ["dock", "hyprland", "special", "workspace", "restore"] - text: I18n.tr("Restore Special Workspace Windows") - description: I18n.tr("When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window") - checked: SettingsData.dockRestoreSpecialWorkspaceOnClick - visible: CompositorService.isHyprland - onToggled: checked => SettingsData.set("dockRestoreSpecialWorkspaceOnClick", checked) - } - - SettingsButtonGroupRow { - settingKey: "dockIndicatorStyle" - tags: ["dock", "indicator", "style", "circle", "line"] - text: I18n.tr("Indicator Style") - model: [I18n.tr("Circle", "dock indicator style option"), I18n.tr("Line", "dock indicator style option")] - buttonPadding: Theme.spacingS - minButtonWidth: 44 - textSize: Theme.fontSizeSmall - currentIndex: SettingsData.dockIndicatorStyle === "circle" ? 0 : 1 - onSelectionChanged: (index, selected) => { - if (selected) { - SettingsData.set("dockIndicatorStyle", index === 0 ? "circle" : "line"); - } - } - } - - SettingsSliderRow { - settingKey: "dockMaxVisibleApps" - tags: ["dock", "overflow", "max", "apps", "limit"] - text: I18n.tr("Max Pinned Apps (0 = Unlimited)") - minimum: 0 - maximum: 30 - value: SettingsData.dockMaxVisibleApps - defaultValue: 0 - unit: "" - onSliderValueChanged: newValue => SettingsData.set("dockMaxVisibleApps", newValue) - } - - SettingsSliderRow { - settingKey: "dockMaxVisibleRunningApps" - tags: ["dock", "overflow", "max", "running", "apps", "limit"] - text: I18n.tr("Max Running Apps (0 = Unlimited)") - minimum: 0 - maximum: 30 - value: SettingsData.dockMaxVisibleRunningApps - defaultValue: 0 - unit: "" - onSliderValueChanged: newValue => SettingsData.set("dockMaxVisibleRunningApps", newValue) - } - - SettingsToggleRow { - settingKey: "dockShowOverflowBadge" - tags: ["dock", "overflow", "badge", "count", "indicator"] - text: I18n.tr("Show Overflow Badge Count") - description: I18n.tr("Displays count when overflow is active") - checked: SettingsData.dockShowOverflowBadge - onToggled: checked => SettingsData.set("dockShowOverflowBadge", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "apps" - title: I18n.tr("Launcher Button") - settingKey: "dockLauncher" - - SettingsToggleRow { - settingKey: "dockLauncherEnabled" - tags: ["dock", "launcher", "button", "apps"] - text: I18n.tr("Show Launcher Button") - checked: SettingsData.dockLauncherEnabled - onToggled: checked => SettingsData.set("dockLauncherEnabled", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingL - visible: SettingsData.dockLauncherEnabled - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Icon") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: parent.width - height: logoModeGroup.implicitHeight - clip: true - - DankButtonGroup { - id: logoModeGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 480 ? 44 : 64 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: { - const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo"), I18n.tr("Dank")]; - if (CompositorService.isNiri) { - modes.push("niri"); - } else if (CompositorService.isHyprland) { - modes.push("Hyprland"); - } else if (CompositorService.isDwl) { - modes.push("mango"); - } else if (CompositorService.isSway) { - modes.push("Sway"); - } else if (CompositorService.isScroll) { - modes.push("Scroll"); - } else if (CompositorService.isMiracle) { - modes.push("Miracle"); - } else { - modes.push(I18n.tr("Compositor")); - } - modes.push(I18n.tr("Custom")); - return modes; - } - currentIndex: { - if (SettingsData.dockLauncherLogoMode === "apps") - return 0; - if (SettingsData.dockLauncherLogoMode === "os") - return 1; - if (SettingsData.dockLauncherLogoMode === "dank") - return 2; - if (SettingsData.dockLauncherLogoMode === "compositor") - return 3; - if (SettingsData.dockLauncherLogoMode === "custom") - return 4; - return 0; - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.set("dockLauncherLogoMode", "apps"); - break; - case 1: - SettingsData.set("dockLauncherLogoMode", "os"); - break; - case 2: - SettingsData.set("dockLauncherLogoMode", "dank"); - break; - case 3: - SettingsData.set("dockLauncherLogoMode", "compositor"); - break; - case 4: - SettingsData.set("dockLauncherLogoMode", "custom"); - break; - } - } - } - } - } - - Row { - width: parent.width - visible: SettingsData.dockLauncherLogoMode === "custom" - spacing: Theme.spacingM - - StyledRect { - width: parent.width - selectButton.width - Theme.spacingM - height: 36 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) - border.color: Theme.outlineStrong - border.width: 1 - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - text: SettingsData.dockLauncherLogoCustomPath || I18n.tr("Select an image file...") - font.pixelSize: Theme.fontSizeMedium - color: SettingsData.dockLauncherLogoCustomPath ? Theme.surfaceText : Theme.outlineButton - width: parent.width - Theme.spacingM * 2 - elide: Text.ElideMiddle - } - } - - DankActionButton { - id: selectButton - iconName: "folder_open" - width: 36 - height: 36 - onClicked: dockLogoFileBrowser.open() - } - } - - Column { - width: parent.width - spacing: Theme.spacingL - visible: SettingsData.dockLauncherLogoMode !== "apps" - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Color Override") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: parent.width - height: colorOverrideRow.implicitHeight - clip: true - - Row { - id: colorOverrideRow - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - DankButtonGroup { - id: colorModeGroup - buttonPadding: parent.parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.parent.width < 480 ? 44 : 64 - textSize: parent.parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")] - currentIndex: { - const override = SettingsData.dockLauncherLogoColorOverride; - if (override === "") - return 0; - if (override === "primary") - return 1; - if (override === "surface") - return 2; - return 3; - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.set("dockLauncherLogoColorOverride", ""); - break; - case 1: - SettingsData.set("dockLauncherLogoColorOverride", "primary"); - break; - case 2: - SettingsData.set("dockLauncherLogoColorOverride", "surface"); - break; - case 3: - const currentOverride = SettingsData.dockLauncherLogoColorOverride; - const isPreset = currentOverride === "" || currentOverride === "primary" || currentOverride === "surface"; - if (isPreset) { - SettingsData.set("dockLauncherLogoColorOverride", "#ffffff"); - } - break; - } - } - } - - Rectangle { - id: colorPickerCircle - visible: { - const override = SettingsData.dockLauncherLogoColorOverride; - return override !== "" && override !== "primary" && override !== "surface"; - } - width: 36 - height: 36 - radius: 18 - color: { - const override = SettingsData.dockLauncherLogoColorOverride; - if (override !== "" && override !== "primary" && override !== "surface") - return override; - return "#ffffff"; - } - border.color: Theme.outline - border.width: 1 - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - PopoutService.colorPickerModal.selectedColor = SettingsData.dockLauncherLogoColorOverride; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Dock Launcher Logo Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - SettingsData.set("dockLauncherLogoColorOverride", selectedColor); - }; - PopoutService.colorPickerModal.show(); - } - } - } - } - } - } - - SettingsSliderRow { - settingKey: "dockLauncherLogoSizeOffset" - tags: ["dock", "launcher", "logo", "size", "offset", "scale"] - text: I18n.tr("Size Offset") - minimum: -12 - maximum: 12 - value: SettingsData.dockLauncherLogoSizeOffset - defaultValue: 0 - onSliderValueChanged: newValue => SettingsData.set("dockLauncherLogoSizeOffset", newValue) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: { - const override = SettingsData.dockLauncherLogoColorOverride; - return override !== "" && override !== "primary" && override !== "surface"; - } - - SettingsSliderRow { - settingKey: "dockLauncherLogoBrightness" - tags: ["dock", "launcher", "logo", "brightness", "color"] - text: I18n.tr("Brightness") - minimum: 0 - maximum: 100 - value: Math.round(SettingsData.dockLauncherLogoBrightness * 100) - unit: "%" - defaultValue: 50 - onSliderValueChanged: newValue => SettingsData.set("dockLauncherLogoBrightness", newValue / 100) - } - - SettingsSliderRow { - settingKey: "dockLauncherLogoContrast" - tags: ["dock", "launcher", "logo", "contrast", "color"] - text: I18n.tr("Contrast") - minimum: 0 - maximum: 200 - value: Math.round(SettingsData.dockLauncherLogoContrast * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("dockLauncherLogoContrast", newValue / 100) - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "photo_size_select_large" - title: I18n.tr("Sizing") - settingKey: "dockSizing" - - SettingsSliderRow { - settingKey: "dockIconSize" - tags: ["dock", "icon", "size", "scale"] - text: I18n.tr("Icon Size") - value: SettingsData.dockIconSize - minimum: 24 - maximum: 96 - unit: "px" - defaultValue: 48 - onSliderValueChanged: newValue => SettingsData.set("dockIconSize", newValue) - } - } - - SettingsCard { - width: parent.width - iconName: "space_bar" - title: I18n.tr("Spacing") - settingKey: "dockSpacing" - collapsible: true - expanded: false - - SettingsSliderRow { - text: I18n.tr("Padding") - value: SettingsData.dockSpacing - minimum: 0 - maximum: 32 - defaultValue: 8 - onSliderValueChanged: newValue => SettingsData.set("dockSpacing", newValue) - } - - SettingsSliderRow { - text: I18n.tr("Exclusive Zone Offset") - value: SettingsData.dockBottomGap - minimum: -100 - maximum: 100 - defaultValue: 0 - onSliderValueChanged: newValue => SettingsData.set("dockBottomGap", newValue) - } - - SettingsSliderRow { - text: I18n.tr("Margin") - value: SettingsData.dockMargin - minimum: 0 - maximum: 100 - defaultValue: 0 - onSliderValueChanged: newValue => SettingsData.set("dockMargin", newValue) - } - } - - SettingsCard { - width: parent.width - iconName: "opacity" - title: I18n.tr("Transparency") - settingKey: "dockTransparency" - - SettingsSliderRow { - text: I18n.tr("Dock Transparency") - value: Math.round(SettingsData.dockTransparency * 100) - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 85 - onSliderValueChanged: newValue => SettingsData.set("dockTransparency", newValue / 100) - } - } - - SettingsCard { - width: parent.width - iconName: "border_style" - title: I18n.tr("Border") - settingKey: "dockBorder" - collapsible: true - expanded: false - - SettingsToggleRow { - text: I18n.tr("Border") - description: I18n.tr("Add a border around the dock") - checked: SettingsData.dockBorderEnabled - onToggled: checked => SettingsData.set("dockBorderEnabled", checked) - } - - SettingsButtonGroupRow { - text: I18n.tr("Border Color") - description: I18n.tr("Choose the border accent color") - visible: SettingsData.dockBorderEnabled - model: [I18n.tr("Surface", "color option"), I18n.tr("Secondary", "color option"), I18n.tr("Primary", "color option")] - buttonPadding: Theme.spacingS - minButtonWidth: 44 - textSize: Theme.fontSizeSmall - currentIndex: { - switch (SettingsData.dockBorderColor) { - case "surfaceText": - return 0; - case "secondary": - return 1; - case "primary": - return 2; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.set("dockBorderColor", "surfaceText"); - break; - case 1: - SettingsData.set("dockBorderColor", "secondary"); - break; - case 2: - SettingsData.set("dockBorderColor", "primary"); - break; - } - } - } - - SettingsSliderRow { - text: I18n.tr("Border Opacity") - visible: SettingsData.dockBorderEnabled - value: SettingsData.dockBorderOpacity * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("dockBorderOpacity", newValue / 100) - } - - SettingsSliderRow { - text: I18n.tr("Border Thickness") - visible: SettingsData.dockBorderEnabled - value: SettingsData.dockBorderThickness - minimum: 1 - maximum: 10 - unit: "px" - defaultValue: 1 - onSliderValueChanged: newValue => SettingsData.set("dockBorderThickness", newValue) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GammaControlTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GammaControlTab.qml deleted file mode 100644 index 7d08c5a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GammaControlTab.qml +++ /dev/null @@ -1,663 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - function formatGammaTime(isoString) { - if (!isoString) - return ""; - try { - const date = new Date(isoString); - if (isNaN(date.getTime())) - return ""; - return date.toLocaleTimeString(Qt.locale(), "HH:mm"); - } catch (e) { - return ""; - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - StyledRect { - width: parent.width - height: gammaSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - Column { - id: gammaSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "brightness_6" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Gamma Control") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: nightModeToggle - - width: parent.width - text: I18n.tr("Night Mode") - description: DisplayService.gammaControlAvailable ? I18n.tr("Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.") : I18n.tr("Gamma control not available. Requires DMS API v6+.") - checked: DisplayService.nightModeEnabled - enabled: DisplayService.gammaControlAvailable - onToggled: checked => { - DisplayService.toggleNightMode(); - } - - Connections { - function onNightModeEnabledChanged() { - nightModeToggle.checked = DisplayService.nightModeEnabled; - } - - target: DisplayService - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - visible: DisplayService.gammaControlAvailable - - SettingsSliderRow { - id: nightTempSlider - settingKey: "nightModeTemperature" - tags: ["gamma", "night", "temperature", "kelvin", "warm", "color", "blue light"] - width: parent.width - parent.leftPadding - parent.rightPadding - text: SessionData.nightModeAutoEnabled ? I18n.tr("Night Temperature") : I18n.tr("Color Temperature") - description: SessionData.nightModeAutoEnabled ? I18n.tr("Color temperature for night mode") : I18n.tr("Warm color temperature to apply") - minimum: 2500 - maximum: 6000 - step: 100 - unit: "K" - value: SessionData.nightModeTemperature - onSliderValueChanged: newValue => { - SessionData.setNightModeTemperature(newValue); - if (SessionData.nightModeHighTemperature < newValue) - SessionData.setNightModeHighTemperature(newValue); - } - } - - SettingsSliderRow { - id: dayTempSlider - settingKey: "nightModeHighTemperature" - tags: ["gamma", "day", "temperature", "kelvin", "color"] - width: parent.width - parent.leftPadding - parent.rightPadding - text: I18n.tr("Day Temperature") - description: I18n.tr("Color temperature for day time") - minimum: SessionData.nightModeTemperature - maximum: 10000 - step: 100 - unit: "K" - value: Math.max(SessionData.nightModeHighTemperature, SessionData.nightModeTemperature) - visible: SessionData.nightModeAutoEnabled - onSliderValueChanged: newValue => SessionData.setNightModeHighTemperature(newValue) - } - } - - DankToggle { - id: automaticToggle - width: parent.width - text: I18n.tr("Automatic Control") - description: I18n.tr("Only adjust gamma based on time or location rules.") - checked: SessionData.nightModeAutoEnabled - visible: DisplayService.gammaControlAvailable - onToggled: checked => { - if (checked && !DisplayService.nightModeEnabled) { - DisplayService.toggleNightMode(); - } else if (!checked && DisplayService.nightModeEnabled) { - DisplayService.toggleNightMode(); - } - SessionData.setNightModeAutoEnabled(checked); - } - - Connections { - target: SessionData - function onNightModeAutoEnabledChanged() { - automaticToggle.checked = SessionData.nightModeAutoEnabled; - } - } - } - - Column { - id: automaticSettings - width: parent.width - spacing: Theme.spacingS - visible: SessionData.nightModeAutoEnabled && DisplayService.gammaControlAvailable - - Connections { - target: SessionData - function onNightModeAutoEnabledChanged() { - automaticSettings.visible = SessionData.nightModeAutoEnabled; - } - } - - Item { - width: parent.width - height: 45 + Theme.spacingM - - DankTabBar { - id: modeTabBarNight - width: 200 - height: 45 - anchors.horizontalCenter: parent.horizontalCenter - model: [ - { - "text": I18n.tr("Time"), - "icon": "access_time" - }, - { - "text": I18n.tr("Location"), - "icon": "place" - } - ] - - Component.onCompleted: { - currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0; - Qt.callLater(updateIndicator); - } - - onTabClicked: index => { - DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time"); - currentIndex = index; - } - - Connections { - target: SessionData - function onNightModeAutoModeChanged() { - modeTabBarNight.currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0; - Qt.callLater(modeTabBarNight.updateIndicator); - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.nightModeAutoMode === "time" - - Column { - spacing: Theme.spacingXS - anchors.horizontalCenter: parent.horizontalCenter - - Row { - spacing: Theme.spacingM - - StyledText { - text: "" - width: 50 - height: 20 - } - - StyledText { - text: I18n.tr("Hour") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: 70 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: I18n.tr("Minute") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: 70 - horizontalAlignment: Text.AlignHCenter - } - } - - Row { - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Start") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: 50 - height: 40 - verticalAlignment: Text.AlignVCenter - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.nightModeStartHour.toString() - options: { - var hours = []; - for (var i = 0; i < 24; i++) { - hours.push(i.toString()); - } - return hours; - } - onValueChanged: value => { - SessionData.setNightModeStartHour(parseInt(value)); - } - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.nightModeStartMinute.toString().padStart(2, '0') - options: { - var minutes = []; - for (var i = 0; i < 60; i += 5) { - minutes.push(i.toString().padStart(2, '0')); - } - return minutes; - } - onValueChanged: value => { - SessionData.setNightModeStartMinute(parseInt(value)); - } - } - } - - Row { - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("End") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: 50 - height: 40 - verticalAlignment: Text.AlignVCenter - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.nightModeEndHour.toString() - options: { - var hours = []; - for (var i = 0; i < 24; i++) { - hours.push(i.toString()); - } - return hours; - } - onValueChanged: value => { - SessionData.setNightModeEndHour(parseInt(value)); - } - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.nightModeEndMinute.toString().padStart(2, '0') - options: { - var minutes = []; - for (var i = 0; i < 60; i += 5) { - minutes.push(i.toString().padStart(2, '0')); - } - return minutes; - } - onValueChanged: value => { - SessionData.setNightModeEndMinute(parseInt(value)); - } - } - } - } - } - - Column { - property bool isLocationMode: SessionData.nightModeAutoMode === "location" - visible: isLocationMode - spacing: Theme.spacingM - width: parent.width - - DankToggle { - id: ipLocationToggle - width: parent.width - text: I18n.tr("Use IP Location") - description: I18n.tr("Automatically detect location based on IP address") - checked: SessionData.nightModeUseIPLocation || false - onToggled: checked => { - SessionData.setNightModeUseIPLocation(checked); - } - - Connections { - target: SessionData - function onNightModeUseIPLocationChanged() { - ipLocationToggle.checked = SessionData.nightModeUseIPLocation; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - leftPadding: Theme.spacingM - visible: !SessionData.nightModeUseIPLocation - - StyledText { - text: I18n.tr("Manual Coordinates") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - Row { - spacing: Theme.spacingL - - Column { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Latitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: 120 - height: 40 - text: SessionData.latitude.toString() - placeholderText: "0.0" - onEditingFinished: { - const lat = parseFloat(text); - if (!isNaN(lat) && lat >= -90 && lat <= 90 && lat !== SessionData.latitude) { - SessionData.setLatitude(lat); - } - } - } - } - - Column { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Longitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: 120 - height: 40 - text: SessionData.longitude.toString() - placeholderText: "0.0" - onEditingFinished: { - const lon = parseFloat(text); - if (!isNaN(lon) && lon >= -180 && lon <= 180 && lon !== SessionData.longitude) { - SessionData.setLongitude(lon); - } - } - } - } - } - - StyledText { - text: I18n.tr("Uses sunrise/sunset times to automatically adjust night mode based on your location.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - parent.leftPadding - wrapMode: Text.WordWrap - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: gammaStatusSection.visible - } - - Column { - id: gammaStatusSection - width: parent.width - spacing: Theme.spacingM - visible: DisplayService.nightModeEnabled && DisplayService.gammaCurrentTemp > 0 - - Row { - width: parent.width - spacing: Theme.spacingS - - DankIcon { - name: DisplayService.gammaIsDay ? "light_mode" : "dark_mode" - size: Theme.iconSizeSmall - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Current Status") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: tempColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: tempColumn - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "device_thermostat" - size: Theme.iconSize - color: Theme.primary - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: DisplayService.gammaCurrentTemp + "K" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Current Temp") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: periodColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: periodColumn - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: DisplayService.gammaIsDay ? "wb_sunny" : "nightlight" - size: Theme.iconSize - color: DisplayService.gammaIsDay ? "#FFA726" : "#7E57C2" - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: DisplayService.gammaIsDay ? I18n.tr("Daytime") : I18n.tr("Night") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Current Period") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.nightModeAutoMode === "location" && (DisplayService.gammaSunriseTime || DisplayService.gammaSunsetTime) - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: sunriseColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: DisplayService.gammaSunriseTime - - Column { - id: sunriseColumn - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "wb_twilight" - size: Theme.iconSize - color: "#FF7043" - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.formatGammaTime(DisplayService.gammaSunriseTime) - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Sunrise") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: sunsetColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: DisplayService.gammaSunsetTime - - Column { - id: sunsetColumn - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "wb_twilight" - size: Theme.iconSize - color: "#5C6BC0" - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: root.formatGammaTime(DisplayService.gammaSunsetTime) - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Sunset") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Rectangle { - width: parent.width - height: nextChangeRow.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: DisplayService.gammaNextTransition - - Row { - id: nextChangeRow - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - name: "schedule" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Next Transition") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: root.formatGammaTime(DisplayService.gammaNextTransition) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GreeterTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GreeterTab.qml deleted file mode 100644 index b3d3a41..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/GreeterTab.qml +++ /dev/null @@ -1,784 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell -import Quickshell.Io -import qs.Common -import qs.Modals.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - readonly property bool greeterFprintToggleAvailable: SettingsData.greeterFingerprintCanEnable || SettingsData.greeterEnableFprint - readonly property bool greeterU2fToggleAvailable: SettingsData.greeterU2fCanEnable || SettingsData.greeterEnableU2f - - function greeterFingerprintDescription() { - const source = SettingsData.greeterFingerprintSource; - const reason = SettingsData.greeterFingerprintReason; - - if (source === "pam") { - switch (reason) { - case "configured_externally": - return SettingsData.greeterEnableFprint ? I18n.tr("Enabled. PAM already provides fingerprint auth.") : I18n.tr("PAM already provides fingerprint auth. Enable this to show it at login."); - case "missing_enrollment": - return SettingsData.greeterEnableFprint ? I18n.tr("Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.") : I18n.tr("PAM provides fingerprint auth, but no prints are enrolled yet."); - case "missing_reader": - return I18n.tr("PAM provides fingerprint auth, but no reader was detected."); - default: - return I18n.tr("PAM provides fingerprint auth, but availability could not be confirmed."); - } - } - - switch (reason) { - case "ready": - return SettingsData.greeterEnableFprint ? I18n.tr("Authentication changes apply automatically. Fingerprint-only login may not unlock Keyring.") : I18n.tr("Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled."); - case "missing_enrollment": - if (SettingsData.greeterEnableFprint) - return I18n.tr("Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync."); - return I18n.tr("Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later."); - case "missing_reader": - return SettingsData.greeterEnableFprint ? I18n.tr("Enabled, but no fingerprint reader was detected.") : I18n.tr("No fingerprint reader detected."); - case "missing_pam_support": - return I18n.tr("Not available — install fprintd and pam_fprintd, or configure greetd PAM."); - default: - return SettingsData.greeterEnableFprint ? I18n.tr("Enabled, but fingerprint availability could not be confirmed.") : I18n.tr("Fingerprint availability could not be confirmed."); - } - } - - function greeterU2fDescription() { - const source = SettingsData.greeterU2fSource; - const reason = SettingsData.greeterU2fReason; - - if (source === "pam") { - return SettingsData.greeterEnableU2f ? I18n.tr("Enabled. PAM already provides security-key auth.") : I18n.tr("PAM already provides security-key auth. Enable this to show it at login."); - } - - switch (reason) { - case "ready": - return SettingsData.greeterEnableU2f ? I18n.tr("Authentication changes apply automatically.") : I18n.tr("Available."); - case "missing_key_registration": - if (SettingsData.greeterEnableU2f) - return I18n.tr("Enabled, but no registered security key was found yet. Register a key and run Sync."); - return I18n.tr("Security-key support was detected, but no registered key was found yet. You can enable this now and register one later."); - case "missing_pam_support": - return I18n.tr("Not available — install or configure pam_u2f, or configure greetd PAM."); - default: - return SettingsData.greeterEnableU2f ? I18n.tr("Enabled, but security-key availability could not be confirmed.") : I18n.tr("Security-key availability could not be confirmed."); - } - } - - function refreshAuthDetection() { - SettingsData.refreshAuthAvailability(); - } - - onVisibleChanged: { - if (visible) - refreshAuthDetection(); - } - - ConfirmModal { - id: greeterActionConfirm - } - - FileBrowserModal { - id: greeterWallpaperBrowserModal - browserTitle: I18n.tr("Select greeter background image") - browserIcon: "wallpaper" - browserType: "wallpaper" - showHiddenFiles: true - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif"] - onFileSelected: path => { - SettingsData.set("greeterWallpaperPath", path); - close(); - } - } - - property string greeterStatusText: "" - property bool greeterStatusRunning: false - property bool greeterSyncRunning: false - property bool greeterInstallActionRunning: false - property string greeterStatusStdout: "" - property string greeterStatusStderr: "" - property string greeterSyncStdout: "" - property string greeterSyncStderr: "" - property string greeterSudoProbeStderr: "" - property string greeterTerminalFallbackStderr: "" - property bool greeterTerminalFallbackFromPrecheck: false - property var cachedFontFamilies: [] - property bool fontsEnumerated: false - property bool greeterBinaryExists: false - property bool greeterEnabled: false - readonly property bool greeterInstalled: greeterBinaryExists || greeterEnabled - - readonly property string greeterActionLabel: { - if (!root.greeterInstalled) - return I18n.tr("Install"); - if (!root.greeterEnabled) - return I18n.tr("Activate"); - return I18n.tr("Uninstall"); - } - readonly property string greeterActionIcon: { - if (!root.greeterInstalled) - return "download"; - if (!root.greeterEnabled) - return "login"; - return "delete"; - } - readonly property var greeterActionCommand: { - if (!root.greeterInstalled) - return ["dms", "greeter", "install", "--terminal"]; - if (!root.greeterEnabled) - return ["dms", "greeter", "enable", "--terminal"]; - return ["dms", "greeter", "uninstall", "--terminal", "--yes"]; - } - property string greeterPendingAction: "" - - function checkGreeterInstallState() { - greetdEnabledCheckProcess.running = true; - greeterBinaryCheckProcess.running = true; - } - - function runGreeterStatus() { - greeterStatusText = ""; - greeterStatusStdout = ""; - greeterStatusStderr = ""; - greeterStatusRunning = true; - greeterStatusProcess.running = true; - } - - function runGreeterInstallAction() { - root.greeterPendingAction = !root.greeterInstalled ? "install" : !root.greeterEnabled ? "activate" : "uninstall"; - greeterStatusText = I18n.tr("Opening terminal: ") + root.greeterActionLabel + "…"; - greeterInstallActionRunning = true; - greeterInstallActionProcess.running = true; - } - - function promptGreeterActionConfirm() { - var title, message, confirmText; - if (!root.greeterInstalled) { - title = I18n.tr("Install Greeter", "greeter action confirmation"); - message = I18n.tr("Install the DMS greeter? A terminal will open for sudo authentication."); - confirmText = I18n.tr("Install"); - } else if (!root.greeterEnabled) { - title = I18n.tr("Activate Greeter", "greeter action confirmation"); - message = I18n.tr("Activate the DMS greeter? A terminal will open for sudo authentication. Run Sync after activation to apply your settings."); - confirmText = I18n.tr("Activate"); - } else { - title = I18n.tr("Uninstall Greeter", "greeter action confirmation"); - message = I18n.tr("Uninstall the DMS greeter? This will remove configuration and restore your previous display manager. A terminal will open for sudo authentication."); - confirmText = I18n.tr("Uninstall"); - } - greeterActionConfirm.showWithOptions({ - "title": title, - "message": message, - "confirmText": confirmText, - "cancelText": I18n.tr("Cancel"), - "confirmColor": Theme.primary, - "onConfirm": () => root.runGreeterInstallAction(), - "onCancel": () => {} - }); - } - - function runGreeterSync() { - greeterSyncStdout = ""; - greeterSyncStderr = ""; - greeterSudoProbeStderr = ""; - greeterTerminalFallbackStderr = ""; - greeterTerminalFallbackFromPrecheck = false; - greeterStatusText = I18n.tr("Checking whether sudo authentication is needed…"); - greeterSyncRunning = true; - greeterSudoProbeProcess.running = true; - } - - function launchGreeterSyncTerminalFallback(fromPrecheck, statusText) { - greeterTerminalFallbackFromPrecheck = fromPrecheck; - if (statusText && statusText !== "") - greeterStatusText = statusText; - greeterTerminalFallbackStderr = ""; - greeterTerminalFallbackProcess.running = true; - } - - function enumerateFonts() { - if (fontsEnumerated) - return; - var fonts = []; - var availableFonts = Qt.fontFamilies(); - for (var i = 0; i < availableFonts.length; i++) { - var fontName = availableFonts[i]; - if (fontName.startsWith(".")) - continue; - fonts.push(fontName); - } - fonts.sort(); - fonts.unshift("Default"); - cachedFontFamilies = fonts; - fontsEnumerated = true; - } - - Component.onCompleted: { - refreshAuthDetection(); - Qt.callLater(enumerateFonts); - Qt.callLater(checkGreeterInstallState); - } - - Process { - id: greetdEnabledCheckProcess - command: ["systemctl", "is-enabled", "greetd"] - running: false - - stdout: StdioCollector { - onStreamFinished: root.greeterEnabled = text.trim() === "enabled" - } - } - - Process { - id: greeterBinaryCheckProcess - command: ["sh", "-c", "test -f /usr/bin/dms-greeter || test -f /usr/local/bin/dms-greeter"] - running: false - - onExited: exitCode => { - root.greeterBinaryExists = (exitCode === 0); - } - } - - Process { - id: greeterStatusProcess - command: ["dms", "greeter", "status"] - running: false - - stdout: StdioCollector { - onStreamFinished: { - root.greeterStatusStdout = text || ""; - } - } - - stderr: StdioCollector { - onStreamFinished: root.greeterStatusStderr = text || "" - } - - onExited: exitCode => { - root.greeterStatusRunning = false; - const out = (root.greeterStatusStdout || "").trim(); - const err = (root.greeterStatusStderr || "").trim(); - if (exitCode === 0) { - root.greeterStatusText = out !== "" ? out : I18n.tr("No status output."); - if (err !== "") - root.greeterStatusText = root.greeterStatusText + "\n\nstderr:\n" + err; - return; - } - var failure = I18n.tr("Failed to run 'dms greeter status'. Ensure DMS is installed and dms is in PATH.", "greeter status error") + " (exit " + exitCode + ")"; - if (out !== "") - failure = failure + "\n\n" + out; - if (err !== "") - failure = failure + "\n\nstderr:\n" + err; - root.greeterStatusText = failure; - } - } - - Process { - id: greeterSyncProcess - command: ["dms", "greeter", "sync", "--yes"] - running: false - - stdout: StdioCollector { - onStreamFinished: root.greeterSyncStdout = text || "" - } - - stderr: StdioCollector { - onStreamFinished: root.greeterSyncStderr = text || "" - } - - onExited: exitCode => { - root.greeterSyncRunning = false; - const out = (root.greeterSyncStdout || "").trim(); - const err = (root.greeterSyncStderr || "").trim(); - if (exitCode === 0) { - var success = I18n.tr("Sync completed successfully."); - if (out !== "") - success = success + "\n\n" + out; - if (err !== "") - success = success + "\n\nstderr:\n" + err; - root.greeterStatusText = success; - } else { - var failure = I18n.tr("Sync failed in background mode. Trying terminal mode so you can authenticate interactively.") + " (exit " + exitCode + ")"; - if (out !== "") - failure = failure + "\n\n" + out; - if (err !== "") - failure = failure + "\n\nstderr:\n" + err; - root.greeterStatusText = failure; - root.launchGreeterSyncTerminalFallback(false, ""); - } - root.checkGreeterInstallState(); - } - } - - Process { - id: greeterSudoProbeProcess - command: ["sudo", "-n", "true"] - running: false - - stderr: StdioCollector { - onStreamFinished: root.greeterSudoProbeStderr = text || "" - } - - onExited: exitCode => { - const err = (root.greeterSudoProbeStderr || "").trim(); - if (exitCode === 0) { - root.greeterStatusText = I18n.tr("Running greeter sync…"); - greeterSyncProcess.running = true; - return; - } - - var authNeeded = I18n.tr("Sync needs sudo authentication. Opening terminal so you can use password or fingerprint."); - if (err !== "") - authNeeded = authNeeded + "\n\n" + err; - root.launchGreeterSyncTerminalFallback(true, authNeeded); - } - } - - Process { - id: greeterTerminalFallbackProcess - command: ["dms", "greeter", "sync", "--terminal", "--yes"] - running: false - - stderr: StdioCollector { - onStreamFinished: root.greeterTerminalFallbackStderr = text || "" - } - - onExited: exitCode => { - root.greeterSyncRunning = false; - if (exitCode === 0) { - var launched = root.greeterTerminalFallbackFromPrecheck ? I18n.tr("Terminal opened. Complete sync authentication there; it will close automatically when done.") : I18n.tr("Terminal fallback opened. Complete sync there; it will close automatically when done."); - root.greeterStatusText = root.greeterStatusText ? root.greeterStatusText + "\n\n" + launched : launched; - return; - } - var fallback = I18n.tr("Terminal fallback failed. Install one of the supported terminal emulators or run 'dms greeter sync' manually.") + " (exit " + exitCode + ")"; - const err = (root.greeterTerminalFallbackStderr || "").trim(); - if (err !== "") - fallback = fallback + "\n\nstderr:\n" + err; - root.greeterStatusText = root.greeterStatusText ? root.greeterStatusText + "\n\n" + fallback : fallback; - } - } - - Process { - id: greeterInstallActionProcess - command: root.greeterActionCommand - running: false - - onExited: exitCode => { - root.greeterInstallActionRunning = false; - const pending = root.greeterPendingAction; - root.greeterPendingAction = ""; - if (exitCode === 0) { - if (pending === "install") - root.greeterStatusText = I18n.tr("Install complete. Greeter has been installed."); - else if (pending === "activate") - root.greeterStatusText = I18n.tr("Greeter activated. greetd is now enabled."); - else - root.greeterStatusText = I18n.tr("Uninstall complete. Greeter has been removed."); - } else { - root.greeterStatusText = I18n.tr("Action failed or terminal was closed.") + " (exit " + exitCode + ")"; - } - root.checkGreeterInstallState(); - } - } - - readonly property var _lockDateFormatPresets: [ - { - format: "", - label: I18n.tr("System Default", "date format option") - }, - { - format: "ddd d", - label: I18n.tr("Day Date", "date format option") - }, - { - format: "ddd MMM d", - label: I18n.tr("Day Month Date", "date format option") - }, - { - format: "MMM d", - label: I18n.tr("Month Date", "date format option") - }, - { - format: "M/d", - label: I18n.tr("Numeric (M/D)", "date format option") - }, - { - format: "d/M", - label: I18n.tr("Numeric (D/M)", "date format option") - }, - { - format: "ddd d MMM yyyy", - label: I18n.tr("Full with Year", "date format option") - }, - { - format: "yyyy-MM-dd", - label: I18n.tr("ISO Date", "date format option") - }, - { - format: "dddd, MMMM d", - label: I18n.tr("Full Day & Month", "date format option") - } - ] - readonly property var _wallpaperFillModes: ["Stretch", "Fit", "Fill", "Tile", "TileVertically", "TileHorizontally", "Pad"] - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "info" - title: I18n.tr("Greeter Status") - settingKey: "greeterStatus" - - StyledText { - text: I18n.tr("Check sync status on demand. Sync copies your theme, settings, and wallpaper configuration to the login screen. Authentication changes apply automatically.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - Item { - width: 1 - height: Theme.spacingS - } - - Rectangle { - width: parent.width - height: Math.min(180, statusTextArea.implicitHeight + Theme.spacingM * 2) - radius: Theme.cornerRadius - color: Theme.surfaceContainerHighest - - StyledText { - id: statusTextArea - anchors.fill: parent - anchors.margins: Theme.spacingM - text: root.greeterStatusRunning ? I18n.tr("Checking…", "greeter status loading") : (root.greeterStatusText || I18n.tr("Click Refresh to check status.", "greeter status placeholder")) - font.pixelSize: Theme.fontSizeSmall - font.family: "monospace" - color: root.greeterStatusRunning ? Theme.surfaceVariantText : Theme.surfaceText - wrapMode: Text.Wrap - verticalAlignment: Text.AlignTop - } - } - - Item { - width: 1 - height: Theme.spacingM - } - - RowLayout { - width: parent.width - spacing: Theme.spacingS - - DankButton { - text: root.greeterActionLabel - iconName: root.greeterActionIcon - horizontalPadding: Theme.spacingL - onClicked: root.promptGreeterActionConfirm() - enabled: !root.greeterInstallActionRunning && !root.greeterSyncRunning - } - - Item { - Layout.fillWidth: true - } - - DankButton { - text: I18n.tr("Refresh") - iconName: "refresh" - horizontalPadding: Theme.spacingL - onClicked: root.runGreeterStatus() - enabled: !root.greeterStatusRunning - } - - DankButton { - text: I18n.tr("Sync") - iconName: "sync" - horizontalPadding: Theme.spacingL - onClicked: root.runGreeterSync() - enabled: root.greeterInstalled && !root.greeterSyncRunning && !root.greeterInstallActionRunning - } - } - } - - SettingsCard { - width: parent.width - iconName: "fingerprint" - title: I18n.tr("Login Authentication") - settingKey: "greeterAuth" - - StyledText { - text: I18n.tr("Enable fingerprint or security key for DMS Greeter. Authentication changes apply automatically.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - SettingsToggleRow { - settingKey: "greeterEnableFprint" - tags: ["greeter", "fingerprint", "fprintd", "login", "auth"] - text: I18n.tr("Enable fingerprint at login") - description: root.greeterFingerprintDescription() - descriptionColor: (SettingsData.greeterFingerprintReason === "ready" || SettingsData.greeterFingerprintReason === "configured_externally") ? Theme.surfaceVariantText : Theme.warning - checked: SettingsData.greeterEnableFprint - enabled: root.greeterFprintToggleAvailable - onToggled: checked => SettingsData.set("greeterEnableFprint", checked) - } - - SettingsToggleRow { - settingKey: "greeterEnableU2f" - tags: ["greeter", "u2f", "security", "key", "login", "auth"] - text: I18n.tr("Enable security key at login") - description: root.greeterU2fDescription() - descriptionColor: (SettingsData.greeterU2fReason === "ready" || SettingsData.greeterU2fReason === "configured_externally") ? Theme.surfaceVariantText : Theme.warning - checked: SettingsData.greeterEnableU2f - enabled: root.greeterU2fToggleAvailable - onToggled: checked => SettingsData.set("greeterEnableU2f", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "palette" - title: I18n.tr("Greeter Appearance") - settingKey: "greeterAppearance" - - StyledText { - text: I18n.tr("Font") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - topPadding: Theme.spacingM - } - - SettingsDropdownRow { - settingKey: "greeterFontFamily" - tags: ["greeter", "font", "typography"] - text: I18n.tr("Greeter font") - description: I18n.tr("Font used on the login screen") - options: root.fontsEnumerated ? root.cachedFontFamilies : ["Default"] - currentValue: (!SettingsData.greeterFontFamily || SettingsData.greeterFontFamily === "" || SettingsData.greeterFontFamily === Theme.defaultFontFamily) ? "Default" : (SettingsData.greeterFontFamily || "Default") - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 400 - onValueChanged: value => { - if (value === "Default") - SettingsData.set("greeterFontFamily", ""); - else - SettingsData.set("greeterFontFamily", value); - } - } - - StyledText { - text: I18n.tr("Time format") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - topPadding: Theme.spacingM - } - - SettingsToggleRow { - settingKey: "greeterUse24Hour" - tags: ["greeter", "time", "24hour"] - text: I18n.tr("24-hour clock") - description: I18n.tr("Greeter only — does not affect main clock") - checked: SettingsData.greeterUse24HourClock - onToggled: checked => SettingsData.set("greeterUse24HourClock", checked) - } - - SettingsToggleRow { - settingKey: "greeterShowSeconds" - tags: ["greeter", "time", "seconds"] - text: I18n.tr("Show seconds") - checked: SettingsData.greeterShowSeconds - onToggled: checked => SettingsData.set("greeterShowSeconds", checked) - } - - SettingsToggleRow { - settingKey: "greeterPadHours" - tags: ["greeter", "time", "12hour"] - text: I18n.tr("Pad hours (02:00 vs 2:00)") - visible: !SettingsData.greeterUse24HourClock - checked: SettingsData.greeterPadHours12Hour - onToggled: checked => SettingsData.set("greeterPadHours12Hour", checked) - } - - StyledText { - text: I18n.tr("Date format on greeter") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - topPadding: Theme.spacingM - } - - SettingsDropdownRow { - settingKey: "greeterLockDateFormat" - tags: ["greeter", "date", "format"] - text: I18n.tr("Date format") - description: I18n.tr("Greeter only — format for the date on the login screen") - options: root._lockDateFormatPresets.map(p => p.label) - currentValue: { - var current = (SettingsData.greeterLockDateFormat !== undefined && SettingsData.greeterLockDateFormat !== "") ? SettingsData.greeterLockDateFormat : SettingsData.lockDateFormat || ""; - var match = root._lockDateFormatPresets.find(p => p.format === current); - return match ? match.label : (current ? I18n.tr("Custom: ") + current : root._lockDateFormatPresets[0].label); - } - onValueChanged: value => { - var preset = root._lockDateFormatPresets.find(p => p.label === value); - SettingsData.set("greeterLockDateFormat", preset ? preset.format : ""); - } - } - - StyledText { - text: I18n.tr("Background") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - topPadding: Theme.spacingM - } - - StyledText { - text: I18n.tr("Use a custom image for the login screen, or leave empty to use your desktop wallpaper.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - Row { - width: parent.width - spacing: Theme.spacingS - - DankTextField { - id: greeterWallpaperPathField - width: parent.width - browseGreeterWallpaperButton.width - Theme.spacingS - placeholderText: I18n.tr("Use desktop wallpaper") - text: SettingsData.greeterWallpaperPath - backgroundColor: Theme.surfaceContainerHighest - onTextChanged: { - if (text !== SettingsData.greeterWallpaperPath) - SettingsData.set("greeterWallpaperPath", text); - } - } - - DankButton { - id: browseGreeterWallpaperButton - text: I18n.tr("Browse") - horizontalPadding: Theme.spacingL - onClicked: greeterWallpaperBrowserModal.open() - } - } - - SettingsDropdownRow { - settingKey: "greeterWallpaperFillMode" - tags: ["greeter", "wallpaper", "background", "fill"] - text: I18n.tr("Wallpaper fill mode") - description: I18n.tr("How the background image is scaled") - options: root._wallpaperFillModes.map(m => I18n.tr(m, "wallpaper fill mode")) - currentValue: { - var mode = (SettingsData.greeterWallpaperFillMode && SettingsData.greeterWallpaperFillMode !== "") ? SettingsData.greeterWallpaperFillMode : (SettingsData.wallpaperFillMode || "Fill"); - var idx = root._wallpaperFillModes.indexOf(mode); - return idx >= 0 ? I18n.tr(root._wallpaperFillModes[idx], "wallpaper fill mode") : I18n.tr("Fill", "wallpaper fill mode"); - } - onValueChanged: value => { - var idx = root._wallpaperFillModes.map(m => I18n.tr(m, "wallpaper fill mode")).indexOf(value); - if (idx >= 0) - SettingsData.set("greeterWallpaperFillMode", root._wallpaperFillModes[idx]); - } - } - - StyledText { - text: I18n.tr("Layout and module positions on the greeter are synced from your shell (e.g. bar config). Run Sync to apply.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - topPadding: Theme.spacingS - } - } - - SettingsCard { - width: parent.width - iconName: "history" - title: I18n.tr("Greeter Behavior") - settingKey: "greeterBehavior" - - StyledText { - text: I18n.tr("Convenience options for the login screen. Sync to apply.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - SettingsToggleRow { - settingKey: "greeterRememberLastSession" - tags: ["greeter", "session", "remember", "login"] - text: I18n.tr("Remember last session") - description: I18n.tr("Pre-select the last used session on the greeter") - checked: SettingsData.greeterRememberLastSession - onToggled: checked => SettingsData.set("greeterRememberLastSession", checked) - } - - SettingsToggleRow { - settingKey: "greeterRememberLastUser" - tags: ["greeter", "user", "remember", "login", "username"] - text: I18n.tr("Remember last user") - description: I18n.tr("Pre-fill the last successful username on the greeter") - checked: SettingsData.greeterRememberLastUser - onToggled: checked => SettingsData.set("greeterRememberLastUser", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "extension" - title: I18n.tr("Dependencies & documentation") - settingKey: "greeterDeps" - - StyledText { - text: I18n.tr("DMS greeter needs: greetd, dms-greeter. Fingerprint: fprintd, pam_fprintd. Security keys: pam_u2f. Add your user to the greeter group. Authentication changes apply automatically and may open a terminal when sudo authentication is required.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - StyledText { - text: I18n.tr("Installation and PAM setup: see the ") + "DankGreeter docs " + I18n.tr("or run ") + "'dms greeter install'." - textFormat: Text.RichText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - linkColor: Theme.primary - width: parent.width - wrapMode: Text.Wrap - onLinkActivated: url => Qt.openUrlExternally(url) - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/KeybindsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/KeybindsTab.qml deleted file mode 100644 index 6bf5d54..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/KeybindsTab.qml +++ /dev/null @@ -1,672 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: keybindsTab - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var parentModal: null - property string selectedCategory: "" - property string searchQuery: "" - property string expandedKey: "" - property bool showingNewBind: false - - property int _lastDataVersion: -1 - property var _cachedCategories: [] - property var _filteredBinds: [] - property real _savedScrollY: 0 - property bool _preserveScroll: false - property string _editingKey: "" - - function _updateFiltered() { - const allBinds = KeybindsService.getFlatBinds(); - if (!searchQuery && !selectedCategory) { - _filteredBinds = allBinds; - return; - } - - const q = searchQuery.toLowerCase(); - const isOverrideFilter = selectedCategory === "__overrides__"; - const result = []; - - for (let i = 0; i < allBinds.length; i++) { - const group = allBinds[i]; - if (q) { - let keyMatch = false; - for (let k = 0; k < group.keys.length; k++) { - if (group.keys[k].key.toLowerCase().indexOf(q) !== -1) { - keyMatch = true; - break; - } - } - if (!keyMatch && group.desc.toLowerCase().indexOf(q) === -1 && group.action.toLowerCase().indexOf(q) === -1) - continue; - } - if (isOverrideFilter) { - let hasOverride = false; - for (let k = 0; k < group.keys.length; k++) { - if (group.keys[k].isOverride) { - hasOverride = true; - break; - } - } - if (!hasOverride) - continue; - } else if (selectedCategory && group.category !== selectedCategory) { - continue; - } - result.push(group); - } - _filteredBinds = result; - } - - function _updateCategories() { - _cachedCategories = ["__overrides__"].concat(KeybindsService.getCategories()); - } - - function getCategoryLabel(cat) { - if (cat === "__overrides__") - return I18n.tr("Overrides"); - return cat; - } - - function toggleExpanded(action) { - expandedKey = expandedKey === action ? "" : action; - } - - function startNewBind() { - showingNewBind = true; - expandedKey = ""; - } - - function cancelNewBind() { - showingNewBind = false; - } - - function saveNewBind(bindData) { - KeybindsService.saveBind("", bindData); - _editingKey = bindData.key; - expandedKey = bindData.action; - } - - function _onSaveSuccess() { - if (showingNewBind) { - showingNewBind = false; - selectedCategory = ""; - } - } - - function scrollToTop() { - flickable.contentY = 0; - } - - function _scrollToExpandedItem() { - for (let i = 0; i < bindsRepeater.count; i++) { - const item = bindsRepeater.itemAt(i); - if (item && item.modelData.action === expandedKey) { - const itemY = item.mapToItem(flickable.contentItem, 0, 0).y; - const itemH = item.height; - const viewH = flickable.height; - if (itemY >= flickable.contentY && itemY + itemH <= flickable.contentY + viewH) - return; - flickable.contentY = Math.max(0, Math.min(itemY - viewH / 4, flickable.contentHeight - viewH)); - return; - } - } - flickable.contentY = _savedScrollY; - } - - Timer { - id: searchDebounce - interval: 150 - onTriggered: keybindsTab._updateFiltered() - } - - Connections { - target: KeybindsService - function onBindsLoaded() { - const savedY = keybindsTab._savedScrollY; - const wasPreserving = keybindsTab._preserveScroll; - keybindsTab._lastDataVersion = KeybindsService._dataVersion; - keybindsTab._updateCategories(); - keybindsTab._updateFiltered(); - keybindsTab._preserveScroll = false; - if (wasPreserving) { - if (keybindsTab.expandedKey) - Qt.callLater(keybindsTab._scrollToExpandedItem); - else - Qt.callLater(() => flickable.contentY = savedY); - } - } - function onBindSaved(key) { - keybindsTab._savedScrollY = flickable.contentY; - keybindsTab._preserveScroll = true; - } - function onBindSaveCompleted(success) { - if (success) - keybindsTab._onSaveSuccess(); - } - function onBindRemoved(key) { - keybindsTab._savedScrollY = flickable.contentY; - keybindsTab._preserveScroll = true; - } - } - - function _ensureCurrentProvider() { - if (!KeybindsService.available) - return; - const cachedProvider = KeybindsService.keybinds?.provider; - const targetProvider = KeybindsService.currentProvider; - if (cachedProvider !== targetProvider || KeybindsService._dataVersion === 0) { - KeybindsService.loadBinds(); - return; - } - if (_lastDataVersion !== KeybindsService._dataVersion) { - _lastDataVersion = KeybindsService._dataVersion; - _updateCategories(); - _updateFiltered(); - } - } - - Component.onCompleted: _ensureCurrentProvider() - - onVisibleChanged: { - if (!visible) - return; - Qt.callLater(scrollToTop); - _ensureCurrentProvider(); - } - - DankFlickable { - id: flickable - anchors.fill: parent - clip: true - contentWidth: width - contentHeight: contentColumn.implicitHeight - - Column { - id: contentColumn - width: flickable.width - spacing: Theme.spacingL - topPadding: Theme.spacingXL - bottomPadding: Theme.spacingXL - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: headerSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: headerSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "keyboard" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM * 2 - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Keyboard Shortcuts") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - readonly property string bindsFile: KeybindsService.currentProvider === "niri" ? "dms/binds.kdl" : "dms/binds.conf" - text: I18n.tr("Click any shortcut to edit. Changes save to %1").arg(bindsFile) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - DankTextField { - id: searchField - width: parent.width - addButton.width - Theme.spacingM - placeholderText: I18n.tr("Search keybinds...") - leftIconName: "search" - onTextChanged: { - keybindsTab.searchQuery = text; - searchDebounce.restart(); - } - } - - DankActionButton { - id: addButton - width: searchField.height - height: searchField.height - circular: false - iconName: "add" - iconSize: Theme.iconSize - iconColor: Theme.primary - anchors.verticalCenter: parent.verticalCenter - enabled: !keybindsTab.showingNewBind - opacity: enabled ? 1 : 0.5 - onClicked: keybindsTab.startNewBind() - } - } - } - } - - StyledRect { - id: warningBox - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: warningSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - - readonly property var status: KeybindsService.dmsStatus - readonly property bool showError: !status.included && status.exists - readonly property bool showWarning: status.included && status.overriddenBy > 0 - readonly property bool showSetup: !status.exists - - color: (showError || showWarning || showSetup) ? Theme.withAlpha(Theme.primary, 0.15) : "transparent" - border.color: (showError || showWarning || showSetup) ? Theme.withAlpha(Theme.primary, 0.3) : "transparent" - border.width: 1 - visible: (showError || showWarning || showSetup) && !KeybindsService.loading - - Column { - id: warningSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: warningBox.showWarning ? "info" : "warning" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - (fixButton.visible ? fixButton.width + Theme.spacingM : 0) - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: { - if (warningBox.showSetup) - return I18n.tr("First Time Setup"); - if (warningBox.showError) - return I18n.tr("Binds Include Missing"); - if (warningBox.showWarning) - return I18n.tr("Possible Override Conflicts"); - return ""; - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.primary - } - - StyledText { - readonly property string bindsFile: KeybindsService.currentProvider === "niri" ? "dms/binds.kdl" : "dms/binds.conf" - text: { - if (warningBox.showSetup) - return I18n.tr("Click 'Setup' to create %1 and add include to config.").arg(bindsFile); - if (warningBox.showError) - return I18n.tr("%1 exists but is not included in config. Custom keybinds will not work until this is fixed.").arg(bindsFile); - if (warningBox.showWarning) { - const count = warningBox.status.overriddenBy; - return I18n.ntr( - "%1 DMS bind may be overridden by config binds that come after the include.", - "%1 DMS binds may be overridden by config binds that come after the include.", - count - ).arg(count); - } - return ""; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankButton { - id: fixButton - visible: warningBox.showError || warningBox.showSetup - text: { - if (KeybindsService.fixing) - return I18n.tr("Fixing..."); - if (warningBox.showSetup) - return I18n.tr("Setup"); - return I18n.tr("Fix Now"); - } - backgroundColor: Theme.primary - textColor: Theme.primaryText - enabled: !KeybindsService.fixing - anchors.verticalCenter: parent.verticalCenter - onClicked: KeybindsService.fixDmsBindsInclude() - } - } - } - } - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: categorySection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: categorySection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Flow { - width: parent.width - spacing: Theme.spacingS - - Rectangle { - readonly property real chipHeight: allChip.implicitHeight + Theme.spacingM - width: allChip.implicitWidth + Theme.spacingL - height: chipHeight - radius: chipHeight / 2 - color: !keybindsTab.selectedCategory ? Theme.primary : Theme.surfaceContainerHighest - - StyledText { - id: allChip - text: I18n.tr("All") - font.pixelSize: Theme.fontSizeSmall - color: !keybindsTab.selectedCategory ? Theme.primaryText : Theme.surfaceVariantText - anchors.centerIn: parent - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - keybindsTab.selectedCategory = ""; - keybindsTab._updateFiltered(); - } - } - } - - Repeater { - model: keybindsTab._cachedCategories - - delegate: Rectangle { - required property string modelData - required property int index - - readonly property real chipHeight: catText.implicitHeight + Theme.spacingM - width: catText.implicitWidth + Theme.spacingL - height: chipHeight - radius: chipHeight / 2 - color: keybindsTab.selectedCategory === modelData ? Theme.primary : (modelData === "__overrides__" ? Theme.withAlpha(Theme.primary, 0.15) : Theme.surfaceContainerHighest) - - StyledText { - id: catText - text: keybindsTab.getCategoryLabel(modelData) - font.pixelSize: Theme.fontSizeSmall - color: keybindsTab.selectedCategory === modelData ? Theme.primaryText : (modelData === "__overrides__" ? Theme.primary : Theme.surfaceVariantText) - anchors.centerIn: parent - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - keybindsTab.selectedCategory = modelData; - keybindsTab._updateFiltered(); - } - } - } - } - } - } - } - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: newBindSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Theme.outlineVariant - border.width: 1 - visible: keybindsTab.showingNewBind - - Column { - id: newBindSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "add" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("New Keybind") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - KeybindItem { - width: parent.width - isNew: true - isExpanded: true - bindData: ({ - keys: [ - { - key: "", - source: "dms", - isOverride: true - } - ], - action: "", - desc: "" - }) - panelWindow: keybindsTab.parentModal - onSaveBind: (originalKey, newData) => keybindsTab.saveNewBind(newData) - onCancelEdit: keybindsTab.cancelNewBind() - } - } - } - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: bindsListHeader.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: bindsListHeader - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "list" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - if (KeybindsService.loading) - return I18n.tr("Shortcuts"); - const count = keybindsTab._filteredBinds.length; - return count === 1 - ? I18n.tr("Shortcut (%1)").arg(count) - : I18n.tr("Shortcuts (%1)").arg(count); - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: KeybindsService.loading - - DankIcon { - id: loadingIcon - name: "sync" - size: 20 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - - RotationAnimation on rotation { - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - running: KeybindsService.loading - } - } - - StyledText { - text: I18n.tr("Loading keybinds...") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: I18n.tr("No keybinds found") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: !KeybindsService.loading && keybindsTab._filteredBinds.length === 0 - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - Repeater { - id: bindsRepeater - model: ScriptModel { - values: keybindsTab._filteredBinds - objectProp: "action" - } - - delegate: Item { - required property var modelData - required property int index - - width: parent.width - height: bindItem.height - - KeybindItem { - id: bindItem - width: Math.min(650, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - bindData: modelData - isExpanded: keybindsTab.expandedKey === modelData.action - panelWindow: keybindsTab.parentModal - onToggleExpand: keybindsTab.toggleExpanded(modelData.action) - onSaveBind: (originalKey, newData) => { - KeybindsService.saveBind(originalKey, newData); - keybindsTab._editingKey = newData.key; - keybindsTab.expandedKey = newData.action; - } - onRemoveBind: key => { - const remainingKey = bindItem.keys.find(k => k.key !== key)?.key ?? ""; - KeybindsService.removeBind(key); - keybindsTab._editingKey = remainingKey; - } - onIsExpandedChanged: { - if (!isExpanded || !keybindsTab._editingKey) - return; - const keyExists = keys.some(k => k.key === keybindsTab._editingKey); - if (keyExists) { - restoreKey = keybindsTab._editingKey; - keybindsTab._editingKey = ""; - } - } - - onKeysChanged: { - if (!isExpanded || !keybindsTab._editingKey) - return; - const keyExists = keys.some(k => k.key === keybindsTab._editingKey); - if (keyExists) { - restoreKey = keybindsTab._editingKey; - keybindsTab._editingKey = ""; - } - } - - Connections { - target: keybindsTab - function on_EditingKeyChanged() { - if (!bindItem.isExpanded || !keybindsTab._editingKey) - return; - const keyExists = bindItem.keys.some(k => k.key === keybindsTab._editingKey); - if (keyExists) { - bindItem.restoreKey = keybindsTab._editingKey; - keybindsTab._editingKey = ""; - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LauncherTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LauncherTab.qml deleted file mode 100644 index 8705d42..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LauncherTab.qml +++ /dev/null @@ -1,1306 +0,0 @@ -import QtQuick -import qs.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - FileBrowserModal { - id: logoFileBrowser - browserTitle: I18n.tr("Select Launcher Logo") - browserIcon: "image" - browserType: "generic" - filterExtensions: ["*.svg", "*.png", "*.jpg", "*.jpeg", "*.webp"] - onFileSelected: path => SettingsData.set("launcherLogoCustomPath", path.replace("file://", "")) - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "apps" - title: I18n.tr("Launcher Button Logo") - settingKey: "launcherLogo" - - StyledText { - width: parent.width - text: I18n.tr("Choose the logo displayed on the launcher button in DankBar") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - Item { - width: parent.width - height: logoModeGroup.implicitHeight - clip: true - - DankButtonGroup { - id: logoModeGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 480 ? 44 : 64 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: { - const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo"), I18n.tr("Dank")]; - if (CompositorService.isNiri) { - modes.push("niri"); - } else if (CompositorService.isHyprland) { - modes.push("Hyprland"); - } else if (CompositorService.isDwl) { - modes.push("mango"); - } else if (CompositorService.isSway) { - modes.push("Sway"); - } else if (CompositorService.isScroll) { - modes.push("Scroll"); - } else if (CompositorService.isMiracle) { - modes.push("Miracle"); - } else { - modes.push(I18n.tr("Compositor")); - } - modes.push(I18n.tr("Custom")); - return modes; - } - currentIndex: { - if (SettingsData.launcherLogoMode === "apps") - return 0; - if (SettingsData.launcherLogoMode === "os") - return 1; - if (SettingsData.launcherLogoMode === "dank") - return 2; - if (SettingsData.launcherLogoMode === "compositor") - return 3; - if (SettingsData.launcherLogoMode === "custom") - return 4; - return 0; - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.set("launcherLogoMode", "apps"); - break; - case 1: - SettingsData.set("launcherLogoMode", "os"); - break; - case 2: - SettingsData.set("launcherLogoMode", "dank"); - break; - case 3: - SettingsData.set("launcherLogoMode", "compositor"); - break; - case 4: - SettingsData.set("launcherLogoMode", "custom"); - break; - } - } - } - } - - Row { - width: parent.width - visible: SettingsData.launcherLogoMode === "custom" - spacing: Theme.spacingM - - StyledRect { - width: parent.width - selectButton.width - Theme.spacingM - height: 36 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) - border.color: Theme.outlineStrong - border.width: 1 - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - text: SettingsData.launcherLogoCustomPath || I18n.tr("Select an image file...") - font.pixelSize: Theme.fontSizeMedium - color: SettingsData.launcherLogoCustomPath ? Theme.surfaceText : Theme.outlineButton - width: parent.width - Theme.spacingM * 2 - elide: Text.ElideMiddle - } - } - - DankActionButton { - id: selectButton - iconName: "folder_open" - width: 36 - height: 36 - onClicked: logoFileBrowser.open() - } - } - - Column { - width: parent.width - spacing: Theme.spacingL - visible: SettingsData.launcherLogoMode !== "apps" - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Color Override") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: parent.width - height: colorOverrideRow.implicitHeight - clip: true - - Row { - id: colorOverrideRow - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingM - - DankButtonGroup { - id: colorModeGroup - buttonPadding: parent.parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.parent.width < 480 ? 44 : 64 - textSize: parent.parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")] - currentIndex: { - const override = SettingsData.launcherLogoColorOverride; - if (override === "") - return 0; - if (override === "primary") - return 1; - if (override === "surface") - return 2; - return 3; - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - SettingsData.set("launcherLogoColorOverride", ""); - break; - case 1: - SettingsData.set("launcherLogoColorOverride", "primary"); - break; - case 2: - SettingsData.set("launcherLogoColorOverride", "surface"); - break; - case 3: - const currentOverride = SettingsData.launcherLogoColorOverride; - const isPreset = currentOverride === "" || currentOverride === "primary" || currentOverride === "surface"; - if (isPreset) { - SettingsData.set("launcherLogoColorOverride", "#ffffff"); - } - break; - } - } - } - - Rectangle { - id: colorPickerCircle - visible: { - const override = SettingsData.launcherLogoColorOverride; - return override !== "" && override !== "primary" && override !== "surface"; - } - width: 36 - height: 36 - radius: 18 - color: { - const override = SettingsData.launcherLogoColorOverride; - if (override !== "" && override !== "primary" && override !== "surface") - return override; - return "#ffffff"; - } - border.color: Theme.outline - border.width: 1 - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - PopoutService.colorPickerModal.selectedColor = SettingsData.launcherLogoColorOverride; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Launcher Logo Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - SettingsData.set("launcherLogoColorOverride", selectedColor); - }; - PopoutService.colorPickerModal.show(); - } - } - } - } - } - } - - SettingsSliderRow { - settingKey: "launcherLogoSizeOffset" - tags: ["launcher", "logo", "size", "offset", "scale"] - text: I18n.tr("Size Offset") - minimum: -12 - maximum: 12 - value: SettingsData.launcherLogoSizeOffset - defaultValue: 0 - onSliderValueChanged: newValue => SettingsData.set("launcherLogoSizeOffset", newValue) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: { - const override = SettingsData.launcherLogoColorOverride; - return override !== "" && override !== "primary" && override !== "surface"; - } - - SettingsSliderRow { - settingKey: "launcherLogoBrightness" - tags: ["launcher", "logo", "brightness", "color"] - text: I18n.tr("Brightness") - minimum: 0 - maximum: 100 - value: Math.round(SettingsData.launcherLogoBrightness * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("launcherLogoBrightness", newValue / 100) - } - - SettingsSliderRow { - settingKey: "launcherLogoContrast" - tags: ["launcher", "logo", "contrast", "color"] - text: I18n.tr("Contrast") - minimum: 0 - maximum: 200 - value: Math.round(SettingsData.launcherLogoContrast * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("launcherLogoContrast", newValue / 100) - } - - SettingsToggleRow { - settingKey: "launcherLogoColorInvertOnMode" - tags: ["launcher", "logo", "invert", "mode", "color"] - text: I18n.tr("Invert on mode change") - checked: SettingsData.launcherLogoColorInvertOnMode - onToggled: checked => SettingsData.set("launcherLogoColorInvertOnMode", checked) - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "terminal" - title: I18n.tr("Launch Prefix") - settingKey: "launchPrefix" - - StyledText { - width: parent.width - text: I18n.tr("Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - DankTextField { - width: parent.width - text: SettingsData.launchPrefix - placeholderText: I18n.tr("Enter launch prefix (e.g., 'uwsm-app')") - onTextEdited: SettingsData.set("launchPrefix", text) - } - } - - SettingsCard { - width: parent.width - iconName: "sort_by_alpha" - title: I18n.tr("Sorting & Layout") - settingKey: "launcherSorting" - - SettingsToggleRow { - settingKey: "sortAppsAlphabetically" - tags: ["launcher", "sort", "alphabetically", "apps", "order"] - text: I18n.tr("Sort Alphabetically") - description: I18n.tr("When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.") - checked: SettingsData.sortAppsAlphabetically - onToggled: checked => SettingsData.set("sortAppsAlphabetically", checked) - } - - SettingsSliderRow { - settingKey: "appLauncherGridColumns" - tags: ["launcher", "grid", "columns", "layout"] - text: I18n.tr("Grid Columns") - description: I18n.tr("Adjust the number of columns in grid view mode.") - minimum: 2 - maximum: 8 - value: SettingsData.appLauncherGridColumns - defaultValue: 5 - onSliderValueChanged: newValue => SettingsData.set("appLauncherGridColumns", newValue) - } - } - - SettingsCard { - width: parent.width - iconName: "tune" - title: I18n.tr("Appearance", "launcher appearance settings") - settingKey: "dankLauncherV2Appearance" - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Size", "launcher size option") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: parent.width - height: sizeGroup.implicitHeight - clip: true - - DankButtonGroup { - id: sizeGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 400 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 400 ? 60 : 80 - textSize: parent.width < 400 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: ["1", "2", "3", "4"] - currentIndex: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 0; - case "compact": - return 1; - case "large": - return 3; - default: - return 2; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - var sizes = ["micro", "compact", "medium", "large"]; - SettingsData.set("dankLauncherV2Size", sizes[index]); - } - } - } - } - - SettingsToggleRow { - settingKey: "dankLauncherV2ShowFooter" - tags: ["launcher", "footer", "hints", "shortcuts"] - text: I18n.tr("Show Footer", "launcher footer visibility") - description: I18n.tr("Show mode tabs and keyboard hints at the bottom.", "launcher footer description") - checked: SettingsData.dankLauncherV2ShowFooter - enabled: SettingsData.dankLauncherV2Size !== "micro" - onToggled: checked => SettingsData.set("dankLauncherV2ShowFooter", checked) - } - - SettingsToggleRow { - settingKey: "dankLauncherV2UnloadOnClose" - tags: ["launcher", "unload", "close", "memory", "vram"] - text: I18n.tr("Unload on Close") - description: I18n.tr("Free VRAM/memory when the launcher is closed. May cause a slight delay when reopening.") - checked: SettingsData.dankLauncherV2UnloadOnClose - onToggled: checked => SettingsData.set("dankLauncherV2UnloadOnClose", checked) - } - - SettingsToggleRow { - settingKey: "dankLauncherV2BorderEnabled" - tags: ["launcher", "border", "outline"] - text: I18n.tr("Border", "launcher border option") - checked: SettingsData.dankLauncherV2BorderEnabled - onToggled: checked => SettingsData.set("dankLauncherV2BorderEnabled", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SettingsData.dankLauncherV2BorderEnabled - - SettingsSliderRow { - settingKey: "dankLauncherV2BorderThickness" - tags: ["launcher", "border", "thickness"] - text: I18n.tr("Thickness", "border thickness") - minimum: 1 - maximum: 6 - value: SettingsData.dankLauncherV2BorderThickness - defaultValue: 2 - unit: "px" - onSliderValueChanged: newValue => SettingsData.set("dankLauncherV2BorderThickness", newValue) - } - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Color", "border color") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: parent.width - height: borderColorGroup.implicitHeight - clip: true - - DankButtonGroup { - id: borderColorGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 400 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 400 ? 50 : 70 - textSize: parent.width < 400 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("Primary", "primary color"), I18n.tr("Secondary", "secondary color"), I18n.tr("Outline", "outline color"), I18n.tr("Text", "text color")] - currentIndex: SettingsData.dankLauncherV2BorderColor === "secondary" ? 1 : SettingsData.dankLauncherV2BorderColor === "outline" ? 2 : SettingsData.dankLauncherV2BorderColor === "surfaceText" ? 3 : 0 - onSelectionChanged: (index, selected) => { - if (!selected) - return; - SettingsData.set("dankLauncherV2BorderColor", index === 1 ? "secondary" : index === 2 ? "outline" : index === 3 ? "surfaceText" : "primary"); - } - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "open_in_new" - title: I18n.tr("Niri Integration").replace("Niri", "niri") - visible: CompositorService.isNiri - - SettingsToggleRow { - settingKey: "spotlightCloseNiriOverview" - tags: ["launcher", "niri", "overview", "close", "launch"] - text: I18n.tr("Close Overview on Launch") - description: I18n.tr("Auto-close Niri overview when launching apps.") - checked: SettingsData.spotlightCloseNiriOverview - onToggled: checked => SettingsData.set("spotlightCloseNiriOverview", checked) - } - - SettingsToggleRow { - settingKey: "niriOverviewOverlayEnabled" - tags: ["launcher", "niri", "overview", "overlay", "enable"] - text: I18n.tr("Enable Overview Overlay") - description: I18n.tr("Show launcher overlay when typing in Niri overview. Disable to use another launcher.") - checked: SettingsData.niriOverviewOverlayEnabled - onToggled: checked => SettingsData.set("niriOverviewOverlayEnabled", checked) - } - } - - SettingsCard { - id: builtInPluginsCard - width: parent.width - iconName: "extension" - title: "DMS" - settingKey: "builtInPlugins" - - Column { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: ["dms_settings", "dms_notepad", "dms_sysmon", "dms_settings_search"] - - delegate: Rectangle { - id: pluginDelegate - required property string modelData - required property int index - readonly property var plugin: AppSearchService.builtInPlugins[modelData] - - width: parent.width - height: 56 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: pluginDelegate.plugin?.cornerIcon ?? "extension" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: pluginDelegate.plugin?.name ?? pluginDelegate.modelData - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - StyledText { - text: pluginDelegate.plugin?.comment ?? "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - Row { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankTextField { - id: triggerField - width: 60 - visible: pluginDelegate.plugin?.isLauncher === true - anchors.verticalCenter: parent.verticalCenter - placeholderText: I18n.tr("Trigger") - onTextEdited: SettingsData.setBuiltInPluginSetting(pluginDelegate.modelData, "trigger", text) - Component.onCompleted: text = SettingsData.getBuiltInPluginSetting(pluginDelegate.modelData, "trigger", pluginDelegate.plugin?.defaultTrigger ?? "") - } - - DankToggle { - id: enableToggle - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.getBuiltInPluginSetting(pluginDelegate.modelData, "enabled", true) - onToggled: SettingsData.setBuiltInPluginSetting(pluginDelegate.modelData, "enabled", checked) - } - } - } - } - } - } - - SettingsCard { - id: pluginVisibilityCard - width: parent.width - iconName: "filter_list" - title: I18n.tr("Plugin Visibility") - settingKey: "pluginVisibility" - - property var allLauncherPlugins: { - SettingsData.launcherPluginVisibility; - SettingsData.launcherPluginOrder; - SettingsData.dankLauncherV2IncludeFilesInAll; - SettingsData.dankLauncherV2IncludeFoldersInAll; - var plugins = []; - var builtIn = AppSearchService.getBuiltInLauncherPlugins() || {}; - for (var pluginId in builtIn) { - var plugin = builtIn[pluginId]; - plugins.push({ - id: pluginId, - name: plugin.name || pluginId, - icon: plugin.cornerIcon || "extension", - iconType: "material", - isBuiltIn: true, - isVirtual: false, - trigger: AppSearchService.getBuiltInPluginTrigger(pluginId) || "" - }); - } - var thirdParty = PluginService.getLauncherPlugins() || {}; - for (var pluginId in thirdParty) { - var plugin = thirdParty[pluginId]; - var rawIcon = plugin.icon || "extension"; - plugins.push({ - id: pluginId, - name: plugin.name || pluginId, - icon: rawIcon.startsWith("material:") ? rawIcon.substring(9) : rawIcon.startsWith("unicode:") ? rawIcon.substring(8) : rawIcon, - iconType: rawIcon.startsWith("unicode:") ? "unicode" : "material", - isBuiltIn: false, - isVirtual: false, - trigger: PluginService.getPluginTrigger(pluginId) || "" - }); - } - if (SettingsData.dankLauncherV2IncludeFilesInAll) { - plugins.push({ - id: "__files", - name: I18n.tr("Files"), - icon: "insert_drive_file", - iconType: "material", - isBuiltIn: false, - isVirtual: true, - trigger: "/" - }); - } - if (SettingsData.dankLauncherV2IncludeFoldersInAll) { - plugins.push({ - id: "__folders", - name: I18n.tr("Folders"), - icon: "folder", - iconType: "material", - isBuiltIn: false, - isVirtual: true, - trigger: "/" - }); - } - return SettingsData.getOrderedLauncherPlugins(plugins); - } - - function reorderPlugin(fromIndex, toIndex) { - if (fromIndex === toIndex) - return; - var currentOrder = allLauncherPlugins.map(p => p.id); - var item = currentOrder.splice(fromIndex, 1)[0]; - currentOrder.splice(toIndex, 0, item); - SettingsData.setLauncherPluginOrder(currentOrder); - } - - StyledText { - width: parent.width - text: I18n.tr("Control which plugins appear in 'All' mode without requiring a trigger prefix. Drag to reorder.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - Column { - id: pluginVisibilityColumn - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: pluginVisibilityCard.allLauncherPlugins - - delegate: Item { - id: visibilityDelegateItem - required property var modelData - required property int index - - property bool held: pluginDragArea.pressed - property real originalY: y - - width: pluginVisibilityColumn.width - height: 52 - z: held ? 2 : 1 - - Rectangle { - id: visibilityDelegate - width: parent.width - height: 52 - radius: Theme.cornerRadius - color: visibilityDelegateItem.held ? Theme.surfaceHover : Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - - Row { - anchors.left: parent.left - anchors.leftMargin: 28 - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Item { - width: Theme.iconSize - height: Theme.iconSize - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - visible: visibilityDelegateItem.modelData.iconType !== "unicode" - name: visibilityDelegateItem.modelData.icon - size: Theme.iconSize - color: Theme.primary - } - - StyledText { - anchors.centerIn: parent - visible: visibilityDelegateItem.modelData.iconType === "unicode" - text: visibilityDelegateItem.modelData.icon - font.pixelSize: Theme.iconSize - color: Theme.primary - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - Row { - spacing: Theme.spacingS - - StyledText { - text: visibilityDelegateItem.modelData.name - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - Rectangle { - visible: visibilityDelegateItem.modelData.isBuiltIn - width: dmsBadgeLabel.implicitWidth + Theme.spacingS - height: 16 - radius: 8 - color: Theme.primaryContainer - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: dmsBadgeLabel - anchors.centerIn: parent - text: "DMS" - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.primary - } - } - } - - StyledText { - text: visibilityDelegateItem.modelData.trigger ? I18n.tr("Trigger: %1").arg(visibilityDelegateItem.modelData.trigger) : I18n.tr("No trigger") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - DankToggle { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - checked: { - switch (visibilityDelegateItem.modelData.id) { - case "__files": - return SettingsData.dankLauncherV2IncludeFilesInAll; - case "__folders": - return SettingsData.dankLauncherV2IncludeFoldersInAll; - default: - return SettingsData.getPluginAllowWithoutTrigger(visibilityDelegateItem.modelData.id); - } - } - onToggled: function (isChecked) { - switch (visibilityDelegateItem.modelData.id) { - case "__files": - SettingsData.set("dankLauncherV2IncludeFilesInAll", isChecked); - break; - case "__folders": - SettingsData.set("dankLauncherV2IncludeFoldersInAll", isChecked); - break; - default: - SettingsData.setPluginAllowWithoutTrigger(visibilityDelegateItem.modelData.id, isChecked); - } - } - } - } - - MouseArea { - id: pluginDragArea - anchors.left: parent.left - anchors.top: parent.top - width: 28 - height: parent.height - hoverEnabled: true - cursorShape: Qt.SizeVerCursor - drag.target: visibilityDelegateItem.held ? visibilityDelegateItem : undefined - drag.axis: Drag.YAxis - preventStealing: true - - onPressed: { - visibilityDelegateItem.originalY = visibilityDelegateItem.y; - } - - onReleased: { - if (!drag.active) { - visibilityDelegateItem.y = visibilityDelegateItem.originalY; - return; - } - const spacing = Theme.spacingS; - const itemH = visibilityDelegateItem.height + spacing; - var newIndex = Math.round(visibilityDelegateItem.y / itemH); - newIndex = Math.max(0, Math.min(newIndex, pluginVisibilityCard.allLauncherPlugins.length - 1)); - pluginVisibilityCard.reorderPlugin(visibilityDelegateItem.index, newIndex); - visibilityDelegateItem.y = visibilityDelegateItem.originalY; - } - } - - DankIcon { - x: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - name: "drag_indicator" - size: 18 - color: Theme.outline - opacity: pluginDragArea.containsMouse || pluginDragArea.pressed ? 1 : 0.5 - } - - Behavior on y { - enabled: !pluginDragArea.pressed && !pluginDragArea.drag.active - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No launcher plugins installed.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: pluginVisibilityCard.allLauncherPlugins.length === 0 - } - } - } - - SettingsCard { - width: parent.width - iconName: "search" - title: I18n.tr("Search Options") - settingKey: "searchOptions" - - SettingsToggleRow { - settingKey: "searchAppActions" - tags: ["launcher", "search", "actions", "shortcuts"] - text: I18n.tr("Search App Actions") - description: I18n.tr("Include desktop actions (shortcuts) in search results.") - checked: SessionData.searchAppActions - onToggled: checked => SessionData.setSearchAppActions(checked) - } - - SettingsToggleRow { - settingKey: "rememberLastQuery" - tags: ["launcher", "remember", "last", "search", "query"] - text: I18n.tr("Remember Last Query") - description: I18n.tr("Autofill last remembered query when opened") - checked: SettingsData.rememberLastQuery - onToggled: checked => SettingsData.set("rememberLastQuery", checked) - } - - SettingsToggleRow { - settingKey: "dankLauncherV2IncludeFilesInAll" - tags: ["launcher", "files", "dsearch", "all", "results", "indexed"] - text: I18n.tr("Include Files in All Tab") - description: I18n.tr("Merge indexed file results into the All tab (requires dsearch).") - checked: SettingsData.dankLauncherV2IncludeFilesInAll - onToggled: checked => SettingsData.set("dankLauncherV2IncludeFilesInAll", checked) - } - - SettingsToggleRow { - settingKey: "dankLauncherV2IncludeFoldersInAll" - tags: ["launcher", "folders", "dirs", "dsearch", "all", "results", "indexed"] - text: I18n.tr("Include Folders in All Tab") - description: I18n.tr("Merge indexed folder results into the All tab (requires dsearch).") - checked: SettingsData.dankLauncherV2IncludeFoldersInAll - onToggled: checked => SettingsData.set("dankLauncherV2IncludeFoldersInAll", checked) - } - } - - SettingsCard { - id: hiddenAppsCard - width: parent.width - iconName: "visibility_off" - title: I18n.tr("Hidden Apps") - settingKey: "hiddenApps" - - property var hiddenAppsModel: { - SessionData.hiddenApps; - const apps = []; - const allApps = AppSearchService.applications || []; - for (const hiddenId of SessionData.hiddenApps) { - const app = allApps.find(a => (a.id || a.execString || a.exec) === hiddenId); - if (app) { - apps.push({ - id: hiddenId, - name: app.name || hiddenId, - icon: app.icon || "", - comment: app.comment || "" - }); - } else { - apps.push({ - id: hiddenId, - name: hiddenId, - icon: "", - comment: "" - }); - } - } - return apps.sort((a, b) => a.name.localeCompare(b.name)); - } - - StyledText { - width: parent.width - text: I18n.tr("Hidden apps won't appear in the launcher. Right-click an app and select 'Hide App' to hide it.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - Column { - id: hiddenAppsList - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: hiddenAppsCard.hiddenAppsModel - - delegate: Rectangle { - width: hiddenAppsList.width - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - border.width: 0 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Image { - width: 24 - height: 24 - source: Paths.resolveIconUrl(modelData.icon || "application-x-executable") - sourceSize.width: 24 - sourceSize.height: 24 - fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - onStatusChanged: { - if (status === Image.Error) - source = "image://icon/application-x-executable"; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: modelData.comment || modelData.id - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: text.length > 0 - } - } - } - - DankActionButton { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - iconName: "visibility" - iconSize: 18 - iconColor: Theme.primary - onClicked: SessionData.showApp(modelData.id) - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No hidden apps.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: hiddenAppsCard.hiddenAppsModel.length === 0 - } - } - } - - SettingsCard { - id: appOverridesCard - width: parent.width - iconName: "edit" - title: I18n.tr("App Customizations") - settingKey: "appOverrides" - - property var overridesModel: { - SessionData.appOverrides; - const items = []; - const allApps = AppSearchService.applications || []; - for (const appId in SessionData.appOverrides) { - const override = SessionData.appOverrides[appId]; - const app = allApps.find(a => (a.id || a.execString || a.exec) === appId); - items.push({ - id: appId, - name: override.name || app?.name || appId, - originalName: app?.name || appId, - icon: override.icon || app?.icon || "", - hasOverride: true - }); - } - return items.sort((a, b) => a.name.localeCompare(b.name)); - } - - StyledText { - width: parent.width - text: I18n.tr("Apps with custom display name, icon, or launch options. Right-click an app and select 'Edit App' to customize.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - Column { - id: overridesList - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: appOverridesCard.overridesModel - - delegate: Rectangle { - width: overridesList.width - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - border.width: 0 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Image { - width: 24 - height: 24 - source: Paths.resolveIconUrl(modelData.icon || "application-x-executable") - sourceSize.width: 24 - sourceSize.height: 24 - fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - onStatusChanged: { - if (status === Image.Error) - source = "image://icon/application-x-executable"; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: modelData.originalName !== modelData.name ? modelData.originalName : modelData.id - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - DankActionButton { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - iconName: "delete" - iconSize: 18 - iconColor: Theme.error - onClicked: SessionData.clearAppOverride(modelData.id) - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No app customizations.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: appOverridesCard.overridesModel.length === 0 - } - } - } - - SettingsCard { - id: recentAppsCard - width: parent.width - iconName: "history" - title: I18n.tr("Recently Used Apps") - settingKey: "recentApps" - collapsible: true - expanded: false - - property var rankedAppsModel: { - var ranking = AppUsageHistoryData.appUsageRanking; - if (!ranking) - return []; - var apps = []; - for (var appId in ranking) { - var appData = ranking[appId]; - apps.push({ - "id": appId, - "name": appData.name, - "exec": appData.exec, - "icon": appData.icon, - "comment": appData.comment, - "usageCount": appData.usageCount, - "lastUsed": appData.lastUsed - }); - } - apps.sort(function (a, b) { - if (a.usageCount !== b.usageCount) - return b.usageCount - a.usageCount; - return a.name.localeCompare(b.name); - }); - return apps.slice(0, 20); - } - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - width: parent.width - clearAllButton.width - Theme.spacingM - text: I18n.tr("Apps are ordered by usage frequency, then last used, then alphabetically.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - anchors.verticalCenter: parent.verticalCenter - } - - DankActionButton { - id: clearAllButton - iconName: "delete_sweep" - iconSize: Theme.iconSize - 2 - iconColor: Theme.error - anchors.verticalCenter: parent.verticalCenter - onClicked: { - AppUsageHistoryData.appUsageRanking = {}; - AppUsageHistoryData.saveSettings(); - } - } - } - - Column { - id: rankedAppsList - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: recentAppsCard.rankedAppsModel - - delegate: Rectangle { - width: rankedAppsList.width - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3) - border.width: 0 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - StyledText { - text: (index + 1).toString() - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primary - width: 20 - anchors.verticalCenter: parent.verticalCenter - } - - Image { - width: 24 - height: 24 - source: Paths.resolveIconUrl(modelData.icon || "application-x-executable") - sourceSize.width: 24 - sourceSize.height: 24 - fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - onStatusChanged: { - if (status === Image.Error) - source = "image://icon/application-x-executable"; - } - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.name || I18n.tr("Unknown App") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: { - if (!modelData.lastUsed) - return I18n.tr("Never used"); - var date = new Date(modelData.lastUsed); - var now = new Date(); - var diffMs = now - date; - var diffMins = Math.floor(diffMs / (1000 * 60)); - var diffHours = Math.floor(diffMs / (1000 * 60 * 60)); - var diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); - if (diffMins < 1) - return I18n.tr("Last launched just now"); - if (diffMins < 60) - return diffMins === 1 ? I18n.tr("Last launched %1 minute ago").arg(diffMins) : I18n.tr("Last launched %1 minutes ago").arg(diffMins); - if (diffHours < 24) - return diffHours === 1 ? I18n.tr("Last launched %1 hour ago").arg(diffHours) : I18n.tr("Last launched %1 hours ago").arg(diffHours); - if (diffDays < 7) - return diffDays === 1 ? I18n.tr("Last launched %1 day ago").arg(diffDays) : I18n.tr("Last launched %1 days ago").arg(diffDays); - return I18n.tr("Last launched %1").arg(date.toLocaleDateString()); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - DankActionButton { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - circular: true - iconName: "close" - iconSize: 16 - iconColor: Theme.error - onClicked: { - var currentRanking = Object.assign({}, AppUsageHistoryData.appUsageRanking || {}); - delete currentRanking[modelData.id]; - AppUsageHistoryData.appUsageRanking = currentRanking; - AppUsageHistoryData.saveSettings(); - } - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No apps have been launched yet.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: recentAppsCard.rankedAppsModel.length === 0 - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LocaleTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LocaleTab.qml deleted file mode 100644 index d4f7f5e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LocaleTab.qml +++ /dev/null @@ -1,91 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: localeTab - - readonly property string _systemDefaultLabel: I18n.tr("System Default") - - function _localeDisplayName(localeCode) { - if (!I18n.presentLocales[localeCode]) - return; - const nativeName = I18n.presentLocales[localeCode].nativeLanguageName; - return nativeName[0].toUpperCase() + nativeName.slice(1); - } - - function _allLocaleOptions() { - return [_systemDefaultLabel].concat(Object.keys(I18n.presentLocales).map(_localeDisplayName)); - } - - function _codeForDisplayName(displayName) { - if (displayName === _systemDefaultLabel) - return ""; - for (const code of Object.keys(I18n.presentLocales)) { - if (_localeDisplayName(code) === displayName) - return code; - } - return ""; - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "locale" - tags: ["locale", "language", "country"] - title: I18n.tr("Locale Settings") - iconName: "language" - - SettingsDropdownRow { - id: localeDropdown - tab: "locale" - tags: ["locale", "language", "country"] - settingKey: "locale" - text: I18n.tr("Current Locale") - description: I18n.tr("Change the locale used by the DMS interface.") - options: localeTab._allLocaleOptions() - enableFuzzySearch: true - - Component.onCompleted: { - currentValue = SessionData.locale ? localeTab._localeDisplayName(SessionData.locale) : localeTab._systemDefaultLabel; - } - - onValueChanged: value => { - SessionData.set("locale", localeTab._codeForDisplayName(value)); - } - } - - SettingsDropdownRow { - id: timeLocaleDropdown - tab: "locale" - tags: ["locale", "time", "date", "format", "region"] - settingKey: "timeLocale" - text: I18n.tr("Time & Date Locale") - description: I18n.tr("Change the locale used for date and time formatting, independent of the interface language.") - options: localeTab._allLocaleOptions() - enableFuzzySearch: true - - Component.onCompleted: { - currentValue = SessionData.timeLocale ? localeTab._localeDisplayName(SessionData.timeLocale) : localeTab._systemDefaultLabel; - } - - onValueChanged: value => { - SessionData.set("timeLocale", localeTab._codeForDisplayName(value)); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LockScreenTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LockScreenTab.qml deleted file mode 100644 index d86589c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/LockScreenTab.qml +++ /dev/null @@ -1,458 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - readonly property bool lockFprintToggleAvailable: SettingsData.lockFingerprintCanEnable || SettingsData.enableFprint - readonly property bool lockU2fToggleAvailable: SettingsData.lockU2fCanEnable || SettingsData.enableU2f - - function lockFingerprintDescription() { - switch (SettingsData.lockFingerprintReason) { - case "ready": - return SettingsData.enableFprint ? I18n.tr("Authentication changes apply automatically.") : I18n.tr("Use fingerprint authentication for the lock screen."); - case "missing_enrollment": - if (SettingsData.enableFprint) - return I18n.tr("Enabled, but no prints are enrolled yet. Authentication changes apply automatically once you enroll fingerprints."); - return I18n.tr("Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later."); - case "missing_reader": - return SettingsData.enableFprint ? I18n.tr("Enabled, but no fingerprint reader was detected.") : I18n.tr("No fingerprint reader detected."); - case "missing_pam_support": - return I18n.tr("Not available — install fprintd and pam_fprintd."); - default: - return SettingsData.enableFprint ? I18n.tr("Enabled, but fingerprint availability could not be confirmed.") : I18n.tr("Fingerprint availability could not be confirmed."); - } - } - - function lockU2fDescription() { - switch (SettingsData.lockU2fReason) { - case "ready": - return SettingsData.enableU2f ? I18n.tr("Authentication changes apply automatically.") : I18n.tr("Use a security key for lock screen authentication.", "lock screen U2F security key setting"); - case "missing_key_registration": - if (SettingsData.enableU2f) - return I18n.tr("Enabled, but no registered security key was found yet. Authentication changes apply automatically once your key is registered or your U2F config is updated."); - return I18n.tr("Security-key support was detected, but no registered key was found yet. You can enable this now and register one later."); - case "missing_pam_support": - return I18n.tr("Not available — install or configure pam_u2f."); - default: - return SettingsData.enableU2f ? I18n.tr("Enabled, but security-key availability could not be confirmed.") : I18n.tr("Security-key availability could not be confirmed."); - } - } - - function refreshAuthDetection() { - SettingsData.refreshAuthAvailability(); - } - - Component.onCompleted: refreshAuthDetection() - onVisibleChanged: { - if (visible) - refreshAuthDetection(); - } - - FileBrowserModal { - id: videoBrowserModal - browserTitle: I18n.tr("Select Video or Folder") - browserIcon: "movie" - browserType: "video" - showHiddenFiles: false - fileExtensions: ["*.mp4", "*.mkv", "*.webm", "*.mov", "*.avi", "*.m4v"] - onFileSelected: path => SettingsData.set("lockScreenVideoPath", path) - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "lock" - title: I18n.tr("Lock Screen layout") - settingKey: "lockLayout" - - SettingsToggleRow { - settingKey: "lockScreenShowPowerActions" - tags: ["lock", "screen", "power", "actions", "shutdown", "reboot"] - text: I18n.tr("Show Power Actions", "Enable power action icon on the lock screen window") - checked: SettingsData.lockScreenShowPowerActions - onToggled: checked => SettingsData.set("lockScreenShowPowerActions", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowSystemIcons" - tags: ["lock", "screen", "system", "icons", "status"] - text: I18n.tr("Show System Icons", "Enable system status icons on the lock screen window") - checked: SettingsData.lockScreenShowSystemIcons - onToggled: checked => SettingsData.set("lockScreenShowSystemIcons", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowTime" - tags: ["lock", "screen", "time", "clock", "display"] - text: I18n.tr("Show System Time", "Enable system time display on the lock screen window") - checked: SettingsData.lockScreenShowTime - onToggled: checked => SettingsData.set("lockScreenShowTime", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowDate" - tags: ["lock", "screen", "date", "calendar", "display"] - text: I18n.tr("Show System Date", "Enable system date display on the lock screen window") - checked: SettingsData.lockScreenShowDate - onToggled: checked => SettingsData.set("lockScreenShowDate", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowProfileImage" - tags: ["lock", "screen", "profile", "image", "avatar", "picture"] - text: I18n.tr("Show Profile Image", "Enable profile image display on the lock screen window") - checked: SettingsData.lockScreenShowProfileImage - onToggled: checked => SettingsData.set("lockScreenShowProfileImage", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowPasswordField" - tags: ["lock", "screen", "password", "field", "input", "visible"] - text: I18n.tr("Show Password Field", "Enable password field display on the lock screen window") - description: I18n.tr("If the field is hidden, it will appear as soon as a key is pressed.") - checked: SettingsData.lockScreenShowPasswordField - onToggled: checked => SettingsData.set("lockScreenShowPasswordField", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenShowMediaPlayer" - tags: ["lock", "screen", "media", "player", "music", "mpris"] - text: I18n.tr("Show Media Player", "Enable media player controls on the lock screen window") - checked: SettingsData.lockScreenShowMediaPlayer - onToggled: checked => SettingsData.set("lockScreenShowMediaPlayer", checked) - } - - SettingsDropdownRow { - settingKey: "lockScreenNotificationMode" - tags: ["lock", "screen", "notification", "notifications", "privacy"] - text: I18n.tr("Notification Display", "lock screen notification privacy setting") - description: I18n.tr("Control what notification information is shown on the lock screen", "lock screen notification privacy setting") - options: [I18n.tr("Disabled", "lock screen notification mode option"), I18n.tr("Count Only", "lock screen notification mode option"), I18n.tr("App Names", "lock screen notification mode option"), I18n.tr("Full Content", "lock screen notification mode option")] - currentValue: options[SettingsData.lockScreenNotificationMode] || options[0] - onValueChanged: value => { - const idx = options.indexOf(value); - if (idx >= 0) { - SettingsData.set("lockScreenNotificationMode", idx); - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "lock" - title: I18n.tr("Lock Screen behaviour") - settingKey: "lockBehavior" - - StyledText { - text: I18n.tr("loginctl not available - lock integration requires DMS socket connection") - font.pixelSize: Theme.fontSizeSmall - color: Theme.warning - visible: !SessionService.loginctlAvailable - width: parent.width - wrapMode: Text.Wrap - } - - SettingsToggleRow { - settingKey: "loginctlLockIntegration" - tags: ["lock", "screen", "loginctl", "dbus", "integration", "external"] - text: I18n.tr("Enable loginctl lock integration") - description: I18n.tr("Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen") - checked: SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration - enabled: SessionService.loginctlAvailable - onToggled: checked => { - if (!SessionService.loginctlAvailable) - return; - SettingsData.set("loginctlLockIntegration", checked); - } - } - - SettingsToggleRow { - settingKey: "lockBeforeSuspend" - tags: ["lock", "screen", "suspend", "sleep", "automatic"] - text: I18n.tr("Lock before suspend") - description: I18n.tr("Automatically lock the screen when the system prepares to suspend") - checked: SettingsData.lockBeforeSuspend - visible: SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration - onToggled: checked => SettingsData.set("lockBeforeSuspend", checked) - } - - SettingsToggleRow { - settingKey: "lockScreenPowerOffMonitorsOnLock" - tags: ["lock", "screen", "monitor", "display", "dpms", "power"] - text: I18n.tr("Power off monitors on lock") - description: I18n.tr("Turn off all displays immediately when the lock screen activates") - checked: SettingsData.lockScreenPowerOffMonitorsOnLock - onToggled: checked => SettingsData.set("lockScreenPowerOffMonitorsOnLock", checked) - } - - SettingsToggleRow { - settingKey: "lockAtStartup" - tags: ["lock", "screen", "startup", "start", "boot", "login", "automatic"] - text: I18n.tr("Lock at startup") - description: I18n.tr("Automatically lock the screen when DMS starts") - checked: SettingsData.lockAtStartup - onToggled: checked => SettingsData.set("lockAtStartup", checked) - } - - StyledText { - text: I18n.tr("Lock screen authentication changes apply automatically and may open a terminal when sudo authentication is required.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - topPadding: Theme.spacingS - } - - SettingsToggleRow { - settingKey: "enableFprint" - tags: ["lock", "screen", "fingerprint", "authentication", "biometric", "fprint"] - text: I18n.tr("Enable fingerprint authentication") - description: root.lockFingerprintDescription() - descriptionColor: SettingsData.lockFingerprintReason === "ready" ? Theme.surfaceVariantText : Theme.warning - checked: SettingsData.enableFprint - enabled: root.lockFprintToggleAvailable - onToggled: checked => SettingsData.set("enableFprint", checked) - } - - SettingsToggleRow { - settingKey: "enableU2f" - tags: ["lock", "screen", "u2f", "yubikey", "security", "key", "fido", "authentication", "hardware"] - text: I18n.tr("Enable security key authentication", "Enable FIDO2/U2F hardware security key for lock screen") - description: root.lockU2fDescription() - descriptionColor: SettingsData.lockU2fReason === "ready" ? Theme.surfaceVariantText : Theme.warning - checked: SettingsData.enableU2f - enabled: root.lockU2fToggleAvailable - onToggled: checked => SettingsData.set("enableU2f", checked) - } - - SettingsDropdownRow { - settingKey: "u2fMode" - tags: ["lock", "screen", "u2f", "yubikey", "security", "key", "mode", "factor", "second"] - text: I18n.tr("Security key mode", "lock screen U2F security key mode setting") - description: I18n.tr("'Alternative' lets the key unlock on its own. 'Second factor' requires password or fingerprint first, then the key.", "lock screen U2F security key mode setting") - visible: SettingsData.enableU2f - options: [I18n.tr("Alternative (OR)", "U2F mode option: key works as standalone unlock method"), I18n.tr("Second Factor (AND)", "U2F mode option: key required after password or fingerprint")] - currentValue: SettingsData.u2fMode === "and" ? I18n.tr("Second Factor (AND)", "U2F mode option: key required after password or fingerprint") : I18n.tr("Alternative (OR)", "U2F mode option: key works as standalone unlock method") - onValueChanged: value => { - if (value === I18n.tr("Second Factor (AND)", "U2F mode option: key required after password or fingerprint")) - SettingsData.set("u2fMode", "and"); - else - SettingsData.set("u2fMode", "or"); - } - } - } - - SettingsCard { - width: parent.width - iconName: "movie" - title: I18n.tr("Video Screensaver") - settingKey: "videoScreensaver" - - StyledText { - visible: !MultimediaService.available - text: I18n.tr("QtMultimedia is not available - video screensaver requires qt multimedia services") - font.pixelSize: Theme.fontSizeSmall - color: Theme.warning - width: parent.width - wrapMode: Text.WordWrap - } - - SettingsToggleRow { - settingKey: "lockScreenVideoEnabled" - tags: ["lock", "screen", "video", "screensaver", "animation", "movie"] - text: I18n.tr("Enable Video Screensaver") - description: I18n.tr("Play a video when the screen locks.") - enabled: MultimediaService.available - checked: SettingsData.lockScreenVideoEnabled - onToggled: checked => SettingsData.set("lockScreenVideoEnabled", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: SettingsData.lockScreenVideoEnabled && MultimediaService.available - - StyledText { - text: I18n.tr("Video Path") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: I18n.tr("Path to a video file or folder containing videos") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outlineVariant - wrapMode: Text.WordWrap - width: parent.width - } - - Row { - width: parent.width - spacing: Theme.spacingS - - DankTextField { - id: videoPathField - width: parent.width - browseVideoButton.width - Theme.spacingS - placeholderText: I18n.tr("/path/to/videos") - text: SettingsData.lockScreenVideoPath - backgroundColor: Theme.surfaceContainerHighest - onTextChanged: { - if (text !== SettingsData.lockScreenVideoPath) { - SettingsData.set("lockScreenVideoPath", text); - } - } - } - - DankButton { - id: browseVideoButton - text: I18n.tr("Browse") - onClicked: videoBrowserModal.open() - } - } - } - - SettingsToggleRow { - settingKey: "lockScreenVideoCycling" - tags: ["lock", "screen", "video", "screensaver", "cycling", "random", "shuffle"] - text: I18n.tr("Automatic Cycling") - description: I18n.tr("Pick a different random video each time from the same folder") - visible: SettingsData.lockScreenVideoEnabled && MultimediaService.available - enabled: MultimediaService.available - checked: SettingsData.lockScreenVideoCycling - onToggled: checked => SettingsData.set("lockScreenVideoCycling", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "monitor" - title: I18n.tr("Lock Screen Display") - settingKey: "lockDisplay" - visible: Quickshell.screens.length > 1 - - StyledText { - text: I18n.tr("Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - SettingsDropdownRow { - id: lockScreenMonitorDropdown - settingKey: "lockScreenActiveMonitor" - tags: ["lock", "screen", "monitor", "display", "active"] - text: I18n.tr("Active Lock Screen Monitor") - options: { - var opts = [I18n.tr("All Monitors")]; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - opts.push(SettingsData.getScreenDisplayName(screens[i])); - } - return opts; - } - - Component.onCompleted: { - if (SettingsData.lockScreenActiveMonitor === "all") { - currentValue = I18n.tr("All Monitors"); - return; - } - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === SettingsData.lockScreenActiveMonitor) { - currentValue = SettingsData.getScreenDisplayName(screens[i]); - return; - } - } - currentValue = I18n.tr("All Monitors"); - } - - onValueChanged: value => { - if (value === I18n.tr("All Monitors")) { - SettingsData.set("lockScreenActiveMonitor", "all"); - return; - } - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (SettingsData.getScreenDisplayName(screens[i]) === value) { - SettingsData.set("lockScreenActiveMonitor", screens[i].name); - return; - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: SettingsData.lockScreenActiveMonitor !== "all" - - Column { - width: parent.width - inactiveColorPreview.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Inactive Monitor Color") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Color displayed on monitors without the lock screen") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - } - - Rectangle { - id: inactiveColorPreview - width: 48 - height: 48 - radius: Theme.cornerRadius - color: SettingsData.lockScreenInactiveColor - border.color: Theme.outline - border.width: 1 - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - PopoutService.colorPickerModal.selectedColor = SettingsData.lockScreenInactiveColor; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Inactive Monitor Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - SettingsData.set("lockScreenInactiveColor", selectedColor); - }; - PopoutService.colorPickerModal.show(); - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MediaPlayerTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MediaPlayerTab.qml deleted file mode 100644 index a844a86..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MediaPlayerTab.qml +++ /dev/null @@ -1,119 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "music_note" - title: I18n.tr("Media Player Settings") - settingKey: "mediaPlayer" - - SettingsToggleRow { - text: I18n.tr("Wave Progress Bars") - description: I18n.tr("Use animated wave progress bars for media playback") - checked: SettingsData.waveProgressEnabled - onToggled: checked => SettingsData.set("waveProgressEnabled", checked) - } - - SettingsToggleRow { - text: I18n.tr("Scroll song title") - description: I18n.tr("Scroll title if it doesn't fit in widget") - checked: SettingsData.scrollTitleEnabled - onToggled: checked => SettingsData.set("scrollTitleEnabled", checked) - } - - SettingsToggleRow { - text: I18n.tr("Audio Visualizer") - description: I18n.tr("Show cava audio visualizer in media widget") - checked: SettingsData.audioVisualizerEnabled - onToggled: checked => SettingsData.set("audioVisualizerEnabled", checked) - } - - SettingsToggleRow { - text: I18n.tr("Adaptive Media Width") - description: I18n.tr("Shrink the media widget to fit shorter song titles while still respecting the configured maximum size") - checked: SettingsData.mediaAdaptiveWidthEnabled - onToggled: checked => SettingsData.set("mediaAdaptiveWidthEnabled", checked) - } - - SettingsDropdownRow { - property var scrollOptsInternal: ["volume", "song", "nothing"] - property var scrollOptsDisplay: [I18n.tr("Change Volume", "media scroll wheel option"), I18n.tr("Change Song", "media scroll wheel option"), I18n.tr("Nothing", "media scroll wheel option")] - - text: I18n.tr("Scroll Wheel") - description: I18n.tr("Scroll wheel behavior on media widget") - settingKey: "audioScrollMode" - tags: ["media", "music", "scroll"] - options: scrollOptsDisplay - currentValue: { - const idx = scrollOptsInternal.indexOf(SettingsData.audioScrollMode); - return idx >= 0 ? scrollOptsDisplay[idx] : scrollOptsDisplay[0]; - } - onValueChanged: value => { - const idx = scrollOptsDisplay.indexOf(value); - if (idx >= 0) - SettingsData.set("audioScrollMode", scrollOptsInternal[idx]); - } - } - - Item { - width: parent.width - height: audioWheelScrollAmountColumn.height - visible: SettingsData.audioScrollMode == "volume" - opacity: visible ? 1 : 0 - - Column { - id: audioWheelScrollAmountColumn - x: Theme.spacingL - width: 120 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Adjust volume per scroll indent") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - font.weight: Font.Medium - horizontalAlignment: Text.AlignLeft - } - - DankTextField { - width: 100 - height: 28 - placeholderText: "5" - text: SettingsData.audioWheelScrollAmount - maximumLength: 2 - font.pixelSize: Theme.fontSizeSmall - topPadding: Theme.spacingXS - bottomPadding: Theme.spacingXS - onEditingFinished: SettingsData.set("audioWheelScrollAmount", parseInt(text, 10)) - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MuxTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MuxTab.qml deleted file mode 100644 index a82cdbe..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/MuxTab.qml +++ /dev/null @@ -1,112 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - readonly property var muxTypeOptions: [ - "tmux", - "zellij" - ] - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "mux" - tags: ["mux", "multiplexer", "tmux", "zellij", "type"] - title: I18n.tr("Multiplexer") - iconName: "terminal" - - SettingsDropdownRow { - tab: "mux" - tags: ["mux", "multiplexer", "tmux", "zellij", "type", "backend"] - settingKey: "muxType" - text: I18n.tr("Multiplexer Type") - description: I18n.tr("Terminal multiplexer backend to use") - options: root.muxTypeOptions - currentValue: SettingsData.muxType - onValueChanged: value => SettingsData.set("muxType", value) - } - } - - SettingsCard { - tab: "mux" - tags: ["mux", "terminal", "custom", "command", "script"] - title: I18n.tr("Terminal") - iconName: "desktop_windows" - - SettingsToggleRow { - tab: "mux" - tags: ["mux", "custom", "command", "override"] - settingKey: "muxUseCustomCommand" - text: I18n.tr("Use Custom Command") - description: I18n.tr("Override terminal with a custom command or script") - checked: SettingsData.muxUseCustomCommand - onToggled: checked => SettingsData.set("muxUseCustomCommand", checked) - } - - Column { - width: parent?.width ?? 0 - spacing: Theme.spacingS - visible: SettingsData.muxUseCustomCommand - - StyledText { - width: parent.width - text: I18n.tr("The custom command used when attaching to sessions (receives the session name as the first argument)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - DankTextField { - width: parent.width - text: SettingsData.muxCustomCommand - placeholderText: I18n.tr("Enter command or script path") - onTextEdited: SettingsData.set("muxCustomCommand", text) - } - } - } - - SettingsCard { - tab: "mux" - tags: ["mux", "session", "filter", "exclude", "hide"] - title: I18n.tr("Session Filter") - iconName: "filter_list" - - Column { - width: parent?.width ?? 0 - spacing: Theme.spacingS - - StyledText { - width: parent.width - text: I18n.tr("Comma-separated list of session names to hide. Wrap in slashes for regex (e.g., /^_.*/).") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - - DankTextField { - width: parent.width - text: SettingsData.muxSessionFilter - placeholderText: I18n.tr("e.g., scratch, /^tmp_.*/, build") - onTextEdited: SettingsData.set("muxSessionFilter", text) - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NetworkTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NetworkTab.qml deleted file mode 100644 index b9b2566..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NetworkTab.qml +++ /dev/null @@ -1,1999 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Modals.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets - -Item { - id: networkTab - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string expandedVpnUuid: "" - property string expandedWifiSsid: "" - property string expandedEthDevice: "" - property int maxPinnedWifiNetworks: 3 - - Component.onCompleted: { - NetworkService.addRef(); - } - - Component.onDestruction: { - NetworkService.removeRef(); - } - - function openVpnFileBrowser() { - vpnFileBrowserLoader.active = true; - if (vpnFileBrowserLoader.item) - vpnFileBrowserLoader.item.open(); - } - - function normalizePinList(value) { - if (Array.isArray(value)) - return value.filter(v => v) - if (typeof value === "string" && value.length > 0) - return [value] - return [] - } - - function getPinnedWifiNetworks() { - const pins = SettingsData.wifiNetworkPins || {} - return normalizePinList(pins["preferredWifi"]) - } - - function toggleWifiPin(ssid) { - const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {})) - let pinnedList = normalizePinList(pins["preferredWifi"]) - const pinIndex = pinnedList.indexOf(ssid) - - if (pinIndex !== -1) { - pinnedList.splice(pinIndex, 1) - } else { - pinnedList.unshift(ssid) - if (pinnedList.length > maxPinnedWifiNetworks) - pinnedList = pinnedList.slice(0, maxPinnedWifiNetworks) - } - - if (pinnedList.length > 0) - pins["preferredWifi"] = pinnedList - else - delete pins["preferredWifi"] - - SettingsData.set("wifiNetworkPins", pins) - } - - LazyLoader { - id: vpnFileBrowserLoader - active: false - - FileBrowserModal { - browserTitle: I18n.tr("Import VPN") - browserIcon: "vpn_key" - browserType: "vpn" - fileExtensions: VPNService.getFileFilter() - - onFileSelected: path => { - VPNService.importVpn(path.replace("file://", "")); - } - } - } - - ConfirmModal { - id: deleteVpnConfirm - } - - ConfirmModal { - id: forgetNetworkConfirm - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(600, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingL - - StyledRect { - width: parent.width - height: overviewSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: overviewSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "lan" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Network Status") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Overview of your network connections") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Grid { - columns: 2 - columnSpacing: Theme.spacingL - rowSpacing: Theme.spacingS - width: parent.width - - StyledText { - text: I18n.tr("Backend") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - StyledText { - text: NetworkService.backend || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: I18n.tr("Status") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - Row { - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: 8 - radius: 4 - anchors.verticalCenter: parent.verticalCenter - color: { - switch (NetworkService.networkStatus) { - case "ethernet": - case "wifi": - return Theme.success; - case "disconnected": - return Theme.error; - default: - return Theme.warning; - } - } - } - - StyledText { - text: { - switch (NetworkService.networkStatus) { - case "ethernet": - return I18n.tr("Ethernet"); - case "wifi": - return I18n.tr("WiFi"); - case "disconnected": - return I18n.tr("Disconnected"); - default: - return NetworkService.networkStatus || I18n.tr("Unknown"); - } - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - StyledText { - text: I18n.tr("Primary") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: NetworkService.primaryConnection.length > 0 - } - StyledText { - text: NetworkService.primaryConnection || "-" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - elide: Text.ElideRight - visible: NetworkService.primaryConnection.length > 0 - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: NetworkService.backend === "networkmanager" && NetworkService.ethernetConnected && NetworkService.wifiConnected - - StyledText { - text: I18n.tr("Preference") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - preferenceLabel.width - preferenceButtons.width - Theme.spacingM * 2 - height: 1 - } - - DankButtonGroup { - id: preferenceButtons - model: [I18n.tr("Auto"), I18n.tr("Ethernet"), I18n.tr("WiFi")] - currentIndex: { - switch (NetworkService.userPreference) { - case "ethernet": - return 1; - case "wifi": - return 2; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - switch (index) { - case 0: - NetworkService.setNetworkPreference("auto"); - break; - case 1: - NetworkService.setNetworkPreference("ethernet"); - break; - case 2: - NetworkService.setNetworkPreference("wifi"); - break; - } - } - } - } - - StyledText { - id: preferenceLabel - visible: false - text: I18n.tr("Preference") - } - } - } - - StyledRect { - width: parent.width - height: ethernetSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: NetworkService.ethernetConnected || (NetworkService.ethernetDevices?.length ?? 0) > 0 - - Column { - id: ethernetSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "settings_ethernet" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Ethernet") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - const devices = NetworkService.ethernetDevices; - const connected = devices.filter(d => d.connected).length; - if (devices.length === 0) - return I18n.tr("No adapters"); - if (connected === 0) - return devices.length === 1 - ? I18n.tr("%1 adapter, none connected").arg(devices.length) - : I18n.tr("%1 adapters, none connected").arg(devices.length); - return I18n.tr("%1 connected").arg(connected); - } - font.pixelSize: Theme.fontSizeSmall - color: NetworkService.ethernetConnected ? Theme.primary : Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Column { - width: parent.width - spacing: 4 - visible: NetworkService.ethernetDevices.length > 0 - - StyledText { - text: I18n.tr("Adapters") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Repeater { - model: NetworkService.ethernetDevices - - delegate: Rectangle { - id: ethDeviceDelegate - required property var modelData - required property int index - - readonly property bool isConnected: modelData.connected || false - readonly property bool isExpanded: networkTab.expandedEthDevice === modelData.name - - width: parent.width - height: isExpanded ? 56 + ethExpandedContent.height : 56 - radius: Theme.cornerRadius - color: ethDeviceMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.width: isConnected ? 2 : 0 - border.color: Theme.primary - clip: true - - Behavior on height { - NumberAnimation { - duration: 150 - easing.type: Easing.OutQuad - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: 56 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - anchors.right: ethDeviceActions.left - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: "lan" - size: 20 - color: isConnected ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - 20 - Theme.spacingS - - StyledText { - text: modelData.name || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: isConnected ? Theme.primary : Theme.surfaceText - font.weight: isConnected ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingXS - - StyledText { - text: { - switch (modelData.state) { - case "activated": - return I18n.tr("Connected"); - case "disconnected": - return I18n.tr("Disconnected"); - case "unavailable": - return I18n.tr("Unavailable"); - default: - return modelData.state || I18n.tr("Unknown"); - } - } - font.pixelSize: Theme.fontSizeSmall - color: isConnected ? Theme.primary : Theme.surfaceVariantText - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: (modelData.ip || "").length > 0 - } - - StyledText { - text: modelData.ip || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: (modelData.ip || "").length > 0 - } - } - } - } - - Row { - id: ethDeviceActions - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: ethExpandBtn.containsMouse ? Theme.surfacePressed : "transparent" - visible: isConnected - - DankIcon { - anchors.centerIn: parent - name: isExpanded ? "expand_less" : "expand_more" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: ethExpandBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (isExpanded) { - networkTab.expandedEthDevice = ""; - } else { - networkTab.expandedEthDevice = modelData.name; - NetworkService.fetchWiredNetworkInfo(NetworkService.ethernetConnectionUuid); - } - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: ethDisconnectBtn.containsMouse ? Theme.errorHover : "transparent" - visible: isConnected - - DankIcon { - anchors.centerIn: parent - name: "link_off" - size: 18 - color: ethDisconnectBtn.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: ethDisconnectBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: NetworkService.disconnectEthernetDevice(modelData.name) - } - } - } - - MouseArea { - id: ethDeviceMouseArea - anchors.fill: parent - anchors.rightMargin: ethDeviceActions.width + Theme.spacingM - hoverEnabled: true - } - } - - Column { - id: ethExpandedContent - width: parent.width - visible: isExpanded - - Rectangle { - width: parent.width - Theme.spacingM * 2 - height: 1 - x: Theme.spacingM - color: Theme.outlineLight - } - - Item { - width: parent.width - height: ethDetailsColumn.implicitHeight + Theme.spacingM * 2 - - Column { - id: ethDetailsColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Flow { - width: parent.width - spacing: Theme.spacingXS - - Repeater { - model: { - const fields = []; - const dev = modelData; - if (!dev) - return fields; - - if (dev.ip) - fields.push({ - label: I18n.tr("IP"), - value: dev.ip - }); - if (dev.speed && dev.speed > 0) - fields.push({ - label: I18n.tr("Speed"), - value: dev.speed + " Mbps" - }); - if (dev.hwAddress) - fields.push({ - label: I18n.tr("MAC"), - value: dev.hwAddress - }); - if (dev.driver) - fields.push({ - label: I18n.tr("Driver"), - value: dev.driver - }); - fields.push({ - label: I18n.tr("State"), - value: dev.state || I18n.tr("Unknown") - }); - - return fields; - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: ethFieldContent.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHigh - border.width: 1 - border.color: Theme.outlineLight - - Row { - id: ethFieldContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: modelData.label + ":" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - Item { - width: parent.width - height: NetworkService.networkWiredInfoLoading ? 40 : 0 - visible: NetworkService.networkWiredInfoLoading - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - id: wiredLoadIcon - name: "sync" - size: 16 - color: Theme.surfaceVariantText - - SequentialAnimation { - running: NetworkService.networkWiredInfoLoading - loops: Animation.Infinite - NumberAnimation { - target: wiredLoadIcon - property: "opacity" - to: 0.3 - duration: 400 - easing.type: Easing.InOutQuad - } - NumberAnimation { - target: wiredLoadIcon - property: "opacity" - to: 1.0 - duration: 400 - easing.type: Easing.InOutQuad - } - onRunningChanged: if (!running) - wiredLoadIcon.opacity = 1.0 - } - } - - StyledText { - text: I18n.tr("Loading...") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - } - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: NetworkService.wiredConnections.length > 0 - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - StyledText { - text: I18n.tr("Saved Configurations") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Repeater { - model: NetworkService.wiredConnections - - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: wiredMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.width: modelData.isActive ? 2 : 0 - border.color: Theme.primary - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "lan" - size: 20 - color: modelData.isActive ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.id || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: modelData.isActive ? Theme.primary : Theme.surfaceText - font.weight: modelData.isActive ? Font.Medium : Font.Normal - } - - StyledText { - text: modelData.isActive ? I18n.tr("Active") : "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - visible: modelData.isActive - } - } - } - - MouseArea { - id: wiredMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!modelData.isActive) { - NetworkService.connectToSpecificWiredConfig(modelData.uuid); - } - } - } - } - } - } - } - } - - StyledRect { - width: parent.width - height: wifiSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: wifiSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: NetworkService.wifiEnabled ? "wifi" : "wifi_off" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - wifiControls.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("WiFi") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - if (NetworkService.wifiToggling) - return I18n.tr("Toggling..."); - if (!NetworkService.wifiEnabled) - return I18n.tr("Disabled"); - if (NetworkService.wifiConnected) - return NetworkService.currentWifiSSID; - return I18n.tr("Not connected"); - } - font.pixelSize: Theme.fontSizeSmall - color: NetworkService.wifiConnected ? Theme.primary : Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Row { - id: wifiControls - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankActionButton { - iconName: "wifi_find" - buttonSize: 32 - visible: NetworkService.backend === "networkmanager" && NetworkService.wifiEnabled && !NetworkService.wifiToggling - onClicked: PopoutService.showHiddenNetworkModal() - } - - DankActionButton { - iconName: "refresh" - buttonSize: 32 - visible: NetworkService.wifiEnabled && !NetworkService.wifiToggling && !NetworkService.isScanning - onClicked: NetworkService.scanWifi() - } - - DankToggle { - checked: NetworkService.wifiEnabled - enabled: !NetworkService.wifiToggling - onToggled: NetworkService.toggleWifiRadio() - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - visible: NetworkService.wifiEnabled && (NetworkService.wifiDevices?.length ?? 0) > 1 - - StyledText { - text: I18n.tr("WiFi Device") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - wifiDeviceLabel.width - wifiDeviceDropdown.width - Theme.spacingM * 2 - height: 1 - } - - DankDropdown { - id: wifiDeviceDropdown - dropdownWidth: 150 - popupWidth: 180 - currentValue: NetworkService.wifiDeviceOverride || I18n.tr("Auto") - options: { - const devices = NetworkService.wifiDevices; - if (!devices || devices.length === 0) - return [I18n.tr("Auto")]; - return [I18n.tr("Auto")].concat(devices.map(d => d.name)); - } - onValueChanged: value => { - const deviceName = value === I18n.tr("Auto") ? "" : value; - NetworkService.setWifiDeviceOverride(deviceName); - } - } - } - - StyledText { - id: wifiDeviceLabel - visible: false - text: I18n.tr("WiFi Device") - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - visible: NetworkService.wifiEnabled - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: NetworkService.wifiEnabled && !NetworkService.wifiToggling - - Column { - width: parent.width - spacing: Theme.spacingS - visible: NetworkService.wifiInterface.length > 0 - - Row { - width: parent.width - height: 24 - - StyledText { - text: I18n.tr("Interface:") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - width: 100 - anchors.verticalCenter: parent.verticalCenter - } - StyledText { - text: NetworkService.wifiInterface || "-" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - height: 24 - visible: NetworkService.wifiIP.length > 0 - - StyledText { - text: I18n.tr("IP Address:") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - width: 100 - anchors.verticalCenter: parent.verticalCenter - } - StyledText { - text: NetworkService.wifiIP || "-" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - height: 24 - visible: NetworkService.wifiConnected - - StyledText { - text: I18n.tr("Signal:") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - width: 100 - anchors.verticalCenter: parent.verticalCenter - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: { - const s = NetworkService.wifiSignalStrength; - if (s >= 50) - return "wifi"; - if (s >= 25) - return "wifi_2_bar"; - return "wifi_1_bar"; - } - size: 18 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: NetworkService.wifiSignalStrength + "%" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - } - } - } - - Item { - width: parent.width - height: Theme.spacingS - } - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Available Networks") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: 1 - height: 1 - Layout.fillWidth: true - } - - StyledText { - text: NetworkService.wifiNetworks?.length ?? 0 - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - - Item { - width: parent.width - height: 80 - visible: NetworkService.isScanning && (NetworkService.wifiNetworks?.length ?? 0) === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - id: scanningIcon - name: "wifi_find" - size: 32 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - - SequentialAnimation { - running: NetworkService.isScanning - loops: Animation.Infinite - NumberAnimation { - target: scanningIcon - property: "opacity" - to: 0.3 - duration: 400 - easing.type: Easing.InOutQuad - } - NumberAnimation { - target: scanningIcon - property: "opacity" - to: 1.0 - duration: 400 - easing.type: Easing.InOutQuad - } - onRunningChanged: if (!running) - scanningIcon.opacity = 1.0 - } - } - - StyledText { - text: I18n.tr("Scanning...") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Column { - width: parent.width - spacing: 4 - visible: (NetworkService.wifiNetworks?.length ?? 0) > 0 - - Repeater { - model: { - const ssid = NetworkService.currentWifiSSID; - const networks = NetworkService.wifiNetworks || []; - const pinnedList = networkTab.getPinnedWifiNetworks(); - - let sorted = [...networks]; - sorted.sort((a, b) => { - const aPinnedIndex = pinnedList.indexOf(a.ssid) - const bPinnedIndex = pinnedList.indexOf(b.ssid) - if (aPinnedIndex !== -1 || bPinnedIndex !== -1) { - if (aPinnedIndex === -1) - return 1 - if (bPinnedIndex === -1) - return -1 - return aPinnedIndex - bPinnedIndex - } - if (a.ssid === ssid) - return -1; - if (b.ssid === ssid) - return 1; - return b.signal - a.signal; - }); - return sorted; - } - - delegate: Rectangle { - id: wifiNetworkDelegate - required property var modelData - required property int index - - readonly property bool isConnected: modelData.ssid === NetworkService.currentWifiSSID - readonly property bool isPinned: networkTab.getPinnedWifiNetworks().includes(modelData.ssid) - readonly property bool isExpanded: networkTab.expandedWifiSsid === modelData.ssid - - width: parent.width - height: isExpanded ? 56 + wifiExpandedContent.height : 56 - radius: Theme.cornerRadius - color: wifiNetworkMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.width: isConnected ? 2 : 0 - border.color: Theme.primary - clip: true - - Behavior on height { - NumberAnimation { - duration: 150 - easing.type: Easing.OutQuad - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: 56 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - anchors.right: wifiNetworkActions.left - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: { - const s = modelData.signal || 0; - if (s >= 50) - return "wifi"; - if (s >= 25) - return "wifi_2_bar"; - return "wifi_1_bar"; - } - size: 20 - color: isConnected ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - 20 - Theme.spacingS - - Row { - anchors.left: parent.left - spacing: Theme.spacingXS - - StyledText { - text: modelData.ssid || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: isConnected ? Theme.primary : Theme.surfaceText - font.weight: isConnected ? Font.Medium : Font.Normal - elide: Text.ElideRight - } - - DankIcon { - name: "push_pin" - size: 14 - color: Theme.primary - visible: isPinned - anchors.verticalCenter: parent.verticalCenter - } - - DankIcon { - name: "visibility_off" - size: 14 - color: Theme.surfaceVariantText - visible: modelData.hidden || false - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingXS - - StyledText { - text: isConnected ? I18n.tr("Connected") : (modelData.secured ? I18n.tr("Secured") : I18n.tr("Open")) - font.pixelSize: Theme.fontSizeSmall - color: isConnected ? Theme.primary : Theme.surfaceVariantText - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: modelData.saved - } - - StyledText { - text: I18n.tr("Saved") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - visible: modelData.saved - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: modelData.hidden || false - } - - StyledText { - text: I18n.tr("Hidden") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: modelData.hidden || false - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: modelData.signal + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - - Row { - id: wifiNetworkActions - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: wifiExpandBtn.containsMouse ? Theme.surfacePressed : "transparent" - visible: isConnected || modelData.saved - - DankIcon { - anchors.centerIn: parent - name: isExpanded ? "expand_less" : "expand_more" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: wifiExpandBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (isExpanded) { - networkTab.expandedWifiSsid = ""; - } else { - networkTab.expandedWifiSsid = modelData.ssid; - NetworkService.fetchNetworkInfo(modelData.ssid); - } - } - } - } - - DankActionButton { - iconName: "qr_code" - buttonSize: 28 - visible: modelData.secured && modelData.saved - onClicked: { - PopoutService.showWifiQRCodeModal(modelData.ssid); - } - } - - DankActionButton { - iconName: isPinned ? "push_pin" : "push_pin" - buttonSize: 28 - iconColor: isPinned ? Theme.primary : Theme.surfaceVariantText - onClicked: { - networkTab.toggleWifiPin(modelData.ssid) - } - } - - DankActionButton { - iconName: "delete" - buttonSize: 28 - iconColor: Theme.error - visible: modelData.saved || isConnected - onClicked: { - forgetNetworkConfirm.showWithOptions({ - title: I18n.tr("Forget Network"), - message: I18n.tr("Forget \"%1\"?").arg(modelData.ssid), - confirmText: I18n.tr("Forget"), - confirmColor: Theme.error, - onConfirm: () => NetworkService.forgetWifiNetwork(modelData.ssid) - }); - } - } - } - - MouseArea { - id: wifiNetworkMouseArea - - anchors.fill: parent - anchors.rightMargin: wifiNetworkActions.width + Theme.spacingM - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (isConnected) { - NetworkService.disconnectWifi(); - return; - } - NetworkService.connectToWifi(modelData.ssid); - } - } - } - - Column { - id: wifiExpandedContent - width: parent.width - visible: isExpanded - - Rectangle { - width: parent.width - Theme.spacingM * 2 - height: 1 - x: Theme.spacingM - color: Theme.outlineLight - } - - Item { - width: parent.width - height: wifiDetailsColumn.implicitHeight + Theme.spacingM * 2 - - Column { - id: wifiDetailsColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Item { - width: parent.width - height: NetworkService.networkInfoLoading ? 40 : 0 - visible: NetworkService.networkInfoLoading - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - id: wifiInfoLoadIcon - name: "sync" - size: 16 - color: Theme.surfaceVariantText - - SequentialAnimation { - running: NetworkService.networkInfoLoading - loops: Animation.Infinite - NumberAnimation { - target: wifiInfoLoadIcon - property: "opacity" - to: 0.3 - duration: 400 - easing.type: Easing.InOutQuad - } - NumberAnimation { - target: wifiInfoLoadIcon - property: "opacity" - to: 1.0 - duration: 400 - easing.type: Easing.InOutQuad - } - onRunningChanged: if (!running) - wifiInfoLoadIcon.opacity = 1.0 - } - } - - StyledText { - text: I18n.tr("Loading...") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: !NetworkService.networkInfoLoading - - Repeater { - model: { - const fields = []; - const net = modelData; - if (!net) - return fields; - - fields.push({ - label: I18n.tr("Signal"), - value: net.signal + "%" - }); - if (net.frequency) - fields.push({ - label: I18n.tr("Frequency"), - value: (net.frequency / 1000).toFixed(1) + " GHz" - }); - if (net.channel) - fields.push({ - label: I18n.tr("Channel"), - value: String(net.channel) - }); - if (net.rate) - fields.push({ - label: I18n.tr("Rate"), - value: net.rate + " Mbps" - }); - if (net.mode) - fields.push({ - label: I18n.tr("Mode"), - value: net.mode - }); - if (net.bssid) - fields.push({ - label: I18n.tr("BSSID"), - value: net.bssid - }); - fields.push({ - label: I18n.tr("Security"), - value: net.secured ? (net.enterprise ? I18n.tr("Enterprise") : I18n.tr("WPA/WPA2")) : I18n.tr("Open") - }); - - return fields; - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: wifiFieldContent.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHigh - border.width: 1 - border.color: Theme.outlineLight - - Row { - id: wifiFieldContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: modelData.label + ":" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - Row { - spacing: Theme.spacingS - visible: (modelData.saved || isConnected) && DMSService.apiVersion > 13 - - DankToggle { - id: autoconnectToggle - text: I18n.tr("Autoconnect") - checked: modelData.autoconnect || false - onToggled: checked => { - NetworkService.setWifiAutoconnect(modelData.ssid, checked); - } - } - } - } - } - } - } - } - } - } - } - } - } - - StyledRect { - width: parent.width - height: vpnSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: DMSNetworkService.vpnAvailable - - Column { - id: vpnSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - vpnHeaderControls.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("VPN") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - if (!DMSNetworkService.connected) - return I18n.tr("Disconnected"); - const names = DMSNetworkService.activeNames || []; - if (names.length <= 1) - return names[0] || I18n.tr("Connected"); - return names[0] + " +" + (names.length - 1); - } - font.pixelSize: Theme.fontSizeSmall - color: DMSNetworkService.connected ? Theme.primary : Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Row { - id: vpnHeaderControls - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - Rectangle { - height: 28 - radius: 14 - width: importVpnRow.width + Theme.spacingM * 2 - color: importVpnArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - opacity: VPNService.importing ? 0.5 : 1.0 - - Row { - id: importVpnRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: VPNService.importing ? "sync" : "add" - size: Theme.fontSizeSmall - color: Theme.primary - } - - StyledText { - text: I18n.tr("Import") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - } - } - - MouseArea { - id: importVpnArea - anchors.fill: parent - hoverEnabled: true - cursorShape: VPNService.importing ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !VPNService.importing - onClicked: networkTab.openVpnFileBrowser() - } - } - - Rectangle { - height: 28 - radius: 14 - width: disconnectAllRow.width + Theme.spacingM * 2 - color: disconnectAllArea.containsMouse ? Theme.errorHover : Theme.surfaceLight - visible: DMSNetworkService.connected - opacity: DMSNetworkService.isBusy ? 0.5 : 1.0 - - Row { - id: disconnectAllRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "link_off" - size: Theme.fontSizeSmall - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Disconnect") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: disconnectAllArea - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !DMSNetworkService.isBusy - onClicked: DMSNetworkService.disconnectAllActive() - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Item { - width: parent.width - height: 100 - visible: DMSNetworkService.profiles.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "vpn_key_off" - size: 36 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No VPN profiles") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("Click Import to add a .ovpn or .conf") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Column { - width: parent.width - spacing: 4 - visible: DMSNetworkService.profiles.length > 0 - - Repeater { - model: DMSNetworkService.profiles - - delegate: Rectangle { - id: vpnProfileRow - required property var modelData - required property int index - - readonly property bool isActive: DMSNetworkService.isActiveUuid(modelData.uuid) - readonly property bool isExpanded: networkTab.expandedVpnUuid === modelData.uuid - readonly property var configData: isExpanded ? VPNService.editConfig : null - - width: parent.width - height: isExpanded ? 56 + vpnExpandedContent.height : 56 - radius: Theme.cornerRadius - color: vpnRowArea.containsMouse ? Theme.primaryHoverLight : (isActive ? Theme.primaryPressed : Theme.surfaceLight) - border.width: isActive ? 2 : 0 - border.color: Theme.primary - opacity: DMSNetworkService.isBusy ? 0.6 : 1.0 - clip: true - - Behavior on height { - NumberAnimation { - duration: 150 - easing.type: Easing.OutQuad - } - } - - MouseArea { - id: vpnRowArea - anchors.fill: parent - hoverEnabled: true - cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor - enabled: !DMSNetworkService.isBusy - onClicked: DMSNetworkService.toggle(modelData.uuid) - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - Row { - width: parent.width - height: 56 - Theme.spacingS * 2 - spacing: Theme.spacingS - - DankIcon { - name: isActive ? "vpn_lock" : "vpn_key_off" - size: 20 - color: isActive ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - spacing: 2 - anchors.verticalCenter: parent.verticalCenter - width: parent.width - 20 - 28 - 28 - Theme.spacingS * 4 - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - color: isActive ? Theme.primary : Theme.surfaceText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: VPNService.getVpnTypeFromProfile(modelData) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.left: parent.left - } - } - - Item { - width: Theme.spacingXS - height: 1 - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: vpnExpandBtn.containsMouse ? Theme.surfacePressed : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: isExpanded ? "expand_less" : "expand_more" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: vpnExpandBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (isExpanded) { - networkTab.expandedVpnUuid = ""; - } else { - networkTab.expandedVpnUuid = modelData.uuid; - VPNService.getConfig(modelData.uuid); - } - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: vpnDeleteBtn.containsMouse ? Theme.errorHover : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: vpnDeleteBtn.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: vpnDeleteBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - deleteVpnConfirm.showWithOptions({ - title: I18n.tr("Delete VPN"), - message: I18n.tr("Delete \"%1\"?").arg(modelData.name), - confirmText: I18n.tr("Delete"), - confirmColor: Theme.error, - onConfirm: () => VPNService.deleteVpn(modelData.uuid) - }); - } - } - } - } - - Column { - id: vpnExpandedContent - width: parent.width - spacing: Theme.spacingXS - visible: isExpanded - - Rectangle { - width: parent.width - height: 1 - color: Theme.outlineLight - } - - Item { - width: parent.width - height: VPNService.configLoading ? 40 : 0 - visible: VPNService.configLoading - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - id: vpnLoadIcon - name: "sync" - size: 16 - color: Theme.surfaceVariantText - - SequentialAnimation { - running: VPNService.configLoading - loops: Animation.Infinite - NumberAnimation { - target: vpnLoadIcon - property: "opacity" - to: 0.3 - duration: 400 - easing.type: Easing.InOutQuad - } - NumberAnimation { - target: vpnLoadIcon - property: "opacity" - to: 1.0 - duration: 400 - easing.type: Easing.InOutQuad - } - onRunningChanged: if (!running) - vpnLoadIcon.opacity = 1.0 - } - } - - StyledText { - text: I18n.tr("Loading...") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: !VPNService.configLoading && configData - - Repeater { - model: { - if (!configData) - return []; - const fields = []; - const data = configData.data || {}; - - if (data.remote) - fields.push({ - label: I18n.tr("Server"), - value: data.remote - }); - if (configData.username || data.username) - fields.push({ - label: I18n.tr("Username"), - value: configData.username || data.username - }); - if (data.cipher) - fields.push({ - label: I18n.tr("Cipher"), - value: data.cipher - }); - if (data.auth) - fields.push({ - label: I18n.tr("Auth"), - value: data.auth - }); - if (data["proto-tcp"] === "yes" || data["proto-tcp"] === "no") - fields.push({ - label: I18n.tr("Protocol"), - value: data["proto-tcp"] === "yes" ? "TCP" : "UDP" - }); - if (data["tunnel-mtu"]) - fields.push({ - label: I18n.tr("MTU"), - value: data["tunnel-mtu"] - }); - if (data["connection-type"]) - fields.push({ - label: I18n.tr("Auth Type"), - value: data["connection-type"] - }); - return fields; - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: vpnFieldContent.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHigh - border.width: 1 - border.color: Theme.outlineLight - - Row { - id: vpnFieldContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: modelData.label + ":" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - DankToggle { - width: parent.width - text: I18n.tr("Autoconnect") - checked: configData ? (configData.autoconnect || false) : false - visible: !VPNService.configLoading && configData !== null - onToggled: checked => { - VPNService.updateConfig(modelData.uuid, {autoconnect: checked}); - } - } - - Item { - width: 1 - height: Theme.spacingXS - } - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NotificationsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NotificationsTab.qml deleted file mode 100644 index c43a5e2..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/NotificationsTab.qml +++ /dev/null @@ -1,900 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - Component.onCompleted: { - if (SettingsData._pendingExpandNotificationRules) { - SettingsData._pendingExpandNotificationRules = false; - notificationRulesCard.userToggledCollapse = true; - notificationRulesCard.expanded = true; - SettingsData._pendingNotificationRuleIndex = -1; - } - } - - readonly property var mutedRules: { - var rules = SettingsData.notificationRules || []; - var out = []; - for (var i = 0; i < rules.length; i++) { - if ((rules[i].action || "").toString().toLowerCase() === "mute") - out.push({ - rule: rules[i], - index: i - }); - } - return out; - } - - readonly property var timeoutOptions: [ - { - text: I18n.tr("Never"), - value: 0 - }, - { - text: I18n.tr("1 second"), - value: 1000 - }, - { - text: I18n.tr("3 seconds"), - value: 3000 - }, - { - text: I18n.tr("5 seconds"), - value: 5000 - }, - { - text: I18n.tr("8 seconds"), - value: 8000 - }, - { - text: I18n.tr("10 seconds"), - value: 10000 - }, - { - text: I18n.tr("15 seconds"), - value: 15000 - }, - { - text: I18n.tr("30 seconds"), - value: 30000 - }, - { - text: I18n.tr("1 minute"), - value: 60000 - }, - { - text: I18n.tr("2 minutes"), - value: 120000 - }, - { - text: I18n.tr("5 minutes"), - value: 300000 - }, - { - text: I18n.tr("10 minutes"), - value: 600000 - } - ] - - readonly property var notificationRuleFieldOptions: [ - { - value: "appName", - label: I18n.tr("App Names", "notification rule match field option") - }, - { - value: "desktopEntry", - label: I18n.tr("Desktop Entry", "notification rule match field option") - }, - { - value: "summary", - label: I18n.tr("Summary", "notification rule match field option") - }, - { - value: "body", - label: I18n.tr("Body", "notification rule match field option") - } - ] - - readonly property var notificationRuleMatchTypeOptions: [ - { - value: "contains", - label: I18n.tr("Contains", "notification rule match type option") - }, - { - value: "exact", - label: I18n.tr("Exact", "notification rule match type option") - }, - { - value: "regex", - label: I18n.tr("Regex", "notification rule match type option") - } - ] - - readonly property var notificationRuleActionOptions: [ - { - value: "default", - label: I18n.tr("Default", "notification rule action option") - }, - { - value: "mute", - label: I18n.tr("Mute Popups", "notification rule action option") - }, - { - value: "ignore", - label: I18n.tr("Ignore Completely", "notification rule action option") - }, - { - value: "popup_only", - label: I18n.tr("Popup Only", "notification rule action option") - }, - { - value: "no_history", - label: I18n.tr("No History", "notification rule action option") - } - ] - - readonly property var notificationRuleUrgencyOptions: [ - { - value: "default", - label: I18n.tr("Default", "notification rule urgency option") - }, - { - value: "low", - label: I18n.tr("Low Priority", "notification rule urgency option") - }, - { - value: "normal", - label: I18n.tr("Normal Priority", "notification rule urgency option") - }, - { - value: "critical", - label: I18n.tr("Critical Priority", "notification rule urgency option") - } - ] - - function getTimeoutText(value) { - if (value === undefined || value === null || isNaN(value)) - return I18n.tr("5 seconds"); - for (let i = 0; i < timeoutOptions.length; i++) { - if (timeoutOptions[i].value === value) - return timeoutOptions[i].text; - } - if (value === 0) - return I18n.tr("Never"); - if (value < 1000) - return value + "ms"; - if (value < 60000) - return Math.round(value / 1000) + " " + I18n.tr("seconds"); - return Math.round(value / 60000) + " " + I18n.tr("minutes"); - } - - function getRuleOptionLabel(options, value, fallback) { - for (let i = 0; i < options.length; i++) { - if (options[i].value === value) - return options[i].label; - } - return fallback; - } - - function getRuleOptionValue(options, label, fallback) { - for (let i = 0; i < options.length; i++) { - if (options[i].label === label) - return options[i].value; - } - return fallback; - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "notifications" - title: I18n.tr("Notification Popups") - settingKey: "notificationPopups" - - SettingsDropdownRow { - settingKey: "notificationPopupPosition" - tags: ["notification", "popup", "position", "screen", "location"] - text: I18n.tr("Popup Position") - description: I18n.tr("Choose where notification popups appear on screen") - currentValue: { - if (SettingsData.notificationPopupPosition === -1) - return I18n.tr("Top Center", "screen position option"); - switch (SettingsData.notificationPopupPosition) { - case SettingsData.Position.Top: - return I18n.tr("Top Right", "screen position option"); - case SettingsData.Position.Bottom: - return I18n.tr("Bottom Left", "screen position option"); - case SettingsData.Position.Left: - return I18n.tr("Top Left", "screen position option"); - case SettingsData.Position.Right: - return I18n.tr("Bottom Right", "screen position option"); - case SettingsData.Position.BottomCenter: - return I18n.tr("Bottom Center", "screen position option"); - default: - return I18n.tr("Top Right", "screen position option"); - } - } - options: [I18n.tr("Top Right", "screen position option"), I18n.tr("Top Left", "screen position option"), I18n.tr("Top Center", "screen position option"), I18n.tr("Bottom Center", "screen position option"), I18n.tr("Bottom Right", "screen position option"), I18n.tr("Bottom Left", "screen position option")] - onValueChanged: value => { - switch (value) { - case I18n.tr("Top Right", "screen position option"): - SettingsData.set("notificationPopupPosition", SettingsData.Position.Top); - break; - case I18n.tr("Top Left", "screen position option"): - SettingsData.set("notificationPopupPosition", SettingsData.Position.Left); - break; - case I18n.tr("Top Center", "screen position option"): - SettingsData.set("notificationPopupPosition", -1); - break; - case I18n.tr("Bottom Center", "screen position option"): - SettingsData.set("notificationPopupPosition", SettingsData.Position.BottomCenter); - break; - case I18n.tr("Bottom Right", "screen position option"): - SettingsData.set("notificationPopupPosition", SettingsData.Position.Right); - break; - case I18n.tr("Bottom Left", "screen position option"): - SettingsData.set("notificationPopupPosition", SettingsData.Position.Bottom); - break; - } - SettingsData.sendTestNotifications(); - } - } - - SettingsToggleRow { - settingKey: "notificationOverlayEnabled" - tags: ["notification", "overlay", "fullscreen", "priority"] - text: I18n.tr("Notification Overlay") - description: I18n.tr("Display all priorities over fullscreen apps") - checked: SettingsData.notificationOverlayEnabled - onToggled: checked => SettingsData.set("notificationOverlayEnabled", checked) - } - - SettingsToggleRow { - settingKey: "notificationCompactMode" - tags: ["notification", "compact", "size", "display", "mode"] - text: I18n.tr("Compact") - description: I18n.tr("Use smaller notification cards") - checked: SettingsData.notificationCompactMode - onToggled: checked => SettingsData.set("notificationCompactMode", checked) - } - - SettingsToggleRow { - settingKey: "notificationPopupShadowEnabled" - tags: ["notification", "popup", "shadow", "radius", "rounded"] - text: I18n.tr("Popup Shadow") - description: I18n.tr("Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.") - checked: SettingsData.notificationPopupShadowEnabled - onToggled: checked => SettingsData.set("notificationPopupShadowEnabled", checked) - } - - SettingsToggleRow { - settingKey: "notificationPopupPrivacyMode" - tags: ["notification", "popup", "privacy", "body", "content", "hide"] - text: I18n.tr("Privacy Mode") - description: I18n.tr("Hide notification content until expanded; popups show collapsed by default") - checked: SettingsData.notificationPopupPrivacyMode - onToggled: checked => SettingsData.set("notificationPopupPrivacyMode", checked) - } - - SettingsToggleRow { - settingKey: "notificationFocusedMonitor" - tags: ["notification", "popup", "focused", "monitor", "display", "screen", "active"] - text: I18n.tr("Focused Monitor Only") - description: I18n.tr("Show notification popups only on the currently focused monitor") - checked: SettingsData.notificationFocusedMonitor - onToggled: checked => SettingsData.set("notificationFocusedMonitor", checked) - } - - Item { - width: parent.width - height: notificationAnimationColumn.implicitHeight + Theme.spacingM * 2 - - Column { - id: notificationAnimationColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.top: parent.top - anchors.topMargin: Theme.spacingM - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Animation Speed") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - } - - StyledText { - text: I18n.tr("Control animation duration for notification popups and history") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } - - DankButtonGroup { - id: notificationSpeedGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingM - minButtonWidth: parent.width < 480 ? 44 : 56 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")] - selectionMode: "single" - currentIndex: SettingsData.notificationAnimationSpeed - onSelectionChanged: (index, selected) => { - if (!selected) - return; - SettingsData.set("notificationAnimationSpeed", index); - } - - Connections { - target: SettingsData - function onNotificationAnimationSpeedChanged() { - notificationSpeedGroup.currentIndex = SettingsData.notificationAnimationSpeed; - } - } - } - - SettingsSliderRow { - id: animationDurationSlider - settingKey: "notificationCustomAnimationDuration" - tags: ["notification", "animation", "duration", "custom", "speed"] - text: I18n.tr("Duration") - description: I18n.tr("Base duration for animations (drag to use Custom)") - minimum: 100 - maximum: 800 - value: Theme.notificationAnimationBaseDuration - unit: "ms" - defaultValue: 400 - onSliderValueChanged: newValue => { - if (SettingsData.notificationAnimationSpeed !== SettingsData.AnimationSpeed.Custom) { - SettingsData.set("notificationAnimationSpeed", SettingsData.AnimationSpeed.Custom); - } - SettingsData.set("notificationCustomAnimationDuration", newValue); - } - - Connections { - target: Theme - function onNotificationAnimationBaseDurationChanged() { - animationDurationSlider.value = Theme.notificationAnimationBaseDuration; - } - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "notifications_off" - title: I18n.tr("Do Not Disturb") - settingKey: "doNotDisturb" - - SettingsToggleRow { - settingKey: "doNotDisturb" - tags: ["notification", "dnd", "mute", "silent", "suppress"] - text: I18n.tr("Enable Do Not Disturb") - description: I18n.tr("Suppress notification popups while enabled") - checked: SessionData.doNotDisturb - onToggled: checked => SessionData.setDoNotDisturb(checked) - } - } - - SettingsCard { - id: notificationRulesCard - width: parent.width - iconName: "rule_settings" - title: I18n.tr("Notification Rules") - settingKey: "notificationRules" - tags: ["notification", "rules", "mute", "ignore", "priority", "regex", "history"] - collapsible: true - expanded: false - - headerActions: [ - DankActionButton { - buttonSize: 36 - iconName: "restart_alt" - iconSize: 20 - visible: JSON.stringify(SettingsData.notificationRules) !== JSON.stringify(SettingsData.getDefaultNotificationRules()) - backgroundColor: Theme.surfaceContainer - iconColor: Theme.surfaceVariantText - onClicked: SettingsData.resetNotificationRules() - }, - DankActionButton { - buttonSize: 36 - iconName: "add" - iconSize: 20 - backgroundColor: Theme.surfaceContainer - iconColor: Theme.primary - onClicked: { - SettingsData.addNotificationRule(); - notificationRulesCard.userToggledCollapse = true; - notificationRulesCard.expanded = true; - } - } - ] - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - bottomPadding: Theme.spacingS - } - - Repeater { - model: SettingsData.notificationRules - - delegate: Rectangle { - id: ruleItem - width: parent.width - height: ruleColumn.implicitHeight + Theme.spacingM - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, 0.5) - - Column { - id: ruleColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - id: ruleLabel - text: I18n.tr("Rule") + " " + (index + 1) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: Math.max(0, parent.width - ruleLabel.implicitWidth - enableToggle.width - deleteBtn.width - Theme.spacingS * 3) - height: 1 - } - - DankToggle { - id: enableToggle - width: 40 - height: 24 - hideText: true - checked: modelData.enabled !== false - onToggled: checked => SettingsData.updateNotificationRuleField(index, "enabled", checked) - } - - Item { - id: deleteBtn - width: 28 - height: 28 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: deleteArea.containsMouse ? Theme.withAlpha(Theme.error, 0.2) : "transparent" - } - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: SettingsData.removeNotificationRule(index) - } - } - } - - Column { - width: parent.width - spacing: 2 - - StyledText { - text: I18n.tr("Pattern") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - text: modelData.pattern || "" - font.pixelSize: Theme.fontSizeSmall - placeholderText: I18n.tr("Pattern") - onEditingFinished: SettingsData.updateNotificationRuleField(index, "pattern", text) - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - Column { - width: (parent.width - Theme.spacingS * 3) / 4 - spacing: 2 - - StyledText { - text: I18n.tr("Field") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankDropdown { - width: parent.width - compactMode: true - dropdownWidth: parent.width - popupWidth: 165 - currentValue: root.getRuleOptionLabel(root.notificationRuleFieldOptions, modelData.field, root.notificationRuleFieldOptions[0].label) - options: root.notificationRuleFieldOptions.map(o => o.label) - onValueChanged: value => SettingsData.updateNotificationRuleField(index, "field", root.getRuleOptionValue(root.notificationRuleFieldOptions, value, "appName")) - } - } - - Column { - width: (parent.width - Theme.spacingS * 3) / 4 - spacing: 2 - - StyledText { - text: I18n.tr("Type") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankDropdown { - width: parent.width - compactMode: true - dropdownWidth: parent.width - currentValue: root.getRuleOptionLabel(root.notificationRuleMatchTypeOptions, modelData.matchType, root.notificationRuleMatchTypeOptions[0].label) - options: root.notificationRuleMatchTypeOptions.map(o => o.label) - onValueChanged: value => SettingsData.updateNotificationRuleField(index, "matchType", root.getRuleOptionValue(root.notificationRuleMatchTypeOptions, value, "contains")) - } - } - - Column { - width: (parent.width - Theme.spacingS * 3) / 4 - spacing: 2 - - StyledText { - text: I18n.tr("Action") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankDropdown { - width: parent.width - compactMode: true - dropdownWidth: parent.width - popupWidth: 170 - currentValue: root.getRuleOptionLabel(root.notificationRuleActionOptions, modelData.action, root.notificationRuleActionOptions[0].label) - options: root.notificationRuleActionOptions.map(o => o.label) - onValueChanged: value => SettingsData.updateNotificationRuleField(index, "action", root.getRuleOptionValue(root.notificationRuleActionOptions, value, "default")) - } - } - - Column { - width: (parent.width - Theme.spacingS * 3) / 4 - spacing: 2 - - StyledText { - text: I18n.tr("Priority") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankDropdown { - width: parent.width - compactMode: true - dropdownWidth: parent.width - popupWidth: 165 - currentValue: root.getRuleOptionLabel(root.notificationRuleUrgencyOptions, modelData.urgency, root.notificationRuleUrgencyOptions[0].label) - options: root.notificationRuleUrgencyOptions.map(o => o.label) - onValueChanged: value => SettingsData.updateNotificationRuleField(index, "urgency", root.getRuleOptionValue(root.notificationRuleUrgencyOptions, value, "default")) - } - } - } - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "volume_off" - title: I18n.tr("Muted Apps") - settingKey: "mutedApps" - tags: ["notification", "mute", "unmute", "popup"] - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: mutedRules.length > 0 ? I18n.tr("Apps with notification popups muted. Unmute or delete to remove.") : I18n.tr("No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - bottomPadding: Theme.spacingS - } - - Repeater { - model: mutedRules - - delegate: Rectangle { - width: parent.width - height: mutedRow.implicitHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, 0.5) - - Row { - id: mutedRow - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingM - - StyledText { - id: mutedAppLabel - text: (modelData.rule && modelData.rule.pattern) ? modelData.rule.pattern : I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: Math.max(0, parent.width - parent.spacing - mutedAppLabel.width - unmuteBtn.width - deleteBtn.width - Theme.spacingS * 5) - height: 1 - } - - DankButton { - id: unmuteBtn - text: I18n.tr("Unmute") - backgroundColor: Theme.surfaceContainer - textColor: Theme.primary - onClicked: SettingsData.removeNotificationRule(modelData.index) - } - - Item { - id: deleteBtn - width: 28 - height: 28 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: deleteArea.containsMouse ? Theme.withAlpha(Theme.error, 0.2) : "transparent" - } - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: SettingsData.removeNotificationRule(modelData.index) - } - } - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "lock" - title: I18n.tr("Lock Screen", "lock screen notifications settings card") - settingKey: "lockScreenNotifications" - - SettingsDropdownRow { - settingKey: "lockScreenNotificationMode" - tags: ["lock", "screen", "notification", "notifications", "privacy"] - text: I18n.tr("Notification Display", "lock screen notification privacy setting") - description: I18n.tr("Control what notification information is shown on the lock screen", "lock screen notification privacy setting") - options: [I18n.tr("Disabled", "lock screen notification mode option"), I18n.tr("Count Only", "lock screen notification mode option"), I18n.tr("App Names", "lock screen notification mode option"), I18n.tr("Full Content", "lock screen notification mode option")] - currentValue: options[SettingsData.lockScreenNotificationMode] || options[0] - onValueChanged: value => { - const idx = options.indexOf(value); - if (idx >= 0) { - SettingsData.set("lockScreenNotificationMode", idx); - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "timer" - title: I18n.tr("Notification Timeouts") - settingKey: "notificationTimeouts" - collapsible: true - expanded: false - - SettingsDropdownRow { - settingKey: "notificationTimeoutLow" - tags: ["notification", "timeout", "low", "priority", "duration"] - text: I18n.tr("Low Priority") - description: I18n.tr("Timeout for low priority notifications") - currentValue: root.getTimeoutText(SettingsData.notificationTimeoutLow) - options: root.timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < root.timeoutOptions.length; i++) { - if (root.timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutLow", root.timeoutOptions[i].value); - break; - } - } - } - } - - SettingsDropdownRow { - settingKey: "notificationTimeoutNormal" - tags: ["notification", "timeout", "normal", "priority", "duration"] - text: I18n.tr("Normal Priority") - description: I18n.tr("Timeout for normal priority notifications") - currentValue: root.getTimeoutText(SettingsData.notificationTimeoutNormal) - options: root.timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < root.timeoutOptions.length; i++) { - if (root.timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutNormal", root.timeoutOptions[i].value); - break; - } - } - } - } - - SettingsDropdownRow { - settingKey: "notificationTimeoutCritical" - tags: ["notification", "timeout", "critical", "priority", "duration"] - text: I18n.tr("Critical Priority") - description: I18n.tr("Timeout for critical priority notifications") - currentValue: root.getTimeoutText(SettingsData.notificationTimeoutCritical) - options: root.timeoutOptions.map(opt => opt.text) - onValueChanged: value => { - for (let i = 0; i < root.timeoutOptions.length; i++) { - if (root.timeoutOptions[i].text === value) { - SettingsData.set("notificationTimeoutCritical", root.timeoutOptions[i].value); - break; - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "history" - title: I18n.tr("History Settings") - settingKey: "notificationHistory" - - SettingsToggleRow { - settingKey: "notificationHistoryEnabled" - tags: ["notification", "history", "enable", "disable", "save"] - text: I18n.tr("Enable History", "notification history toggle label") - description: I18n.tr("Save dismissed notifications to history", "notification history toggle description") - checked: SettingsData.notificationHistoryEnabled - onToggled: checked => SettingsData.set("notificationHistoryEnabled", checked) - } - - SettingsSliderRow { - settingKey: "notificationHistoryMaxCount" - tags: ["notification", "history", "max", "count", "limit"] - text: I18n.tr("Maximum History") - description: I18n.tr("Maximum number of notifications to keep", "notification history limit") - value: SettingsData.notificationHistoryMaxCount - minimum: 10 - maximum: 200 - step: 10 - unit: "" - defaultValue: 50 - onSliderValueChanged: newValue => SettingsData.set("notificationHistoryMaxCount", newValue) - } - - SettingsDropdownRow { - settingKey: "notificationHistoryMaxAgeDays" - tags: ["notification", "history", "max", "age", "days", "retention"] - text: I18n.tr("History Retention", "notification history retention settings label") - description: I18n.tr("Auto-delete notifications older than this", "notification history setting") - currentValue: { - switch (SettingsData.notificationHistoryMaxAgeDays) { - case 0: - return I18n.tr("Forever", "notification history retention option"); - case 1: - return I18n.tr("1 day", "notification history retention option"); - case 3: - return I18n.tr("3 days", "notification history retention option"); - case 7: - return I18n.tr("7 days", "notification history retention option"); - case 14: - return I18n.tr("14 days", "notification history retention option"); - case 30: - return I18n.tr("30 days", "notification history retention option"); - default: - return SettingsData.notificationHistoryMaxAgeDays + " " + I18n.tr("days"); - } - } - options: [I18n.tr("Forever", "notification history retention option"), I18n.tr("1 day", "notification history retention option"), I18n.tr("3 days", "notification history retention option"), I18n.tr("7 days", "notification history retention option"), I18n.tr("14 days", "notification history retention option"), I18n.tr("30 days", "notification history retention option")] - onValueChanged: value => { - let days = 7; - if (value === I18n.tr("Forever", "notification history retention option")) - days = 0; - else if (value === I18n.tr("1 day", "notification history retention option")) - days = 1; - else if (value === I18n.tr("3 days", "notification history retention option")) - days = 3; - else if (value === I18n.tr("7 days", "notification history retention option")) - days = 7; - else if (value === I18n.tr("14 days", "notification history retention option")) - days = 14; - else if (value === I18n.tr("30 days", "notification history retention option")) - days = 30; - SettingsData.set("notificationHistoryMaxAgeDays", days); - } - } - - SettingsToggleRow { - settingKey: "notificationHistorySaveLow" - tags: ["notification", "history", "save", "low", "priority"] - text: I18n.tr("Low Priority") - description: I18n.tr("Save low priority notifications to history", "notification history setting") - checked: SettingsData.notificationHistorySaveLow - onToggled: checked => SettingsData.set("notificationHistorySaveLow", checked) - } - - SettingsToggleRow { - settingKey: "notificationHistorySaveNormal" - tags: ["notification", "history", "save", "normal", "priority"] - text: I18n.tr("Normal Priority") - description: I18n.tr("Save normal priority notifications to history", "notification history setting") - checked: SettingsData.notificationHistorySaveNormal - onToggled: checked => SettingsData.set("notificationHistorySaveNormal", checked) - } - - SettingsToggleRow { - settingKey: "notificationHistorySaveCritical" - tags: ["notification", "history", "save", "critical", "priority"] - text: I18n.tr("Critical Priority") - description: I18n.tr("Save critical priority notifications to history", "notification history setting") - checked: SettingsData.notificationHistorySaveCritical - onToggled: checked => SettingsData.set("notificationHistorySaveCritical", checked) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/OSDTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/OSDTab.qml deleted file mode 100644 index 4bf26d8..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/OSDTab.qml +++ /dev/null @@ -1,165 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "tune" - title: I18n.tr("On-screen Displays") - settingKey: "osd" - - SettingsDropdownRow { - settingKey: "osdPosition" - text: I18n.tr("OSD Position") - description: I18n.tr("Choose where on-screen displays appear on screen") - currentValue: { - switch (SettingsData.osdPosition) { - case SettingsData.Position.Top: - return I18n.tr("Top Right", "screen position option"); - case SettingsData.Position.Left: - return I18n.tr("Top Left", "screen position option"); - case SettingsData.Position.TopCenter: - return I18n.tr("Top Center", "screen position option"); - case SettingsData.Position.Right: - return I18n.tr("Bottom Right", "screen position option"); - case SettingsData.Position.Bottom: - return I18n.tr("Bottom Left", "screen position option"); - case SettingsData.Position.BottomCenter: - return I18n.tr("Bottom Center", "screen position option"); - case SettingsData.Position.LeftCenter: - return I18n.tr("Left Center", "screen position option"); - case SettingsData.Position.RightCenter: - return I18n.tr("Right Center", "screen position option"); - default: - return I18n.tr("Bottom Center", "screen position option"); - } - } - options: [I18n.tr("Top Right", "screen position option"), I18n.tr("Top Left", "screen position option"), I18n.tr("Top Center", "screen position option"), I18n.tr("Bottom Right", "screen position option"), I18n.tr("Bottom Left", "screen position option"), I18n.tr("Bottom Center", "screen position option"), I18n.tr("Left Center", "screen position option"), I18n.tr("Right Center", "screen position option")] - onValueChanged: value => { - if (value === I18n.tr("Top Right", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.Top); - } else if (value === I18n.tr("Top Left", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.Left); - } else if (value === I18n.tr("Top Center", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.TopCenter); - } else if (value === I18n.tr("Bottom Right", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.Right); - } else if (value === I18n.tr("Bottom Left", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.Bottom); - } else if (value === I18n.tr("Bottom Center", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.BottomCenter); - } else if (value === I18n.tr("Left Center", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.LeftCenter); - } else if (value === I18n.tr("Right Center", "screen position option")) { - SettingsData.set("osdPosition", SettingsData.Position.RightCenter); - } - } - } - - SettingsToggleRow { - settingKey: "osdAlwaysShowValue" - text: I18n.tr("Always Show Percentage") - description: I18n.tr("Display volume and brightness percentage values in OSD popups") - checked: SettingsData.osdAlwaysShowValue - onToggled: checked => SettingsData.set("osdAlwaysShowValue", checked) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - settingKey: "osdVolumeEnabled" - text: I18n.tr("Volume") - description: I18n.tr("Show on-screen display when volume changes") - checked: SettingsData.osdVolumeEnabled - onToggled: checked => SettingsData.set("osdVolumeEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdMediaVolumeEnabled" - text: I18n.tr("Media Volume") - description: I18n.tr("Show on-screen display when media player volume changes") - checked: SettingsData.osdMediaVolumeEnabled - onToggled: checked => SettingsData.set("osdMediaVolumeEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdMediaPlaybackEnabled" - text: I18n.tr("Media Playback") - description: I18n.tr("Show on-screen display when media player status changes") - checked: SettingsData.osdMediaPlaybackEnabled - onToggled: checked => SettingsData.set("osdMediaPlaybackEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdBrightnessEnabled" - text: I18n.tr("Brightness") - description: I18n.tr("Show on-screen display when brightness changes") - checked: SettingsData.osdBrightnessEnabled - onToggled: checked => SettingsData.set("osdBrightnessEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdIdleInhibitorEnabled" - text: I18n.tr("Idle Inhibitor") - description: I18n.tr("Show on-screen display when idle inhibitor state changes") - checked: SettingsData.osdIdleInhibitorEnabled - onToggled: checked => SettingsData.set("osdIdleInhibitorEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdMicMuteEnabled" - text: I18n.tr("Microphone Mute") - description: I18n.tr("Show on-screen display when microphone is muted/unmuted") - checked: SettingsData.osdMicMuteEnabled - onToggled: checked => SettingsData.set("osdMicMuteEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdCapsLockEnabled" - text: I18n.tr("Caps Lock") - description: I18n.tr("Show on-screen display when caps lock state changes") - checked: SettingsData.osdCapsLockEnabled - onToggled: checked => SettingsData.set("osdCapsLockEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdPowerProfileEnabled" - text: I18n.tr("Power Profile") - description: I18n.tr("Show on-screen display when power profile changes") - checked: SettingsData.osdPowerProfileEnabled - onToggled: checked => SettingsData.set("osdPowerProfileEnabled", checked) - } - - SettingsToggleRow { - settingKey: "osdAudioOutputEnabled" - text: I18n.tr("Audio Output Switch") - description: I18n.tr("Show on-screen display when cycling audio output devices") - checked: SettingsData.osdAudioOutputEnabled - onToggled: checked => SettingsData.set("osdAudioOutputEnabled", checked) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginBrowser.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginBrowser.qml deleted file mode 100644 index b1f0a6f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginBrowser.qml +++ /dev/null @@ -1,856 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property var allPlugins: [] - property string searchQuery: "" - property var filteredPlugins: [] - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - property bool isLoading: false - property var parentModal: null - property bool pendingInstallHandled: false - property string typeFilter: "" - - function updateFilteredPlugins() { - var filtered = []; - var query = searchQuery ? searchQuery.toLowerCase() : ""; - - for (var i = 0; i < allPlugins.length; i++) { - var plugin = allPlugins[i]; - var isFirstParty = plugin.firstParty || false; - - if (!SessionData.showThirdPartyPlugins && !isFirstParty) - continue; - if (typeFilter !== "") { - var hasCapability = plugin.capabilities && plugin.capabilities.includes(typeFilter); - if (!hasCapability) - continue; - } - - if (query.length === 0) { - filtered.push(plugin); - continue; - } - - var name = plugin.name ? plugin.name.toLowerCase() : ""; - var description = plugin.description ? plugin.description.toLowerCase() : ""; - var author = plugin.author ? plugin.author.toLowerCase() : ""; - - if (name.indexOf(query) !== -1 || description.indexOf(query) !== -1 || author.indexOf(query) !== -1) - filtered.push(plugin); - } - - filtered.sort((a, b) => { - if (a.featured !== b.featured) - return a.featured ? -1 : 1; - if (a.firstParty !== b.firstParty) - return a.firstParty ? -1 : 1; - return 0; - }); - - filteredPlugins = filtered; - selectedIndex = -1; - keyboardNavigationActive = false; - } - - function selectNext() { - if (filteredPlugins.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.min(selectedIndex + 1, filteredPlugins.length - 1); - } - - function selectPrevious() { - if (filteredPlugins.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.max(selectedIndex - 1, -1); - if (selectedIndex === -1) - keyboardNavigationActive = false; - } - - function installPlugin(pluginName, enableAfterInstall) { - ToastService.showInfo(I18n.tr("Installing: %1", "installation progress").arg(pluginName)); - DMSService.install(pluginName, response => { - if (response.error) { - ToastService.showError(I18n.tr("Install failed: %1", "installation error").arg(response.error)); - return; - } - ToastService.showInfo(I18n.tr("Installed: %1", "installation success").arg(pluginName)); - PluginService.scanPlugins(); - refreshPlugins(); - if (enableAfterInstall) { - Qt.callLater(() => { - PluginService.enablePlugin(pluginName); - const plugin = PluginService.availablePlugins[pluginName]; - if (plugin?.type === "desktop") { - const defaultConfig = DesktopWidgetRegistry.getDefaultConfig(pluginName); - SettingsData.createDesktopWidgetInstance(pluginName, plugin.name || pluginName, defaultConfig); - } - hide(); - }); - } - }); - } - - function refreshPlugins() { - isLoading = true; - DMSService.listPlugins(); - if (DMSService.apiVersion >= 8) - DMSService.listInstalled(); - } - - function checkPendingInstall() { - if (!PopoutService.pendingPluginInstall || pendingInstallHandled) - return; - pendingInstallHandled = true; - var pluginId = PopoutService.pendingPluginInstall; - PopoutService.pendingPluginInstall = ""; - urlInstallConfirm.showWithOptions({ - "title": I18n.tr("Install Plugin", "plugin installation dialog title"), - "message": I18n.tr("Install plugin '%1' from the DMS registry?", "plugin installation confirmation").arg(pluginId), - "confirmText": I18n.tr("Install", "install action button"), - "cancelText": I18n.tr("Cancel"), - "onConfirm": () => installPlugin(pluginId, true), - "onCancel": () => hide() - }); - } - - function show() { - if (parentModal) - parentModal.shouldHaveFocus = false; - visible = true; - Qt.callLater(() => browserSearchField.forceActiveFocus()); - } - - function hide() { - visible = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - objectName: "pluginBrowser" - title: I18n.tr("Browse Plugins", "plugin browser window title") - minimumSize: Qt.size(450, 400) - implicitWidth: 600 - implicitHeight: 650 - color: Theme.surfaceContainer - visible: false - - onVisibleChanged: { - if (visible) { - pendingInstallHandled = false; - refreshPlugins(); - Qt.callLater(() => { - browserSearchField.forceActiveFocus(); - checkPendingInstall(); - }); - return; - } - allPlugins = []; - searchQuery = ""; - filteredPlugins = []; - selectedIndex = -1; - keyboardNavigationActive = false; - isLoading = false; - } - - Connections { - target: DMSService - - function onPluginsListReceived(plugins) { - root.isLoading = false; - root.allPlugins = plugins; - root.updateFilteredPlugins(); - } - - function onInstalledPluginsReceived(plugins) { - var pluginMap = {}; - for (var i = 0; i < plugins.length; i++) { - var plugin = plugins[i]; - if (plugin.id) - pluginMap[plugin.id] = true; - if (plugin.name) - pluginMap[plugin.name] = true; - } - var updated = root.allPlugins.map(p => { - var isInstalled = pluginMap[p.name] || pluginMap[p.id] || false; - return Object.assign({}, p, { - "installed": isInstalled - }); - }); - root.allPlugins = updated; - root.updateFilteredPlugins(); - } - } - - ConfirmModal { - id: urlInstallConfirm - } - - FocusScope { - id: browserKeyHandler - - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Escape: - root.hide(); - event.accepted = true; - return; - case Qt.Key_Down: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_Up: - root.selectPrevious(); - event.accepted = true; - return; - } - } - - Item { - id: browserContent - anchors.fill: parent - anchors.margins: Theme.spacingL - - Item { - id: headerArea - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: Math.max(headerIcon.height, headerText.height, refreshButton.height, closeButton.height) - - MouseArea { - anchors.fill: parent - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - DankIcon { - id: headerIcon - name: "store" - size: Theme.iconSize - color: Theme.primary - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: headerText - text: I18n.tr("Browse Plugins", "plugin browser header") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.left: headerIcon.right - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - } - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankButton { - id: thirdPartyButton - text: SessionData.showThirdPartyPlugins ? I18n.tr("Hide 3rd Party") : I18n.tr("Show 3rd Party") - iconName: SessionData.showThirdPartyPlugins ? "visibility_off" : "visibility" - height: 28 - onClicked: { - if (SessionData.showThirdPartyPlugins) { - SessionData.setShowThirdPartyPlugins(false); - root.updateFilteredPlugins(); - return; - } - thirdPartyConfirmLoader.active = true; - if (thirdPartyConfirmLoader.item) - thirdPartyConfirmLoader.item.show(); - } - } - - DankActionButton { - id: refreshButton - iconName: "refresh" - iconSize: 18 - iconColor: Theme.primary - visible: !root.isLoading - onClicked: root.refreshPlugins() - } - - DankActionButton { - visible: windowControls.supported - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 2 - iconColor: Theme.outline - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - id: closeButton - iconName: "close" - iconSize: Theme.iconSize - 2 - iconColor: Theme.outline - onClicked: root.hide() - } - } - } - - StyledText { - id: descriptionText - anchors.left: parent.left - anchors.right: parent.right - anchors.top: headerArea.bottom - anchors.topMargin: Theme.spacingM - text: I18n.tr("Install plugins from the DMS plugin registry", "plugin browser description") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - wrapMode: Text.WordWrap - } - - DankTextField { - id: browserSearchField - anchors.left: parent.left - anchors.right: parent.right - anchors.top: descriptionText.bottom - anchors.topMargin: Theme.spacingM - height: 48 - cornerRadius: Theme.cornerRadius - backgroundColor: Theme.surfaceContainerHigh - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: "search" - leftIconSize: Theme.iconSize - leftIconColor: Theme.surfaceVariantText - leftIconFocusedColor: Theme.primary - showClearButton: true - textColor: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - placeholderText: I18n.tr("Search plugins...", "plugin search placeholder") - text: root.searchQuery - focus: true - ignoreLeftRightKeys: true - keyForwardTargets: [browserKeyHandler] - onTextEdited: { - root.searchQuery = text; - root.updateFilteredPlugins(); - } - } - - Item { - id: listArea - anchors.left: parent.left - anchors.right: parent.right - anchors.top: browserSearchField.bottom - anchors.topMargin: Theme.spacingM - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.spacingM - - Item { - anchors.fill: parent - visible: root.isLoading - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - name: "sync" - size: 48 - color: Theme.primary - anchors.horizontalCenter: parent.horizontalCenter - - RotationAnimator on rotation { - from: 0 - to: -360 - duration: 1000 - loops: Animation.Infinite - running: root.isLoading - } - } - - StyledText { - text: I18n.tr("Loading...", "loading indicator") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - DankListView { - id: pluginBrowserList - - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - anchors.bottomMargin: Theme.spacingS - spacing: Theme.spacingS - model: ScriptModel { - values: root.filteredPlugins - } - clip: true - visible: !root.isLoading - add: null - displaced: null - - ScrollBar.vertical: DankScrollbar { - id: browserScrollbar - } - - delegate: Rectangle { - width: pluginBrowserList.width - height: pluginDelegateColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex - property bool isInstalled: modelData.installed || false - property bool isFirstParty: modelData.firstParty || false - property bool isFeatured: modelData.featured || false - property bool isCompatible: PluginService.checkPluginCompatibility(modelData.requires_dms) - color: isSelected ? Theme.primarySelected : Theme.withAlpha(Theme.surfaceVariant, 0.3) - border.color: isSelected ? Theme.primary : Theme.withAlpha(Theme.outline, 0.2) - border.width: isSelected ? 2 : 1 - - Column { - id: pluginDelegateColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: modelData.icon || "extension" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - installButton.width - Theme.spacingM - spacing: 2 - - Row { - spacing: Theme.spacingXS - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - height: 16 - width: featuredRow.implicitWidth + Theme.spacingXS * 2 - radius: 8 - color: Theme.withAlpha(Theme.secondary, 0.15) - border.color: Theme.withAlpha(Theme.secondary, 0.4) - border.width: 1 - visible: isFeatured - anchors.verticalCenter: parent.verticalCenter - - Row { - id: featuredRow - anchors.centerIn: parent - spacing: 2 - - DankIcon { - name: "star" - size: 10 - color: Theme.secondary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("featured") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.secondary - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - - Rectangle { - height: 16 - width: firstPartyText.implicitWidth + Theme.spacingXS * 2 - radius: 8 - color: Theme.withAlpha(Theme.primary, 0.15) - border.color: Theme.withAlpha(Theme.primary, 0.4) - border.width: 1 - visible: isFirstParty - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: firstPartyText - anchors.centerIn: parent - text: I18n.tr("official") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.primary - font.weight: Font.Medium - } - } - - Rectangle { - height: 16 - width: thirdPartyText.implicitWidth + Theme.spacingXS * 2 - radius: 8 - color: Theme.withAlpha(Theme.warning, 0.15) - border.color: Theme.withAlpha(Theme.warning, 0.4) - border.width: 1 - visible: !isFirstParty - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: thirdPartyText - anchors.centerIn: parent - text: I18n.tr("3rd party") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.warning - font.weight: Font.Medium - } - } - } - - StyledText { - text: { - const author = I18n.tr("by %1", "author attribution").arg(modelData.author || I18n.tr("Unknown", "unknown author")); - const source = modelData.repo ? ` • ${I18n.tr("source", "source code link")}` : ""; - return author + source; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - linkColor: Theme.primary - textFormat: Text.RichText - elide: Text.ElideRight - width: parent.width - onLinkActivated: url => Qt.openUrlExternally(url) - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - } - } - } - - Rectangle { - id: installButton - - property string buttonState: { - if (isInstalled) - return "installed"; - if (!isCompatible) - return "incompatible"; - return "available"; - } - - width: buttonState === "incompatible" ? incompatRow.implicitWidth + Theme.spacingM * 2 : 80 - height: 32 - radius: Theme.cornerRadius - anchors.verticalCenter: parent.verticalCenter - color: { - switch (buttonState) { - case "installed": - return Theme.surfaceVariant; - case "incompatible": - return Theme.withAlpha(Theme.warning, 0.15); - default: - return Theme.primary; - } - } - opacity: buttonState === "available" && installMouseArea.containsMouse ? 0.9 : 1 - border.width: buttonState !== "available" ? 1 : 0 - border.color: buttonState === "incompatible" ? Theme.warning : Theme.outline - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Row { - id: incompatRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: { - switch (installButton.buttonState) { - case "installed": - return "check"; - case "incompatible": - return "warning"; - default: - return "download"; - } - } - size: 14 - color: { - switch (installButton.buttonState) { - case "installed": - return Theme.surfaceText; - case "incompatible": - return Theme.warning; - default: - return Theme.surface; - } - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - switch (installButton.buttonState) { - case "installed": - return I18n.tr("Installed", "installed status"); - case "incompatible": - return I18n.tr("Requires %1", "version requirement").arg(modelData.requires_dms); - default: - return I18n.tr("Install", "install action button"); - } - } - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: { - switch (installButton.buttonState) { - case "installed": - return Theme.surfaceText; - case "incompatible": - return Theme.warning; - default: - return Theme.surface; - } - } - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: installMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: installButton.buttonState === "available" ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: installButton.buttonState === "available" - onClicked: { - const isDesktop = modelData.type === "desktop"; - root.installPlugin(modelData.name, isDesktop); - } - } - } - } - - StyledText { - text: modelData.description || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - width: parent.width - wrapMode: Text.WordWrap - visible: modelData.description && modelData.description.length > 0 - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: modelData.capabilities && modelData.capabilities.length > 0 - - Repeater { - model: modelData.capabilities || [] - - Rectangle { - height: 18 - width: capabilityText.implicitWidth + Theme.spacingXS * 2 - radius: 9 - color: Theme.withAlpha(Theme.primary, 0.1) - border.color: Theme.withAlpha(Theme.primary, 0.3) - border.width: 1 - - StyledText { - id: capabilityText - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.primary - } - } - } - } - } - } - } - - StyledText { - anchors.centerIn: listArea - text: I18n.tr("No plugins found", "empty plugin list") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: !root.isLoading && root.filteredPlugins.length === 0 - } - } - } - } - - LazyLoader { - id: thirdPartyConfirmLoader - active: false - - FloatingWindow { - id: thirdPartyConfirmModal - - property bool disablePopupTransparency: true - - function show() { - visible = true; - } - - function hide() { - visible = false; - } - - objectName: "thirdPartyConfirm" - title: I18n.tr("Third-Party Plugin Warning") - implicitWidth: 500 - implicitHeight: 350 - color: Theme.surfaceContainer - visible: false - - FocusScope { - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - thirdPartyConfirmModal.hide(); - event.accepted = true; - } - } - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingL - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Third-Party Plugin Warning") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - parent.spacing * 2 - Theme.iconSize - parent.children[1].implicitWidth - closeConfirmBtn.width - height: 1 - } - - DankActionButton { - id: closeConfirmBtn - iconName: "close" - iconSize: Theme.iconSize - 2 - iconColor: Theme.outline - anchors.verticalCenter: parent.verticalCenter - onClicked: thirdPartyConfirmModal.hide() - } - } - - StyledText { - width: parent.width - text: I18n.tr("Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - wrapMode: Text.WordWrap - } - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("• Plugins may contain bugs or security issues") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: I18n.tr("• Review code before installation when possible") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: I18n.tr("• Install only from trusted sources") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - Item { - width: parent.width - height: parent.height - parent.spacing * 3 - y - } - - Row { - anchors.right: parent.right - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Cancel") - iconName: "close" - onClicked: thirdPartyConfirmModal.hide() - } - - DankButton { - text: I18n.tr("I Understand") - iconName: "check" - onClicked: { - SessionData.setShowThirdPartyPlugins(true); - root.updateFilteredPlugins(); - thirdPartyConfirmModal.hide(); - } - } - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginListItem.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginListItem.qml deleted file mode 100644 index 39a5d1e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginListItem.qml +++ /dev/null @@ -1,439 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var pluginData: null - property string expandedPluginId: "" - property bool hasUpdate: false - property bool isReloading: false - property var sharedTooltip: null - - property string pluginId: pluginData ? pluginData.id : "" - property string pluginDirectoryName: { - if (pluginData && pluginData.pluginDirectory) { - var path = pluginData.pluginDirectory; - return path.substring(path.lastIndexOf('/') + 1); - } - return pluginId; - } - property string pluginName: pluginData ? (pluginData.name || pluginData.id) : "" - property string pluginVersion: pluginData ? (pluginData.version || "1.0.0") : "" - property string pluginAuthor: pluginData ? (pluginData.author || "Unknown") : "" - property string pluginDescription: pluginData ? (pluginData.description || "") : "" - property string pluginIcon: pluginData ? (pluginData.icon || "extension") : "extension" - property string pluginSettingsPath: pluginData ? (pluginData.settingsPath || "") : "" - property var pluginPermissions: pluginData ? (pluginData.permissions || []) : [] - property bool hasSettings: pluginData && pluginData.settings !== undefined && pluginData.settings !== "" - property bool isDesktopPlugin: pluginData ? (pluginData.type === "desktop") : false - property bool showSettings: hasSettings && !isDesktopPlugin - property bool isSystemPlugin: pluginData ? (pluginData.source === "system") : false - property string requiresDms: pluginData ? (pluginData.requires_dms || "") : "" - property bool meetsRequirements: requiresDms ? PluginService.checkPluginCompatibility(requiresDms) : true - - Connections { - target: SystemUpdateService - function onSemverVersionChanged() { - root.meetsRequirementsChanged(); - } - } - property bool isExpanded: expandedPluginId === pluginId - property bool isLoaded: { - PluginService.loadedPlugins; - return PluginService.loadedPlugins[pluginId] !== undefined; - } - - width: parent.width - height: pluginItemColumn.implicitHeight + Theme.spacingM * 2 + settingsContainer.height - radius: Theme.cornerRadius - color: (pluginMouseArea.containsMouse || updateArea.containsMouse || uninstallArea.containsMouse || reloadArea.containsMouse) ? Theme.surfacePressed : (isExpanded ? Theme.surfaceContainerHighest : Theme.surfaceContainerHigh) - border.width: 0 - - MouseArea { - id: pluginMouseArea - anchors.fill: parent - anchors.bottomMargin: root.isExpanded ? settingsContainer.height : 0 - hoverEnabled: true - cursorShape: root.showSettings ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: root.showSettings - onClicked: { - root.expandedPluginId = root.expandedPluginId === root.pluginId ? "" : root.pluginId; - } - } - - Column { - id: pluginItemColumn - width: parent.width - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: root.pluginIcon - size: Theme.iconSize - color: root.isLoaded ? Theme.primary : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - toggleRow.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - Row { - spacing: Theme.spacingXS - width: parent.width - - StyledText { - text: root.pluginName - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - width: incompatIcon.width + Theme.spacingXS * 2 - height: 18 - radius: 9 - color: Theme.withAlpha(Theme.error, 0.15) - visible: !root.meetsRequirements - anchors.verticalCenter: parent.verticalCenter - - Row { - anchors.centerIn: parent - spacing: 2 - - DankIcon { - id: incompatIcon - name: "warning" - size: 12 - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: { - if (root.sharedTooltip) - root.sharedTooltip.show(I18n.tr("Requires DMS %1").arg(root.requiresDms), parent, 0, 0, "top"); - } - onExited: { - if (root.sharedTooltip) - root.sharedTooltip.hide(); - } - } - } - - DankIcon { - name: root.showSettings ? (root.isExpanded ? "expand_less" : "expand_more") : "" - size: 16 - color: root.showSettings ? Theme.primary : "transparent" - anchors.verticalCenter: parent.verticalCenter - visible: root.showSettings - } - - Rectangle { - width: desktopLabel.implicitWidth + Theme.spacingXS * 2 - height: 18 - radius: 9 - color: Theme.withAlpha(Theme.secondary, 0.15) - visible: root.isDesktopPlugin - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: desktopLabel - anchors.centerIn: parent - text: I18n.tr("Desktop Widget") - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.secondary - } - } - } - - StyledText { - text: I18n.tr("v%1 by %2").arg(root.pluginVersion).arg(root.pluginAuthor) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Row { - id: toggleRow - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: updateArea.containsMouse ? Theme.surfaceContainerHighest : "transparent" - visible: DMSService.dmsAvailable && root.isLoaded && root.hasUpdate && !root.isSystemPlugin - - DankIcon { - anchors.centerIn: parent - name: "download" - size: 16 - color: updateArea.containsMouse ? Theme.primary : Theme.surfaceVariantText - } - - MouseArea { - id: updateArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const currentPluginName = root.pluginName; - const currentPluginId = root.pluginId; - DMSService.update(currentPluginName, response => { - if (response.error) { - ToastService.showError("Update failed: " + response.error); - return; - } - ToastService.showInfo("Plugin updated: " + currentPluginName); - PluginService.forceRescanPlugin(currentPluginId); - if (DMSService.apiVersion >= 8) - DMSService.listInstalled(); - }); - } - onEntered: { - if (root.sharedTooltip) - root.sharedTooltip.show(I18n.tr("Update Plugin"), parent, 0, 0, "top"); - } - onExited: { - if (root.sharedTooltip) - root.sharedTooltip.hide(); - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: uninstallArea.containsMouse ? Theme.surfaceContainerHighest : "transparent" - visible: DMSService.dmsAvailable && !root.isSystemPlugin - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 16 - color: uninstallArea.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: uninstallArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const currentPluginName = root.pluginName; - DMSService.uninstall(currentPluginName, response => { - if (response.error) { - ToastService.showError("Uninstall failed: " + response.error); - return; - } - ToastService.showInfo("Plugin uninstalled: " + currentPluginName); - PluginService.scanPlugins(); - if (root.isExpanded) - root.expandedPluginId = ""; - }); - } - onEntered: { - if (root.sharedTooltip) - root.sharedTooltip.show(I18n.tr("Uninstall Plugin"), parent, 0, 0, "top"); - } - onExited: { - if (root.sharedTooltip) - root.sharedTooltip.hide(); - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: reloadArea.containsMouse ? Theme.surfaceContainerHighest : "transparent" - visible: root.isLoaded - - DankIcon { - anchors.centerIn: parent - name: "refresh" - size: 16 - color: reloadArea.containsMouse ? Theme.primary : Theme.surfaceVariantText - } - - MouseArea { - id: reloadArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const currentPluginId = root.pluginId; - const currentPluginName = root.pluginName; - root.isReloading = true; - if (PluginService.reloadPlugin(currentPluginId)) { - ToastService.showInfo("Plugin reloaded: " + currentPluginName); - return; - } - ToastService.showError("Failed to reload plugin: " + currentPluginName); - root.isReloading = false; - } - onEntered: { - if (root.sharedTooltip) - root.sharedTooltip.show(I18n.tr("Reload Plugin"), parent, 0, 0, "top"); - } - onExited: { - if (root.sharedTooltip) - root.sharedTooltip.hide(); - } - } - } - - DankToggle { - id: pluginToggle - anchors.verticalCenter: parent.verticalCenter - checked: root.isLoaded - onToggled: isChecked => { - const currentPluginId = root.pluginId; - const currentPluginName = root.pluginName; - - if (isChecked) { - if (PluginService.enablePlugin(currentPluginId)) { - ToastService.showInfo("Plugin enabled: " + currentPluginName); - return; - } - ToastService.showError("Failed to enable plugin: " + currentPluginName); - return; - } - if (PluginService.disablePlugin(currentPluginId)) { - ToastService.showInfo("Plugin disabled: " + currentPluginName); - if (root.isExpanded) - root.expandedPluginId = ""; - return; - } - ToastService.showError("Failed to disable plugin: " + currentPluginName); - } - } - } - } - - StyledText { - width: parent.width - text: root.pluginDescription - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - visible: root.pluginDescription !== "" - horizontalAlignment: Text.AlignLeft - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: root.pluginPermissions && Array.isArray(root.pluginPermissions) && root.pluginPermissions.length > 0 - - Repeater { - model: root.pluginPermissions - - Rectangle { - height: 20 - width: permissionText.implicitWidth + Theme.spacingXS * 2 - radius: 10 - color: Theme.withAlpha(Theme.primary, 0.1) - border.color: Theme.withAlpha(Theme.primary, 0.3) - border.width: 1 - - StyledText { - id: permissionText - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.primary - } - } - } - } - } - - FocusScope { - id: settingsContainer - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - height: root.isExpanded && root.showSettings ? (settingsLoader.item ? settingsLoader.item.implicitHeight + Theme.spacingL * 2 : 0) : 0 - clip: true - focus: root.isExpanded && root.showSettings - - Keys.onPressed: event => { - event.accepted = true; - } - - Rectangle { - anchors.fill: parent - color: Theme.surfaceContainerHighest - radius: Theme.cornerRadius - anchors.topMargin: Theme.spacingXS - border.width: 0 - } - - Loader { - id: settingsLoader - anchors.fill: parent - anchors.margins: Theme.spacingL - active: root.isExpanded && root.showSettings && root.isLoaded - asynchronous: false - - source: { - if (active && root.pluginSettingsPath) { - var path = root.pluginSettingsPath; - if (!path.startsWith("file://")) { - path = "file://" + path; - } - return path; - } - return ""; - } - - onLoaded: { - if (item && typeof PluginService !== "undefined") { - item.pluginService = PluginService; - } - if (item && typeof PopoutService !== "undefined" && "popoutService" in item) { - item.popoutService = PopoutService; - } - if (item) { - Qt.callLater(() => { - settingsContainer.focus = true; - item.forceActiveFocus(); - }); - } - } - } - - StyledText { - anchors.centerIn: parent - text: !root.isLoaded ? "Enable plugin to access settings" : (settingsLoader.status === Loader.Error ? "Failed to load settings" : "No configurable settings") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: root.isExpanded && (!settingsLoader.active || settingsLoader.status === Loader.Error) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginsTab.qml deleted file mode 100644 index 1f83a0f..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PluginsTab.qml +++ /dev/null @@ -1,450 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -FocusScope { - id: pluginsTab - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string expandedPluginId: "" - property bool isRefreshingPlugins: false - property var parentModal: null - property var installedPluginsData: ({}) - property bool isReloading: false - property alias sharedTooltip: sharedTooltip - - focus: true - - DankTooltipV2 { - id: sharedTooltip - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - StyledRect { - width: parent.width - height: headerColumn.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: headerColumn - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "extension" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - width: parent.width - Theme.iconSize - Theme.spacingM - - StyledText { - text: I18n.tr("Plugin Management") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Manage and configure plugins for extending DMS functionality") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - StyledRect { - width: parent.width - height: dmsWarningColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.warning, 0.1) - border.color: Theme.warning - border.width: 1 - visible: !DMSService.dmsAvailable - - Column { - id: dmsWarningColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: "warning" - size: 16 - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("DMS Plugin Manager Unavailable") - font.pixelSize: Theme.fontSizeSmall - color: Theme.warning - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: I18n.tr("The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - StyledRect { - id: incompatWarning - property var incompatPlugins: [] - width: parent.width - height: incompatWarningColumn.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.error, 0.1) - border.color: Theme.error - border.width: 1 - visible: incompatPlugins.length > 0 - - function refresh() { - incompatPlugins = PluginService.getIncompatiblePlugins(); - } - - Component.onCompleted: Qt.callLater(refresh) - - Column { - id: incompatWarningColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - Row { - spacing: Theme.spacingXS - - DankIcon { - name: "error" - size: 16 - color: Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Incompatible Plugins Loaded") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: I18n.tr("Some plugins require a newer version of DMS:") + " " + incompatWarning.incompatPlugins.map(p => p.name + " (" + p.requires_dms + ")").join(", ") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Connections { - target: PluginService - function onPluginLoaded() { - incompatWarning.refresh(); - } - function onPluginUnloaded() { - incompatWarning.refresh(); - } - } - - Connections { - target: SystemUpdateService - function onSemverVersionChanged() { - incompatWarning.refresh(); - } - } - } - - Flow { - width: parent.width - spacing: Theme.spacingM - - DankButton { - text: I18n.tr("Browse") - iconName: "store" - enabled: DMSService.dmsAvailable - onClicked: { - showPluginBrowser(); - } - } - - DankButton { - text: I18n.tr("Scan") - iconName: "refresh" - onClicked: { - pluginsTab.isRefreshingPlugins = true; - PluginService.scanPlugins(); - if (DMSService.dmsAvailable) { - DMSService.listInstalled(); - } - pluginsTab.refreshPluginList(); - } - } - - DankButton { - text: I18n.tr("Create Dir") - iconName: "create_new_folder" - onClicked: { - PluginService.createPluginDirectory(); - ToastService.showInfo("Created plugin directory: " + PluginService.pluginDirectory); - } - } - } - } - } - - StyledRect { - width: parent.width - height: directoryColumn.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: directoryColumn - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Plugin Directory") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: PluginService.pluginDirectory - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - font.family: "monospace" - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Place plugin directories here. Each plugin should have a plugin.json manifest file.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - StyledRect { - width: parent.width - height: Math.max(200, availableColumn.implicitHeight + Theme.spacingL * 2) - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: availableColumn - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Available Plugins") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Column { - width: parent.width - spacing: Theme.spacingM - - Repeater { - id: pluginRepeater - model: PluginService.availablePluginsList - - PluginListItem { - pluginData: modelData - expandedPluginId: pluginsTab.expandedPluginId - hasUpdate: { - if (DMSService.apiVersion < 8) - return false; - return pluginsTab.installedPluginsData[pluginId] || pluginsTab.installedPluginsData[pluginName] || false; - } - isReloading: pluginsTab.isReloading - sharedTooltip: pluginsTab.sharedTooltip - onExpandedPluginIdChanged: { - pluginsTab.expandedPluginId = expandedPluginId; - } - onIsReloadingChanged: { - pluginsTab.isReloading = isReloading; - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("No plugins found.") + "\n" + I18n.tr("Place plugins in %1").arg(PluginService.pluginDirectory) - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - horizontalAlignment: Text.AlignHCenter - visible: pluginRepeater.model && pluginRepeater.model.length === 0 - } - } - } - } - } - } - - function refreshPluginList() { - pluginsTab.isRefreshingPlugins = false; - } - - Connections { - target: PluginService - function onPluginLoaded() { - refreshPluginList(); - if (isReloading) { - isReloading = false; - } - } - function onPluginUnloaded() { - refreshPluginList(); - if (!isReloading && pluginsTab.expandedPluginId !== "" && !PluginService.isPluginLoaded(pluginsTab.expandedPluginId)) { - pluginsTab.expandedPluginId = ""; - } - } - function onPluginListUpdated() { - if (DMSService.apiVersion >= 8) { - DMSService.listInstalled(); - } - refreshPluginList(); - } - function onPluginDataChanged(pluginId) { - var plugin = PluginService.availablePlugins[pluginId]; - if (!plugin || !PluginService.isPluginLoaded(pluginId)) - return; - var isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher")); - if (isLauncher) { - pluginsTab.isReloading = true; - PluginService.reloadPlugin(pluginId); - } - } - } - - Connections { - target: DMSService - function onPluginsListReceived(plugins) { - if (!pluginBrowserLoader.item) - return; - pluginBrowserLoader.item.isLoading = false; - pluginBrowserLoader.item.allPlugins = plugins; - pluginBrowserLoader.item.updateFilteredPlugins(); - } - function onInstalledPluginsReceived(plugins) { - var pluginMap = {}; - for (var i = 0; i < plugins.length; i++) { - var plugin = plugins[i]; - var hasUpdate = plugin.hasUpdate || false; - if (plugin.id) { - pluginMap[plugin.id] = hasUpdate; - } - if (plugin.name) { - pluginMap[plugin.name] = hasUpdate; - } - } - installedPluginsData = pluginMap; - Qt.callLater(refreshPluginList); - } - function onOperationSuccess(message) { - ToastService.showInfo(message); - } - function onOperationError(error) { - ToastService.showError(error); - } - } - - Component.onCompleted: { - if (DMSService.dmsAvailable && DMSService.apiVersion >= 8) - DMSService.listInstalled(); - if (PopoutService.pendingPluginInstall) - Qt.callLater(showPluginBrowser); - } - - Connections { - target: PopoutService - function onPendingPluginInstallChanged() { - if (PopoutService.pendingPluginInstall) - showPluginBrowser(); - } - } - - LazyLoader { - id: pluginBrowserLoader - active: false - - PluginBrowser { - id: pluginBrowserItem - - Component.onCompleted: { - pluginBrowserItem.parentModal = pluginsTab.parentModal; - } - } - } - - function showPluginBrowser() { - pluginBrowserLoader.active = true; - if (pluginBrowserLoader.item) - pluginBrowserLoader.item.show(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PowerSleepTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PowerSleepTab.qml deleted file mode 100644 index 7282d34..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PowerSleepTab.qml +++ /dev/null @@ -1,598 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - readonly property var timeoutOptions: [I18n.tr("Never"), I18n.tr("1 minute"), I18n.tr("2 minutes"), I18n.tr("3 minutes"), I18n.tr("5 minutes"), I18n.tr("10 minutes"), I18n.tr("15 minutes"), I18n.tr("20 minutes"), I18n.tr("30 minutes"), I18n.tr("1 hour"), I18n.tr("1 hour 30 minutes"), I18n.tr("2 hours"), I18n.tr("3 hours")] - readonly property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800] - - function getTimeoutIndex(timeout) { - var idx = timeoutValues.indexOf(timeout); - return idx >= 0 ? idx : 0; - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "schedule" - title: I18n.tr("Idle Settings") - settingKey: "idleSettings" - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Power source") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable - } - - Item { - width: Theme.spacingS - height: 1 - visible: BatteryService.batteryAvailable - } - - DankButtonGroup { - id: powerCategory - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable - model: [I18n.tr("AC Power"), I18n.tr("Battery")] - currentIndex: 0 - selectionMode: "single" - checkEnabled: false - onSelectionChanged: (index, selected) => { - if (!selected) - return; - currentIndex = index; - } - } - } - - SettingsToggleRow { - settingKey: "fadeToLockEnabled" - tags: ["fade", "lock", "screen", "idle", "grace period"] - text: I18n.tr("Fade to lock screen") - description: I18n.tr("Gradually fade the screen before locking with a configurable grace period") - checked: SettingsData.fadeToLockEnabled - onToggled: checked => SettingsData.set("fadeToLockEnabled", checked) - } - - SettingsToggleRow { - settingKey: "fadeToDpmsEnabled" - tags: ["fade", "dpms", "monitor", "screen", "idle", "grace period"] - text: I18n.tr("Fade to monitor off") - description: I18n.tr("Gradually fade the screen before turning off monitors with a configurable grace period") - checked: SettingsData.fadeToDpmsEnabled - onToggled: checked => SettingsData.set("fadeToDpmsEnabled", checked) - } - - SettingsToggleRow { - settingKey: "lockBeforeSuspend" - tags: ["lock", "suspend", "sleep", "security"] - text: I18n.tr("Lock before suspend") - description: I18n.tr("Automatically lock the screen when the system prepares to suspend") - checked: SettingsData.lockBeforeSuspend - visible: SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration - onToggled: checked => SettingsData.set("lockBeforeSuspend", checked) - } - - SettingsDropdownRow { - id: fadeGracePeriodDropdown - settingKey: "fadeToLockGracePeriod" - tags: ["fade", "grace", "period", "timeout", "lock"] - property var periodOptions: [I18n.tr("1 second"), I18n.tr("2 seconds"), I18n.tr("3 seconds"), I18n.tr("4 seconds"), I18n.tr("5 seconds"), I18n.tr("10 seconds"), I18n.tr("15 seconds"), I18n.tr("20 seconds"), I18n.tr("30 seconds")] - property var periodValues: [1, 2, 3, 4, 5, 10, 15, 20, 30] - - text: I18n.tr("Lock fade grace period") - options: periodOptions - visible: SettingsData.fadeToLockEnabled - enabled: SettingsData.fadeToLockEnabled - - Component.onCompleted: { - const currentPeriod = SettingsData.fadeToLockGracePeriod; - const index = periodValues.indexOf(currentPeriod); - currentValue = index >= 0 ? periodOptions[index] : I18n.tr("5 seconds"); - } - - onValueChanged: value => { - const index = periodOptions.indexOf(value); - if (index < 0) - return; - SettingsData.set("fadeToLockGracePeriod", periodValues[index]); - } - } - - SettingsDropdownRow { - id: fadeDpmsGracePeriodDropdown - settingKey: "fadeToDpmsGracePeriod" - tags: ["fade", "grace", "period", "timeout", "dpms", "monitor"] - property var periodOptions: [I18n.tr("1 second"), I18n.tr("2 seconds"), I18n.tr("3 seconds"), I18n.tr("4 seconds"), I18n.tr("5 seconds"), I18n.tr("10 seconds"), I18n.tr("15 seconds"), I18n.tr("20 seconds"), I18n.tr("30 seconds")] - property var periodValues: [1, 2, 3, 4, 5, 10, 15, 20, 30] - - text: I18n.tr("Monitor fade grace period") - options: periodOptions - visible: SettingsData.fadeToDpmsEnabled - enabled: SettingsData.fadeToDpmsEnabled - - Component.onCompleted: { - const currentPeriod = SettingsData.fadeToDpmsGracePeriod; - const index = periodValues.indexOf(currentPeriod); - currentValue = index >= 0 ? periodOptions[index] : I18n.tr("5 seconds"); - } - - onValueChanged: value => { - const index = periodOptions.indexOf(value); - if (index < 0) - return; - SettingsData.set("fadeToDpmsGracePeriod", periodValues[index]); - } - } - SettingsDropdownRow { - id: powerProfileDropdown - settingKey: "powerProfile" - tags: ["power", "profile", "performance", "balanced", "saver", "battery"] - property var profileOptions: [I18n.tr("Don't Change"), Theme.getPowerProfileLabel(0), Theme.getPowerProfileLabel(1), Theme.getPowerProfileLabel(2)] - property var profileValues: ["", "0", "1", "2"] - - width: parent.width - addHorizontalPadding: true - text: I18n.tr("Switch to power profile") - options: profileOptions - - Connections { - target: powerCategory - function onCurrentIndexChanged() { - const currentProfile = powerCategory.currentIndex === 0 ? SettingsData.acProfileName : SettingsData.batteryProfileName; - const index = powerProfileDropdown.profileValues.indexOf(currentProfile); - powerProfileDropdown.currentValue = powerProfileDropdown.profileOptions[index]; - } - } - - Component.onCompleted: { - const currentProfile = powerCategory.currentIndex === 0 ? SettingsData.acProfileName : SettingsData.batteryProfileName; - const index = profileValues.indexOf(currentProfile); - currentValue = profileOptions[index]; - } - - onValueChanged: value => { - const index = profileOptions.indexOf(value); - if (index >= 0) { - const profileValue = profileValues[index]; - if (powerCategory.currentIndex === 0) { - SettingsData.set("acProfileName", profileValue); - } else { - SettingsData.set("batteryProfileName", profileValue); - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsDropdownRow { - id: lockDropdown - settingKey: "lockTimeout" - tags: ["lock", "timeout", "idle", "automatic", "security"] - text: I18n.tr("Automatically lock after") - options: root.timeoutOptions - - Connections { - target: powerCategory - function onCurrentIndexChanged() { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acLockTimeout : SettingsData.batteryLockTimeout; - lockDropdown.currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - } - - Component.onCompleted: { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acLockTimeout : SettingsData.batteryLockTimeout; - currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - - onValueChanged: value => { - const index = root.timeoutOptions.indexOf(value); - if (index < 0) - return; - const timeout = root.timeoutValues[index]; - if (powerCategory.currentIndex === 0) { - SettingsData.set("acLockTimeout", timeout); - } else { - SettingsData.set("batteryLockTimeout", timeout); - } - } - } - - SettingsDropdownRow { - id: monitorDropdown - settingKey: "monitorTimeout" - tags: ["monitor", "display", "screen", "timeout", "off", "idle"] - text: I18n.tr("Turn off monitors after") - options: root.timeoutOptions - - Connections { - target: powerCategory - function onCurrentIndexChanged() { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acMonitorTimeout : SettingsData.batteryMonitorTimeout; - monitorDropdown.currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - } - - Component.onCompleted: { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acMonitorTimeout : SettingsData.batteryMonitorTimeout; - currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - - onValueChanged: value => { - const index = root.timeoutOptions.indexOf(value); - if (index < 0) - return; - const timeout = root.timeoutValues[index]; - if (powerCategory.currentIndex === 0) { - SettingsData.set("acMonitorTimeout", timeout); - } else { - SettingsData.set("batteryMonitorTimeout", timeout); - } - } - } - - SettingsDropdownRow { - id: suspendDropdown - settingKey: "suspendTimeout" - tags: ["suspend", "sleep", "timeout", "idle", "system"] - text: I18n.tr("Suspend system after") - options: root.timeoutOptions - - Connections { - target: powerCategory - function onCurrentIndexChanged() { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acSuspendTimeout : SettingsData.batterySuspendTimeout; - suspendDropdown.currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - } - - Component.onCompleted: { - const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acSuspendTimeout : SettingsData.batterySuspendTimeout; - currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)]; - } - - onValueChanged: value => { - const index = root.timeoutOptions.indexOf(value); - if (index < 0) - return; - const timeout = root.timeoutValues[index]; - if (powerCategory.currentIndex === 0) { - SettingsData.set("acSuspendTimeout", timeout); - } else { - SettingsData.set("batterySuspendTimeout", timeout); - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: SessionService.hibernateSupported - - StyledText { - text: I18n.tr("Suspend behavior") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - leftPadding: Theme.spacingM - } - - DankButtonGroup { - id: suspendBehaviorSelector - anchors.horizontalCenter: parent.horizontalCenter - model: [I18n.tr("Suspend"), I18n.tr("Hibernate"), I18n.tr("Suspend then Hibernate")] - selectionMode: "single" - checkEnabled: false - - Connections { - target: powerCategory - function onCurrentIndexChanged() { - const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior; - suspendBehaviorSelector.currentIndex = behavior; - } - } - - Component.onCompleted: { - const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior; - currentIndex = behavior; - } - - onSelectionChanged: (index, selected) => { - if (!selected) - return; - currentIndex = index; - if (powerCategory.currentIndex === 0) { - SettingsData.set("acSuspendBehavior", index); - } else { - SettingsData.set("batterySuspendBehavior", index); - } - } - } - } - - StyledText { - text: I18n.tr("Idle monitoring not supported - requires newer Quickshell version") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - anchors.horizontalCenter: parent.horizontalCenter - visible: !IdleService.idleMonitorAvailable - } - } - - SettingsCard { - width: parent.width - iconName: "tune" - title: I18n.tr("Power Menu Customization") - settingKey: "powerMenu" - - StyledText { - text: I18n.tr("Customize which actions appear in the power menu") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.Wrap - } - - SettingsToggleRow { - settingKey: "powerMenuGridLayout" - tags: ["power", "menu", "grid", "layout", "list"] - text: I18n.tr("Use Grid Layout") - description: I18n.tr("Display power menu actions in a grid instead of a list") - checked: SettingsData.powerMenuGridLayout - onToggled: checked => SettingsData.set("powerMenuGridLayout", checked) - } - - SettingsDropdownRow { - id: defaultActionDropdown - settingKey: "powerMenuDefaultAction" - tags: ["power", "menu", "default", "action", "reboot", "logout", "shutdown"] - text: I18n.tr("Default selected action") - options: [I18n.tr("Reboot"), I18n.tr("Log Out"), I18n.tr("Power Off"), I18n.tr("Lock"), I18n.tr("Suspend"), I18n.tr("Restart DMS"), I18n.tr("Hibernate")] - property var actionValues: ["reboot", "logout", "poweroff", "lock", "suspend", "restart", "hibernate"] - - Component.onCompleted: { - const currentAction = SettingsData.powerMenuDefaultAction || "logout"; - const index = actionValues.indexOf(currentAction); - currentValue = index >= 0 ? options[index] : I18n.tr("Log Out"); - } - - onValueChanged: value => { - const index = options.indexOf(value); - if (index < 0) - return; - SettingsData.set("powerMenuDefaultAction", actionValues[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: [ - { - key: "reboot", - label: I18n.tr("Show Reboot") - }, - { - key: "logout", - label: I18n.tr("Show Log Out") - }, - { - key: "poweroff", - label: I18n.tr("Show Power Off") - }, - { - key: "lock", - label: I18n.tr("Show Lock") - }, - { - key: "suspend", - label: I18n.tr("Show Suspend") - }, - { - key: "restart", - label: I18n.tr("Show Restart DMS"), - desc: I18n.tr("Restart the DankMaterialShell") - }, - { - key: "hibernate", - label: I18n.tr("Show Hibernate"), - desc: I18n.tr("Only visible if hibernate is supported by your system"), - hibernate: true - } - ] - - SettingsToggleRow { - required property var modelData - settingKey: "powerMenuAction_" + modelData.key - tags: ["power", "menu", "action", "show", modelData.key] - text: modelData.label - description: modelData.desc || "" - visible: !modelData.hibernate || SessionService.hibernateSupported - checked: SettingsData.powerMenuActions.includes(modelData.key) - onToggled: checked => { - let actions = [...SettingsData.powerMenuActions]; - if (checked && !actions.includes(modelData.key)) { - actions.push(modelData.key); - } else if (!checked) { - actions = actions.filter(a => a !== modelData.key); - } - SettingsData.set("powerMenuActions", actions); - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "check_circle" - title: I18n.tr("Power Action Confirmation") - settingKey: "powerConfirmation" - - SettingsToggleRow { - settingKey: "powerActionConfirm" - tags: ["power", "confirm", "hold", "button", "safety"] - text: I18n.tr("Hold to Confirm Power Actions") - description: I18n.tr("Require holding button/key to confirm power off, restart, suspend, hibernate and logout") - checked: SettingsData.powerActionConfirm - onToggled: checked => SettingsData.set("powerActionConfirm", checked) - } - - SettingsDropdownRow { - id: holdDurationDropdown - settingKey: "powerActionHoldDuration" - tags: ["power", "hold", "duration", "confirm", "time"] - property var durationOptions: [I18n.tr("250 ms"), I18n.tr("500 ms"), I18n.tr("750 ms"), I18n.tr("1 second"), I18n.tr("2 seconds"), I18n.tr("3 seconds"), I18n.tr("5 seconds"), I18n.tr("10 seconds")] - property var durationValues: [0.25, 0.5, 0.75, 1, 2, 3, 5, 10] - - text: I18n.tr("Hold Duration") - options: durationOptions - visible: SettingsData.powerActionConfirm - - Component.onCompleted: { - const currentDuration = SettingsData.powerActionHoldDuration; - const index = durationValues.indexOf(currentDuration); - currentValue = index >= 0 ? durationOptions[index] : I18n.tr("500 ms"); - } - - onValueChanged: value => { - const index = durationOptions.indexOf(value); - if (index < 0) - return; - SettingsData.set("powerActionHoldDuration", durationValues[index]); - } - } - } - - SettingsCard { - width: parent.width - iconName: "developer_mode" - title: I18n.tr("Custom Power Actions") - settingKey: "customPowerActions" - - Repeater { - model: [ - { - key: "customPowerActionLock", - label: I18n.tr("Custom Lock Command"), - placeholder: "/usr/bin/myLock.sh" - }, - { - key: "customPowerActionLogout", - label: I18n.tr("Custom Logout Command"), - placeholder: "/usr/bin/myLogout.sh" - }, - { - key: "customPowerActionSuspend", - label: I18n.tr("Custom Suspend Command"), - placeholder: "/usr/bin/mySuspend.sh" - }, - { - key: "customPowerActionHibernate", - label: I18n.tr("Custom Hibernate Command"), - placeholder: "/usr/bin/myHibernate.sh" - }, - { - key: "customPowerActionReboot", - label: I18n.tr("Custom Reboot Command"), - placeholder: "/usr/bin/myReboot.sh" - }, - { - key: "customPowerActionPowerOff", - label: I18n.tr("Custom Power Off Command"), - placeholder: "/usr/bin/myPowerOff.sh" - } - ] - - Column { - required property var modelData - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: parent.width - placeholderText: modelData.placeholder - backgroundColor: Theme.surfaceContainerHighest - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - - Component.onCompleted: { - var val = SettingsData[modelData.key]; - if (val) - text = val; - } - - onTextEdited: { - SettingsData.set(modelData.key, text.trim()); - } - } - } - } - } - - SettingsCard { - width: parent.width - iconName: "tune" - title: I18n.tr("Advanced") - settingKey: "powerAdvanced" - collapsible: true - expanded: false - - SettingsSliderRow { - settingKey: "batteryChargeLimit" - tags: ["battery", "charge", "limit", "percentage", "power"] - text: I18n.tr("Battery Charge Limit") - description: I18n.tr("Note: this only changes the percentage, it does not actually limit charging.") - value: SettingsData.batteryChargeLimit - minimum: 50 - maximum: 100 - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("batteryChargeLimit", newValue) - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PrinterTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PrinterTab.qml deleted file mode 100644 index 437dc47..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/PrinterTab.qml +++ /dev/null @@ -1,1702 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -Item { - id: printerTab - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property bool showAddPrinter: false - property bool manualEntryMode: false - property string manualHost: "" - property string manualPort: "631" - property string manualProtocol: "ipp" - property bool testingConnection: false - property var testConnectionResult: null - property string newPrinterName: "" - property string selectedDeviceUri: "" - property var selectedDevice: null - property string selectedPpd: "" - property string newPrinterLocation: "" - property string newPrinterInfo: "" - property var suggestedPPDs: [] - - function resetAddPrinterForm() { - manualEntryMode = false; - manualHost = ""; - manualPort = "631"; - manualProtocol = "ipp"; - testingConnection = false; - testConnectionResult = null; - newPrinterName = ""; - selectedDeviceUri = ""; - selectedDevice = null; - selectedPpd = ""; - newPrinterLocation = ""; - newPrinterInfo = ""; - suggestedPPDs = []; - } - - Connections { - target: CupsService - function onPpdsChanged() { - if (printerTab.manualEntryMode && printerTab.testConnectionResult?.success) - printerTab.selectDriverlessPPD(); - } - } - - function selectDriverlessPPD() { - if (printerTab.selectedPpd || CupsService.ppds.length === 0) - return; - - const probeModel = printerTab.testConnectionResult?.data?.makeModel || ""; - let suggested = []; - - // Try to find a model-specific PPD match - if (probeModel) { - const normalizedModel = probeModel.toLowerCase().replace(/[^a-z0-9]/g, ""); - const modelMatches = CupsService.ppds.filter(p => { - const normalizedPPD = (p.makeModel || "").toLowerCase().replace(/[^a-z0-9]/g, ""); - return normalizedPPD.includes(normalizedModel) || normalizedModel.includes(normalizedPPD); - }); - if (modelMatches.length > 0) - suggested = suggested.concat(modelMatches); - } - - // Always include driverless as an option - const driverless = CupsService.ppds.filter(p => p.name === "driverless" || p.name === "everywhere"); - for (const d of driverless) { - if (!suggested.find(s => s.name === d.name)) - suggested.push(d); - } - - if (suggested.length > 0) { - printerTab.selectedPpd = suggested[0].name; - printerTab.suggestedPPDs = suggested; - } - } - - function selectDevice(device) { - if (!device) - return; - selectedDevice = device; - selectedDeviceUri = device.uri; - if (!newPrinterName) { - newPrinterName = CupsService.suggestPrinterName(device); - } - if (device.location && !newPrinterLocation) { - newPrinterLocation = CupsService.decodeUri(device.location); - } - suggestedPPDs = CupsService.getMatchingPPDs(device); - if (suggestedPPDs.length > 0 && !selectedPpd) { - selectedPpd = suggestedPPDs[0].name; - } - } - - Component.onCompleted: { - CupsService.getClasses(); - } - - ConfirmModal { - id: deletePrinterConfirm - } - - ConfirmModal { - id: purgeJobsConfirm - } - - ConfirmModal { - id: deleteClassConfirm - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(600, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingL - - StyledRect { - width: parent.width - height: overviewSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: overviewSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "print" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("CUPS Print Server") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Grid { - columns: 2 - columnSpacing: Theme.spacingL - rowSpacing: Theme.spacingS - width: parent.width - - StyledText { - text: I18n.tr("Status") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - Row { - spacing: Theme.spacingS - - Rectangle { - width: 8 - height: 8 - radius: 4 - anchors.verticalCenter: parent.verticalCenter - color: CupsService.cupsAvailable ? Theme.success : Theme.error - } - - StyledText { - text: CupsService.cupsAvailable ? I18n.tr("Available") : I18n.tr("Unavailable") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - StyledText { - text: I18n.tr("Printers") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - StyledText { - text: CupsService.printerNames.length.toString() - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: I18n.tr("Total Jobs") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - } - StyledText { - text: CupsService.getTotalJobsNum().toString() - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - } - } - } - - StyledRect { - width: parent.width - height: addPrinterSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: CupsService.cupsAvailable - - Column { - id: addPrinterSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "add_circle" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - addPrinterToggleBtn.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Add Printer") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.tr("Configure a new printer") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - Rectangle { - id: addPrinterToggleBtn - width: 28 - height: 28 - radius: 14 - color: addPrinterToggleArea.containsMouse ? Theme.surfacePressed : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: printerTab.showAddPrinter ? "expand_less" : "expand_more" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: addPrinterToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - printerTab.showAddPrinter = !printerTab.showAddPrinter; - if (printerTab.showAddPrinter) { - if (CupsService.devices.length === 0) { - CupsService.getDevices(); - CupsService.getPPDs(); - } - } else { - printerTab.resetAddPrinterForm(); - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: printerTab.showAddPrinter - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Row { - width: parent.width - spacing: Theme.spacingS - - Rectangle { - width: discoverRow.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - color: !printerTab.manualEntryMode ? Theme.primary : (discoverArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight) - - Row { - id: discoverRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "search" - size: 16 - color: !printerTab.manualEntryMode ? Theme.onPrimary : Theme.surfaceText - } - - StyledText { - text: I18n.tr("Discover Devices", "Toggle button to scan for printers via mDNS/Avahi") - font.pixelSize: Theme.fontSizeSmall - color: !printerTab.manualEntryMode ? Theme.onPrimary : Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: discoverArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - printerTab.manualEntryMode = false; - printerTab.testConnectionResult = null; - printerTab.testingConnection = false; - } - } - } - - Rectangle { - width: manualRow.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - color: printerTab.manualEntryMode ? Theme.primary : (manualArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight) - - Row { - id: manualRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "edit" - size: 16 - color: printerTab.manualEntryMode ? Theme.onPrimary : Theme.surfaceText - } - - StyledText { - text: I18n.tr("Add by Address", "Toggle button to manually add a printer by IP or hostname") - font.pixelSize: Theme.fontSizeSmall - color: printerTab.manualEntryMode ? Theme.onPrimary : Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: manualArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - printerTab.manualEntryMode = true; - printerTab.selectedDevice = null; - printerTab.selectedDeviceUri = ""; - if (CupsService.ppds.length === 0) - CupsService.getPPDs(); - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: !printerTab.manualEntryMode - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Device") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankDropdown { - id: deviceDropdown - dropdownWidth: parent.width - 80 - scanDevicesBtn.width - Theme.spacingS * 2 - popupWidth: parent.width - 80 - scanDevicesBtn.width - Theme.spacingS * 2 - enableFuzzySearch: true - emptyText: I18n.tr("No devices found") - currentValue: { - if (CupsService.loadingDevices) - return I18n.tr("Scanning..."); - if (printerTab.selectedDevice) - return CupsService.getDeviceDisplayName(printerTab.selectedDevice); - return I18n.tr("Select device..."); - } - options: CupsService.filteredDevices.map(d => CupsService.getDeviceDisplayName(d)) - onValueChanged: value => { - const filtered = CupsService.filteredDevices; - const device = filtered.find(d => CupsService.getDeviceDisplayName(d) === value); - if (device) - printerTab.selectDevice(device); - } - } - - DankActionButton { - id: scanDevicesBtn - iconName: "refresh" - buttonSize: 32 - anchors.verticalCenter: parent.verticalCenter - enabled: !CupsService.loadingDevices - onClicked: CupsService.getDevices() - - RotationAnimation on rotation { - running: CupsService.loadingDevices - loops: Animation.Infinite - from: 0 - to: 360 - duration: 1000 - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: printerTab.selectedDevice !== null - - Item { - width: 80 - height: 1 - } - - StyledText { - text: CupsService.getDeviceSubtitle(printerTab.selectedDevice) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - 80 - Theme.spacingS - elide: Text.ElideRight - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: printerTab.manualEntryMode - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Host", "Label for printer IP address or hostname input field") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: parent.width - 80 - Theme.spacingS - placeholderText: I18n.tr("IP address or hostname", "Placeholder text for manual printer address input") - text: printerTab.manualHost - onTextEdited: { - printerTab.manualHost = text; - printerTab.testConnectionResult = null; - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Port", "Label for printer port number input field") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: 80 - placeholderText: "631" - text: printerTab.manualPort - onTextEdited: { - printerTab.manualPort = text; - printerTab.testConnectionResult = null; - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Protocol", "Label for printer protocol selector, e.g. ipp, ipps, lpd, socket") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankDropdown { - id: protocolDropdown - dropdownWidth: 120 - popupWidth: 120 - currentValue: printerTab.manualProtocol - options: ["ipp", "ipps", "lpd", "socket"] - onValueChanged: value => { - printerTab.manualProtocol = value; - printerTab.testConnectionResult = null; - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - Item { - width: 80 - height: 1 - } - - DankButton { - text: printerTab.testingConnection ? I18n.tr("Testing...", "Button state while testing printer connection") : I18n.tr("Test Connection", "Button to test connection to a printer by IP address") - iconName: printerTab.testingConnection ? "sync" : "lan" - buttonHeight: 36 - enabled: printerTab.manualHost.length > 0 && !printerTab.testingConnection - onClicked: { - printerTab.testingConnection = true; - printerTab.testConnectionResult = null; - const port = parseInt(printerTab.manualPort) || 631; - CupsService.testConnection(printerTab.manualHost, port, printerTab.manualProtocol, response => { - printerTab.testingConnection = false; - if (response.error) { - printerTab.testConnectionResult = { - "success": false, - "error": response.error - }; - } else if (response.result) { - printerTab.testConnectionResult = { - "success": response.result.reachable === true, - "data": response.result - }; - if (response.result.reachable) { - if (response.result.uri) - printerTab.selectedDeviceUri = response.result.uri; - if (response.result.name && !printerTab.newPrinterName) - printerTab.newPrinterName = response.result.name.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").substring(0, 32) || "Printer"; - // Load PPDs if not loaded yet, then select driverless - if (CupsService.ppds.length === 0) { - CupsService.getPPDs(); - } - selectDriverlessPPD(); - } - } - }); - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: printerTab.testConnectionResult !== null - - Row { - spacing: Theme.spacingS - - Item { - width: 80 - height: 1 - } - - Rectangle { - width: 8 - height: 8 - radius: 4 - anchors.verticalCenter: parent.verticalCenter - color: printerTab.testConnectionResult?.success ? Theme.success : Theme.error - } - - StyledText { - text: printerTab.testConnectionResult?.success ? I18n.tr("Printer reachable", "Status message when test connection to printer succeeds") : I18n.tr("Connection failed", "Status message when test connection to printer fails") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: printerTab.testConnectionResult?.success ? Theme.success : Theme.error - } - } - - Row { - spacing: Theme.spacingS - visible: printerTab.testConnectionResult?.success && (printerTab.testConnectionResult?.data?.makeModel || printerTab.testConnectionResult?.data?.info) - - Item { - width: 80 - height: 1 - } - - StyledText { - text: printerTab.testConnectionResult?.data?.makeModel || printerTab.testConnectionResult?.data?.info || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - Row { - spacing: Theme.spacingS - visible: !printerTab.testConnectionResult?.success && printerTab.testConnectionResult?.data?.error - - Item { - width: 80 - height: 1 - } - - StyledText { - text: printerTab.testConnectionResult?.data?.error || printerTab.testConnectionResult?.error || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.parent.width - 80 - Theme.spacingS - wrapMode: Text.WordWrap - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Driver") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankDropdown { - id: ppdDropdown - dropdownWidth: parent.width - 80 - refreshPpdsBtn.width - Theme.spacingS * 2 - popupWidth: parent.width - 80 - refreshPpdsBtn.width - Theme.spacingS * 2 - enableFuzzySearch: true - emptyText: I18n.tr("No drivers found") - currentValue: { - if (CupsService.loadingPPDs) - return I18n.tr("Loading..."); - if (printerTab.selectedPpd) { - const ppd = CupsService.ppds.find(p => p.name === printerTab.selectedPpd); - if (ppd) { - const isSuggested = printerTab.suggestedPPDs.some(s => s.name === ppd.name); - return (isSuggested ? "★ " : "") + (ppd.makeModel || ppd.name); - } - return printerTab.selectedPpd; - } - return printerTab.suggestedPPDs.length > 0 ? I18n.tr("Recommended available") : I18n.tr("Select driver..."); - } - options: { - const suggested = printerTab.suggestedPPDs.map(p => "★ " + (p.makeModel || p.name)); - const others = CupsService.ppds.filter(p => !printerTab.suggestedPPDs.some(s => s.name === p.name)).map(p => p.makeModel || p.name); - return suggested.concat(others); - } - onValueChanged: value => { - const cleanValue = value.replace(/^★ /, ""); - const ppd = CupsService.ppds.find(p => (p.makeModel || p.name) === cleanValue); - if (ppd) - printerTab.selectedPpd = ppd.name; - } - } - - DankActionButton { - id: refreshPpdsBtn - iconName: "refresh" - buttonSize: 32 - anchors.verticalCenter: parent.verticalCenter - enabled: !CupsService.loadingPPDs - onClicked: CupsService.getPPDs() - - RotationAnimation on rotation { - running: CupsService.loadingPPDs - loops: Animation.Infinite - from: 0 - to: 360 - duration: 1000 - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Name") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: parent.width - 80 - Theme.spacingS - placeholderText: I18n.tr("Printer name (no spaces)") - text: printerTab.newPrinterName - onTextEdited: printerTab.newPrinterName = text.replace(/\s/g, "-") - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Location") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: parent.width - 80 - Theme.spacingS - placeholderText: I18n.tr("Optional location") - text: printerTab.newPrinterLocation - onTextEdited: printerTab.newPrinterLocation = text - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Description") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: parent.width - 80 - Theme.spacingS - placeholderText: I18n.tr("Optional description") - text: printerTab.newPrinterInfo - onTextEdited: printerTab.newPrinterInfo = text - } - } - } - - Row { - LayoutMirroring.enabled: false - width: parent.width - spacing: Theme.spacingS - layoutDirection: Qt.RightToLeft - - DankButton { - text: CupsService.creatingPrinter ? I18n.tr("Creating...") : I18n.tr("Create Printer") - iconName: CupsService.creatingPrinter ? "sync" : "add" - buttonHeight: 36 - enabled: printerTab.newPrinterName.length > 0 && printerTab.selectedDeviceUri.length > 0 && printerTab.selectedPpd.length > 0 && !CupsService.creatingPrinter - onClicked: { - CupsService.createPrinter(printerTab.newPrinterName, printerTab.selectedDeviceUri, printerTab.selectedPpd, { - location: printerTab.newPrinterLocation, - information: printerTab.newPrinterInfo - }); - printerTab.resetAddPrinterForm(); - printerTab.showAddPrinter = false; - } - } - } - } - } - } - - StyledRect { - width: parent.width - height: printersSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: CupsService.cupsAvailable - - Column { - id: printersSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "print" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - refreshBtn.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Printers") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - const count = CupsService.printerNames.length; - if (count === 0) - return I18n.tr("No printers configured"); - return I18n.ntr("%1 printer", "%1 printers", count).arg(count); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankActionButton { - id: refreshBtn - iconName: "refresh" - buttonSize: 32 - anchors.verticalCenter: parent.verticalCenter - onClicked: CupsService.getState() - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Item { - width: parent.width - height: 80 - visible: CupsService.printerNames.length === 0 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "print_disabled" - size: 32 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No printers found") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - Column { - width: parent.width - spacing: 4 - visible: CupsService.printerNames.length > 0 - - Repeater { - model: CupsService.printerNames - - delegate: Rectangle { - id: printerDelegate - required property string modelData - required property int index - - readonly property var printerData: CupsService.getPrinterData(modelData) - readonly property bool isExpanded: CupsService.expandedPrinter === modelData || hasJobs - readonly property bool hasJobs: (printerData?.jobs?.length ?? 0) > 0 - readonly property bool isIdle: printerData?.state === "idle" - readonly property bool isStopped: printerData?.state === "stopped" - - width: parent.width - height: isExpanded ? 56 + expandedContent.height : 56 - radius: Theme.cornerRadius - color: printerMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - border.width: CupsService.selectedPrinter === modelData ? 2 : 0 - border.color: Theme.primary - clip: true - - Behavior on height { - NumberAnimation { - duration: 150 - easing.type: Easing.OutQuad - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - width: parent.width - height: 56 - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - anchors.right: printerActions.left - anchors.rightMargin: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: isStopped ? "print_disabled" : "print" - size: 20 - color: isStopped ? Theme.error : (isIdle ? Theme.primary : Theme.warning) - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - 20 - Theme.spacingS - - StyledText { - text: modelData - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: CupsService.selectedPrinter === modelData ? Font.Medium : Font.Normal - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingXS - - StyledText { - text: CupsService.getPrinterStateTranslation(printerData?.state || "") - font.pixelSize: Theme.fontSizeSmall - color: { - switch (printerData?.state) { - case "idle": - return Theme.primary; - case "stopped": - return Theme.error; - case "processing": - return Theme.warning; - default: - return Theme.surfaceVariantText; - } - } - } - - StyledText { - text: "•" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: (printerData?.jobs?.length ?? 0) > 0 - } - - StyledText { - text: I18n.ntr("%1 job", "%1 jobs", printerData?.jobs?.length ?? 0).arg(printerData?.jobs?.length ?? 0) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: (printerData?.jobs?.length ?? 0) > 0 - } - } - } - } - - Row { - id: printerActions - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: expandBtn.containsMouse ? Theme.surfacePressed : "transparent" - - DankIcon { - anchors.centerIn: parent - name: isExpanded ? "expand_less" : "expand_more" - size: 18 - color: Theme.surfaceText - } - - MouseArea { - id: expandBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - CupsService.expandedPrinter = isExpanded ? "" : modelData; - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: deleteBtn.containsMouse ? Theme.errorHover : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteBtn.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - deletePrinterConfirm.showWithOptions({ - title: I18n.tr("Delete Printer"), - message: I18n.tr("Delete \"%1\"?").arg(modelData), - confirmText: I18n.tr("Delete"), - confirmColor: Theme.error, - onConfirm: () => CupsService.deletePrinter(modelData) - }); - } - } - } - } - - MouseArea { - id: printerMouseArea - anchors.fill: parent - anchors.rightMargin: printerActions.width + Theme.spacingM - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - CupsService.setSelectedPrinter(modelData); - } - } - } - - Column { - id: expandedContent - width: parent.width - visible: isExpanded - - Rectangle { - width: parent.width - Theme.spacingM * 2 - height: 1 - x: Theme.spacingM - color: Theme.outlineLight - } - - Item { - width: parent.width - height: detailsColumn.implicitHeight + Theme.spacingM * 2 - - Column { - id: detailsColumn - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingS - - Flow { - width: parent.width - spacing: Theme.spacingXS - - Repeater { - model: { - const fields = []; - const p = printerData; - if (!p) - return fields; - - fields.push({ - label: I18n.tr("State"), - value: CupsService.getPrinterStateTranslation(p.state) - }); - if (p.stateReason && p.stateReason !== "none") - fields.push({ - label: I18n.tr("Reason"), - value: CupsService.getPrinterStateReasonTranslation(p.stateReason) - }); - if (p.makeModel) - fields.push({ - label: I18n.tr("Model"), - value: p.makeModel - }); - if (p.location) - fields.push({ - label: I18n.tr("Location"), - value: p.location - }); - fields.push({ - label: I18n.tr("Accepting"), - value: p.accepting ? I18n.tr("Yes") : I18n.tr("No") - }); - - return fields; - } - - delegate: Rectangle { - required property var modelData - required property int index - - width: fieldContent.width + Theme.spacingM * 2 - height: 32 - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHigh - border.width: 1 - border.color: Theme.outlineLight - - Row { - id: fieldContent - anchors.centerIn: parent - spacing: Theme.spacingXS - - StyledText { - text: modelData.label + ":" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.value - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - Rectangle { - height: 28 - width: pauseResumeRow.width + Theme.spacingM * 2 - radius: 14 - color: pauseResumeArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - - Row { - id: pauseResumeRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: isStopped ? "play_arrow" : "pause" - size: 16 - color: Theme.surfaceText - } - - StyledText { - text: isStopped ? I18n.tr("Resume") : I18n.tr("Pause") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: pauseResumeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (isStopped) { - CupsService.resumePrinter(modelData); - } else { - CupsService.pausePrinter(modelData); - } - } - } - } - - Rectangle { - height: 28 - width: testPageRow.width + Theme.spacingM * 2 - radius: 14 - color: testPageArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - - Row { - id: testPageRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "description" - size: 16 - color: Theme.surfaceText - } - - StyledText { - text: I18n.tr("Test Page") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: testPageArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: CupsService.printTestPage(modelData) - } - } - - Rectangle { - height: 28 - width: acceptRejectRow.width + Theme.spacingM * 2 - radius: 14 - color: acceptRejectArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - - Row { - id: acceptRejectRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: printerData?.accepting ? "block" : "check_circle" - size: 16 - color: Theme.surfaceText - } - - StyledText { - text: printerData?.accepting ? I18n.tr("Reject Jobs") : I18n.tr("Accept Jobs") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: acceptRejectArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (printerData?.accepting) { - CupsService.rejectJobs(modelData); - } else { - CupsService.acceptJobs(modelData); - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: (printerData?.jobs?.length ?? 0) > 0 - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Jobs") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: 1 - height: 1 - Layout.fillWidth: true - } - - Rectangle { - height: 24 - width: purgeRow.width + Theme.spacingM * 2 - radius: 12 - color: purgeArea.containsMouse ? Theme.errorHover : Theme.surfaceLight - - Row { - id: purgeRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "delete_sweep" - size: 14 - color: purgeArea.containsMouse ? Theme.error : Theme.surfaceText - } - - StyledText { - text: I18n.tr("Clear All") - font.pixelSize: Theme.fontSizeSmall - 1 - color: purgeArea.containsMouse ? Theme.error : Theme.surfaceText - font.weight: Font.Medium - } - } - - MouseArea { - id: purgeArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - purgeJobsConfirm.showWithOptions({ - title: I18n.tr("Clear All Jobs"), - message: I18n.tr("Cancel all jobs for \"%1\"?").arg(modelData), - confirmText: I18n.tr("Clear"), - confirmColor: Theme.error, - onConfirm: () => CupsService.purgeJobs(modelData) - }); - } - } - } - } - - Repeater { - model: printerData?.jobs ?? [] - - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 44 - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHighest - border.width: 1 - border.color: Theme.outlineLight - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: jobActions.left - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "description" - size: 18 - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 1 - width: parent.width - 18 - Theme.spacingS - - StyledText { - text: "[" + modelData.id + "] " + CupsService.getJobStateTranslation(modelData.state) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: { - const size = Math.round((modelData.size || 0) / 1024); - const date = new Date(modelData.timeCreated); - return size + " KB • " + date.toLocaleString(Qt.locale(), Locale.ShortFormat); - } - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - anchors.left: parent.left - } - } - } - - Row { - id: jobActions - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: 4 - - Rectangle { - width: 24 - height: 24 - radius: 12 - color: holdJobBtn.containsMouse ? Theme.surfacePressed : "transparent" - visible: modelData.state === "pending" - - DankIcon { - anchors.centerIn: parent - name: "pause" - size: 14 - color: Theme.surfaceVariantText - } - - MouseArea { - id: holdJobBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: CupsService.holdJob(modelData.id) - } - } - - Rectangle { - width: 24 - height: 24 - radius: 12 - color: restartJobBtn.containsMouse ? Theme.surfacePressed : "transparent" - visible: modelData.state === "pending-held" || modelData.state === "completed" || modelData.state === "aborted" - - DankIcon { - anchors.centerIn: parent - name: "replay" - size: 14 - color: Theme.surfaceVariantText - } - - MouseArea { - id: restartJobBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: CupsService.restartJob(modelData.id) - } - } - - Rectangle { - width: 24 - height: 24 - radius: 12 - color: cancelJobBtn.containsMouse ? Theme.errorHover : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "close" - size: 14 - color: cancelJobBtn.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: cancelJobBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: CupsService.cancelJob(printerDelegate.modelData, modelData.id) - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - - StyledRect { - width: parent.width - height: classesSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - visible: CupsService.cupsAvailable && CupsService.printerClasses.length > 0 - - Column { - id: classesSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "workspaces" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - refreshClassesBtn.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: I18n.tr("Printer Classes") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: I18n.ntr("%1 class", "%1 classes", CupsService.printerClasses.length).arg(CupsService.printerClasses.length) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankActionButton { - id: refreshClassesBtn - iconName: "refresh" - buttonSize: 32 - anchors.verticalCenter: parent.verticalCenter - onClicked: CupsService.getClasses() - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) - } - - Column { - width: parent.width - spacing: 4 - - Repeater { - model: CupsService.printerClasses - - delegate: Rectangle { - required property var modelData - required property int index - - width: parent.width - height: 48 - radius: Theme.cornerRadius - color: classMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.right: classActions.left - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "workspaces" - size: 20 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.name || I18n.tr("Unknown") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - StyledText { - text: I18n.ntr("%1 printer", "%1 printers", modelData.members?.length ?? 0).arg(modelData.members?.length ?? 0) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - - Row { - id: classActions - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: deleteClassBtn.containsMouse ? Theme.errorHover : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteClassBtn.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteClassBtn - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - deleteClassConfirm.showWithOptions({ - title: I18n.tr("Delete Class"), - message: I18n.tr("Delete class \"%1\"?").arg(modelData.name), - confirmText: I18n.tr("Delete"), - confirmColor: Theme.error, - onConfirm: () => CupsService.deleteClass(modelData.name) - }); - } - } - } - } - - MouseArea { - id: classMouseArea - anchors.fill: parent - anchors.rightMargin: classActions.width + Theme.spacingM - hoverEnabled: true - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/RunningAppsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/RunningAppsTab.qml deleted file mode 100644 index 022e131..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/RunningAppsTab.qml +++ /dev/null @@ -1,175 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "find_replace" - title: I18n.tr("App ID Substitutions") - settingKey: "appIdSubstitutions" - tags: ["app", "icon", "substitution", "replacement", "pattern", "window", "class", "regex"] - - headerActions: [ - DankActionButton { - buttonSize: 36 - iconName: "restart_alt" - iconSize: 20 - visible: JSON.stringify(SettingsData.appIdSubstitutions) !== JSON.stringify(SettingsData.getDefaultAppIdSubstitutions()) - backgroundColor: Theme.surfaceContainer - iconColor: Theme.surfaceVariantText - onClicked: SettingsData.resetAppIdSubstitutions() - }, - DankActionButton { - buttonSize: 36 - iconName: "add" - iconSize: 20 - backgroundColor: Theme.surfaceContainer - iconColor: Theme.primary - onClicked: SettingsData.addAppIdSubstitution("", "", "exact") - } - ] - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Map window class names to icon names for proper icon display") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - bottomPadding: Theme.spacingS - } - - Repeater { - model: SettingsData.appIdSubstitutions - - delegate: Rectangle { - id: subItem - width: parent.width - height: subColumn.implicitHeight + Theme.spacingM - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.surfaceContainer, 0.5) - - Column { - id: subColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingS - - Column { - width: (parent.width - deleteBtn.width - Theme.spacingS) / 2 - spacing: 2 - - StyledText { - text: I18n.tr("Pattern") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankTextField { - id: patternField - width: parent.width - text: modelData.pattern - font.pixelSize: Theme.fontSizeSmall - onEditingFinished: SettingsData.updateAppIdSubstitution(index, text, replacementField.text, modelData.type) - } - } - - Column { - width: (parent.width - deleteBtn.width - Theme.spacingS) / 2 - spacing: 2 - - StyledText { - text: I18n.tr("Replacement") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankTextField { - id: replacementField - width: parent.width - text: modelData.replacement - font.pixelSize: Theme.fontSizeSmall - onEditingFinished: SettingsData.updateAppIdSubstitution(index, patternField.text, text, modelData.type) - } - } - - Item { - id: deleteBtn - width: 32 - height: 40 - anchors.verticalCenter: parent.verticalCenter - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: deleteArea.containsMouse ? Theme.withAlpha(Theme.error, 0.2) : "transparent" - } - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 18 - color: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText - } - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: SettingsData.removeAppIdSubstitution(index) - } - } - } - - Column { - width: 120 - spacing: 2 - - StyledText { - text: I18n.tr("Type") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - } - - DankDropdown { - width: parent.width - compactMode: true - dropdownWidth: 120 - currentValue: modelData.type - options: ["exact", "contains", "regex"] - onValueChanged: value => SettingsData.updateAppIdSubstitution(index, modelData.pattern, modelData.replacement, value) - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SoundsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SoundsTab.qml deleted file mode 100644 index a8e9958..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SoundsTab.qml +++ /dev/null @@ -1,168 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "sounds" - tags: ["sound", "audio", "notification", "volume"] - title: I18n.tr("System Sounds") - settingKey: "systemSounds" - iconName: SettingsData.soundsEnabled ? "volume_up" : "volume_off" - visible: AudioService.soundsAvailable - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "enable", "system"] - settingKey: "soundsEnabled" - text: I18n.tr("Enable System Sounds") - description: I18n.tr("Play sounds for system events") - checked: SettingsData.soundsEnabled - onToggled: checked => SettingsData.set("soundsEnabled", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SettingsData.soundsEnabled - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - } - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "theme", "system"] - settingKey: "useSystemSoundTheme" - visible: AudioService.gsettingsAvailable - text: I18n.tr("Use System Theme") - description: I18n.tr("Use sound theme from system settings") - checked: SettingsData.useSystemSoundTheme - onToggled: checked => SettingsData.set("useSystemSoundTheme", checked) - } - - SettingsDropdownRow { - tab: "sounds" - tags: ["sound", "theme", "select"] - settingKey: "soundTheme" - visible: SettingsData.useSystemSoundTheme && AudioService.availableSoundThemes.length > 0 - enabled: SettingsData.useSystemSoundTheme && AudioService.availableSoundThemes.length > 0 - text: I18n.tr("Sound Theme") - description: I18n.tr("Select system sound theme") - options: AudioService.availableSoundThemes - currentValue: { - const theme = AudioService.currentSoundTheme; - if (theme && AudioService.availableSoundThemes.includes(theme)) - return theme; - return AudioService.availableSoundThemes.length > 0 ? AudioService.availableSoundThemes[0] : ""; - } - onValueChanged: value => { - if (value && value !== AudioService.currentSoundTheme) - AudioService.setSoundTheme(value); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: AudioService.gsettingsAvailable - } - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "login", "startup", "boot"] - settingKey: "soundLogin" - text: I18n.tr("Login") - description: I18n.tr("Play sound after logging in") - checked: SettingsData.soundLogin - onToggled: checked => SettingsData.set("soundLogin", checked) - } - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "notification", "new"] - settingKey: "soundNewNotification" - text: I18n.tr("New Notification") - description: I18n.tr("Play sound when new notification arrives") - checked: SettingsData.soundNewNotification - onToggled: checked => SettingsData.set("soundNewNotification", checked) - } - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "volume", "changed"] - settingKey: "soundVolumeChanged" - text: I18n.tr("Volume Changed") - description: I18n.tr("Play sound when volume is adjusted") - checked: SettingsData.soundVolumeChanged - onToggled: checked => SettingsData.set("soundVolumeChanged", checked) - } - - SettingsToggleRow { - tab: "sounds" - tags: ["sound", "power", "plugged"] - settingKey: "soundPluggedIn" - visible: BatteryService.batteryAvailable - text: I18n.tr("Plugged In") - description: I18n.tr("Play sound when power cable is connected") - checked: SettingsData.soundPluggedIn - onToggled: checked => SettingsData.set("soundPluggedIn", checked) - } - } - } - - Rectangle { - width: parent.width - height: notAvailableText.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12) - visible: !AudioService.soundsAvailable - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "info" - size: Theme.iconSizeSmall - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: notAvailableText - font.pixelSize: Theme.fontSizeSmall - text: I18n.tr("System sounds are not available. Install %1 for sound support.").arg("qt6-multimedia") - wrapMode: Text.WordWrap - width: parent.width - Theme.iconSizeSmall - Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SystemUpdaterTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SystemUpdaterTab.qml deleted file mode 100644 index 5a61dbb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/SystemUpdaterTab.qml +++ /dev/null @@ -1,142 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "refresh" - title: I18n.tr("System Updater") - settingKey: "systemUpdater" - - SettingsToggleRow { - text: I18n.tr("Hide Updater Widget", "When updater widget is used, then hide it if no update found") - description: I18n.tr("When updater widget is used, then hide it if no update found") - checked: SettingsData.updaterHideWidget - onToggled: checked => { - SettingsData.set("updaterHideWidget", checked); - } - } - - SettingsToggleRow { - text: I18n.tr("Use Custom Command") - description: I18n.tr("Use custom command for update your system") - checked: SettingsData.updaterUseCustomCommand - onToggled: checked => { - if (!checked) { - updaterCustomCommand.text = ""; - updaterTerminalCustomClass.text = ""; - SettingsData.set("updaterCustomCommand", ""); - SettingsData.set("updaterTerminalAdditionalParams", ""); - } - SettingsData.set("updaterUseCustomCommand", checked); - } - } - - FocusScope { - width: parent.width - Theme.spacingM * 2 - height: customCommandColumn.implicitHeight - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - - Column { - id: customCommandColumn - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("System update custom command") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: updaterCustomCommand - width: parent.width - placeholderText: "myPkgMngr --sysupdate" - backgroundColor: Theme.surfaceContainerHighest - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - - Component.onCompleted: { - if (SettingsData.updaterCustomCommand) { - text = SettingsData.updaterCustomCommand; - } - } - - onTextEdited: SettingsData.set("updaterCustomCommand", text.trim()) - - MouseArea { - anchors.fill: parent - onPressed: mouse => { - updaterCustomCommand.forceActiveFocus(); - mouse.accepted = false; - } - } - } - } - } - - FocusScope { - width: parent.width - Theme.spacingM * 2 - height: terminalParamsColumn.implicitHeight - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - - Column { - id: terminalParamsColumn - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Terminal custom additional parameters") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: updaterTerminalCustomClass - width: parent.width - placeholderText: "-T udpClass" - backgroundColor: Theme.surfaceContainerHighest - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - - Component.onCompleted: { - if (SettingsData.updaterTerminalAdditionalParams) { - text = SettingsData.updaterTerminalAdditionalParams; - } - } - - onTextEdited: SettingsData.set("updaterTerminalAdditionalParams", text.trim()) - - MouseArea { - anchors.fill: parent - onPressed: mouse => { - updaterTerminalCustomClass.forceActiveFocus(); - mouse.accepted = false; - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeBrowser.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeBrowser.qml deleted file mode 100644 index 1df32c7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeBrowser.qml +++ /dev/null @@ -1,697 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import qs.Common -import qs.Modals.Common -import qs.Services -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property var allThemes: [] - property string searchQuery: "" - property var filteredThemes: [] - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - property bool isLoading: false - property var parentModal: null - property bool pendingInstallHandled: false - property string pendingApplyThemeId: "" - - function updateFilteredThemes() { - var filtered = []; - var query = searchQuery ? searchQuery.toLowerCase() : ""; - - for (var i = 0; i < allThemes.length; i++) { - var theme = allThemes[i]; - - if (query.length === 0) { - filtered.push(theme); - continue; - } - - var name = theme.name ? theme.name.toLowerCase() : ""; - var description = theme.description ? theme.description.toLowerCase() : ""; - var author = theme.author ? theme.author.toLowerCase() : ""; - - if (name.indexOf(query) !== -1 || description.indexOf(query) !== -1 || author.indexOf(query) !== -1) - filtered.push(theme); - } - - filteredThemes = filtered; - selectedIndex = -1; - keyboardNavigationActive = false; - } - - function selectNext() { - if (filteredThemes.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.min(selectedIndex + 1, filteredThemes.length - 1); - } - - function selectPrevious() { - if (filteredThemes.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.max(selectedIndex - 1, -1); - if (selectedIndex === -1) - keyboardNavigationActive = false; - } - - function installTheme(themeId, themeName, applyAfterInstall) { - ToastService.showInfo(I18n.tr("Installing: %1", "installation progress").arg(themeName)); - DMSService.installTheme(themeId, response => { - if (response.error) { - ToastService.showError(I18n.tr("Install failed: %1", "installation error").arg(response.error)); - return; - } - ToastService.showInfo(I18n.tr("Installed: %1", "installation success").arg(themeName)); - if (applyAfterInstall) - pendingApplyThemeId = themeId; - refreshThemes(); - }); - } - - function applyInstalledTheme(themeId, installedThemes) { - for (var i = 0; i < installedThemes.length; i++) { - var theme = installedThemes[i]; - if (theme.id === themeId) { - var sourceDir = theme.sourceDir || theme.id; - var themePath = Quickshell.env("HOME") + "/.config/DankMaterialShell/themes/" + sourceDir + "/theme.json"; - SettingsData.set("customThemeFile", themePath); - Theme.switchThemeCategory("registry", "custom"); - Theme.switchTheme("custom", true, true); - hide(); - return; - } - } - } - - function uninstallTheme(themeId, themeName) { - ToastService.showInfo(I18n.tr("Uninstalling: %1", "uninstallation progress").arg(themeName)); - DMSService.uninstallTheme(themeId, response => { - if (response.error) { - ToastService.showError(I18n.tr("Uninstall failed: %1", "uninstallation error").arg(response.error)); - return; - } - ToastService.showInfo(I18n.tr("Uninstalled: %1", "uninstallation success").arg(themeName)); - refreshThemes(); - }); - } - - function refreshThemes() { - isLoading = true; - DMSService.listThemes(); - DMSService.listInstalledThemes(); - } - - function checkPendingInstall() { - if (!PopoutService.pendingThemeInstall || pendingInstallHandled) - return; - pendingInstallHandled = true; - var themeId = PopoutService.pendingThemeInstall; - PopoutService.pendingThemeInstall = ""; - urlInstallConfirm.showWithOptions({ - "title": I18n.tr("Install Theme", "theme installation dialog title"), - "message": I18n.tr("Install theme '%1' from the DMS registry?", "theme installation confirmation").arg(themeId), - "confirmText": I18n.tr("Install", "install action button"), - "cancelText": I18n.tr("Cancel"), - "onConfirm": () => installTheme(themeId, themeId, true), - "onCancel": () => hide() - }); - } - - function show() { - if (parentModal) - parentModal.shouldHaveFocus = false; - visible = true; - Qt.callLater(() => browserSearchField.forceActiveFocus()); - } - - function hide() { - visible = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - objectName: "themeBrowser" - title: I18n.tr("Browse Themes", "theme browser window title") - minimumSize: Qt.size(550, 450) - implicitWidth: 700 - implicitHeight: 700 - color: Theme.surfaceContainer - visible: false - - onVisibleChanged: { - if (visible) { - pendingInstallHandled = false; - refreshThemes(); - Qt.callLater(() => { - browserSearchField.forceActiveFocus(); - checkPendingInstall(); - }); - return; - } - allThemes = []; - searchQuery = ""; - filteredThemes = []; - selectedIndex = -1; - keyboardNavigationActive = false; - isLoading = false; - } - - ConfirmModal { - id: urlInstallConfirm - } - - Connections { - target: DMSService - function onThemesListReceived(themes) { - isLoading = false; - allThemes = themes; - updateFilteredThemes(); - } - function onInstalledThemesReceived(themes) { - if (!pendingApplyThemeId) - return; - var themeId = pendingApplyThemeId; - pendingApplyThemeId = ""; - applyInstalledTheme(themeId, themes); - } - } - - FocusScope { - id: browserKeyHandler - - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Escape: - root.hide(); - event.accepted = true; - return; - case Qt.Key_Down: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_Up: - root.selectPrevious(); - event.accepted = true; - return; - } - } - - Item { - id: browserContent - anchors.fill: parent - anchors.margins: Theme.spacingL - - Item { - id: headerArea - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: Math.max(headerIcon.height, headerText.height, refreshButton.height, closeButton.height) - - MouseArea { - anchors.fill: parent - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - DankIcon { - id: headerIcon - name: "palette" - size: Theme.iconSize - color: Theme.primary - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: headerText - text: I18n.tr("Browse Themes", "theme browser header") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.left: headerIcon.right - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - } - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - id: refreshButton - iconName: "refresh" - iconSize: 18 - iconColor: Theme.primary - visible: !root.isLoading - onClicked: root.refreshThemes() - } - - DankActionButton { - visible: windowControls.supported - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 2 - iconColor: Theme.outline - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - id: closeButton - iconName: "close" - iconSize: Theme.iconSize - 2 - iconColor: Theme.outline - onClicked: root.hide() - } - } - } - - StyledText { - id: descriptionText - anchors.left: parent.left - anchors.right: parent.right - anchors.top: headerArea.bottom - anchors.topMargin: Theme.spacingM - text: I18n.tr("Install color themes from the DMS theme registry", "theme browser description") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - wrapMode: Text.WordWrap - } - - DankTextField { - id: browserSearchField - anchors.left: parent.left - anchors.right: parent.right - anchors.top: descriptionText.bottom - anchors.topMargin: Theme.spacingM - height: 48 - cornerRadius: Theme.cornerRadius - backgroundColor: Theme.surfaceContainerHigh - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: "search" - leftIconSize: Theme.iconSize - leftIconColor: Theme.surfaceVariantText - leftIconFocusedColor: Theme.primary - showClearButton: true - textColor: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - placeholderText: I18n.tr("Search themes...", "theme search placeholder") - text: root.searchQuery - focus: true - ignoreLeftRightKeys: true - keyForwardTargets: [browserKeyHandler] - onTextEdited: { - root.searchQuery = text; - root.updateFilteredThemes(); - } - } - - Item { - id: listArea - anchors.left: parent.left - anchors.right: parent.right - anchors.top: browserSearchField.bottom - anchors.topMargin: Theme.spacingM - anchors.bottom: parent.bottom - - Item { - anchors.fill: parent - visible: root.isLoading - - Column { - anchors.centerIn: parent - spacing: Theme.spacingM - - DankIcon { - name: "sync" - size: 48 - color: Theme.primary - anchors.horizontalCenter: parent.horizontalCenter - - RotationAnimator on rotation { - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - running: root.isLoading - } - } - - StyledText { - text: I18n.tr("Loading...", "loading indicator") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - DankListView { - id: themeBrowserList - - anchors.fill: parent - spacing: Theme.spacingS - model: ScriptModel { - values: root.filteredThemes - } - clip: true - visible: !root.isLoading - - ScrollBar.vertical: DankScrollbar { - id: browserScrollbar - } - - delegate: Rectangle { - id: themeDelegate - width: themeBrowserList.width - height: hasPreview ? 140 : themeDelegateContent.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex - property bool isInstalled: modelData.installed || false - property bool isFirstParty: modelData.firstParty || false - property bool hasVariants: modelData.hasVariants || false - property var variants: modelData.variants || null - property string selectedVariantId: { - if (!hasVariants || !variants) - return ""; - if (variants.type === "multi") { - const mode = Theme.isLightMode ? "light" : "dark"; - const defaults = variants.defaults?.[mode] || variants.defaults?.dark || {}; - return (defaults.flavor || "") + (defaults.accent ? "-" + defaults.accent : ""); - } - return variants.default || (variants.options?.[0]?.id ?? ""); - } - property string previewPath: { - const baseDir = "/tmp/dankdots-plugin-registry/themes/" + (modelData.sourceDir || modelData.id); - const mode = Theme.isLightMode ? "light" : "dark"; - if (hasVariants && selectedVariantId) { - if (variants?.type === "multi") - return baseDir + "/preview-" + selectedVariantId + ".svg"; - return baseDir + "/preview-" + selectedVariantId + "-" + mode + ".svg"; - } - return baseDir + "/preview-" + mode + ".svg"; - } - property bool hasPreview: previewImage.status === Image.Ready - color: isSelected ? Theme.primarySelected : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) - border.color: isSelected ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: isSelected ? 2 : 1 - - Row { - id: themeDelegateContent - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Rectangle { - width: hasPreview ? 180 : 0 - height: parent.height - radius: Theme.cornerRadius - 2 - color: Theme.surfaceContainerHigh - visible: hasPreview - - Image { - id: previewImage - anchors.fill: parent - anchors.margins: 2 - source: "file://" + previewPath - fillMode: Image.PreserveAspectFit - smooth: true - mipmap: true - } - } - - DankIcon { - name: "palette" - size: 48 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - visible: !hasPreview - } - - Column { - width: parent.width - (hasPreview ? 180 : 48) - Theme.spacingM - installButton.width - Theme.spacingM - spacing: 6 - anchors.verticalCenter: parent.verticalCenter - - Row { - spacing: Theme.spacingXS - width: parent.width - - StyledText { - text: modelData.name - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - height: 18 - width: versionText.implicitWidth + Theme.spacingS - radius: 9 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.15) - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: versionText - anchors.centerIn: parent - text: modelData.version || "1.0.0" - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - } - } - - Rectangle { - height: 18 - width: firstPartyText.implicitWidth + Theme.spacingS - radius: 9 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15) - border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.4) - border.width: 1 - visible: isFirstParty - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: firstPartyText - anchors.centerIn: parent - text: I18n.tr("official") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - } - } - - Rectangle { - height: 18 - width: variantsText.implicitWidth + Theme.spacingS - radius: 9 - color: Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.15) - border.color: Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.4) - border.width: 1 - visible: themeDelegate.hasVariants - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: variantsText - anchors.centerIn: parent - text: { - if (themeDelegate.variants?.type === "multi") - return I18n.tr("%1 variants").arg(themeDelegate.variants?.accents?.length ?? 0); - return I18n.tr("%1 variants").arg(themeDelegate.variants?.options?.length ?? 0); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.secondary - font.weight: Font.Medium - } - } - } - - StyledText { - text: I18n.tr("by %1", "author attribution").arg(modelData.author || I18n.tr("Unknown", "unknown author")) - font.pixelSize: Theme.fontSizeMedium - color: Theme.outline - elide: Text.ElideRight - width: parent.width - } - - StyledText { - text: modelData.description || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - maximumLineCount: themeDelegate.hasVariants ? 2 : 3 - elide: Text.ElideRight - visible: modelData.description && modelData.description.length > 0 - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: themeDelegate.hasVariants && themeDelegate.variants?.type !== "multi" - - Repeater { - model: themeDelegate.variants?.options ?? [] - - Rectangle { - property bool isActive: themeDelegate.selectedVariantId === modelData.id - height: 22 - width: variantChipText.implicitWidth + Theme.spacingS * 2 - radius: 11 - color: isActive ? Theme.primary : Theme.surfaceContainerHigh - border.color: isActive ? Theme.primary : Theme.outline - border.width: 1 - - StyledText { - id: variantChipText - anchors.centerIn: parent - text: modelData.name - font.pixelSize: Theme.fontSizeSmall - color: isActive ? Theme.primaryText : Theme.surfaceText - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: themeDelegate.selectedVariantId = modelData.id - } - } - } - } - - Flow { - width: parent.width - spacing: Theme.spacingXS - visible: themeDelegate.hasVariants && themeDelegate.variants?.type === "multi" - - Repeater { - model: themeDelegate.variants?.accents ?? [] - - Rectangle { - width: 18 - height: 18 - radius: 9 - color: modelData.color || Theme.primary - border.color: Theme.outline - border.width: 1 - - DankTooltipV2 { - id: accentTooltip - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: accentTooltip.show(modelData.name || modelData.id, parent, 0, 0, "top") - onExited: accentTooltip.hide() - } - } - } - } - } - - Rectangle { - id: installButton - width: 90 - height: 36 - radius: Theme.cornerRadius - anchors.verticalCenter: parent.verticalCenter - color: isInstalled ? (uninstallMouseArea.containsMouse ? Theme.error : Theme.surfaceVariant) : Theme.primary - opacity: installMouseArea.containsMouse || uninstallMouseArea.containsMouse ? 0.9 : 1 - border.width: isInstalled ? 1 : 0 - border.color: isInstalled ? (uninstallMouseArea.containsMouse ? Theme.error : Theme.outline) : "transparent" - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: isInstalled ? (uninstallMouseArea.containsMouse ? "delete" : "check") : "download" - size: 16 - color: isInstalled ? (uninstallMouseArea.containsMouse ? "white" : Theme.surfaceText) : Theme.surface - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: { - if (!isInstalled) - return I18n.tr("Install", "install action button"); - if (uninstallMouseArea.containsMouse) - return I18n.tr("Uninstall", "uninstall action button"); - return I18n.tr("Installed", "installed status"); - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: isInstalled ? (uninstallMouseArea.containsMouse ? "white" : Theme.surfaceText) : Theme.surface - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: installMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - visible: !isInstalled - onClicked: root.installTheme(modelData.id, modelData.name, false) - } - - MouseArea { - id: uninstallMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - visible: isInstalled - onClicked: root.uninstallTheme(modelData.id, modelData.name) - } - } - } - } - } - - StyledText { - anchors.centerIn: listArea - text: I18n.tr("No themes found", "empty theme list") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceVariantText - visible: !root.isLoading && root.filteredThemes.length === 0 - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeColorsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeColorsTab.qml deleted file mode 100644 index ce080c4..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/ThemeColorsTab.qml +++ /dev/null @@ -1,3016 +0,0 @@ -import QtCore -import QtQuick -import QtQuick.Effects -import Quickshell -import qs.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: themeColorsTab - - property var cachedIconThemes: SettingsData.availableIconThemes - property var cachedCursorThemes: SettingsData.availableCursorThemes - property var cachedMatugenSchemes: Theme.availableMatugenSchemes.map(option => option.label) - property var installedRegistryThemes: [] - property var templateDetection: [] - - property var cursorIncludeStatus: ({ - "exists": false, - "included": false - }) - property bool checkingCursorInclude: false - property bool fixingCursorInclude: false - - function getCursorConfigPaths() { - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - switch (CompositorService.compositor) { - case "niri": - return { - "configFile": configDir + "/niri/config.kdl", - "cursorFile": configDir + "/niri/dms/cursor.kdl", - "grepPattern": 'include.*"dms/cursor.kdl"', - "includeLine": 'include "dms/cursor.kdl"' - }; - case "hyprland": - return { - "configFile": configDir + "/hypr/hyprland.conf", - "cursorFile": configDir + "/hypr/dms/cursor.conf", - "grepPattern": 'source.*dms/cursor.conf', - "includeLine": "source = ./dms/cursor.conf" - }; - case "dwl": - return { - "configFile": configDir + "/mango/config.conf", - "cursorFile": configDir + "/mango/dms/cursor.conf", - "grepPattern": 'source.*dms/cursor.conf', - "includeLine": "source=./dms/cursor.conf" - }; - default: - return null; - } - } - - function checkCursorIncludeStatus() { - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland" && compositor !== "dwl") { - cursorIncludeStatus = { - "exists": false, - "included": false - }; - return; - } - - const filename = (compositor === "niri") ? "cursor.kdl" : "cursor.conf"; - const compositorArg = (compositor === "dwl") ? "mangowc" : compositor; - - checkingCursorInclude = true; - Proc.runCommand("check-cursor-include", ["dms", "config", "resolve-include", compositorArg, filename], (output, exitCode) => { - checkingCursorInclude = false; - if (exitCode !== 0) { - cursorIncludeStatus = { - "exists": false, - "included": false - }; - return; - } - try { - cursorIncludeStatus = JSON.parse(output.trim()); - } catch (e) { - cursorIncludeStatus = { - "exists": false, - "included": false - }; - } - }); - } - - function fixCursorInclude() { - const paths = getCursorConfigPaths(); - if (!paths) - return; - fixingCursorInclude = true; - const cursorDir = paths.cursorFile.substring(0, paths.cursorFile.lastIndexOf("/")); - const unixTime = Math.floor(Date.now() / 1000); - const backupFile = paths.configFile + ".backup" + unixTime; - Proc.runCommand("fix-cursor-include", ["sh", "-c", `cp "${paths.configFile}" "${backupFile}" 2>/dev/null; ` + `mkdir -p "${cursorDir}" && ` + `touch "${paths.cursorFile}" && ` + `if ! grep -v '^[[:space:]]*\\(//\\|#\\)' "${paths.configFile}" 2>/dev/null | grep -q '${paths.grepPattern}'; then ` + `echo '' >> "${paths.configFile}" && ` + `echo '${paths.includeLine}' >> "${paths.configFile}"; fi`], (output, exitCode) => { - fixingCursorInclude = false; - if (exitCode !== 0) - return; - checkCursorIncludeStatus(); - SettingsData.updateCompositorCursor(); - }); - } - - function isTemplateDetected(templateId) { - if (!templateDetection || templateDetection.length === 0) - return true; - var item = templateDetection.find(i => i.id === templateId); - return !item || item.detected !== false; - } - - function getTemplateDescription(templateId, baseDescription) { - if (isTemplateDetected(templateId)) - return baseDescription; - if (baseDescription) - return baseDescription + " · " + I18n.tr("Not detected"); - return I18n.tr("Not detected"); - } - - function getTemplateDescriptionColor(templateId) { - if (isTemplateDetected(templateId)) - return Theme.surfaceVariantText; - return Theme.warning; - } - - function openBlurBorderColorPicker() { - PopoutService.colorPickerModal.selectedColor = SettingsData.blurBorderCustomColor ?? "#ffffff"; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Blur Border Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (color) { - SettingsData.set("blurBorderCustomColor", color.toString()); - }; - PopoutService.colorPickerModal.open(); - } - - function openM3ShadowColorPicker() { - PopoutService.colorPickerModal.selectedColor = SettingsData.m3ElevationCustomColor ?? "#000000"; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Shadow Color"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (color) { - SettingsData.set("m3ElevationCustomColor", color.toString()); - }; - PopoutService.colorPickerModal.show(); - } - - function formatThemeAutoTime(isoString) { - if (!isoString) - return ""; - try { - const date = new Date(isoString); - if (isNaN(date.getTime())) - return ""; - return date.toLocaleTimeString(Qt.locale(), "HH:mm"); - } catch (e) { - return ""; - } - } - - Component.onCompleted: { - SettingsData.detectAvailableIconThemes(); - SettingsData.detectAvailableCursorThemes(); - if (DMSService.dmsAvailable) - DMSService.listInstalledThemes(); - if (PopoutService.pendingThemeInstall) - Qt.callLater(() => showThemeBrowser()); - Proc.runCommand("template-check", ["dms", "matugen", "check"], (output, exitCode) => { - if (exitCode !== 0) - return; - try { - themeColorsTab.templateDetection = JSON.parse(output.trim()); - } catch (e) {} - }); - if (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl) - checkCursorIncludeStatus(); - } - - Connections { - target: DMSService - function onInstalledThemesReceived(themes) { - themeColorsTab.installedRegistryThemes = themes; - } - } - - Connections { - target: PopoutService - function onPendingThemeInstallChanged() { - if (PopoutService.pendingThemeInstall) - showThemeBrowser(); - } - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "theme" - tags: ["color", "palette", "theme", "appearance"] - title: I18n.tr("Theme Color") - settingKey: "themeColor" - iconName: "palette" - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - property string registryThemeName: { - if (Theme.currentThemeCategory !== "registry") - return ""; - for (var i = 0; i < themeColorsTab.installedRegistryThemes.length; i++) { - var t = themeColorsTab.installedRegistryThemes[i]; - if (SettingsData.customThemeFile && SettingsData.customThemeFile.endsWith((t.sourceDir || t.id) + "/theme.json")) - return t.name; - } - return ""; - } - text: { - if (Theme.currentTheme === Theme.dynamic) - return I18n.tr("Current Theme: %1", "current theme label").arg(I18n.tr("Dynamic", "dynamic theme name")); - if (Theme.currentThemeCategory === "registry" && registryThemeName) - return I18n.tr("Current Theme: %1", "current theme label").arg(registryThemeName); - return I18n.tr("Current Theme: %1", "current theme label").arg(Theme.getThemeColors(Theme.currentThemeName).name); - } - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: { - if (Theme.currentTheme === Theme.dynamic) - return I18n.tr("Material colors generated from wallpaper", "dynamic theme description"); - if (Theme.currentThemeCategory === "registry") - return I18n.tr("Color theme from DMS registry", "registry theme description"); - if (Theme.currentTheme === Theme.custom) - return I18n.tr("Custom theme loaded from JSON file", "custom theme description"); - return I18n.tr("Material Design inspired color themes", "generic theme description"); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - wrapMode: Text.WordWrap - width: Math.min(parent.width, 400) - horizontalAlignment: Text.AlignHCenter - } - } - - Column { - id: themeCategoryColumn - spacing: Theme.spacingM - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - - Item { - width: parent.width - height: themeCategoryGroup.implicitHeight - clip: true - - DankButtonGroup { - id: themeCategoryGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 420 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 420 ? 44 : 64 - textSize: parent.width < 420 ? Theme.fontSizeSmall : Theme.fontSizeMedium - property bool isRegistryTheme: Theme.currentThemeCategory === "registry" - property int pendingIndex: -1 - property int computedIndex: { - if (isRegistryTheme) - return 3; - if (Theme.currentTheme === Theme.dynamic) - return 1; - if (Theme.currentThemeName === "custom") - return 2; - return 0; - } - - model: DMSService.dmsAvailable ? [I18n.tr("Generic", "theme category option"), I18n.tr("Auto", "theme category option"), I18n.tr("Custom", "theme category option"), I18n.tr("Browse", "theme category option")] : [I18n.tr("Generic", "theme category option"), I18n.tr("Auto", "theme category option"), I18n.tr("Custom", "theme category option")] - currentIndex: pendingIndex >= 0 ? pendingIndex : computedIndex - selectionMode: "single" - onSelectionChanged: (index, selected) => { - if (!selected) - return; - pendingIndex = index; - } - onAnimationCompleted: { - if (pendingIndex < 0) - return; - const idx = pendingIndex; - pendingIndex = -1; - switch (idx) { - case 0: - Theme.switchThemeCategory("generic", "blue"); - break; - case 1: - if (ToastService.wallpaperErrorStatus === "matugen_missing") - ToastService.showError(I18n.tr("matugen not found - install matugen package for dynamic theming", "matugen error")); - else if (ToastService.wallpaperErrorStatus === "error") - ToastService.showError(I18n.tr("Wallpaper processing failed - check wallpaper path", "wallpaper error")); - else - Theme.switchThemeCategory("dynamic", Theme.dynamic); - break; - case 2: - Theme.switchThemeCategory("custom", "custom"); - break; - case 3: - Theme.switchThemeCategory("registry", ""); - break; - } - } - } - } - - Item { - width: parent.width - height: genericColorGrid.implicitHeight + Math.ceil(genericColorGrid.dotSize * 0.05) - visible: Theme.currentThemeCategory === "generic" && Theme.currentTheme !== Theme.dynamic && Theme.currentThemeName !== "custom" - - Grid { - id: genericColorGrid - property var colorList: ["blue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral", "monochrome"] - property int dotSize: parent.width < 300 ? 28 : 32 - columns: Math.ceil(colorList.length / 2) - rowSpacing: Theme.spacingS - columnSpacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - Repeater { - model: genericColorGrid.colorList - - Rectangle { - required property string modelData - property string themeName: modelData - width: genericColorGrid.dotSize - height: genericColorGrid.dotSize - radius: width / 2 - color: Theme.getThemeColors(themeName).primary - border.color: Theme.outline - border.width: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 2 : 1 - scale: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 1.1 : 1 - - Rectangle { - width: nameText.contentWidth + Theme.spacingS * 2 - height: nameText.contentHeight + Theme.spacingXS * 2 - color: Theme.surfaceContainer - radius: Theme.cornerRadius - anchors.bottom: parent.top - anchors.bottomMargin: Theme.spacingXS - anchors.horizontalCenter: parent.horizontalCenter - visible: mouseArea.containsMouse - - StyledText { - id: nameText - text: Theme.getThemeColors(parent.parent.themeName).name - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.centerIn: parent - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: Theme.switchTheme(parent.themeName) - } - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: Theme.currentTheme === Theme.dynamic && Theme.currentThemeCategory !== "registry" - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledRect { - width: 120 - height: 90 - radius: Theme.cornerRadius - color: Theme.surfaceVariant - - Image { - anchors.fill: parent - anchors.margins: 1 - source: { - var wp = Theme.wallpaperPath; - if (!wp || wp === "" || wp.startsWith("#")) - return ""; - if (wp.startsWith("file://")) - wp = wp.substring(7); - return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/'); - } - fillMode: Image.PreserveAspectCrop - visible: Theme.wallpaperPath && !Theme.wallpaperPath.startsWith("#") - sourceSize.width: 120 - sourceSize.height: 120 - asynchronous: true - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskSource: autoWallpaperMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: Theme.wallpaperPath && Theme.wallpaperPath.startsWith("#") ? Theme.wallpaperPath : "transparent" - visible: Theme.wallpaperPath && Theme.wallpaperPath.startsWith("#") - } - - Rectangle { - id: autoWallpaperMask - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: "black" - visible: false - layer.enabled: true - } - - DankIcon { - anchors.centerIn: parent - name: (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") ? "error" : "palette" - size: Theme.iconSizeLarge - color: (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") ? Theme.error : Theme.surfaceVariantText - visible: !Theme.wallpaperPath - } - } - - Column { - width: parent.width - 120 - Theme.spacingM - spacing: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: { - if (ToastService.wallpaperErrorStatus === "error") - return I18n.tr("Wallpaper Error", "wallpaper error status"); - if (ToastService.wallpaperErrorStatus === "matugen_missing") - return I18n.tr("Matugen Missing", "matugen not found status"); - if (Theme.wallpaperPath) - return Theme.wallpaperPath.split('/').pop(); - return I18n.tr("No wallpaper selected", "no wallpaper status"); - } - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - } - - StyledText { - text: { - if (ToastService.wallpaperErrorStatus === "error") - return I18n.tr("Wallpaper processing failed", "wallpaper processing error"); - if (ToastService.wallpaperErrorStatus === "matugen_missing") - return I18n.tr("Install matugen package for dynamic theming", "matugen installation hint"); - if (Theme.wallpaperPath) - return Theme.wallpaperPath; - return I18n.tr("Dynamic colors from wallpaper", "dynamic colors description"); - } - font.pixelSize: Theme.fontSizeSmall - color: (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") ? Theme.error : Theme.surfaceVariantText - elide: Text.ElideMiddle - maximumLineCount: 2 - width: parent.width - wrapMode: Text.WordWrap - } - } - } - - SettingsDropdownRow { - tab: "theme" - tags: ["matugen", "palette", "algorithm", "dynamic"] - settingKey: "matugenScheme" - text: I18n.tr("Matugen Palette") - description: I18n.tr("Select the palette algorithm used for wallpaper-based colors") - options: cachedMatugenSchemes - currentValue: Theme.getMatugenScheme(SettingsData.matugenScheme).label - enabled: Theme.matugenAvailable - opacity: enabled ? 1 : 0.4 - onValueChanged: value => { - for (var i = 0; i < Theme.availableMatugenSchemes.length; i++) { - var option = Theme.availableMatugenSchemes[i]; - if (option.label === value) { - SettingsData.setMatugenScheme(option.value); - break; - } - } - } - } - - StyledText { - text: { - var scheme = Theme.getMatugenScheme(SettingsData.matugenScheme); - return scheme.description + " (" + scheme.value + ")"; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - } - - SettingsSliderRow { - tab: "theme" - tags: ["matugen", "contrast", "dynamic"] - settingKey: "matugenContrast" - text: I18n.tr("Matugen Contrast") - description: I18n.tr("Adjusts contrast of generated colors (-100 = minimum, 0 = standard, 100 = maximum)") - value: Math.round(SettingsData.matugenContrast * 100) - minimum: -100 - maximum: 100 - unit: "%" - defaultValue: 0 - enabled: Theme.matugenAvailable - opacity: enabled ? 1 : 0.4 - onSliderDragFinished: finalValue => SettingsData.setMatugenContrast(finalValue / 100) - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: Theme.currentThemeName === "custom" && Theme.currentThemeCategory !== "registry" - - Row { - width: parent.width - spacing: Theme.spacingM - - DankActionButton { - buttonSize: 48 - iconName: "folder_open" - iconSize: Theme.iconSize - backgroundColor: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) - iconColor: Theme.primary - onClicked: fileBrowserModal.open() - } - - Column { - width: parent.width - 48 - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: SettingsData.customThemeFile ? SettingsData.customThemeFile.split('/').pop() : I18n.tr("No custom theme file", "no custom theme file status") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - } - - StyledText { - text: SettingsData.customThemeFile || I18n.tr("Click to select a custom theme JSON file", "custom theme file hint") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - } - } - } - } - - Column { - id: registrySection - width: parent.width - spacing: Theme.spacingM - visible: Theme.currentThemeCategory === "registry" - - Grid { - id: themeGrid - property int cardWidth: registrySection.width < 350 ? 100 : 140 - property int cardHeight: registrySection.width < 350 ? 72 : 100 - columns: Math.max(1, Math.floor((registrySection.width + spacing) / (cardWidth + spacing))) - spacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - visible: themeColorsTab.installedRegistryThemes.length > 0 - - Repeater { - model: themeColorsTab.installedRegistryThemes - - Rectangle { - id: themeCard - property bool isActive: Theme.currentThemeCategory === "registry" && Theme.currentThemeName === "custom" && SettingsData.customThemeFile && SettingsData.customThemeFile.endsWith((modelData.sourceDir || modelData.id) + "/theme.json") - property bool hasVariants: modelData.hasVariants || false - property var variants: modelData.variants || null - property string selectedVariant: hasVariants ? SettingsData.getRegistryThemeVariant(modelData.id, variants?.default || "") : "" - property string previewPath: { - const baseDir = Quickshell.env("HOME") + "/.config/DankMaterialShell/themes/" + (modelData.sourceDir || modelData.id); - const mode = Theme.isLightMode ? "light" : "dark"; - if (hasVariants && selectedVariant) - return baseDir + "/preview-" + selectedVariant + "-" + mode + ".svg"; - return baseDir + "/preview-" + mode + ".svg"; - } - width: themeGrid.cardWidth - height: themeGrid.cardHeight - radius: Theme.cornerRadius - color: Theme.surfaceVariant - border.color: isActive ? Theme.primary : Theme.outline - border.width: isActive ? 2 : 1 - scale: isActive ? 1.03 : 1 - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - - Image { - id: previewImage - anchors.fill: parent - anchors.margins: 2 - source: "file://" + themeCard.previewPath - fillMode: Image.PreserveAspectFit - smooth: true - mipmap: true - } - - DankIcon { - anchors.centerIn: parent - name: "palette" - size: themeGrid.cardWidth < 120 ? 24 : 32 - color: Theme.primary - visible: previewImage.status === Image.Error || previewImage.status === Image.Null - } - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: themeGrid.cardWidth < 120 ? 18 : 22 - radius: Theme.cornerRadius - color: Qt.rgba(0, 0, 0, 0.6) - - StyledText { - anchors.centerIn: parent - text: modelData.name - font.pixelSize: themeGrid.cardWidth < 120 ? Theme.fontSizeSmall - 2 : Theme.fontSizeSmall - color: "white" - font.weight: Font.Medium - elide: Text.ElideRight - width: parent.width - Theme.spacingXS * 2 - horizontalAlignment: Text.AlignHCenter - } - } - - Rectangle { - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: themeGrid.cardWidth < 120 ? 2 : 4 - width: themeGrid.cardWidth < 120 ? 16 : 20 - height: width - radius: width / 2 - color: Theme.primary - visible: themeCard.isActive - - DankIcon { - anchors.centerIn: parent - name: "check" - size: themeGrid.cardWidth < 120 ? 10 : 14 - color: Theme.surface - } - } - - Rectangle { - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: themeGrid.cardWidth < 120 ? 2 : 4 - width: themeGrid.cardWidth < 120 ? 16 : 20 - height: width - radius: width / 2 - color: Theme.secondary - visible: themeCard.hasVariants && !deleteButton.visible - - StyledText { - anchors.centerIn: parent - text: { - if (themeCard.variants?.type === "multi") - return themeCard.variants?.accents?.length || 0; - return themeCard.variants?.options?.length || 0; - } - font.pixelSize: themeGrid.cardWidth < 120 ? Theme.fontSizeSmall - 4 : Theme.fontSizeSmall - 2 - color: Theme.surface - font.weight: Font.Bold - } - } - - MouseArea { - id: cardMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const themesDir = Quickshell.env("HOME") + "/.config/DankMaterialShell/themes"; - const themePath = themesDir + "/" + (modelData.sourceDir || modelData.id) + "/theme.json"; - SettingsData.set("customThemeFile", themePath); - Theme.switchTheme("custom", true, true); - } - } - - Rectangle { - id: deleteButton - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: themeGrid.cardWidth < 120 ? 2 : 4 - width: themeGrid.cardWidth < 120 ? 18 : 24 - height: width - radius: width / 2 - color: deleteMouseArea.containsMouse ? Theme.error : Qt.rgba(0, 0, 0, 0.6) - opacity: cardMouseArea.containsMouse || deleteMouseArea.containsMouse ? 1 : 0 - visible: opacity > 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - } - } - - DankIcon { - anchors.centerIn: parent - name: "close" - size: themeGrid.cardWidth < 120 ? 10 : 14 - color: "white" - } - - MouseArea { - id: deleteMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - ToastService.showInfo(I18n.tr("Uninstalling: %1", "uninstallation progress").arg(modelData.name)); - DMSService.uninstallTheme(modelData.id, response => { - if (response.error) { - ToastService.showError(I18n.tr("Uninstall failed: %1", "uninstallation error").arg(response.error)); - return; - } - ToastService.showInfo(I18n.tr("Uninstalled: %1", "uninstallation success").arg(modelData.name)); - DMSService.listInstalledThemes(); - }); - } - } - } - } - } - } - - StyledText { - text: I18n.tr("No themes installed. Browse themes to install from the registry.", "no registry themes installed hint") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - visible: themeColorsTab.installedRegistryThemes.length === 0 - horizontalAlignment: Text.AlignHCenter - } - - DankButton { - text: I18n.tr("Browse Themes", "browse themes button") - iconName: "store" - anchors.horizontalCenter: parent.horizontalCenter - onClicked: showThemeBrowser() - } - } - - Column { - id: variantSelector - width: parent.width - spacing: Theme.spacingS - visible: activeThemeId !== "" && activeThemeVariants !== null && (isMultiVariant || (activeThemeVariants.options && activeThemeVariants.options.length > 0)) - - property string activeThemeId: { - switch (Theme.currentThemeCategory) { - case "registry": - if (Theme.currentTheme !== "custom") - return ""; - for (var i = 0; i < themeColorsTab.installedRegistryThemes.length; i++) { - var t = themeColorsTab.installedRegistryThemes[i]; - if (SettingsData.customThemeFile && SettingsData.customThemeFile.endsWith((t.sourceDir || t.id) + "/theme.json")) - return t.id; - } - return ""; - case "custom": - return Theme.currentThemeId || ""; - default: - return ""; - } - } - property var activeThemeVariants: { - if (!activeThemeId) - return null; - switch (Theme.currentThemeCategory) { - case "registry": - for (var i = 0; i < themeColorsTab.installedRegistryThemes.length; i++) { - var t = themeColorsTab.installedRegistryThemes[i]; - if (t.id === activeThemeId && t.hasVariants) - return t.variants; - } - return null; - case "custom": - return Theme.currentThemeVariants || null; - default: - return null; - } - } - property bool isMultiVariant: activeThemeVariants?.type === "multi" - property string colorMode: Theme.isLightMode ? "light" : "dark" - property var multiDefaults: { - if (!isMultiVariant || !activeThemeVariants?.defaults) - return {}; - return activeThemeVariants.defaults[colorMode] || activeThemeVariants.defaults.dark || {}; - } - property var storedMulti: activeThemeId ? SettingsData.getRegistryThemeMultiVariant(activeThemeId, multiDefaults, colorMode) : multiDefaults - property string selectedFlavor: { - var sf = storedMulti.flavor || multiDefaults.flavor || ""; - for (var i = 0; i < flavorOptions.length; i++) { - if (flavorOptions[i].id === sf) - return sf; - } - if (flavorOptions.length > 0) - return flavorOptions[0].id; - return sf; - } - property string selectedAccent: storedMulti.accent || multiDefaults.accent || "" - property var flavorOptions: { - if (!isMultiVariant || !activeThemeVariants?.flavors) - return []; - return activeThemeVariants.flavors.filter(f => { - if (f.mode) - return f.mode === colorMode || f.mode === "both"; - return !!f[colorMode]; - }); - } - property var flavorNames: flavorOptions.map(f => f.name) - property int flavorIndex: { - for (var i = 0; i < flavorOptions.length; i++) { - if (flavorOptions[i].id === selectedFlavor) - return i; - } - return 0; - } - property string selectedVariant: activeThemeId ? SettingsData.getRegistryThemeVariant(activeThemeId, activeThemeVariants?.default || "") : "" - property var variantNames: { - if (!activeThemeVariants?.options) - return []; - return activeThemeVariants.options.map(v => v.name); - } - property int selectedIndex: { - if (!activeThemeVariants?.options || !selectedVariant) - return 0; - for (var i = 0; i < activeThemeVariants.options.length; i++) { - if (activeThemeVariants.options[i].id === selectedVariant) - return i; - } - return 0; - } - - Item { - width: parent.width - height: flavorButtonGroup.implicitHeight - clip: true - visible: variantSelector.isMultiVariant && variantSelector.flavorOptions.length > 1 - - DankButtonGroup { - id: flavorButtonGroup - anchors.horizontalCenter: parent.horizontalCenter - property int _count: variantSelector.flavorNames.length - property real _maxPerItem: _count > 1 ? (parent.width - (_count - 1) * spacing) / _count : parent.width - buttonPadding: _maxPerItem < 55 ? Theme.spacingXS : (_maxPerItem < 75 ? Theme.spacingS : Theme.spacingL) - minButtonWidth: Math.min(_maxPerItem < 55 ? 28 : (_maxPerItem < 75 ? 44 : 64), Math.max(28, Math.floor(_maxPerItem))) - textSize: _maxPerItem < 55 ? Theme.fontSizeSmall - 2 : (_maxPerItem < 75 ? Theme.fontSizeSmall : Theme.fontSizeMedium) - checkEnabled: _maxPerItem >= 55 - property int pendingIndex: -1 - model: variantSelector.flavorNames - currentIndex: pendingIndex >= 0 ? pendingIndex : variantSelector.flavorIndex - selectionMode: "single" - onSelectionChanged: (index, selected) => { - if (!selected) - return; - pendingIndex = index; - } - onAnimationCompleted: { - if (pendingIndex < 0 || pendingIndex >= variantSelector.flavorOptions.length) - return; - const flavorId = variantSelector.flavorOptions[pendingIndex]?.id; - const idx = pendingIndex; - pendingIndex = -1; - if (!flavorId || flavorId === variantSelector.selectedFlavor) - return; - Theme.screenTransition(); - SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, flavorId, variantSelector.selectedAccent, variantSelector.colorMode); - } - } - } - - Item { - width: parent.width - height: accentColorsGrid.implicitHeight - visible: variantSelector.isMultiVariant && variantSelector.activeThemeVariants?.accents?.length > 0 - - Grid { - id: accentColorsGrid - property int accentCount: variantSelector.activeThemeVariants?.accents?.length ?? 0 - property int dotSize: parent.width < 300 ? 28 : 32 - columns: accentCount > 0 ? Math.ceil(accentCount / 2) : 1 - rowSpacing: Theme.spacingS - columnSpacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - Repeater { - model: variantSelector.activeThemeVariants?.accents || [] - - Rectangle { - required property var modelData - required property int index - property string accentId: modelData.id - property bool isSelected: accentId === variantSelector.selectedAccent - width: accentColorsGrid.dotSize - height: accentColorsGrid.dotSize - radius: width / 2 - color: modelData.color || modelData[variantSelector.selectedFlavor]?.primary || Theme.primary - border.color: Theme.outline - border.width: isSelected ? 2 : 1 - scale: isSelected ? 1.1 : 1 - - Rectangle { - width: accentNameText.contentWidth + Theme.spacingS * 2 - height: accentNameText.contentHeight + Theme.spacingXS * 2 - color: Theme.surfaceContainer - radius: Theme.cornerRadius - anchors.bottom: parent.top - anchors.bottomMargin: Theme.spacingXS - anchors.horizontalCenter: parent.horizontalCenter - visible: accentMouseArea.containsMouse - - StyledText { - id: accentNameText - text: modelData.name - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.centerIn: parent - } - } - - MouseArea { - id: accentMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (parent.isSelected) - return; - Theme.screenTransition(); - SettingsData.setRegistryThemeMultiVariant(variantSelector.activeThemeId, variantSelector.selectedFlavor, parent.accentId, variantSelector.colorMode); - } - } - - Behavior on scale { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.emphasizedEasing - } - } - } - } - } - } - - Item { - width: parent.width - height: variantButtonGroup.implicitHeight - clip: true - visible: !variantSelector.isMultiVariant && variantSelector.variantNames.length > 0 - - DankButtonGroup { - id: variantButtonGroup - anchors.horizontalCenter: parent.horizontalCenter - property int _count: variantSelector.variantNames.length - property real _maxPerItem: _count > 1 ? (parent.width - (_count - 1) * spacing) / _count : parent.width - buttonPadding: _maxPerItem < 55 ? Theme.spacingXS : (_maxPerItem < 75 ? Theme.spacingS : Theme.spacingL) - minButtonWidth: Math.min(_maxPerItem < 55 ? 28 : (_maxPerItem < 75 ? 44 : 64), Math.max(28, Math.floor(_maxPerItem))) - textSize: _maxPerItem < 55 ? Theme.fontSizeSmall - 2 : (_maxPerItem < 75 ? Theme.fontSizeSmall : Theme.fontSizeMedium) - checkEnabled: _maxPerItem >= 55 - property int pendingIndex: -1 - model: variantSelector.variantNames - currentIndex: pendingIndex >= 0 ? pendingIndex : variantSelector.selectedIndex - selectionMode: "single" - onSelectionChanged: (index, selected) => { - if (!selected) - return; - pendingIndex = index; - } - onAnimationCompleted: { - if (pendingIndex < 0 || !variantSelector.activeThemeVariants?.options) - return; - const variantId = variantSelector.activeThemeVariants.options[pendingIndex]?.id; - const idx = pendingIndex; - pendingIndex = -1; - if (!variantId || variantId === variantSelector.selectedVariant) - return; - Theme.screenTransition(); - SettingsData.setRegistryThemeVariant(variantSelector.activeThemeId, variantId); - } - } - } - } - } - } - - SettingsCard { - tab: "theme" - tags: ["automatic", "color", "mode", "schedule", "sunrise", "sunset"] - title: I18n.tr("Automatic Color Mode") - settingKey: "automaticColorMode" - iconName: "schedule" - - Column { - width: parent.width - spacing: Theme.spacingM - - DankToggle { - id: themeModeAutoToggle - width: parent.width - text: I18n.tr("Automatic Control") - checked: SessionData.themeModeAutoEnabled - onToggled: checked => { - SessionData.setThemeModeAutoEnabled(checked); - } - - Connections { - target: SessionData - function onThemeModeAutoEnabledChanged() { - themeModeAutoToggle.checked = SessionData.themeModeAutoEnabled; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.themeModeAutoEnabled - - DankToggle { - width: parent.width - text: I18n.tr("Share Gamma Control Settings") - checked: SessionData.themeModeShareGammaSettings - onToggled: checked => { - SessionData.setThemeModeShareGammaSettings(checked); - } - } - - Item { - width: parent.width - height: 45 + Theme.spacingM - - DankTabBar { - id: themeModeTabBar - width: 200 - height: 45 - anchors.horizontalCenter: parent.horizontalCenter - model: [ - { - "text": I18n.tr("Time", "theme auto mode tab"), - "icon": "access_time" - }, - { - "text": I18n.tr("Location", "theme auto mode tab"), - "icon": "place" - } - ] - - Component.onCompleted: { - currentIndex = SessionData.themeModeAutoMode === "location" ? 1 : 0; - Qt.callLater(updateIndicator); - } - - onTabClicked: index => { - SessionData.setThemeModeAutoMode(index === 1 ? "location" : "time"); - currentIndex = index; - } - - Connections { - target: SessionData - function onThemeModeAutoModeChanged() { - themeModeTabBar.currentIndex = SessionData.themeModeAutoMode === "location" ? 1 : 0; - Qt.callLater(themeModeTabBar.updateIndicator); - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.themeModeAutoMode === "time" && !SessionData.themeModeShareGammaSettings - - Column { - spacing: Theme.spacingXS - anchors.horizontalCenter: parent.horizontalCenter - - Row { - spacing: Theme.spacingM - - StyledText { - text: "" - width: 50 - height: 20 - } - - StyledText { - text: I18n.tr("Hour") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: 70 - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: I18n.tr("Minute") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: 70 - horizontalAlignment: Text.AlignHCenter - } - } - - Row { - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Start") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: 50 - height: 40 - verticalAlignment: Text.AlignVCenter - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.themeModeStartHour.toString() - options: { - var hours = []; - for (var i = 0; i < 24; i++) - hours.push(i.toString()); - return hours; - } - onValueChanged: value => { - SessionData.setThemeModeStartHour(parseInt(value)); - } - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.themeModeStartMinute.toString().padStart(2, '0') - options: { - var minutes = []; - for (var i = 0; i < 60; i += 5) { - minutes.push(i.toString().padStart(2, '0')); - } - return minutes; - } - onValueChanged: value => { - SessionData.setThemeModeStartMinute(parseInt(value)); - } - } - } - - Row { - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("End") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: 50 - height: 40 - verticalAlignment: Text.AlignVCenter - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.themeModeEndHour.toString() - options: { - var hours = []; - for (var i = 0; i < 24; i++) - hours.push(i.toString()); - return hours; - } - onValueChanged: value => { - SessionData.setThemeModeEndHour(parseInt(value)); - } - } - - DankDropdown { - dropdownWidth: 70 - currentValue: SessionData.themeModeEndMinute.toString().padStart(2, '0') - options: { - var minutes = []; - for (var i = 0; i < 60; i += 5) { - minutes.push(i.toString().padStart(2, '0')); - } - return minutes; - } - onValueChanged: value => { - SessionData.setThemeModeEndMinute(parseInt(value)); - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.themeModeAutoMode === "location" && !SessionData.themeModeShareGammaSettings - - DankToggle { - id: themeModeIpLocationToggle - width: parent.width - text: I18n.tr("Use IP Location") - checked: SessionData.nightModeUseIPLocation || false - onToggled: checked => { - SessionData.setNightModeUseIPLocation(checked); - } - - Connections { - target: SessionData - function onNightModeUseIPLocationChanged() { - themeModeIpLocationToggle.checked = SessionData.nightModeUseIPLocation; - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: !SessionData.nightModeUseIPLocation - - StyledText { - text: I18n.tr("Manual Coordinates") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - width: parent.width - } - - Row { - spacing: Theme.spacingL - anchors.horizontalCenter: parent.horizontalCenter - - Column { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Latitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: 120 - height: 40 - text: SessionData.latitude.toString() - placeholderText: "0.0" - onEditingFinished: { - const lat = parseFloat(text); - if (!isNaN(lat) && lat >= -90 && lat <= 90 && lat !== SessionData.latitude) { - SessionData.setLatitude(lat); - } - } - } - } - - Column { - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Longitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - width: 120 - height: 40 - text: SessionData.longitude.toString() - placeholderText: "0.0" - onEditingFinished: { - const lon = parseFloat(text); - if (!isNaN(lon) && lon >= -180 && lon <= 180 && lon !== SessionData.longitude) { - SessionData.setLongitude(lon); - } - } - } - } - } - - StyledText { - text: I18n.tr("Uses sunrise/sunset times based on your location.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("Using shared settings from Gamma Control") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - visible: SessionData.themeModeShareGammaSettings - } - - Rectangle { - width: parent.width - height: statusRow.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Row { - id: statusRow - anchors.centerIn: parent - spacing: Theme.spacingL - width: parent.width - Theme.spacingM * 2 - - Column { - spacing: 2 - width: (parent.width - Theme.spacingL * 2) / 3 - anchors.verticalCenter: parent.verticalCenter - - Row { - spacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - Rectangle { - width: 8 - height: 8 - radius: 4 - color: SessionData.themeModeAutoEnabled ? Theme.success : Theme.error - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Automation") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - } - - StyledText { - text: SessionData.themeModeAutoEnabled ? I18n.tr("Enabled") : I18n.tr("Disabled") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - width: parent.width - } - } - - Column { - spacing: 2 - width: (parent.width - Theme.spacingL * 2) / 3 - anchors.verticalCenter: parent.verticalCenter - - Row { - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingS - - DankIcon { - name: SessionData.isLightMode ? "light_mode" : "dark_mode" - size: Theme.iconSize - color: SessionData.isLightMode ? "#FFA726" : "#7E57C2" - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: SessionData.isLightMode ? I18n.tr("Light Mode") : I18n.tr("Dark Mode") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Bold - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: I18n.tr("Active") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - width: parent.width - } - } - - Column { - spacing: 2 - width: (parent.width - Theme.spacingL * 2) / 3 - anchors.verticalCenter: parent.verticalCenter - visible: SessionData.themeModeAutoEnabled && SessionData.themeModeNextTransition - - Row { - spacing: Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - name: "schedule" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Next Transition") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - StyledText { - text: themeColorsTab.formatThemeAutoTime(SessionData.themeModeNextTransition) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - width: parent.width - } - } - } - } - } - } - } - - SettingsCard { - tab: "theme" - tags: ["light", "dark", "mode", "appearance"] - title: I18n.tr("Color Mode") - settingKey: "colorMode" - iconName: "contrast" - - SettingsToggleRow { - tab: "theme" - tags: ["light", "dark", "mode"] - settingKey: "isLightMode" - text: I18n.tr("Light Mode") - description: I18n.tr("Use light theme instead of dark theme") - checked: SessionData.isLightMode - onToggled: checked => { - Theme.screenTransition(); - Theme.setLightMode(checked); - } - } - } - - SettingsCard { - tab: "theme" - tags: ["transparency", "opacity", "widget", "styling"] - title: I18n.tr("Widget Styling") - settingKey: "widgetStyling" - iconName: "opacity" - - SettingsButtonGroupRow { - tab: "theme" - tags: ["widget", "style", "colorful", "default"] - settingKey: "widgetColorMode" - text: I18n.tr("Widget Style") - description: I18n.tr("Change bar appearance") - model: [I18n.tr("Default", "widget style option"), I18n.tr("Colorful", "widget style option")] - currentIndex: SettingsData.widgetColorMode === "colorful" ? 1 : 0 - onSelectionChanged: (index, selected) => { - if (!selected) - return; - SettingsData.set("widgetColorMode", index === 1 ? "colorful" : "default"); - } - } - - SettingsButtonGroupRow { - tab: "theme" - tags: ["widget", "background", "color"] - settingKey: "widgetBackgroundColor" - text: I18n.tr("Widget Background Color") - description: I18n.tr("Choose the background color for widgets") - model: ["sth", "s", "sc", "sch"] - buttonHeight: 20 - minButtonWidth: 32 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 2 - spacing: 1 - currentIndex: { - switch (SettingsData.widgetBackgroundColor) { - case "sth": - return 0; - case "s": - return 1; - case "sc": - return 2; - case "sch": - return 3; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const colorOptions = ["sth", "s", "sc", "sch"]; - SettingsData.set("widgetBackgroundColor", colorOptions[index]); - } - } - - SettingsDropdownRow { - tab: "theme" - tags: ["control", "center", "tile", "button", "color", "active"] - settingKey: "controlCenterTileColorMode" - text: I18n.tr("Control Center Tile Color") - description: I18n.tr("Active tile background and icon color", "control center tile color setting description") - options: [I18n.tr("Primary", "tile color option"), I18n.tr("Primary Container", "tile color option"), I18n.tr("Secondary", "tile color option"), I18n.tr("Surface Variant", "tile color option")] - currentValue: { - switch (SettingsData.controlCenterTileColorMode) { - case "primaryContainer": - return I18n.tr("Primary Container", "tile color option"); - case "secondary": - return I18n.tr("Secondary", "tile color option"); - case "surfaceVariant": - return I18n.tr("Surface Variant", "tile color option"); - default: - return I18n.tr("Primary", "tile color option"); - } - } - onValueChanged: value => { - if (value === I18n.tr("Primary Container", "tile color option")) { - SettingsData.set("controlCenterTileColorMode", "primaryContainer"); - } else if (value === I18n.tr("Secondary", "tile color option")) { - SettingsData.set("controlCenterTileColorMode", "secondary"); - } else if (value === I18n.tr("Surface Variant", "tile color option")) { - SettingsData.set("controlCenterTileColorMode", "surfaceVariant"); - } else { - SettingsData.set("controlCenterTileColorMode", "primary"); - } - } - } - - SettingsDropdownRow { - tab: "theme" - tags: ["button", "color", "primary", "accent"] - settingKey: "buttonColorMode" - text: I18n.tr("Button Color") - description: I18n.tr("Color for primary action buttons") - options: [I18n.tr("Primary", "button color option"), I18n.tr("Primary Container", "button color option"), I18n.tr("Secondary", "button color option"), I18n.tr("Surface Variant", "button color option")] - currentValue: { - switch (SettingsData.buttonColorMode) { - case "primaryContainer": - return I18n.tr("Primary Container", "button color option"); - case "secondary": - return I18n.tr("Secondary", "button color option"); - case "surfaceVariant": - return I18n.tr("Surface Variant", "button color option"); - default: - return I18n.tr("Primary", "button color option"); - } - } - onValueChanged: value => { - if (value === I18n.tr("Primary Container", "button color option")) { - SettingsData.set("buttonColorMode", "primaryContainer"); - } else if (value === I18n.tr("Secondary", "button color option")) { - SettingsData.set("buttonColorMode", "secondary"); - } else if (value === I18n.tr("Surface Variant", "button color option")) { - SettingsData.set("buttonColorMode", "surfaceVariant"); - } else { - SettingsData.set("buttonColorMode", "primary"); - } - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["popup", "transparency", "opacity", "modal"] - settingKey: "popupTransparency" - text: I18n.tr("Popup Transparency") - description: I18n.tr("Controls opacity of all popouts, modals, and their content layers") - value: Math.round(SettingsData.popupTransparency * 100) - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("popupTransparency", newValue / 100) - } - - SettingsSliderRow { - tab: "theme" - tags: ["corner", "radius", "rounded", "square"] - settingKey: "cornerRadius" - text: I18n.tr("Corner Radius") - description: I18n.tr("0 = square corners") - value: SettingsData.cornerRadius - minimum: 0 - maximum: 32 - unit: "px" - defaultValue: 12 - onSliderValueChanged: newValue => SettingsData.setCornerRadius(newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["elevation", "shadow", "lift", "m3", "material"] - settingKey: "m3ElevationEnabled" - text: I18n.tr("Shadows") - description: I18n.tr("Material inspired shadows and elevation on modals, popouts, and dialogs") - checked: SettingsData.m3ElevationEnabled ?? true - onToggled: checked => SettingsData.set("m3ElevationEnabled", checked) - } - - SettingsSliderRow { - tab: "theme" - tags: ["elevation", "shadow", "intensity", "blur", "m3"] - settingKey: "m3ElevationIntensity" - text: I18n.tr("Shadow Intensity") - description: I18n.tr("Controls the base blur radius and offset of shadows") - value: SettingsData.m3ElevationIntensity ?? 12 - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: 12 - visible: SettingsData.m3ElevationEnabled ?? true - onSliderValueChanged: newValue => SettingsData.set("m3ElevationIntensity", newValue) - } - - SettingsSliderRow { - tab: "theme" - tags: ["elevation", "shadow", "opacity", "transparency", "m3"] - settingKey: "m3ElevationOpacity" - text: I18n.tr("Shadow Opacity") - description: I18n.tr("Controls the transparency of the shadow") - value: SettingsData.m3ElevationOpacity ?? 30 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 30 - visible: SettingsData.m3ElevationEnabled ?? true - onSliderValueChanged: newValue => SettingsData.set("m3ElevationOpacity", newValue) - } - - SettingsDropdownRow { - tab: "theme" - tags: ["elevation", "shadow", "color", "m3"] - settingKey: "m3ElevationColorMode" - text: I18n.tr("Shadow Color") - description: I18n.tr("Base color for shadows (opacity is applied automatically)") - options: [I18n.tr("Default (Black)", "shadow color option"), I18n.tr("Text Color", "shadow color option"), I18n.tr("Primary", "shadow color option"), I18n.tr("Surface Variant", "shadow color option"), I18n.tr("Custom", "shadow color option")] - currentValue: { - switch (SettingsData.m3ElevationColorMode) { - case "text": - return I18n.tr("Text Color", "shadow color option"); - case "primary": - return I18n.tr("Primary", "shadow color option"); - case "surfaceVariant": - return I18n.tr("Surface Variant", "shadow color option"); - case "custom": - return I18n.tr("Custom", "shadow color option"); - default: - return I18n.tr("Default (Black)", "shadow color option"); - } - } - visible: SettingsData.m3ElevationEnabled ?? true - onValueChanged: value => { - if (value === I18n.tr("Primary", "shadow color option")) { - SettingsData.set("m3ElevationColorMode", "primary"); - } else if (value === I18n.tr("Surface Variant", "shadow color option")) { - SettingsData.set("m3ElevationColorMode", "surfaceVariant"); - } else if (value === I18n.tr("Custom", "shadow color option")) { - SettingsData.set("m3ElevationColorMode", "custom"); - openM3ShadowColorPicker(); - } else if (value === I18n.tr("Text Color", "shadow color option")) { - SettingsData.set("m3ElevationColorMode", "text"); - } else { - SettingsData.set("m3ElevationColorMode", "default"); - } - } - } - - SettingsDropdownRow { - tab: "theme" - tags: ["elevation", "shadow", "direction", "light", "advanced", "m3"] - settingKey: "m3ElevationLightDirection" - text: I18n.tr("Light Direction") - description: I18n.tr("Controls shadow cast direction for elevation layers") - options: [I18n.tr("Auto (Bar-aware)", "shadow direction option"), I18n.tr("Top (Default)", "shadow direction option"), I18n.tr("Top Left", "shadow direction option"), I18n.tr("Top Right", "shadow direction option"), I18n.tr("Bottom", "shadow direction option")] - currentValue: { - switch (SettingsData.m3ElevationLightDirection) { - case "autoBar": - return I18n.tr("Auto (Bar-aware)", "shadow direction option"); - case "topLeft": - return I18n.tr("Top Left", "shadow direction option"); - case "topRight": - return I18n.tr("Top Right", "shadow direction option"); - case "bottom": - return I18n.tr("Bottom", "shadow direction option"); - default: - return I18n.tr("Top (Default)", "shadow direction option"); - } - } - visible: SettingsData.m3ElevationEnabled ?? true - onValueChanged: value => { - if (value === I18n.tr("Auto (Bar-aware)", "shadow direction option")) { - SettingsData.set("m3ElevationLightDirection", "autoBar"); - } else if (value === I18n.tr("Top Left", "shadow direction option")) { - SettingsData.set("m3ElevationLightDirection", "topLeft"); - } else if (value === I18n.tr("Top Right", "shadow direction option")) { - SettingsData.set("m3ElevationLightDirection", "topRight"); - } else if (value === I18n.tr("Bottom", "shadow direction option")) { - SettingsData.set("m3ElevationLightDirection", "bottom"); - } else { - SettingsData.set("m3ElevationLightDirection", "top"); - } - } - } - - Item { - visible: (SettingsData.m3ElevationEnabled ?? true) && SettingsData.m3ElevationColorMode === "custom" - width: parent.width - implicitHeight: 36 - height: implicitHeight - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Custom Shadow Color") - color: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - verticalAlignment: Text.AlignVCenter - } - - Rectangle { - width: 26 - height: 26 - radius: 13 - color: SettingsData.m3ElevationCustomColor ?? "#000000" - border.color: Theme.outline - border.width: 1 - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: openM3ShadowColorPicker() - } - } - } - } - - SettingsToggleRow { - tab: "theme" - tags: ["elevation", "shadow", "modal", "dialog", "m3"] - settingKey: "modalElevationEnabled" - text: I18n.tr("Modal Shadows") - description: I18n.tr("Shadow elevation on modals and dialogs") - checked: SettingsData.modalElevationEnabled ?? true - visible: SettingsData.m3ElevationEnabled ?? true - onToggled: checked => SettingsData.set("modalElevationEnabled", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["elevation", "shadow", "popout", "popup", "osd", "dropdown", "m3"] - settingKey: "popoutElevationEnabled" - text: I18n.tr("Popout Shadows") - description: I18n.tr("Shadow elevation on popouts, OSDs, and dropdowns") - checked: SettingsData.popoutElevationEnabled ?? true - visible: SettingsData.m3ElevationEnabled ?? true - onToggled: checked => SettingsData.set("popoutElevationEnabled", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["elevation", "shadow", "bar", "panel", "navigation", "m3"] - settingKey: "barElevationEnabled" - text: I18n.tr("Bar Shadows") - description: I18n.tr("Shadow elevation on bars and panels") - checked: SettingsData.barElevationEnabled ?? true - visible: SettingsData.m3ElevationEnabled ?? true - onToggled: checked => SettingsData.set("barElevationEnabled", checked) - } - } - - SettingsCard { - tab: "theme" - tags: ["blur", "background", "transparency", "glass", "frosted"] - title: I18n.tr("Background Blur") - settingKey: "blurEnabled" - iconName: "blur_on" - - SettingsToggleRow { - tab: "theme" - tags: ["blur", "background", "transparency", "glass", "frosted"] - settingKey: "blurEnabled" - text: I18n.tr("Background Blur") - description: BlurService.available ? I18n.tr("Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.") : I18n.tr("Requires a newer version of Quickshell") - checked: SettingsData.blurEnabled ?? false - enabled: BlurService.available - onToggled: checked => SettingsData.set("blurEnabled", checked) - } - - SettingsDropdownRow { - tab: "theme" - tags: ["blur", "border", "outline", "edge"] - settingKey: "blurBorderColor" - text: I18n.tr("Blur Border Color") - description: I18n.tr("Border color around blurred surfaces") - visible: SettingsData.blurEnabled - options: [I18n.tr("Outline", "blur border color"), I18n.tr("Primary", "blur border color"), I18n.tr("Secondary", "blur border color"), I18n.tr("Text Color", "blur border color"), I18n.tr("Custom", "blur border color")] - currentValue: { - switch (SettingsData.blurBorderColor) { - case "primary": - return I18n.tr("Primary", "blur border color"); - case "secondary": - return I18n.tr("Secondary", "blur border color"); - case "surfaceText": - return I18n.tr("Text Color", "blur border color"); - case "custom": - return I18n.tr("Custom", "blur border color"); - default: - return I18n.tr("Outline", "blur border color"); - } - } - onValueChanged: value => { - if (value === I18n.tr("Primary", "blur border color")) { - SettingsData.set("blurBorderColor", "primary"); - } else if (value === I18n.tr("Secondary", "blur border color")) { - SettingsData.set("blurBorderColor", "secondary"); - } else if (value === I18n.tr("Text Color", "blur border color")) { - SettingsData.set("blurBorderColor", "surfaceText"); - } else if (value === I18n.tr("Custom", "blur border color")) { - SettingsData.set("blurBorderColor", "custom"); - openBlurBorderColorPicker(); - } else { - SettingsData.set("blurBorderColor", "outline"); - } - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["blur", "border", "opacity"] - settingKey: "blurBorderOpacity" - text: I18n.tr("Blur Border Opacity") - visible: SettingsData.blurEnabled - value: Math.round((SettingsData.blurBorderOpacity ?? 1.0) * 100) - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("blurBorderOpacity", newValue / 100) - } - } - - SettingsCard { - tab: "theme" - tags: ["niri", "layout", "gaps", "radius", "window", "border"] - title: I18n.tr("Niri Layout Overrides").replace("Niri", "niri") - settingKey: "niriLayout" - iconName: "crop_square" - visible: CompositorService.isNiri - - SettingsToggleRow { - tab: "theme" - tags: ["niri", "gaps", "override"] - settingKey: "niriLayoutGapsOverrideEnabled" - text: I18n.tr("Override Gaps") - description: I18n.tr("Use custom gaps instead of bar spacing") - checked: SettingsData.niriLayoutGapsOverride >= 0 - onToggled: checked => { - if (checked) { - const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - SettingsData.set("niriLayoutGapsOverride", currentGaps); - return; - } - SettingsData.set("niriLayoutGapsOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["niri", "gaps", "override"] - settingKey: "niriLayoutGapsOverride" - text: I18n.tr("Window Gaps") - description: I18n.tr("Space between windows") - visible: SettingsData.niriLayoutGapsOverride >= 0 - value: Math.max(0, SettingsData.niriLayoutGapsOverride) - minimum: 0 - maximum: 50 - unit: "px" - defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) - onSliderValueChanged: newValue => SettingsData.set("niriLayoutGapsOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["niri", "radius", "override"] - settingKey: "niriLayoutRadiusOverrideEnabled" - text: I18n.tr("Override Corner Radius") - description: I18n.tr("Use custom window radius instead of theme radius") - checked: SettingsData.niriLayoutRadiusOverride >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("niriLayoutRadiusOverride", SettingsData.cornerRadius); - return; - } - SettingsData.set("niriLayoutRadiusOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["niri", "radius", "override"] - settingKey: "niriLayoutRadiusOverride" - text: I18n.tr("Window Corner Radius") - description: I18n.tr("Rounded corners for windows") - visible: SettingsData.niriLayoutRadiusOverride >= 0 - value: Math.max(0, SettingsData.niriLayoutRadiusOverride) - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: SettingsData.cornerRadius - onSliderValueChanged: newValue => SettingsData.set("niriLayoutRadiusOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["niri", "border", "override"] - settingKey: "niriLayoutBorderSizeEnabled" - text: I18n.tr("Override Border Size") - description: I18n.tr("Use custom border/focus-ring width") - checked: SettingsData.niriLayoutBorderSize >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("niriLayoutBorderSize", 2); - return; - } - SettingsData.set("niriLayoutBorderSize", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["niri", "border", "override"] - settingKey: "niriLayoutBorderSize" - text: I18n.tr("Border Size") - description: I18n.tr("Width of window border and focus ring") - visible: SettingsData.niriLayoutBorderSize >= 0 - value: Math.max(0, SettingsData.niriLayoutBorderSize) - minimum: 0 - maximum: 10 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("niriLayoutBorderSize", newValue) - } - } - - SettingsCard { - tab: "theme" - tags: ["hyprland", "layout", "gaps", "radius", "window", "border", "rounding"] - title: I18n.tr("Hyprland Layout Overrides") - settingKey: "hyprlandLayout" - iconName: "crop_square" - visible: CompositorService.isHyprland - - SettingsToggleRow { - tab: "theme" - tags: ["hyprland", "gaps", "override"] - settingKey: "hyprlandLayoutGapsOverrideEnabled" - text: I18n.tr("Override Gaps") - description: I18n.tr("Use custom gaps instead of bar spacing") - checked: SettingsData.hyprlandLayoutGapsOverride >= 0 - onToggled: checked => { - if (checked) { - const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - SettingsData.set("hyprlandLayoutGapsOverride", currentGaps); - return; - } - SettingsData.set("hyprlandLayoutGapsOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["hyprland", "gaps", "override"] - settingKey: "hyprlandLayoutGapsOverride" - text: I18n.tr("Window Gaps") - description: I18n.tr("Space between windows (gaps_in and gaps_out)") - visible: SettingsData.hyprlandLayoutGapsOverride >= 0 - value: Math.max(0, SettingsData.hyprlandLayoutGapsOverride) - minimum: 0 - maximum: 50 - unit: "px" - defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) - onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutGapsOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["hyprland", "radius", "override", "rounding"] - settingKey: "hyprlandLayoutRadiusOverrideEnabled" - text: I18n.tr("Override Corner Radius") - description: I18n.tr("Use custom window rounding instead of theme radius") - checked: SettingsData.hyprlandLayoutRadiusOverride >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("hyprlandLayoutRadiusOverride", SettingsData.cornerRadius); - return; - } - SettingsData.set("hyprlandLayoutRadiusOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["hyprland", "radius", "override", "rounding"] - settingKey: "hyprlandLayoutRadiusOverride" - text: I18n.tr("Window Rounding") - description: I18n.tr("Rounded corners for windows (decoration.rounding)") - visible: SettingsData.hyprlandLayoutRadiusOverride >= 0 - value: Math.max(0, SettingsData.hyprlandLayoutRadiusOverride) - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: SettingsData.cornerRadius - onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutRadiusOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["hyprland", "border", "override"] - settingKey: "hyprlandLayoutBorderSizeEnabled" - text: I18n.tr("Override Border Size") - description: I18n.tr("Use custom border size") - checked: SettingsData.hyprlandLayoutBorderSize >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("hyprlandLayoutBorderSize", 2); - return; - } - SettingsData.set("hyprlandLayoutBorderSize", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["hyprland", "border", "override"] - settingKey: "hyprlandLayoutBorderSize" - text: I18n.tr("Border Size") - description: I18n.tr("Width of window border (general.border_size)") - visible: SettingsData.hyprlandLayoutBorderSize >= 0 - value: Math.max(0, SettingsData.hyprlandLayoutBorderSize) - minimum: 0 - maximum: 10 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutBorderSize", newValue) - } - } - - SettingsCard { - tab: "theme" - tags: ["mangowc", "mango", "dwl", "layout", "gaps", "radius", "window", "border"] - title: I18n.tr("MangoWC Layout Overrides") - settingKey: "mangoLayout" - iconName: "crop_square" - visible: CompositorService.isDwl - - SettingsToggleRow { - tab: "theme" - tags: ["mangowc", "mango", "gaps", "override"] - settingKey: "mangoLayoutGapsOverrideEnabled" - text: I18n.tr("Override Gaps") - description: I18n.tr("Use custom gaps instead of bar spacing") - checked: SettingsData.mangoLayoutGapsOverride >= 0 - onToggled: checked => { - if (checked) { - const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - SettingsData.set("mangoLayoutGapsOverride", currentGaps); - return; - } - SettingsData.set("mangoLayoutGapsOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["mangowc", "mango", "gaps", "override"] - settingKey: "mangoLayoutGapsOverride" - text: I18n.tr("Window Gaps") - description: I18n.tr("Space between windows (gappih/gappiv/gappoh/gappov)") - visible: SettingsData.mangoLayoutGapsOverride >= 0 - value: Math.max(0, SettingsData.mangoLayoutGapsOverride) - minimum: 0 - maximum: 50 - unit: "px" - defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) - onSliderValueChanged: newValue => SettingsData.set("mangoLayoutGapsOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["mangowc", "mango", "radius", "override"] - settingKey: "mangoLayoutRadiusOverrideEnabled" - text: I18n.tr("Override Corner Radius") - description: I18n.tr("Use custom window radius instead of theme radius") - checked: SettingsData.mangoLayoutRadiusOverride >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("mangoLayoutRadiusOverride", SettingsData.cornerRadius); - return; - } - SettingsData.set("mangoLayoutRadiusOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["mangowc", "mango", "radius", "override"] - settingKey: "mangoLayoutRadiusOverride" - text: I18n.tr("Window Corner Radius") - description: I18n.tr("Rounded corners for windows (border_radius)") - visible: SettingsData.mangoLayoutRadiusOverride >= 0 - value: Math.max(0, SettingsData.mangoLayoutRadiusOverride) - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: SettingsData.cornerRadius - onSliderValueChanged: newValue => SettingsData.set("mangoLayoutRadiusOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["mangowc", "mango", "border", "override"] - settingKey: "mangoLayoutBorderSizeEnabled" - text: I18n.tr("Override Border Size") - description: I18n.tr("Use custom border size") - checked: SettingsData.mangoLayoutBorderSize >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("mangoLayoutBorderSize", 2); - return; - } - SettingsData.set("mangoLayoutBorderSize", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["mangowc", "mango", "border", "override"] - settingKey: "mangoLayoutBorderSize" - text: I18n.tr("Border Size") - description: I18n.tr("Width of window border (borderpx)") - visible: SettingsData.mangoLayoutBorderSize >= 0 - value: Math.max(0, SettingsData.mangoLayoutBorderSize) - minimum: 0 - maximum: 10 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("mangoLayoutBorderSize", newValue) - } - } - - SettingsCard { - tab: "theme" - tags: ["modal", "darken", "background", "overlay"] - title: I18n.tr("Modal Background") - settingKey: "modalBackground" - iconName: "layers" - - SettingsToggleRow { - tab: "theme" - tags: ["modal", "darken", "background", "overlay"] - settingKey: "modalDarkenBackground" - text: I18n.tr("Darken Modal Background") - description: I18n.tr("Show darkened overlay behind modal dialogs") - checked: SettingsData.modalDarkenBackground - onToggled: checked => SettingsData.set("modalDarkenBackground", checked) - } - } - - SettingsCard { - tab: "theme" - tags: ["applications", "portal", "dark", "terminal"] - title: I18n.tr("Applications") - settingKey: "applications" - iconName: "apps" - - SettingsToggleRow { - tab: "theme" - tags: ["portal", "sync", "dark", "mode"] - settingKey: "syncModeWithPortal" - text: I18n.tr("Sync Mode with Portal") - description: I18n.tr("Sync dark mode with settings portals for system-wide theme hints") - checked: SettingsData.syncModeWithPortal - onToggled: checked => SettingsData.set("syncModeWithPortal", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["terminal", "dark", "always"] - settingKey: "terminalsAlwaysDark" - text: I18n.tr("Terminals - Always use Dark Theme") - description: I18n.tr("Force terminal applications to always use dark color schemes") - checked: SettingsData.terminalsAlwaysDark - onToggled: checked => SettingsData.set("terminalsAlwaysDark", checked) - } - } - - SettingsCard { - tab: "theme" - tags: ["cursor", "mouse", "pointer", "theme", "size"] - title: I18n.tr("Cursor Theme") - settingKey: "cursorTheme" - iconName: "mouse" - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledRect { - id: cursorWarningBox - width: parent.width - height: cursorWarningContent.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - - readonly property bool showError: themeColorsTab.cursorIncludeStatus.exists && !themeColorsTab.cursorIncludeStatus.included - readonly property bool showSetup: !themeColorsTab.cursorIncludeStatus.exists && !themeColorsTab.cursorIncludeStatus.included - - color: (showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.15) : "transparent" - border.color: (showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.3) : "transparent" - border.width: 1 - visible: (showError || showSetup) && !themeColorsTab.checkingCursorInclude - - Row { - id: cursorWarningContent - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - (cursorFixButton.visible ? cursorFixButton.width + Theme.spacingM : 0) - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: cursorWarningBox.showSetup ? I18n.tr("Cursor Config Not Configured") : I18n.tr("Cursor Include Missing") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.warning - } - - StyledText { - text: cursorWarningBox.showSetup ? I18n.tr("Click 'Setup' to create cursor config and add include to your compositor config.") : I18n.tr("dms/cursor config exists but is not included. Cursor settings won't apply.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } - } - - DankButton { - id: cursorFixButton - visible: cursorWarningBox.showError || cursorWarningBox.showSetup - text: themeColorsTab.fixingCursorInclude ? I18n.tr("Fixing...") : (cursorWarningBox.showSetup ? I18n.tr("Setup") : I18n.tr("Fix Now")) - backgroundColor: Theme.warning - textColor: Theme.background - enabled: !themeColorsTab.fixingCursorInclude - anchors.verticalCenter: parent.verticalCenter - onClicked: themeColorsTab.fixCursorInclude() - } - } - } - - SettingsDropdownRow { - tab: "theme" - tags: ["cursor", "mouse", "pointer", "theme"] - settingKey: "cursorTheme" - text: I18n.tr("Cursor Theme") - description: I18n.tr("Mouse pointer appearance") - currentValue: SettingsData.cursorSettings.theme - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 236 - options: cachedCursorThemes - onValueChanged: value => { - SettingsData.setCursorTheme(value); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["cursor", "mouse", "pointer", "size"] - settingKey: "cursorSize" - text: I18n.tr("Cursor Size") - description: I18n.tr("Mouse pointer size in pixels") - value: SettingsData.cursorSettings.size - minimum: 12 - maximum: 128 - unit: "px" - defaultValue: 24 - onSliderValueChanged: newValue => SettingsData.setCursorSize(newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["cursor", "hide", "typing"] - settingKey: "cursorHideWhenTyping" - text: I18n.tr("Hide When Typing") - description: I18n.tr("Hide cursor when pressing keyboard keys") - visible: CompositorService.isNiri || CompositorService.isHyprland - checked: { - if (CompositorService.isNiri) - return SettingsData.cursorSettings.niri?.hideWhenTyping || false; - if (CompositorService.isHyprland) - return SettingsData.cursorSettings.hyprland?.hideOnKeyPress || false; - return false; - } - onToggled: checked => { - const updated = JSON.parse(JSON.stringify(SettingsData.cursorSettings)); - if (CompositorService.isNiri) { - if (!updated.niri) - updated.niri = {}; - updated.niri.hideWhenTyping = checked; - } else if (CompositorService.isHyprland) { - if (!updated.hyprland) - updated.hyprland = {}; - updated.hyprland.hideOnKeyPress = checked; - } - SettingsData.set("cursorSettings", updated); - } - } - - SettingsToggleRow { - tab: "theme" - tags: ["cursor", "hide", "touch"] - settingKey: "cursorHideOnTouch" - text: I18n.tr("Hide on Touch") - description: I18n.tr("Hide cursor when using touch input") - visible: CompositorService.isHyprland - checked: SettingsData.cursorSettings.hyprland?.hideOnTouch || false - onToggled: checked => { - const updated = JSON.parse(JSON.stringify(SettingsData.cursorSettings)); - if (!updated.hyprland) - updated.hyprland = {}; - updated.hyprland.hideOnTouch = checked; - SettingsData.set("cursorSettings", updated); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["cursor", "hide", "timeout", "inactive"] - settingKey: "cursorHideAfterInactive" - text: I18n.tr("Auto-Hide Timeout") - description: I18n.tr("Hide cursor after inactivity (0 = disabled)") - value: { - if (CompositorService.isNiri) - return SettingsData.cursorSettings.niri?.hideAfterInactiveMs || 0; - if (CompositorService.isHyprland) - return SettingsData.cursorSettings.hyprland?.inactiveTimeout || 0; - if (CompositorService.isDwl) - return SettingsData.cursorSettings.dwl?.cursorHideTimeout || 0; - return 0; - } - minimum: 0 - maximum: CompositorService.isNiri ? 5000 : 10 - unit: CompositorService.isNiri ? "ms" : "s" - defaultValue: 0 - onSliderValueChanged: newValue => { - const updated = JSON.parse(JSON.stringify(SettingsData.cursorSettings)); - if (CompositorService.isNiri) { - if (!updated.niri) - updated.niri = {}; - updated.niri.hideAfterInactiveMs = newValue; - } else if (CompositorService.isHyprland) { - if (!updated.hyprland) - updated.hyprland = {}; - updated.hyprland.inactiveTimeout = newValue; - } else if (CompositorService.isDwl) { - if (!updated.dwl) - updated.dwl = {}; - updated.dwl.cursorHideTimeout = newValue; - } - SettingsData.set("cursorSettings", updated); - } - } - } - } - - SettingsCard { - tab: "theme" - tags: ["icon", "theme", "system"] - title: I18n.tr("Icon Theme") - settingKey: "iconTheme" - iconName: "interests" - - SettingsDropdownRow { - tab: "theme" - tags: ["icon", "theme", "system"] - settingKey: "iconTheme" - text: I18n.tr("Icon Theme") - description: I18n.tr("DankShell & System Icons (requires restart)") - currentValue: SettingsData.iconTheme - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 236 - options: cachedIconThemes - onValueChanged: value => { - SettingsData.setIconTheme(value); - if (Quickshell.env("QT_QPA_PLATFORMTHEME") != "gtk3" && Quickshell.env("QT_QPA_PLATFORMTHEME") != "qt6ct" && Quickshell.env("QT_QPA_PLATFORMTHEME_QT6") != "qt6ct") { - ToastService.showError(I18n.tr("Missing Environment Variables", "qt theme env error title"), I18n.tr("You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.", "qt theme env error body")); - } - } - } - } - - SettingsCard { - tab: "theme" - tags: ["matugen", "templates", "theming"] - title: I18n.tr("Matugen Templates") - settingKey: "matugenTemplates" - iconName: "auto_awesome" - collapsible: true - expanded: false - visible: Theme.matugenAvailable - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "user", "templates"] - settingKey: "runUserMatugenTemplates" - text: I18n.tr("Run User Templates") - description: "" - checked: SettingsData.runUserMatugenTemplates - onToggled: checked => SettingsData.set("runUserMatugenTemplates", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "dms", "templates"] - settingKey: "runDmsMatugenTemplates" - text: I18n.tr("Run DMS Templates") - description: "" - checked: SettingsData.runDmsMatugenTemplates - onToggled: checked => SettingsData.set("runDmsMatugenTemplates", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "gtk", "template"] - settingKey: "matugenTemplateGtk" - text: "GTK" - description: getTemplateDescription("gtk", "") - descriptionColor: getTemplateDescriptionColor("gtk") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateGtk - onToggled: checked => SettingsData.set("matugenTemplateGtk", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "niri", "template"] - settingKey: "matugenTemplateNiri" - text: "niri" - description: getTemplateDescription("niri", "") - descriptionColor: getTemplateDescriptionColor("niri") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateNiri - onToggled: checked => SettingsData.set("matugenTemplateNiri", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "hyprland", "template"] - settingKey: "matugenTemplateHyprland" - text: "Hyprland" - description: getTemplateDescription("hyprland", "") - descriptionColor: getTemplateDescriptionColor("hyprland") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateHyprland - onToggled: checked => SettingsData.set("matugenTemplateHyprland", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "mangowc", "template"] - settingKey: "matugenTemplateMangowc" - text: "mangowc" - description: getTemplateDescription("mangowc", "") - descriptionColor: getTemplateDescriptionColor("mangowc") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateMangowc - onToggled: checked => SettingsData.set("matugenTemplateMangowc", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "qt5ct", "template"] - settingKey: "matugenTemplateQt5ct" - text: "qt5ct" - description: getTemplateDescription("qt5ct", "") - descriptionColor: getTemplateDescriptionColor("qt5ct") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateQt5ct - onToggled: checked => SettingsData.set("matugenTemplateQt5ct", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "qt6ct", "template"] - settingKey: "matugenTemplateQt6ct" - text: "qt6ct" - description: getTemplateDescription("qt6ct", "") - descriptionColor: getTemplateDescriptionColor("qt6ct") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateQt6ct - onToggled: checked => SettingsData.set("matugenTemplateQt6ct", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "firefox", "template"] - settingKey: "matugenTemplateFirefox" - text: "Firefox" - description: getTemplateDescription("firefox", "") - descriptionColor: getTemplateDescriptionColor("firefox") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateFirefox - onToggled: checked => SettingsData.set("matugenTemplateFirefox", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "pywalfox", "template"] - settingKey: "matugenTemplatePywalfox" - text: "pywalfox" - description: getTemplateDescription("pywalfox", "") - descriptionColor: getTemplateDescriptionColor("pywalfox") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplatePywalfox - onToggled: checked => SettingsData.set("matugenTemplatePywalfox", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "zenbrowser", "template"] - settingKey: "matugenTemplateZenBrowser" - text: "zenbrowser" - description: getTemplateDescription("zenbrowser", "") - descriptionColor: getTemplateDescriptionColor("zenbrowser") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateZenBrowser - onToggled: checked => SettingsData.set("matugenTemplateZenBrowser", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "vesktop", "discord", "template"] - settingKey: "matugenTemplateVesktop" - text: "vesktop" - description: getTemplateDescription("vesktop", "") - descriptionColor: getTemplateDescriptionColor("vesktop") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateVesktop - onToggled: checked => SettingsData.set("matugenTemplateVesktop", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "equibop", "discord", "template"] - settingKey: "matugenTemplateEquibop" - text: "equibop" - description: getTemplateDescription("equibop", "") - descriptionColor: getTemplateDescriptionColor("equibop") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateEquibop - onToggled: checked => SettingsData.set("matugenTemplateEquibop", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "ghostty", "terminal", "template"] - settingKey: "matugenTemplateGhostty" - text: "Ghostty" - description: getTemplateDescription("ghostty", "") - descriptionColor: getTemplateDescriptionColor("ghostty") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateGhostty - onToggled: checked => SettingsData.set("matugenTemplateGhostty", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "kitty", "terminal", "template"] - settingKey: "matugenTemplateKitty" - text: "kitty" - description: getTemplateDescription("kitty", "") - descriptionColor: getTemplateDescriptionColor("kitty") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateKitty - onToggled: checked => SettingsData.set("matugenTemplateKitty", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "foot", "terminal", "template"] - settingKey: "matugenTemplateFoot" - text: "foot" - description: getTemplateDescription("foot", "") - descriptionColor: getTemplateDescriptionColor("foot") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateFoot - onToggled: checked => SettingsData.set("matugenTemplateFoot", checked) - } - - SettingsDivider { - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - } - - SettingsToggleRow { - id: neovimThemeToggle - tab: "theme" - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovim" - text: "neovim" - description: getTemplateDescription("nvim", I18n.tr("Required plugin: ") + "https://github.com/AvengeMedia/base46") - descriptionColor: getTemplateDescriptionColor("nvim") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateNeovim - onToggled: checked => SettingsData.set("matugenTemplateNeovim", checked) - } - - SettingsDropdownRow { - text: I18n.tr("Dark mode base") - tab: "theme" - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovimSettings" - description: "Base to derive dark theme from" - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - currentValue: SettingsData.matugenTemplateNeovimSettings?.dark?.baseTheme ?? "github_dark" - options: ["aquarium", "ashes", "aylin", "ayu_dark", "bearded-arc", "carbonfox", "catppuccin", "chadracula", "chadracula-evondev", "chadtain", "chocolate", "darcula-dark", "dark_horizon", "decay", "default-dark", "doomchad", "eldritch", "embark", "everblush", "everforest", "falcon", "flexoki", "flouromachine", "gatekeeper", "github_dark", "gruvbox", "gruvchad", "hiberbee", "horizon", "jabuti", "jellybeans", "kanagawa", "kanagawa-dragon", "material-darker", "material-deep-ocean", "melange", "midnight_breeze", "mito-laser", "monekai", "monochrome", "mountain", "neofusion", "nightfox", "nightlamp", "nightowl", "nord", "obsidian-ember", "oceanic-next", "onedark", "onenord", "oxocarbon", "palenight", "pastelDark", "pastelbeans", "penumbra_dark", "poimandres", "radium", "rosepine", "rxyhn", "scaryforest", "seoul256_dark", "solarized_dark", "solarized_osaka", "starlight", "sweetpastel", "tokyodark", "tokyonight", "tomorrow_night", "tundra", "vesper", "vscode_dark", "wombat", "yoru", "zenburn"] - enableFuzzySearch: true - onValueChanged: value => { - const settings = SettingsData.matugenTemplateNeovimSettings; - settings.dark.baseTheme = value; - SettingsData.set("matugenTemplateNeovimSettings", settings); - } - } - - SettingsDropdownRow { - text: I18n.tr("Light mode base") - tab: "theme" - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovimSettings" - description: "Base to derive light theme from" - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - currentValue: SettingsData.matugenTemplateNeovimSettings?.light?.baseTheme ?? "github_light" - options: ["ayu_light", "blossom_light", "catppuccin-latte", "default-light", "everforest_light", "flex-light", "flexoki-light", "github_light", "gruvbox_light", "material-lighter", "nano-light", "oceanic-light", "one_light", "onenord_light", "penumbra_light", "rosepine-dawn", "seoul256_light", "solarized_light", "sunrise_breeze", "vscode_light"] - enableFuzzySearch: true - onValueChanged: value => { - const settings = SettingsData.matugenTemplateNeovimSettings; - settings.light.baseTheme = value; - SettingsData.set("matugenTemplateNeovimSettings", settings); - } - } - - SettingsSliderRow { - text: I18n.tr("Dark mode harmony") - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovimSettings" - description: "How much should the base dark theme be tinted" - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - minimum: 0 - maximum: 100 - value: (SettingsData.matugenTemplateNeovimSettings?.dark?.harmony ?? 0.5) * 100 - defaultValue: 50 - onSliderValueChanged: value => { - const settings = SettingsData.matugenTemplateNeovimSettings; - settings.dark.harmony = value / 100; - SettingsData.set("matugenTemplateNeovimSettings", settings); - } - } - - SettingsSliderRow { - text: I18n.tr("Light mode harmony") - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovimSettings" - description: "How much should the base light theme be tinted" - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - minimum: 0 - maximum: 100 - value: (SettingsData.matugenTemplateNeovimSettings?.light?.harmony ?? 0.5) * 100 - defaultValue: 50 - onSliderValueChanged: value => { - const settings = SettingsData.matugenTemplateNeovimSettings; - settings.light.harmony = value / 100; - SettingsData.set("matugenTemplateNeovimSettings", settings); - } - } - - SettingsToggleRow { - text: I18n.tr("Follow DMS background color") - tags: ["matugen", "neovim", "terminal", "template"] - settingKey: "matugenTemplateNeovimSetBackground" - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - checked: SettingsData.matugenTemplateNeovimSetBackground ?? true - onToggled: checked => SettingsData.set("matugenTemplateNeovimSetBackground", checked) - } - - SettingsDivider { - visible: neovimThemeToggle.visible && neovimThemeToggle.checked - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "alacritty", "terminal", "template"] - settingKey: "matugenTemplateAlacritty" - text: "Alacritty" - description: getTemplateDescription("alacritty", "") - descriptionColor: getTemplateDescriptionColor("alacritty") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateAlacritty - onToggled: checked => SettingsData.set("matugenTemplateAlacritty", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "wezterm", "terminal", "template"] - settingKey: "matugenTemplateWezterm" - text: "WezTerm" - description: getTemplateDescription("wezterm", "") - descriptionColor: getTemplateDescriptionColor("wezterm") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateWezterm - onToggled: checked => SettingsData.set("matugenTemplateWezterm", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "dgop", "template"] - settingKey: "matugenTemplateDgop" - text: "dgop" - description: getTemplateDescription("dgop", "") - descriptionColor: getTemplateDescriptionColor("dgop") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateDgop - onToggled: checked => SettingsData.set("matugenTemplateDgop", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "kcolorscheme", "kde", "template"] - settingKey: "matugenTemplateKcolorscheme" - text: "KColorScheme" - description: getTemplateDescription("kcolorscheme", "") - descriptionColor: getTemplateDescriptionColor("kcolorscheme") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateKcolorscheme - onToggled: checked => SettingsData.set("matugenTemplateKcolorscheme", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "vscode", "code", "template"] - settingKey: "matugenTemplateVscode" - text: "VS Code" - description: getTemplateDescription("vscode", "") - descriptionColor: getTemplateDescriptionColor("vscode") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateVscode - onToggled: checked => SettingsData.set("matugenTemplateVscode", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "emacs", "template"] - settingKey: "matugenTemplateEmacs" - text: "Emacs" - description: getTemplateDescription("emacs", "") - descriptionColor: getTemplateDescriptionColor("emacs") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateEmacs - onToggled: checked => SettingsData.set("matugenTemplateEmacs", checked) - } - - SettingsToggleRow { - tab: "theme" - tags: ["matugen", "zed", "template"] - settingKey: "matugenTemplateZed" - text: "Zed" - description: getTemplateDescription("zed", "") - descriptionColor: getTemplateDescriptionColor("zed") - visible: SettingsData.runDmsMatugenTemplates - checked: SettingsData.matugenTemplateZed - onToggled: checked => SettingsData.set("matugenTemplateZed", checked) - } - } - - Rectangle { - width: parent.width - height: warningText.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12) - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "info" - size: Theme.iconSizeSmall - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: warningText - font.pixelSize: Theme.fontSizeSmall - text: I18n.tr("The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).") - wrapMode: Text.WordWrap - width: parent.width - Theme.iconSizeSmall - Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - } - } - } - - SettingsCard { - tab: "theme" - tags: ["system", "app", "theming", "gtk", "qt"] - title: I18n.tr("System App Theming") - settingKey: "systemAppTheming" - iconName: "brush" - visible: Theme.matugenAvailable - - Row { - width: parent.width - spacing: Theme.spacingM - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "folder" - size: 16 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Apply GTK Colors") - font.pixelSize: Theme.fontSizeMedium - color: Theme.primary - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: Theme.applyGtkColors() - } - } - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: 48 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "settings" - size: 16 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Apply Qt Colors") - font.pixelSize: Theme.fontSizeMedium - color: Theme.primary - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: Theme.applyQtColors() - } - } - } - - StyledText { - text: I18n.tr('Generate baseline GTK3/4 or QT5/QT6 (requires qt6ct-kde) configurations to follow DMS colors. Only needed once.

It is recommended to configure adw-gtk3 prior to applying GTK themes.').arg(Theme.primary) - textFormat: Text.RichText - linkColor: Theme.primary - onLinkActivated: url => Qt.openUrlExternally(url) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignHCenter - - MouseArea { - anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - } - } - } - } - } - - FileBrowserModal { - id: fileBrowserModal - browserTitle: I18n.tr("Select Custom Theme", "custom theme file browser title") - filterExtensions: ["*.json"] - showHiddenFiles: true - - function selectCustomTheme() { - shouldBeVisible = true; - } - - onFileSelected: function (filePath) { - if (filePath.endsWith(".json")) { - SettingsData.set("customThemeFile", filePath); - Theme.switchTheme("custom"); - close(); - } - } - } - - LazyLoader { - id: themeBrowserLoader - active: false - - ThemeBrowser { - id: themeBrowserItem - } - } - - function showThemeBrowser() { - themeBrowserLoader.active = true; - if (themeBrowserLoader.item) - themeBrowserLoader.item.show(); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TimeWeatherTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TimeWeatherTab.qml deleted file mode 100644 index 61f4d43..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TimeWeatherTab.qml +++ /dev/null @@ -1,1148 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - readonly property string _systemDefaultLabel: I18n.tr("System Default") - - function weekStartQt() { - if (SettingsData.firstDayOfWeek < 0 || SettingsData.firstDayOfWeek >= 7) - return Qt.locale().firstDayOfWeek; - return SettingsData.firstDayOfWeek; - } - - function weekStartJs() { - return weekStartQt() % 7; - } - - function _dayNames() { - return Array(7).fill(0).map((_, i) => new Date(Date.UTC(2026, 2, 1 + i, 0, 0, 0)).toLocaleDateString(I18n.locale(), "dddd")).map(d => d[0].toUpperCase() + d.slice(1)); - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "time" - tags: ["time", "clock", "format", "24hour"] - title: I18n.tr("Time Format") - settingKey: "timeFormat" - iconName: "schedule" - - SettingsToggleRow { - tab: "time" - tags: ["time", "24hour", "format"] - settingKey: "use24HourClock" - text: I18n.tr("24-Hour Format") - description: I18n.tr("Use 24-hour time format instead of 12-hour AM/PM") - checked: SettingsData.use24HourClock - onToggled: checked => SettingsData.set("use24HourClock", checked) - } - - SettingsToggleRow { - tab: "time" - tags: ["time", "seconds", "clock"] - settingKey: "showSeconds" - text: I18n.tr("Show Seconds") - description: I18n.tr("Display seconds in the clock") - checked: SettingsData.showSeconds - onToggled: checked => SettingsData.set("showSeconds", checked) - } - - SettingsToggleRow { - tab: "time" - tags: ["time", "12hour", "format", "padding", "leading", "zero"] - settingKey: "padHours12Hour" - text: I18n.tr("Pad Hours") - description: "02:31 PM vs 2:31 PM" - checked: SettingsData.padHours12Hour - onToggled: checked => SettingsData.set("padHours12Hour", checked) - visible: !SettingsData.use24HourClock - } - } - - SettingsCard { - tab: "time" - tags: ["date", "format", "calendar"] - title: I18n.tr("Date Format") - settingKey: "dateFormat" - iconName: "calendar_today" - - SettingsToggleRow { - tab: "time" - tags: ["show", "week"] - settingKey: "showWeekNumber" - text: I18n.tr("Show Week Number") - description: I18n.tr("Show week number in the calendar") - checked: SettingsData.showWeekNumber - onToggled: checked => SettingsData.set("showWeekNumber", checked) - } - - SettingsDropdownRow { - tab: "time" - tags: ["first", "day", "week"] - settingKey: "firstDayOfWeek" - text: I18n.tr("First Day of Week") - options: [root._systemDefaultLabel].concat(root._dayNames()) - currentValue: { - if (SettingsData.firstDayOfWeek < 0 || SettingsData.firstDayOfWeek >= 7) - return root._systemDefaultLabel; - return root._dayNames()[root.weekStartJs()]; - } - onValueChanged: value => { - if (value === root._systemDefaultLabel) { - SettingsData.set("firstDayOfWeek", -1); - return; - } - SettingsData.set("firstDayOfWeek", root._dayNames().indexOf(value)); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsDropdownRow { - tab: "time" - tags: ["date", "format", "topbar"] - settingKey: "clockDateFormat" - text: I18n.tr("Top Bar Format") - description: "Preview: " + (SettingsData.clockDateFormat ? new Date().toLocaleDateString(I18n.locale(), SettingsData.clockDateFormat) : new Date().toLocaleDateString(I18n.locale(), "ddd d")) - options: [I18n.tr("System Default", "date format option"), I18n.tr("Day Date", "date format option"), I18n.tr("Day Month Date", "date format option"), I18n.tr("Month Date", "date format option"), I18n.tr("Numeric (M/D)", "date format option"), I18n.tr("Numeric (D/M)", "date format option"), I18n.tr("Full with Year", "date format option"), I18n.tr("ISO Date", "date format option"), I18n.tr("Full Day & Month", "date format option"), I18n.tr("Custom...", "date format option")] - currentValue: { - if (!SettingsData.clockDateFormat || SettingsData.clockDateFormat.length === 0) - return I18n.tr("System Default", "date format option"); - const presets = [ - { - "format": "ddd d", - "label": I18n.tr("Day Date", "date format option") - }, - { - "format": "ddd MMM d", - "label": I18n.tr("Day Month Date", "date format option") - }, - { - "format": "MMM d", - "label": I18n.tr("Month Date", "date format option") - }, - { - "format": "M/d", - "label": I18n.tr("Numeric (M/D)", "date format option") - }, - { - "format": "d/M", - "label": I18n.tr("Numeric (D/M)", "date format option") - }, - { - "format": "ddd d MMM yyyy", - "label": I18n.tr("Full with Year", "date format option") - }, - { - "format": "yyyy-MM-dd", - "label": I18n.tr("ISO Date", "date format option") - }, - { - "format": "dddd, MMMM d", - "label": I18n.tr("Full Day & Month", "date format option") - } - ]; - const match = presets.find(p => p.format === SettingsData.clockDateFormat); - return match ? match.label : I18n.tr("Custom: ") + SettingsData.clockDateFormat; - } - onValueChanged: value => { - const formatMap = {}; - formatMap[I18n.tr("System Default", "date format option")] = ""; - formatMap[I18n.tr("Day Date", "date format option")] = "ddd d"; - formatMap[I18n.tr("Day Month Date", "date format option")] = "ddd MMM d"; - formatMap[I18n.tr("Month Date", "date format option")] = "MMM d"; - formatMap[I18n.tr("Numeric (M/D)", "date format option")] = "M/d"; - formatMap[I18n.tr("Numeric (D/M)", "date format option")] = "d/M"; - formatMap[I18n.tr("Full with Year", "date format option")] = "ddd d MMM yyyy"; - formatMap[I18n.tr("ISO Date", "date format option")] = "yyyy-MM-dd"; - formatMap[I18n.tr("Full Day & Month", "date format option")] = "dddd, MMMM d"; - if (value === I18n.tr("Custom...", "date format option")) { - customFormatInput.visible = true; - } else { - customFormatInput.visible = false; - SettingsData.set("clockDateFormat", formatMap[value]); - } - } - } - - DankTextField { - id: customFormatInput - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - visible: false - placeholderText: I18n.tr("Enter custom top bar format (e.g., ddd MMM d)") - text: SettingsData.clockDateFormat - onTextChanged: { - if (visible && text) - SettingsData.set("clockDateFormat", text); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsDropdownRow { - tab: "time" - tags: ["date", "format", "lock", "screen"] - settingKey: "lockDateFormat" - text: I18n.tr("Lock Screen Format") - description: "Preview: " + (SettingsData.lockDateFormat ? new Date().toLocaleDateString(I18n.locale(), SettingsData.lockDateFormat) : new Date().toLocaleDateString(I18n.locale(), Locale.LongFormat)) - options: [I18n.tr("System Default", "date format option"), I18n.tr("Day Date", "date format option"), I18n.tr("Day Month Date", "date format option"), I18n.tr("Month Date", "date format option"), I18n.tr("Numeric (M/D)", "date format option"), I18n.tr("Numeric (D/M)", "date format option"), I18n.tr("Full with Year", "date format option"), I18n.tr("ISO Date", "date format option"), I18n.tr("Full Day & Month", "date format option"), I18n.tr("Custom...", "date format option")] - currentValue: { - if (!SettingsData.lockDateFormat || SettingsData.lockDateFormat.length === 0) - return I18n.tr("System Default", "date format option"); - const presets = [ - { - "format": "ddd d", - "label": I18n.tr("Day Date", "date format option") - }, - { - "format": "ddd MMM d", - "label": I18n.tr("Day Month Date", "date format option") - }, - { - "format": "MMM d", - "label": I18n.tr("Month Date", "date format option") - }, - { - "format": "M/d", - "label": I18n.tr("Numeric (M/D)", "date format option") - }, - { - "format": "d/M", - "label": I18n.tr("Numeric (D/M)", "date format option") - }, - { - "format": "ddd d MMM yyyy", - "label": I18n.tr("Full with Year", "date format option") - }, - { - "format": "yyyy-MM-dd", - "label": I18n.tr("ISO Date", "date format option") - }, - { - "format": "dddd, MMMM d", - "label": I18n.tr("Full Day & Month", "date format option") - } - ]; - const match = presets.find(p => p.format === SettingsData.lockDateFormat); - return match ? match.label : I18n.tr("Custom: ") + SettingsData.lockDateFormat; - } - onValueChanged: value => { - const formatMap = {}; - formatMap[I18n.tr("System Default", "date format option")] = ""; - formatMap[I18n.tr("Day Date", "date format option")] = "ddd d"; - formatMap[I18n.tr("Day Month Date", "date format option")] = "ddd MMM d"; - formatMap[I18n.tr("Month Date", "date format option")] = "MMM d"; - formatMap[I18n.tr("Numeric (M/D)", "date format option")] = "M/d"; - formatMap[I18n.tr("Numeric (D/M)", "date format option")] = "d/M"; - formatMap[I18n.tr("Full with Year", "date format option")] = "ddd d MMM yyyy"; - formatMap[I18n.tr("ISO Date", "date format option")] = "yyyy-MM-dd"; - formatMap[I18n.tr("Full Day & Month", "date format option")] = "dddd, MMMM d"; - if (value === I18n.tr("Custom...", "date format option")) { - customLockFormatInput.visible = true; - } else { - customLockFormatInput.visible = false; - SettingsData.set("lockDateFormat", formatMap[value]); - } - } - } - - DankTextField { - id: customLockFormatInput - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - visible: false - placeholderText: I18n.tr("Enter custom lock screen format (e.g., dddd, MMMM d)") - text: SettingsData.lockDateFormat - onTextChanged: { - if (visible && text) - SettingsData.set("lockDateFormat", text); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Rectangle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - height: formatHelp.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: formatHelp - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Format Legend") - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - } - - Row { - width: parent.width - spacing: Theme.spacingL - - Column { - width: (parent.width - Theme.spacingL) / 2 - spacing: 2 - - StyledText { - text: I18n.tr("• d - Day (1-31)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• dd - Day (01-31)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• ddd - Day name (Mon)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• dddd - Day name (Monday)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• M - Month (1-12)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - Column { - width: (parent.width - Theme.spacingL) / 2 - spacing: 2 - - StyledText { - text: I18n.tr("• MM - Month (01-12)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• MMM - Month (Jan)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• MMMM - Month (January)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• yy - Year (24)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - StyledText { - text: I18n.tr("• yyyy - Year (2024)") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - } - } - - SettingsCard { - tab: "time" - tags: ["weather", "enable", "forecast"] - title: I18n.tr("Weather") - settingKey: "weather" - iconName: "cloud" - - SettingsToggleRow { - tab: "time" - tags: ["weather", "enable"] - settingKey: "weatherEnabled" - text: I18n.tr("Enable Weather") - description: I18n.tr("Show weather information in top bar and control center") - checked: SettingsData.weatherEnabled - onToggled: checked => SettingsData.set("weatherEnabled", checked) - } - - Column { - width: parent.width - spacing: 0 - visible: SettingsData.weatherEnabled - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - tab: "time" - tags: ["weather", "imperial", "fahrenheit", "units"] - settingKey: "useFahrenheit" - text: I18n.tr("Use Imperial Units") - description: I18n.tr("Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)") - checked: SettingsData.useFahrenheit - onToggled: checked => SettingsData.set("useFahrenheit", checked) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: !SettingsData.useFahrenheit - } - - SettingsToggleRow { - tab: "time" - tags: ["weather", "wind", "speed", "units", "metric"] - settingKey: "windSpeedUnit" - text: I18n.tr("Wind Speed in m/s") - description: I18n.tr("Use meters per second instead of km/h for wind speed") - checked: SettingsData.windSpeedUnit === "ms" - onToggled: checked => SettingsData.set("windSpeedUnit", checked ? "ms" : "kmh") - visible: !SettingsData.useFahrenheit - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - tab: "time" - tags: ["weather", "location", "auto", "gps"] - settingKey: "useAutoLocation" - text: I18n.tr("Auto Location") - description: I18n.tr("Automatically determine your location using your IP address") - checked: SettingsData.useAutoLocation - onToggled: checked => SettingsData.set("useAutoLocation", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: !SettingsData.useAutoLocation - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Item { - width: parent.width - height: locationContent.height - - Column { - id: locationContent - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Custom Location") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Latitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: latitudeInput - width: parent.width - height: 48 - placeholderText: "40.7128" - backgroundColor: Theme.surfaceVariant - normalBorderColor: Theme.primarySelected - focusedBorderColor: Theme.primary - keyNavigationTab: longitudeInput - - Component.onCompleted: { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(','); - if (coords.length > 0) - text = coords[0].trim(); - } - } - - Connections { - target: SettingsData - function onWeatherCoordinatesChanged() { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(','); - if (coords.length > 0) - latitudeInput.text = coords[0].trim(); - } - } - } - - onTextEdited: { - if (text && longitudeInput.text) { - const coords = text + "," + longitudeInput.text; - SessionData.weatherCoordinates = coords; - SessionData.saveSettings(); - } - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Longitude") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: longitudeInput - width: parent.width - height: 48 - placeholderText: "-74.0060" - backgroundColor: Theme.surfaceVariant - normalBorderColor: Theme.primarySelected - focusedBorderColor: Theme.primary - keyNavigationTab: locationSearchInput - keyNavigationBacktab: latitudeInput - - Component.onCompleted: { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(','); - if (coords.length > 1) - text = coords[1].trim(); - } - } - - Connections { - target: SettingsData - function onWeatherCoordinatesChanged() { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(','); - if (coords.length > 1) - longitudeInput.text = coords[1].trim(); - } - } - } - - onTextEdited: { - if (text && latitudeInput.text) { - const coords = latitudeInput.text + "," + text; - SessionData.weatherCoordinates = coords; - SessionData.saveSettings(); - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Location Search") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - font.weight: Font.Medium - } - - DankLocationSearch { - id: locationSearchInput - width: parent.width - currentLocation: "" - placeholderText: I18n.tr("New York, NY") - keyNavigationBacktab: longitudeInput - onLocationSelected: (displayName, coordinates) => { - SettingsData.setWeatherLocation(displayName, coordinates); - const coords = coordinates.split(','); - if (coords.length >= 2) { - latitudeInput.text = coords[0].trim(); - longitudeInput.text = coords[1].trim(); - } - } - } - } - } - } - } - } - } - - SettingsCard { - tab: "time" - tags: ["weather", "current", "display"] - title: I18n.tr("Current Weather") - settingKey: "weather" - iconName: "visibility" - visible: SettingsData.weatherEnabled - - Column { - width: parent.width - spacing: Theme.spacingL - visible: !WeatherService.weather.available - - DankIcon { - name: "cloud_off" - size: Theme.iconSize * 2 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: I18n.tr("No Weather Data Available") - font.pixelSize: Theme.fontSizeLarge - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: WeatherService.weather.available - - Item { - width: parent.width - height: 70 - - DankIcon { - id: refreshButton - name: "refresh" - size: Theme.iconSize - 4 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4) - anchors.right: parent.right - anchors.top: parent.top - - property bool isRefreshing: false - enabled: !isRefreshing - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ForbiddenCursor - onClicked: { - refreshButton.isRefreshing = true; - WeatherService.forceRefresh(); - refreshTimer.restart(); - } - enabled: parent.enabled - } - - Timer { - id: refreshTimer - interval: 2000 - onTriggered: refreshButton.isRefreshing = false - } - - NumberAnimation on rotation { - running: refreshButton.isRefreshing - from: 0 - to: 360 - duration: 1000 - loops: Animation.Infinite - } - } - - Item { - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - width: weatherIcon.width + tempColumn.width + sunriseColumn.width + Theme.spacingM * 2 - height: 70 - - DankIcon { - id: weatherIcon - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.iconSize * 1.5 - color: Theme.primary - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - - layer.enabled: Theme.elevationEnabled - layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1) - shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1) - shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) : 0 - blurMax: Theme.elevationBlurMax - shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) - shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2 - } - } - - Column { - id: tempColumn - spacing: Theme.spacingXS - anchors.left: weatherIcon.right - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - - Item { - width: tempText.width + unitText.width + Theme.spacingXS - height: tempText.height - - StyledText { - id: tempText - text: (SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" - font.pixelSize: Theme.fontSizeLarge + 4 - color: Theme.surfaceText - font.weight: Font.Light - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: unitText - text: SettingsData.useFahrenheit ? "F" : "C" - font.pixelSize: Theme.fontSizeMedium - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.left: tempText.right - anchors.leftMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (WeatherService.weather.available) - SettingsData.set("useFahrenheit", !SettingsData.useFahrenheit); - } - enabled: WeatherService.weather.available - } - } - } - - StyledText { - property var feelsLike: SettingsData.useFahrenheit ? (WeatherService.weather.feelsLikeF || WeatherService.weather.tempF) : (WeatherService.weather.feelsLike || WeatherService.weather.temp) - text: I18n.tr("Feels Like %1°").arg(feelsLike) - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5) - } - - StyledText { - text: WeatherService.weather.city || "" - font.pixelSize: Theme.fontSizeMedium - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - visible: text.length > 0 - } - } - - Column { - id: sunriseColumn - spacing: Theme.spacingXS - anchors.left: tempColumn.right - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: WeatherService.weather.sunrise && WeatherService.weather.sunset - - Item { - width: sunriseIcon.width + sunriseText.width + Theme.spacingXS - height: sunriseIcon.height - - DankIcon { - id: sunriseIcon - name: "wb_twilight" - size: Theme.iconSize - 6 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: sunriseText - text: WeatherService.weather.sunrise || "" - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.left: sunriseIcon.right - anchors.leftMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - } - } - - Item { - width: sunsetIcon.width + sunsetText.width + Theme.spacingXS - height: sunsetIcon.height - - DankIcon { - id: sunsetIcon - name: "bedtime" - size: Theme.iconSize - 6 - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: sunsetText - text: WeatherService.weather.sunset || "" - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) - anchors.left: sunsetIcon.right - anchors.leftMargin: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - } - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - } - - GridLayout { - width: parent.width - height: 95 - columns: 6 - columnSpacing: Theme.spacingS - rowSpacing: 0 - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "device_thermostat" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Feels Like") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - text: (SettingsData.useFahrenheit ? (WeatherService.weather.feelsLikeF || WeatherService.weather.tempF) : (WeatherService.weather.feelsLike || WeatherService.weather.temp)) + "°" - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "humidity_low" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Humidity") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - text: WeatherService.weather.humidity ? WeatherService.weather.humidity + "%" : "--" - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "air" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Wind") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - id: windText - text: { - SettingsData.windSpeedUnit; - SettingsData.useFahrenheit; - return WeatherService.formatSpeed(WeatherService.weather.wind) || "--"; - } - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: SettingsData.useFahrenheit ? Qt.ArrowCursor : Qt.PointingHandCursor - enabled: !SettingsData.useFahrenheit - onClicked: SettingsData.set("windSpeedUnit", SettingsData.windSpeedUnit === "kmh" ? "ms" : "kmh") - } - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "speed" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Pressure") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - text: { - if (!WeatherService.weather.pressure) - return "--"; - if (SettingsData.useFahrenheit) - return (WeatherService.weather.pressure * 0.02953).toFixed(2) + " inHg"; - return WeatherService.weather.pressure + " hPa"; - } - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "rainy" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Rain Chance") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - text: WeatherService.weather.precipitationProbability ? WeatherService.weather.precipitationProbability + "%" : "0%" - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - anchors.horizontalCenter: parent.horizontalCenter - DankIcon { - anchors.centerIn: parent - name: "wb_sunny" - size: Theme.iconSize - 4 - color: Theme.primary - } - } - - Column { - anchors.horizontalCenter: parent.horizontalCenter - spacing: 2 - StyledText { - text: I18n.tr("Visibility") - font.pixelSize: Theme.fontSizeSmall - color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - StyledText { - text: I18n.tr("Good") - font.pixelSize: Theme.fontSizeSmall + 1 - color: Theme.surfaceText - font.weight: Font.Medium - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TypographyMotionTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TypographyMotionTab.qml deleted file mode 100644 index 8648acb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/TypographyMotionTab.qml +++ /dev/null @@ -1,490 +0,0 @@ -import QtQuick -import qs.Common -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - property var cachedFontFamilies: [] - property var cachedMonoFamilies: [] - property bool fontsEnumerated: false - - function enumerateFonts() { - var fonts = []; - var availableFonts = Qt.fontFamilies(); - - for (var i = 0; i < availableFonts.length; i++) { - var fontName = availableFonts[i]; - if (fontName.startsWith(".")) - continue; - fonts.push(fontName); - } - fonts.sort(); - fonts.unshift("Default"); - cachedFontFamilies = fonts; - cachedMonoFamilies = fonts; - } - - Timer { - id: fontEnumerationTimer - interval: 50 - running: false - onTriggered: { - if (fontsEnumerated) - return; - enumerateFonts(); - fontsEnumerated = true; - } - } - - Component.onCompleted: { - fontEnumerationTimer.start(); - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "typography" - tags: ["font", "family", "text", "typography"] - title: I18n.tr("Typography") - settingKey: "typography" - iconName: "text_fields" - - SettingsDropdownRow { - tab: "typography" - tags: ["font", "family", "normal", "text"] - settingKey: "fontFamily" - text: I18n.tr("Normal Font") - description: I18n.tr("Select the font family for UI text") - options: root.fontsEnumerated ? root.cachedFontFamilies : ["Default"] - currentValue: SettingsData.fontFamily === Theme.defaultFontFamily ? "Default" : (SettingsData.fontFamily || "Default") - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 400 - onValueChanged: value => { - if (value === "Default") - SettingsData.set("fontFamily", Theme.defaultFontFamily); - else - SettingsData.set("fontFamily", value); - } - } - - SettingsDropdownRow { - tab: "typography" - tags: ["font", "monospace", "code", "terminal"] - settingKey: "monoFontFamily" - text: I18n.tr("Monospace Font") - description: I18n.tr("Select monospace font for process list and technical displays") - options: root.fontsEnumerated ? root.cachedMonoFamilies : ["Default"] - currentValue: SettingsData.monoFontFamily === SettingsData.defaultMonoFontFamily ? "Default" : (SettingsData.monoFontFamily || "Default") - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 400 - onValueChanged: value => { - if (value === "Default") - SettingsData.set("monoFontFamily", SettingsData.defaultMonoFontFamily); - else - SettingsData.set("monoFontFamily", value); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsDropdownRow { - tab: "typography" - tags: ["font", "weight", "bold", "light"] - settingKey: "fontWeight" - text: I18n.tr("Font Weight") - description: I18n.tr("Select font weight for UI text") - options: ["Thin", "Extra Light", "Light", "Regular", "Medium", "Demi Bold", "Bold", "Extra Bold", "Black"] - currentValue: { - switch (SettingsData.fontWeight) { - case Font.Thin: - return "Thin"; - case Font.ExtraLight: - return "Extra Light"; - case Font.Light: - return "Light"; - case Font.Normal: - return "Regular"; - case Font.Medium: - return "Medium"; - case Font.DemiBold: - return "Demi Bold"; - case Font.Bold: - return "Bold"; - case Font.ExtraBold: - return "Extra Bold"; - case Font.Black: - return "Black"; - default: - return "Regular"; - } - } - onValueChanged: value => { - var weight; - switch (value) { - case "Thin": - weight = Font.Thin; - break; - case "Extra Light": - weight = Font.ExtraLight; - break; - case "Light": - weight = Font.Light; - break; - case "Regular": - weight = Font.Normal; - break; - case "Medium": - weight = Font.Medium; - break; - case "Demi Bold": - weight = Font.DemiBold; - break; - case "Bold": - weight = Font.Bold; - break; - case "Extra Bold": - weight = Font.ExtraBold; - break; - case "Black": - weight = Font.Black; - break; - default: - weight = Font.Normal; - break; - } - SettingsData.set("fontWeight", weight); - } - } - - SettingsSliderRow { - tab: "typography" - tags: ["font", "scale", "size", "zoom"] - settingKey: "fontScale" - text: I18n.tr("Font Scale") - description: I18n.tr("Scale all font sizes throughout the shell") - minimum: 75 - maximum: 150 - value: Math.round(SettingsData.fontScale * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => SettingsData.set("fontScale", newValue / 100) - } - } - - SettingsCard { - tab: "typography" - tags: ["animation", "speed", "motion", "duration"] - title: I18n.tr("Animation Speed") - settingKey: "animationSpeed" - iconName: "animation" - - Item { - width: parent.width - height: animationSpeedGroup.implicitHeight - clip: true - - DankButtonGroup { - id: animationSpeedGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 480 ? 44 : 64 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")] - selectionMode: "single" - currentIndex: SettingsData.animationSpeed - onSelectionChanged: (index, selected) => { - if (!selected) - return; - SettingsData.set("animationSpeed", index); - } - - Connections { - target: SettingsData - function onAnimationSpeedChanged() { - animationSpeedGroup.currentIndex = SettingsData.animationSpeed; - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsSliderRow { - id: durationSlider - tab: "typography" - tags: ["animation", "duration", "custom", "speed"] - settingKey: "customAnimationDuration" - text: I18n.tr("Animation Duration") - description: I18n.tr("Globally scale all animation durations") - minimum: 0 - maximum: 1000 - value: Theme.currentAnimationBaseDuration - unit: "ms" - defaultValue: 200 - onSliderValueChanged: newValue => { - SettingsData.set("animationSpeed", SettingsData.AnimationSpeed.Custom); - SettingsData.set("customAnimationDuration", newValue); - } - - Connections { - target: SettingsData - function onAnimationSpeedChanged() { - if (SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom) - return; - durationSlider.value = Theme.currentAnimationBaseDuration; - } - } - - Connections { - target: Theme - function onCurrentAnimationBaseDurationChanged() { - if (SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom) - return; - durationSlider.value = Theme.currentAnimationBaseDuration; - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - tab: "typography" - tags: ["animation", "sync", "popout", "modal", "global"] - settingKey: "syncComponentAnimationSpeeds" - text: I18n.tr("Sync Popouts & Modals") - description: I18n.tr("Popouts and Modals follow global Animation Speed (disable to customize independently)") - checked: SettingsData.syncComponentAnimationSpeeds - onToggled: checked => SettingsData.set("syncComponentAnimationSpeeds", checked) - - Connections { - target: SettingsData - function onSyncComponentAnimationSpeedsChanged() { - } - } - } - } - - SettingsCard { - tab: "typography" - tags: ["animation", "speed", "motion", "duration", "popout", "sync"] - title: I18n.tr("%1 Animation Speed").arg(I18n.tr("Popouts")) - settingKey: "popoutAnimationSpeed" - iconName: "open_in_new" - - Item { - width: parent.width - height: popoutSpeedGroup.implicitHeight - clip: true - - DankButtonGroup { - id: popoutSpeedGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 480 ? 44 : 64 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")] - selectionMode: "single" - currentIndex: SettingsData.popoutAnimationSpeed - onSelectionChanged: (index, selected) => { - if (!selected) - return; - if (SettingsData.syncComponentAnimationSpeeds) - SettingsData.set("syncComponentAnimationSpeeds", false); - SettingsData.set("popoutAnimationSpeed", index); - } - - Connections { - target: SettingsData - function onPopoutAnimationSpeedChanged() { - popoutSpeedGroup.currentIndex = SettingsData.popoutAnimationSpeed; - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsSliderRow { - id: popoutDurationSlider - tab: "typography" - tags: ["animation", "duration", "custom", "speed", "popout"] - settingKey: "popoutCustomAnimationDuration" - text: I18n.tr("Custom Duration") - description: I18n.tr("%1 custom animation duration").arg(I18n.tr("Popouts")) - minimum: 0 - maximum: 1000 - value: Theme.popoutAnimationDuration - unit: "ms" - defaultValue: 150 - onSliderValueChanged: newValue => { - if (SettingsData.syncComponentAnimationSpeeds) - SettingsData.set("syncComponentAnimationSpeeds", false); - SettingsData.set("popoutAnimationSpeed", SettingsData.AnimationSpeed.Custom); - SettingsData.set("popoutCustomAnimationDuration", newValue); - } - - Connections { - target: SettingsData - function onPopoutAnimationSpeedChanged() { - if (SettingsData.popoutAnimationSpeed === SettingsData.AnimationSpeed.Custom) - return; - popoutDurationSlider.value = Theme.popoutAnimationDuration; - } - } - - Connections { - target: Theme - function onPopoutAnimationDurationChanged() { - if (!SettingsData.syncComponentAnimationSpeeds && SettingsData.popoutAnimationSpeed === SettingsData.AnimationSpeed.Custom) - return; - popoutDurationSlider.value = Theme.popoutAnimationDuration; - } - } - } - } - - SettingsCard { - tab: "typography" - tags: ["animation", "speed", "motion", "duration", "modal", "sync"] - title: I18n.tr("%1 Animation Speed").arg(I18n.tr("Modals")) - settingKey: "modalAnimationSpeed" - iconName: "web_asset" - - Item { - width: parent.width - height: modalSpeedGroup.implicitHeight - clip: true - - DankButtonGroup { - id: modalSpeedGroup - anchors.horizontalCenter: parent.horizontalCenter - buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL - minButtonWidth: parent.width < 480 ? 44 : 64 - textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium - model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")] - selectionMode: "single" - currentIndex: SettingsData.modalAnimationSpeed - onSelectionChanged: (index, selected) => { - if (!selected) - return; - if (SettingsData.syncComponentAnimationSpeeds) - SettingsData.set("syncComponentAnimationSpeeds", false); - SettingsData.set("modalAnimationSpeed", index); - } - - Connections { - target: SettingsData - function onModalAnimationSpeedChanged() { - modalSpeedGroup.currentIndex = SettingsData.modalAnimationSpeed; - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsSliderRow { - id: modalDurationSlider - tab: "typography" - tags: ["animation", "duration", "custom", "speed", "modal"] - settingKey: "modalCustomAnimationDuration" - text: I18n.tr("Custom Duration") - description: I18n.tr("%1 custom animation duration").arg(I18n.tr("Modals")) - minimum: 0 - maximum: 1000 - value: Theme.modalAnimationDuration - unit: "ms" - defaultValue: 150 - onSliderValueChanged: newValue => { - if (SettingsData.syncComponentAnimationSpeeds) - SettingsData.set("syncComponentAnimationSpeeds", false); - SettingsData.set("modalAnimationSpeed", SettingsData.AnimationSpeed.Custom); - SettingsData.set("modalCustomAnimationDuration", newValue); - } - - Connections { - target: SettingsData - function onModalAnimationSpeedChanged() { - if (SettingsData.modalAnimationSpeed === SettingsData.AnimationSpeed.Custom) - return; - modalDurationSlider.value = Theme.modalAnimationDuration; - } - } - - Connections { - target: Theme - function onModalAnimationDurationChanged() { - if (!SettingsData.syncComponentAnimationSpeeds && SettingsData.modalAnimationSpeed === SettingsData.AnimationSpeed.Custom) - return; - modalDurationSlider.value = Theme.modalAnimationDuration; - } - } - } - } - - SettingsCard { - tab: "typography" - tags: ["animation", "ripple", "effect", "material", "feedback"] - title: I18n.tr("Ripple Effects") - settingKey: "enableRippleEffects" - iconName: "radio_button_unchecked" - - SettingsToggleRow { - tab: "typography" - tags: ["animation", "ripple", "effect", "material", "click"] - settingKey: "enableRippleEffects" - text: I18n.tr("Enable Ripple Effects") - description: I18n.tr("Show Material Design ripple animations on interactive elements") - checked: SettingsData.enableRippleEffects ?? true - onToggled: newValue => SettingsData.set("enableRippleEffects", newValue) - - Connections { - target: SettingsData - function onEnableRippleEffectsChanged() { - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WallpaperTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WallpaperTab.qml deleted file mode 100644 index c0f83c1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WallpaperTab.qml +++ /dev/null @@ -1,1368 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import qs.Common -import qs.Modals.FileBrowser -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var parentModal: null - property string selectedMonitorName: { - var screens = Quickshell.screens; - return screens.length > 0 ? screens[0].name : ""; - } - property string currentWallpaper: { - if (!SessionData.perMonitorWallpaper) - return SessionData.wallpaperPath; - var map = SessionData.monitorWallpapers; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name !== selectedMonitorName) - continue; - var screen = screens[i]; - if (map[screen.name] !== undefined) - return map[screen.name]; - if (screen.model && map[screen.model] !== undefined) - return map[screen.model]; - var displayName = SettingsData.getScreenDisplayName(screen); - if (displayName && map[displayName] !== undefined) - return map[displayName]; - break; - } - return SessionData.wallpaperPath; - } - - Component.onCompleted: { - WallpaperCyclingService.cyclingActive; - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - tab: "wallpaper" - tags: ["background", "image", "picture"] - title: I18n.tr("Wallpaper") - settingKey: "wallpaper" - iconName: "wallpaper" - - Row { - width: parent.width - spacing: Theme.spacingL - - StyledRect { - id: wallpaperPreview - width: 160 - height: 90 - radius: Theme.cornerRadius - color: Theme.surfaceVariant - - Image { - anchors.fill: parent - anchors.margins: 1 - source: { - var wp = root.currentWallpaper; - if (wp === "" || wp.startsWith("#")) - return ""; - if (wp.startsWith("file://")) - wp = wp.substring(7); - return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/'); - } - fillMode: Image.PreserveAspectCrop - visible: root.currentWallpaper !== "" && !root.currentWallpaper.startsWith("#") - sourceSize.width: 160 - sourceSize.height: 160 - asynchronous: true - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskSource: wallpaperMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: root.currentWallpaper.startsWith("#") ? root.currentWallpaper : "transparent" - visible: root.currentWallpaper !== "" && root.currentWallpaper.startsWith("#") - } - - Rectangle { - id: wallpaperMask - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: "black" - visible: false - layer.enabled: true - } - - DankIcon { - anchors.centerIn: parent - name: "image" - size: Theme.iconSizeLarge + 8 - color: Theme.surfaceVariantText - visible: root.currentWallpaper === "" - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: Qt.rgba(0, 0, 0, 0.7) - visible: wallpaperMouseArea.containsMouse - - Row { - anchors.centerIn: parent - spacing: 4 - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "folder_open" - size: 18 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.openMainWallpaperBrowser() - } - } - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "palette" - size: 18 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - PopoutService.colorPickerModal.selectedColor = root.currentWallpaper.startsWith("#") ? root.currentWallpaper : Theme.primary; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Wallpaper Color", "wallpaper color picker title"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorWallpaper(selectedMonitorName, selectedColor); - } else { - SessionData.setWallpaperColor(selectedColor); - } - }; - PopoutService.colorPickerModal.show(); - } - } - } - - Rectangle { - width: 32 - height: 32 - radius: 16 - color: Qt.rgba(255, 255, 255, 0.9) - visible: root.currentWallpaper !== "" - - DankIcon { - anchors.centerIn: parent - name: "clear" - size: 18 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorWallpaper(selectedMonitorName, ""); - } else { - if (Theme.currentTheme === Theme.dynamic) - Theme.switchTheme("blue"); - SessionData.clearWallpaper(); - } - } - } - } - } - } - - MouseArea { - id: wallpaperMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - propagateComposedEvents: true - acceptedButtons: Qt.NoButton - } - } - - Column { - width: parent.width - 160 - Theme.spacingL - spacing: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: root.currentWallpaper ? root.currentWallpaper.split('/').pop() : I18n.tr("No wallpaper selected") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: root.currentWallpaper - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - horizontalAlignment: Text.AlignLeft - visible: root.currentWallpaper !== "" - } - - Row { - anchors.left: parent.left - spacing: Theme.spacingS - layoutDirection: I18n.isRtl ? Qt.RightToLeft : Qt.LeftToRight - visible: root.currentWallpaper !== "" - - DankActionButton { - buttonSize: 32 - iconName: "skip_previous" - iconSize: Theme.iconSizeSmall - enabled: root.currentWallpaper && !root.currentWallpaper.startsWith("#") && !root.currentWallpaper.startsWith("we") - opacity: enabled ? 1 : 0.5 - backgroundColor: Theme.surfaceContainerHigh - iconColor: Theme.surfaceText - onClicked: { - if (SessionData.perMonitorWallpaper) { - WallpaperCyclingService.cyclePrevForMonitor(selectedMonitorName); - } else { - WallpaperCyclingService.cyclePrevManually(); - } - } - } - - DankActionButton { - buttonSize: 32 - iconName: "skip_next" - iconSize: Theme.iconSizeSmall - enabled: root.currentWallpaper && !root.currentWallpaper.startsWith("#") && !root.currentWallpaper.startsWith("we") - opacity: enabled ? 1 : 0.5 - backgroundColor: Theme.surfaceContainerHigh - iconColor: Theme.surfaceText - onClicked: { - if (SessionData.perMonitorWallpaper) { - WallpaperCyclingService.cycleNextForMonitor(selectedMonitorName); - } else { - WallpaperCyclingService.cycleNextManually(); - } - } - } - } - } - } - - Item { - width: parent.width - height: fillModeGroup.height - visible: root.currentWallpaper !== "" && !root.currentWallpaper.startsWith("#") - - DankButtonGroup { - id: fillModeGroup - property var internalModes: ["Stretch", "Fit", "Fill", "Tile", "TileVertically", "TileHorizontally", "Pad"] - anchors.horizontalCenter: parent.horizontalCenter - model: [I18n.tr("Stretch", "wallpaper fill mode"), I18n.tr("Fit", "wallpaper fill mode"), I18n.tr("Fill", "wallpaper fill mode"), I18n.tr("Tile", "wallpaper fill mode"), I18n.tr("Tile V", "wallpaper fill mode"), I18n.tr("Tile H", "wallpaper fill mode"), I18n.tr("Pad", "wallpaper fill mode")] - selectionMode: "single" - buttonHeight: 28 - minButtonWidth: 48 - buttonPadding: Theme.spacingS - checkIconSize: 0 - textSize: Theme.fontSizeSmall - checkEnabled: false - currentIndex: { - var mode = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaperFillMode(selectedMonitorName) : SettingsData.wallpaperFillMode; - return internalModes.indexOf(mode); - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorWallpaperFillMode(selectedMonitorName, internalModes[index]); - } else { - SettingsData.set("wallpaperFillMode", internalModes[index]); - } - } - - Connections { - target: SettingsData - function onWallpaperFillModeChanged() { - if (SessionData.perMonitorWallpaper) - return; - fillModeGroup.currentIndex = fillModeGroup.internalModes.indexOf(SettingsData.wallpaperFillMode); - } - } - - Connections { - target: root - function onSelectedMonitorNameChanged() { - if (!SessionData.perMonitorWallpaper) - return; - fillModeGroup.currentIndex = Qt.binding(() => { - var mode = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaperFillMode(selectedMonitorName) : SettingsData.wallpaperFillMode; - return fillModeGroup.internalModes.indexOf(mode); - }); - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: SessionData.wallpaperPath !== "" - } - - SettingsToggleRow { - tab: "wallpaper" - tags: ["per-mode", "light", "dark", "theme"] - settingKey: "perModeWallpaper" - visible: SessionData.wallpaperPath !== "" - text: I18n.tr("Per-Mode Wallpapers") - description: I18n.tr("Set different wallpapers for light and dark mode") - checked: SessionData.perModeWallpaper - onToggled: toggled => SessionData.setPerModeWallpaper(toggled) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.perModeWallpaper - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - - Row { - width: parent.width - Theme.spacingM * 2 - spacing: Theme.spacingL - - Column { - width: (parent.width - Theme.spacingL) / 2 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Light Mode") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledRect { - width: parent.width - height: width * 9 / 16 - radius: Theme.cornerRadius - color: Theme.surfaceVariant - - Image { - anchors.fill: parent - anchors.margins: 1 - source: { - var wp = SessionData.wallpaperPathLight; - if (wp === "" || wp.startsWith("#")) - return ""; - if (wp.startsWith("file://")) - wp = wp.substring(7); - return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/'); - } - fillMode: Image.PreserveAspectCrop - visible: { - var lightWallpaper = SessionData.wallpaperPathLight; - return lightWallpaper !== "" && !lightWallpaper.startsWith("#"); - } - sourceSize.width: 160 - sourceSize.height: 160 - asynchronous: true - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskSource: lightMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: { - var lightWallpaper = SessionData.wallpaperPathLight; - return lightWallpaper.startsWith("#") ? lightWallpaper : "transparent"; - } - visible: { - var lightWallpaper = SessionData.wallpaperPathLight; - return lightWallpaper !== "" && lightWallpaper.startsWith("#"); - } - } - - Rectangle { - id: lightMask - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: "black" - visible: false - layer.enabled: true - } - - DankIcon { - anchors.centerIn: parent - name: "light_mode" - size: Theme.iconSizeLarge - color: Theme.surfaceVariantText - visible: SessionData.wallpaperPathLight === "" - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: Qt.rgba(0, 0, 0, 0.7) - visible: lightModeMouseArea.containsMouse - - Row { - anchors.centerIn: parent - spacing: 4 - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "folder_open" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.openLightWallpaperBrowser() - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "palette" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - var lightWallpaper = SessionData.wallpaperPathLight; - PopoutService.colorPickerModal.selectedColor = lightWallpaper.startsWith("#") ? lightWallpaper : Theme.primary; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Light Mode Color", "light mode wallpaper color picker title"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - SessionData.wallpaperPathLight = selectedColor; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - }; - PopoutService.colorPickerModal.show(); - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - visible: SessionData.wallpaperPathLight !== "" - - DankIcon { - anchors.centerIn: parent - name: "clear" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - SessionData.wallpaperPathLight = ""; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - } - } - } - } - } - - MouseArea { - id: lightModeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - propagateComposedEvents: true - acceptedButtons: Qt.NoButton - } - } - - StyledText { - text: { - var lightWallpaper = SessionData.wallpaperPathLight; - return lightWallpaper ? lightWallpaper.split('/').pop() : I18n.tr("Not set", "wallpaper not set label"); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - } - } - - Column { - width: (parent.width - Theme.spacingL) / 2 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Dark Mode") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledRect { - width: parent.width - height: width * 9 / 16 - radius: Theme.cornerRadius - color: Theme.surfaceVariant - - Image { - anchors.fill: parent - anchors.margins: 1 - source: { - var wp = SessionData.wallpaperPathDark; - if (wp === "" || wp.startsWith("#")) - return ""; - if (wp.startsWith("file://")) - wp = wp.substring(7); - return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/'); - } - fillMode: Image.PreserveAspectCrop - visible: { - var darkWallpaper = SessionData.wallpaperPathDark; - return darkWallpaper !== "" && !darkWallpaper.startsWith("#"); - } - sourceSize.width: 160 - sourceSize.height: 160 - asynchronous: true - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskSource: darkMask - maskThresholdMin: 0.5 - maskSpreadAtMin: 1 - } - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: { - var darkWallpaper = SessionData.wallpaperPathDark; - return darkWallpaper.startsWith("#") ? darkWallpaper : "transparent"; - } - visible: { - var darkWallpaper = SessionData.wallpaperPathDark; - return darkWallpaper !== "" && darkWallpaper.startsWith("#"); - } - } - - Rectangle { - id: darkMask - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: "black" - visible: false - layer.enabled: true - } - - DankIcon { - anchors.centerIn: parent - name: "dark_mode" - size: Theme.iconSizeLarge - color: Theme.surfaceVariantText - visible: SessionData.wallpaperPathDark === "" - } - - Rectangle { - anchors.fill: parent - anchors.margins: 1 - radius: Theme.cornerRadius - 1 - color: Qt.rgba(0, 0, 0, 0.7) - visible: darkModeMouseArea.containsMouse - - Row { - anchors.centerIn: parent - spacing: 4 - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "folder_open" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.openDarkWallpaperBrowser() - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - - DankIcon { - anchors.centerIn: parent - name: "palette" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (!PopoutService.colorPickerModal) - return; - var darkWallpaper = SessionData.wallpaperPathDark; - PopoutService.colorPickerModal.selectedColor = darkWallpaper.startsWith("#") ? darkWallpaper : Theme.primary; - PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Dark Mode Color", "dark mode wallpaper color picker title"); - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - SessionData.wallpaperPathDark = selectedColor; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - }; - PopoutService.colorPickerModal.show(); - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: 14 - color: Qt.rgba(255, 255, 255, 0.9) - visible: SessionData.wallpaperPathDark !== "" - - DankIcon { - anchors.centerIn: parent - name: "clear" - size: 16 - color: "black" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - SessionData.wallpaperPathDark = ""; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - } - } - } - } - } - - MouseArea { - id: darkModeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - propagateComposedEvents: true - acceptedButtons: Qt.NoButton - } - } - - StyledText { - text: { - var darkWallpaper = SessionData.wallpaperPathDark; - return darkWallpaper ? darkWallpaper.split('/').pop() : I18n.tr("Not set", "wallpaper not set label"); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideMiddle - maximumLineCount: 1 - width: parent.width - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: CompositorService.isNiri - } - - SettingsToggleRow { - tab: "wallpaper" - tags: ["blur", "overview", "niri"] - settingKey: "blurWallpaperOnOverview" - visible: CompositorService.isNiri - text: I18n.tr("Blur on Overview") - description: I18n.tr("Blur wallpaper when niri overview is open") - checked: SettingsData.blurWallpaperOnOverview - onToggled: checked => SettingsData.set("blurWallpaperOnOverview", checked) - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: SessionData.wallpaperPath !== "" - } - - SettingsToggleRow { - tab: "wallpaper" - tags: ["per-monitor", "multi-monitor", "display"] - settingKey: "perMonitorWallpaper" - visible: SessionData.wallpaperPath !== "" - text: I18n.tr("Per-Monitor Wallpapers") - description: I18n.tr("Set different wallpapers for each connected monitor") - checked: SessionData.perMonitorWallpaper - onToggled: toggled => SessionData.setPerMonitorWallpaper(toggled) - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.perMonitorWallpaper - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - - SettingsDropdownRow { - tab: "wallpaper" - tags: ["monitor", "display", "screen"] - settingKey: "selectedMonitor" - width: parent.width - Theme.spacingM * 2 - text: I18n.tr("Wallpaper Monitor") - description: I18n.tr("Select monitor to configure wallpaper") - currentValue: { - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === selectedMonitorName) { - return SettingsData.getScreenDisplayName(screens[i]); - } - } - return I18n.tr("No monitors", "no monitors available label"); - } - options: { - var screenNames = []; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - screenNames.push(SettingsData.getScreenDisplayName(screens[i])); - } - return screenNames; - } - onValueChanged: value => { - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (SettingsData.getScreenDisplayName(screens[i]) === value) { - selectedMonitorName = screens[i].name; - return; - } - } - } - } - - SettingsDropdownRow { - tab: "wallpaper" - tags: ["matugen", "target", "monitor", "theming"] - settingKey: "matugenTargetMonitor" - width: parent.width - Theme.spacingM * 2 - text: I18n.tr("Matugen Target Monitor") - description: I18n.tr("Monitor whose wallpaper drives dynamic theming colors") - currentValue: { - var screens = Quickshell.screens; - if (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "") { - return screens.length > 0 ? SettingsData.getScreenDisplayName(screens[0]) + " " + I18n.tr("(Default)", "default monitor label suffix") : I18n.tr("No monitors", "no monitors available label"); - } - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === SettingsData.matugenTargetMonitor) { - return SettingsData.getScreenDisplayName(screens[i]); - } - } - return SettingsData.matugenTargetMonitor; - } - options: { - var screenNames = []; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - var label = SettingsData.getScreenDisplayName(screens[i]); - if (i === 0 && (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "")) { - label += " " + I18n.tr("(Default)", "default monitor label suffix"); - } - screenNames.push(label); - } - return screenNames; - } - onValueChanged: value => { - var cleanValue = value.replace(" " + I18n.tr("(Default)", "default monitor label suffix"), ""); - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (SettingsData.getScreenDisplayName(screens[i]) === cleanValue) { - SettingsData.setMatugenTargetMonitor(screens[i].name); - return; - } - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - visible: (SessionData.wallpaperPath !== "" || SessionData.perMonitorWallpaper) && !SessionData.perModeWallpaper - } - - SettingsToggleRow { - id: cyclingToggle - tab: "wallpaper" - tags: ["cycling", "automatic", "rotate", "slideshow"] - settingKey: "wallpaperCyclingEnabled" - visible: (SessionData.wallpaperPath !== "" || SessionData.perMonitorWallpaper) && !SessionData.perModeWallpaper - text: I18n.tr("Automatic Cycling") - description: I18n.tr("Automatically cycle through wallpapers in the same folder") - checked: SessionData.perMonitorWallpaper ? SessionData.getMonitorCyclingSettings(selectedMonitorName).enabled : SessionData.wallpaperCyclingEnabled - onToggled: toggled => { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorCyclingEnabled(selectedMonitorName, toggled); - } else { - SessionData.setWallpaperCyclingEnabled(toggled); - } - } - - Connections { - target: root - function onSelectedMonitorNameChanged() { - cyclingToggle.checked = Qt.binding(() => { - return SessionData.perMonitorWallpaper ? SessionData.getMonitorCyclingSettings(selectedMonitorName).enabled : SessionData.wallpaperCyclingEnabled; - }); - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - visible: SessionData.perMonitorWallpaper ? SessionData.getMonitorCyclingSettings(selectedMonitorName).enabled : SessionData.wallpaperCyclingEnabled - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - - Row { - spacing: Theme.spacingL - width: parent.width - Theme.spacingM * 2 - - StyledText { - text: I18n.tr("Mode:") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: 200 - height: 45 + Theme.spacingM - - DankTabBar { - id: modeTabBar - width: 200 - height: 45 - model: [ - { - "text": I18n.tr("Interval", "wallpaper cycling mode tab"), - "icon": "schedule" - }, - { - "text": I18n.tr("Time", "wallpaper cycling mode tab"), - "icon": "access_time" - } - ] - currentIndex: { - if (SessionData.perMonitorWallpaper) { - return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "time" ? 1 : 0; - } - return SessionData.wallpaperCyclingMode === "time" ? 1 : 0; - } - onTabClicked: index => { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorCyclingMode(selectedMonitorName, index === 1 ? "time" : "interval"); - } else { - SessionData.setWallpaperCyclingMode(index === 1 ? "time" : "interval"); - } - } - - Connections { - target: root - function onSelectedMonitorNameChanged() { - modeTabBar.currentIndex = Qt.binding(() => { - if (SessionData.perMonitorWallpaper) { - return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "time" ? 1 : 0; - } - return SessionData.wallpaperCyclingMode === "time" ? 1 : 0; - }); - Qt.callLater(modeTabBar.updateIndicator); - } - } - } - } - } - - SettingsDropdownRow { - id: intervalDropdown - property var intervalOptions: [I18n.tr("5 seconds", "wallpaper interval"), I18n.tr("10 seconds", "wallpaper interval"), I18n.tr("15 seconds", "wallpaper interval"), I18n.tr("20 seconds", "wallpaper interval"), I18n.tr("25 seconds", "wallpaper interval"), I18n.tr("30 seconds", "wallpaper interval"), I18n.tr("35 seconds", "wallpaper interval"), I18n.tr("40 seconds", "wallpaper interval"), I18n.tr("45 seconds", "wallpaper interval"), I18n.tr("50 seconds", "wallpaper interval"), I18n.tr("55 seconds", "wallpaper interval"), I18n.tr("1 minute", "wallpaper interval"), I18n.tr("5 minutes", "wallpaper interval"), I18n.tr("15 minutes", "wallpaper interval"), I18n.tr("30 minutes", "wallpaper interval"), I18n.tr("1 hour", "wallpaper interval"), I18n.tr("1 hour 30 minutes", "wallpaper interval"), I18n.tr("2 hours", "wallpaper interval"), I18n.tr("3 hours", "wallpaper interval"), I18n.tr("4 hours", "wallpaper interval"), I18n.tr("6 hours", "wallpaper interval"), I18n.tr("8 hours", "wallpaper interval"), I18n.tr("12 hours", "wallpaper interval")] - - property var intervalValues: [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 300, 900, 1800, 3600, 5400, 7200, 10800, 14400, 21600, 28800, 43200] - tab: "wallpaper" - tags: ["interval", "cycling", "time", "frequency"] - settingKey: "wallpaperCyclingInterval" - width: parent.width - Theme.spacingM * 2 - visible: { - if (SessionData.perMonitorWallpaper) { - return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "interval"; - } - return SessionData.wallpaperCyclingMode === "interval"; - } - text: I18n.tr("Interval") - description: I18n.tr("How often to change wallpaper") - options: intervalOptions - currentValue: { - var currentSeconds; - if (SessionData.perMonitorWallpaper) { - currentSeconds = SessionData.getMonitorCyclingSettings(selectedMonitorName).interval; - } else { - currentSeconds = SessionData.wallpaperCyclingInterval; - } - const index = intervalValues.indexOf(currentSeconds); - return index >= 0 ? intervalOptions[index] : I18n.tr("5 minutes", "wallpaper interval"); - } - onValueChanged: value => { - const index = intervalOptions.indexOf(value); - if (index < 0) - return; - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorCyclingInterval(selectedMonitorName, intervalValues[index]); - } else { - SessionData.setWallpaperCyclingInterval(intervalValues[index]); - } - } - - Connections { - target: root - function onSelectedMonitorNameChanged() { - Qt.callLater(() => { - var currentSeconds; - if (SessionData.perMonitorWallpaper) { - currentSeconds = SessionData.getMonitorCyclingSettings(selectedMonitorName).interval; - } else { - currentSeconds = SessionData.wallpaperCyclingInterval; - } - const index = intervalDropdown.intervalValues.indexOf(currentSeconds); - intervalDropdown.currentValue = index >= 0 ? intervalDropdown.intervalOptions[index] : I18n.tr("5 minutes", "wallpaper interval"); - }); - } - } - } - - Row { - spacing: Theme.spacingM - visible: { - if (SessionData.perMonitorWallpaper) { - return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "time"; - } - return SessionData.wallpaperCyclingMode === "time"; - } - width: parent.width - Theme.spacingM * 2 - - StyledText { - text: I18n.tr("Daily at:") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - id: timeTextField - width: 100 - height: 40 - text: { - if (SessionData.perMonitorWallpaper) { - return SessionData.getMonitorCyclingSettings(selectedMonitorName).time; - } - return SessionData.wallpaperCyclingTime; - } - placeholderText: "00:00" - maximumLength: 5 - topPadding: Theme.spacingS - bottomPadding: Theme.spacingS - onAccepted: { - var isValid = /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/.test(text); - if (isValid) { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorCyclingTime(selectedMonitorName, text); - } else { - SessionData.setWallpaperCyclingTime(text); - } - } else { - if (SessionData.perMonitorWallpaper) { - text = SessionData.getMonitorCyclingSettings(selectedMonitorName).time; - } else { - text = SessionData.wallpaperCyclingTime; - } - } - } - onEditingFinished: { - var isValid = /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/.test(text); - if (isValid) { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorCyclingTime(selectedMonitorName, text); - } else { - SessionData.setWallpaperCyclingTime(text); - } - } else { - if (SessionData.perMonitorWallpaper) { - text = SessionData.getMonitorCyclingSettings(selectedMonitorName).time; - } else { - text = SessionData.wallpaperCyclingTime; - } - } - } - anchors.verticalCenter: parent.verticalCenter - - validator: RegularExpressionValidator { - regularExpression: /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/ - } - - Connections { - target: root - function onSelectedMonitorNameChanged() { - Qt.callLater(() => { - if (SessionData.perMonitorWallpaper) { - timeTextField.text = SessionData.getMonitorCyclingSettings(selectedMonitorName).time; - } else { - timeTextField.text = SessionData.wallpaperCyclingTime; - } - }); - } - } - } - - StyledText { - text: I18n.tr("24-hour format") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - } - - SettingsDropdownRow { - tab: "wallpaper" - tags: ["transition", "effect", "animation", "change"] - settingKey: "wallpaperTransition" - text: I18n.tr("Transition Effect") - description: I18n.tr("Visual effect used when wallpaper changes") - - function getTransitionLabel(t) { - switch (t) { - case "random": - return I18n.tr("Random", "wallpaper transition option"); - case "none": - return I18n.tr("None", "wallpaper transition option"); - case "fade": - return I18n.tr("Fade", "wallpaper transition option"); - case "wipe": - return I18n.tr("Wipe", "wallpaper transition option"); - case "disc": - return I18n.tr("Disc", "wallpaper transition option"); - case "stripes": - return I18n.tr("Stripes", "wallpaper transition option"); - case "iris bloom": - return I18n.tr("Iris Bloom", "wallpaper transition option"); - case "pixelate": - return I18n.tr("Pixelate", "wallpaper transition option"); - case "portal": - return I18n.tr("Portal", "wallpaper transition option"); - default: - return t.charAt(0).toUpperCase() + t.slice(1); - } - } - - currentValue: getTransitionLabel(SessionData.wallpaperTransition) - options: [I18n.tr("Random", "wallpaper transition option")].concat(SessionData.availableWallpaperTransitions.map(t => getTransitionLabel(t))) - onValueChanged: value => { - const transitionMap = {}; - transitionMap[I18n.tr("Random", "wallpaper transition option")] = "random"; - SessionData.availableWallpaperTransitions.forEach(t => { - transitionMap[getTransitionLabel(t)] = t; - }); - SessionData.setWallpaperTransition(transitionMap[value] || value.toLowerCase()); - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: SessionData.wallpaperTransition === "random" - leftPadding: Theme.spacingM - rightPadding: Theme.spacingM - - StyledText { - text: I18n.tr("Include Transitions") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - StyledText { - text: I18n.tr("Select which transitions to include in randomization") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - Theme.spacingM * 2 - } - - DankButtonGroup { - id: transitionGroup - width: parent.width - Theme.spacingM * 2 - selectionMode: "multi" - model: SessionData.availableWallpaperTransitions.filter(t => t !== "none") - initialSelection: SessionData.includedTransitions - currentSelection: SessionData.includedTransitions - - onSelectionChanged: (index, selected) => { - const transition = model[index]; - let newIncluded = SessionData.includedTransitions.slice(); - - if (selected && !newIncluded.includes(transition)) { - newIncluded.push(transition); - } else if (!selected && newIncluded.includes(transition)) { - newIncluded = newIncluded.filter(t => t !== transition); - } - - SessionData.includedTransitions = newIncluded; - } - } - } - } - - SettingsCard { - tab: "wallpaper" - tags: ["external", "disable", "swww", "hyprpaper", "swaybg"] - title: I18n.tr("External Wallpaper Management", "wallpaper settings external management") - settingKey: "disableWallpaper" - iconName: "wallpaper" - - SettingsToggleRow { - tab: "wallpaper" - tags: ["disable", "external", "management"] - settingKey: "disableWallpapers" - text: I18n.tr("Disable Built-in Wallpapers", "wallpaper settings disable toggle") - description: I18n.tr("Use an external wallpaper manager like swww, hyprpaper, or swaybg.", "wallpaper settings disable description") - checked: { - var prefs = SettingsData.screenPreferences?.wallpaper; - if (!prefs) - return false; - if (Array.isArray(prefs) && prefs.length === 0) - return true; - return false; - } - onToggled: checked => { - var prefs = SettingsData.screenPreferences || {}; - var newPrefs = Object.assign({}, prefs); - newPrefs.wallpaper = checked ? [] : ["all"]; - SettingsData.set("screenPreferences", newPrefs); - } - } - } - - SettingsCard { - tab: "wallpaper" - tags: ["blur", "layer", "niri", "compositor"] - title: I18n.tr("Blur Wallpaper Layer") - settingKey: "blurWallpaper" - visible: CompositorService.isNiri - - SettingsToggleRow { - tab: "wallpaper" - tags: ["blur", "duplicate", "layer", "compositor"] - settingKey: "blurredWallpaperLayer" - text: I18n.tr("Duplicate Wallpaper with Blur") - description: I18n.tr("Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.") - checked: SettingsData.blurredWallpaperLayer - onToggled: checked => SettingsData.set("blurredWallpaperLayer", checked) - } - } - } - } - - function openMainWallpaperBrowser() { - mainWallpaperBrowserLoader.active = true; - if (mainWallpaperBrowserLoader.item) - mainWallpaperBrowserLoader.item.open(); - } - - function openLightWallpaperBrowser() { - lightWallpaperBrowserLoader.active = true; - if (lightWallpaperBrowserLoader.item) - lightWallpaperBrowserLoader.item.open(); - } - - function openDarkWallpaperBrowser() { - darkWallpaperBrowserLoader.active = true; - if (darkWallpaperBrowserLoader.item) - darkWallpaperBrowserLoader.item.open(); - } - - LazyLoader { - id: mainWallpaperBrowserLoader - active: false - - FileBrowserModal { - parentModal: root.parentModal - browserTitle: I18n.tr("Select Wallpaper", "wallpaper file browser title") - browserIcon: "wallpaper" - browserType: "wallpaper" - showHiddenFiles: true - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - onFileSelected: path => { - if (SessionData.perMonitorWallpaper) { - SessionData.setMonitorWallpaper(selectedMonitorName, path); - } else { - SessionData.setWallpaper(path); - } - close(); - } - } - } - - LazyLoader { - id: lightWallpaperBrowserLoader - active: false - - FileBrowserModal { - parentModal: root.parentModal - browserTitle: I18n.tr("Select Wallpaper", "light mode wallpaper file browser title") - browserIcon: "light_mode" - browserType: "wallpaper" - showHiddenFiles: true - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - onFileSelected: path => { - SessionData.wallpaperPathLight = path; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - close(); - } - } - } - - LazyLoader { - id: darkWallpaperBrowserLoader - active: false - - FileBrowserModal { - parentModal: root.parentModal - browserTitle: I18n.tr("Select Wallpaper", "dark mode wallpaper file browser title") - browserIcon: "dark_mode" - browserType: "wallpaper" - showHiddenFiles: true - fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"] - onFileSelected: path => { - SessionData.wallpaperPathDark = path; - SessionData.syncWallpaperForCurrentMode(); - SessionData.saveSettings(); - close(); - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetSelectionPopup.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetSelectionPopup.qml deleted file mode 100644 index 817e980..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetSelectionPopup.qml +++ /dev/null @@ -1,382 +0,0 @@ -import QtQuick -import Quickshell -import qs.Common -import qs.Widgets - -FloatingWindow { - id: root - - property bool disablePopupTransparency: true - property var allWidgets: [] - property string targetSection: "" - property string searchQuery: "" - property var filteredWidgets: [] - property int selectedIndex: -1 - property bool keyboardNavigationActive: false - property var parentModal: null - - signal widgetSelected(string widgetId, string targetSection) - - function updateFilteredWidgets() { - if (!searchQuery || searchQuery.length === 0) { - filteredWidgets = allWidgets.slice(); - return; - } - - var filtered = []; - var query = searchQuery.toLowerCase(); - - for (var i = 0; i < allWidgets.length; i++) { - var widget = allWidgets[i]; - var text = widget.text ? widget.text.toLowerCase() : ""; - var description = widget.description ? widget.description.toLowerCase() : ""; - var id = widget.id ? widget.id.toLowerCase() : ""; - - if (text.indexOf(query) !== -1 || description.indexOf(query) !== -1 || id.indexOf(query) !== -1) - filtered.push(widget); - } - - filteredWidgets = filtered; - selectedIndex = -1; - keyboardNavigationActive = false; - } - - onAllWidgetsChanged: { - updateFilteredWidgets(); - } - - function selectNext() { - if (filteredWidgets.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.min(selectedIndex + 1, filteredWidgets.length - 1); - } - - function selectPrevious() { - if (filteredWidgets.length === 0) - return; - keyboardNavigationActive = true; - selectedIndex = Math.max(selectedIndex - 1, -1); - if (selectedIndex === -1) - keyboardNavigationActive = false; - } - - function selectWidget() { - if (selectedIndex < 0 || selectedIndex >= filteredWidgets.length) - return; - var widget = filteredWidgets[selectedIndex]; - root.widgetSelected(widget.id, root.targetSection); - root.hide(); - } - - function show() { - if (parentModal) - parentModal.shouldHaveFocus = false; - visible = true; - Qt.callLater(() => { - searchField.forceActiveFocus(); - }); - } - - function hide() { - visible = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal && parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - objectName: "widgetSelectionPopup" - title: I18n.tr("Add Widget") - minimumSize: Qt.size(400, 350) - implicitWidth: 500 - implicitHeight: 550 - color: Theme.surfaceContainer - visible: false - - onVisibleChanged: { - if (visible) { - Qt.callLater(() => { - searchField.forceActiveFocus(); - }); - return; - } - allWidgets = []; - targetSection = ""; - searchQuery = ""; - filteredWidgets = []; - selectedIndex = -1; - keyboardNavigationActive = false; - if (!parentModal) - return; - parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible); - Qt.callLater(() => { - if (parentModal && parentModal.modalFocusScope) - parentModal.modalFocusScope.forceActiveFocus(); - }); - } - - FocusScope { - id: widgetKeyHandler - - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - switch (event.key) { - case Qt.Key_Escape: - root.hide(); - event.accepted = true; - return; - case Qt.Key_Down: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_Up: - root.selectPrevious(); - event.accepted = true; - return; - case Qt.Key_Return: - case Qt.Key_Enter: - if (root.keyboardNavigationActive) { - root.selectWidget(); - } else if (root.filteredWidgets.length > 0) { - var firstWidget = root.filteredWidgets[0]; - root.widgetSelected(firstWidget.id, root.targetSection); - root.hide(); - } - event.accepted = true; - return; - } - if (event.modifiers & Qt.ControlModifier) { - switch (event.key) { - case Qt.Key_N: - case Qt.Key_J: - root.selectNext(); - event.accepted = true; - return; - case Qt.Key_P: - case Qt.Key_K: - root.selectPrevious(); - event.accepted = true; - return; - } - } - } - - Column { - anchors.fill: parent - spacing: 0 - - Item { - id: titleBar - width: parent.width - height: 48 - - MouseArea { - anchors.fill: parent - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - - Rectangle { - anchors.fill: parent - color: Theme.surfaceContainer - opacity: 0.5 - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "add_circle" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Add Widget to %1 Section").arg(root.targetSection) - font.pixelSize: Theme.fontSizeXLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - visible: windowControls.supported - circular: false - iconName: root.maximized ? "fullscreen_exit" : "fullscreen" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: windowControls.tryToggleMaximize() - } - - DankActionButton { - circular: false - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: root.hide() - } - } - } - - Item { - width: parent.width - height: parent.height - titleBar.height - - Column { - id: contentColumn - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Select a widget to add. You can add multiple instances of the same widget if needed.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - width: parent.width - wrapMode: Text.WordWrap - } - - DankTextField { - id: searchField - width: parent.width - height: 48 - cornerRadius: Theme.cornerRadius - backgroundColor: Theme.surfaceContainerHigh - normalBorderColor: Theme.outlineMedium - focusedBorderColor: Theme.primary - leftIconName: "search" - leftIconSize: Theme.iconSize - leftIconColor: Theme.surfaceVariantText - leftIconFocusedColor: Theme.primary - showClearButton: true - textColor: Theme.surfaceText - font.pixelSize: Theme.fontSizeMedium - placeholderText: I18n.tr("Search widgets...") - text: root.searchQuery - focus: true - ignoreLeftRightKeys: true - keyForwardTargets: [widgetKeyHandler] - onTextEdited: { - root.searchQuery = text; - updateFilteredWidgets(); - } - Keys.onPressed: event => { - if (event.key === Qt.Key_Escape) { - root.hide(); - event.accepted = true; - return; - } - if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) - event.accepted = false; - } - } - - DankListView { - id: widgetList - - width: parent.width - height: parent.height - y - spacing: Theme.spacingS - model: root.filteredWidgets - clip: true - - delegate: Rectangle { - width: widgetList.width - height: 60 - radius: Theme.cornerRadius - property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex - color: isSelected ? Theme.primarySelected : widgetArea.containsMouse ? Theme.primaryHover : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) - border.color: isSelected ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: isSelected ? 2 : 1 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: modelData.icon - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - width: parent.width - Theme.iconSize - Theme.spacingM * 3 - - StyledText { - text: modelData.text - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - } - - StyledText { - text: modelData.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - elide: Text.ElideRight - width: parent.width - wrapMode: Text.WordWrap - } - } - - DankIcon { - name: "add" - size: Theme.iconSize - 4 - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: widgetArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.widgetSelected(modelData.id, root.targetSection); - root.hide(); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } - } - - FloatingWindowControls { - id: windowControls - targetWindow: root - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/DeviceAliasRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/DeviceAliasRow.qml deleted file mode 100644 index bec5ff1..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/DeviceAliasRow.qml +++ /dev/null @@ -1,180 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - required property var deviceNode - property string deviceType: "output" - - property bool showHideButton: false - property bool isHidden: false - - signal editRequested(var deviceNode) - signal resetRequested(var deviceNode) - signal hideRequested(var deviceNode) - - width: parent?.width ?? 0 - height: deviceRowContent.height + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: deviceMouseArea.containsMouse ? Theme.surfaceHover : "transparent" - - readonly property bool hasCustomAlias: AudioService.hasDeviceAlias(deviceNode?.name ?? "") - readonly property string displayedName: AudioService.displayName(deviceNode) - - Row { - id: deviceRowContent - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: root.deviceType === "input" ? "mic" : "speaker" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.iconSize - Theme.spacingM * 3 - buttonsRow.width - spacing: 2 - - StyledText { - text: root.displayedName - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - elide: Text.ElideRight - horizontalAlignment: Text.AlignLeft - } - - Column { - width: parent.width - spacing: 2 - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: root.deviceNode?.name ?? "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - (customAliasLabel.visible ? customAliasLabel.width + Theme.spacingS : 0) - elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignLeft - } - - Rectangle { - id: customAliasLabel - visible: root.hasCustomAlias - height: customAliasText.implicitHeight + 4 - width: customAliasText.implicitWidth + Theme.spacingS * 2 - radius: 3 - color: Theme.withAlpha(Theme.primary, 0.15) - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: customAliasText - text: I18n.tr("Custom") - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.primary - font.weight: Font.Medium - anchors.centerIn: parent - } - } - } - - StyledText { - visible: root.hasCustomAlias - text: I18n.tr("Original: %1").arg(AudioService.originalName(root.deviceNode)) - font.pixelSize: Theme.fontSizeSmall - 1 - color: Theme.surfaceVariantText - width: parent.width - elide: Text.ElideRight - opacity: 0.6 - horizontalAlignment: Text.AlignLeft - } - } - } - - Row { - id: buttonsRow - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankActionButton { - id: resetButton - visible: root.hasCustomAlias - buttonSize: 36 - iconName: "restart_alt" - iconSize: 20 - backgroundColor: Theme.surfaceContainerHigh - iconColor: Theme.surfaceVariantText - tooltipText: I18n.tr("Reset to default name") - anchors.verticalCenter: parent.verticalCenter - onClicked: { - root.resetRequested(root.deviceNode); - } - } - - DankActionButton { - id: hideButton - visible: root.showHideButton - buttonSize: 36 - iconName: root.isHidden ? "visibility" : "visibility_off" - iconSize: 20 - backgroundColor: Theme.surfaceContainerHigh - iconColor: root.isHidden ? Theme.primary : Theme.surfaceVariantText - tooltipText: root.isHidden ? I18n.tr("Show device") : I18n.tr("Hide device") - anchors.verticalCenter: parent.verticalCenter - onClicked: { - root.hideRequested(root.deviceNode); - } - } - - DankActionButton { - id: editButton - buttonSize: 36 - iconName: "edit" - iconSize: 20 - backgroundColor: Theme.buttonBg - iconColor: Theme.buttonText - tooltipText: I18n.tr("Set custom name") - anchors.verticalCenter: parent.verticalCenter - visible: !root.isHidden - onClicked: { - root.editRequested(root.deviceNode); - } - } - } - } - - MouseArea { - id: deviceMouseArea - anchors.fill: parent - hoverEnabled: true - propagateComposedEvents: true - z: -1 - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml deleted file mode 100644 index 5e49936..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml +++ /dev/null @@ -1,117 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - property string settingKey: "" - - property string text: "" - property string description: "" - - readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey - - function findParentFlickable() { - let p = root.parent; - while (p) { - if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) - return p; - p = p.parent; - } - return null; - } - - Component.onCompleted: { - if (!settingKey) - return; - let flickable = findParentFlickable(); - if (flickable) - SettingsSearchService.registerCard(settingKey, root, flickable); - } - - Component.onDestruction: { - if (settingKey) - SettingsSearchService.unregisterCard(settingKey); - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0) - visible: root.isHighlighted - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - property alias model: buttonGroup.model - property alias currentIndex: buttonGroup.currentIndex - property alias selectionMode: buttonGroup.selectionMode - property alias buttonHeight: buttonGroup.buttonHeight - property alias minButtonWidth: buttonGroup.minButtonWidth - property alias buttonPadding: buttonGroup.buttonPadding - property alias checkIconSize: buttonGroup.checkIconSize - property alias textSize: buttonGroup.textSize - property alias spacing: buttonGroup.spacing - property alias checkEnabled: buttonGroup.checkEnabled - - signal selectionChanged(int index, bool selected) - - width: parent?.width ?? 0 - height: 60 - - Row { - id: contentRow - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - Column { - width: parent.width - buttonGroup.width - Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: root.text - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - visible: root.text !== "" - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - visible: root.description !== "" - horizontalAlignment: Text.AlignLeft - } - } - - DankButtonGroup { - id: buttonGroup - anchors.verticalCenter: parent.verticalCenter - selectionMode: "single" - onSelectionChanged: (index, selected) => root.selectionChanged(index, selected) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsCard.qml deleted file mode 100644 index 65642a0..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsCard.qml +++ /dev/null @@ -1,199 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - property string settingKey: "" - - property string title: "" - property string iconName: "" - property bool collapsible: false - property bool expanded: true - property real headerLeftPadding: 0 - - default property alias content: contentColumn.children - property alias headerActions: headerActionsRow.children - - readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey - - width: parent?.width ?? 0 - height: { - var hasHeader = root.title !== "" || root.iconName !== ""; - if (collapsed) - return headerRow.height + Theme.spacingL * 2; - var h = Theme.spacingL * 2 + contentColumn.height; - if (hasHeader) - h += headerRow.height + Theme.spacingM; - return h; - } - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - readonly property bool collapsed: collapsible && !expanded - readonly property bool hasHeader: root.title !== "" || root.iconName !== "" - property bool userToggledCollapse: false - - function findParentFlickable() { - let p = root.parent; - while (p) { - if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) { - return p; - } - p = p.parent; - } - return null; - } - - Component.onCompleted: { - if (settingKey) { - let flickable = findParentFlickable(); - if (flickable) { - SettingsSearchService.registerCard(settingKey, root, flickable); - } - } - } - - Component.onDestruction: { - if (settingKey) { - SettingsSearchService.unregisterCard(settingKey); - } - } - - Behavior on height { - enabled: root.userToggledCollapse - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - onRunningChanged: { - if (!running) - root.userToggledCollapse = false; - } - } - } - - Rectangle { - id: highlightBorder - anchors.fill: parent - anchors.margins: -2 - radius: root.radius + 2 - color: "transparent" - border.width: 2 - border.color: Theme.primary - opacity: root.isHighlighted ? 1 : 0 - visible: opacity > 0 - z: 100 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Column { - id: mainColumn - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: root.hasHeader ? Theme.spacingM : 0 - clip: true - - Item { - id: headerRow - width: parent.width - height: root.hasHeader ? Math.max(headerIcon.height, headerText.height, headerActionsRow.height) : 0 - visible: root.hasHeader - - Row { - anchors.left: parent.left - anchors.leftMargin: root.headerLeftPadding - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - id: headerIcon - name: root.iconName - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - visible: root.iconName !== "" - } - - StyledText { - id: headerText - text: root.title - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - visible: root.title !== "" - width: implicitWidth - horizontalAlignment: Text.AlignLeft - } - } - - Row { - id: headerActionsRow - anchors.right: root.collapsible ? caretIcon.left : parent.right - anchors.rightMargin: root.collapsible ? Theme.spacingS : 0 - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - } - - DankIcon { - id: caretIcon - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - name: root.expanded ? "expand_less" : "expand_more" - size: Theme.iconSize - 2 - color: Theme.surfaceVariantText - visible: root.collapsible - } - - MouseArea { - anchors.left: parent.left - anchors.right: headerActionsRow.left - anchors.top: parent.top - anchors.bottom: parent.bottom - enabled: root.collapsible - cursorShape: root.collapsible ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: { - root.userToggledCollapse = true; - root.expanded = !root.expanded; - } - } - - MouseArea { - visible: root.collapsible - anchors.left: caretIcon.left - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.leftMargin: -Theme.spacingS - enabled: root.collapsible - cursorShape: root.collapsible ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: { - root.userToggledCollapse = true; - root.expanded = !root.expanded; - } - } - } - - Column { - id: contentColumn - width: parent.width - spacing: Theme.spacingM - visible: !root.collapsed - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsColorPicker.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsColorPicker.qml deleted file mode 100644 index 68011fa..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsColorPicker.qml +++ /dev/null @@ -1,119 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - property string colorMode: "primary" - property color customColor: "#ffffff" - property string pickerTitle: I18n.tr("Choose Color") - - signal colorModeSelected(string mode) - signal customColorSelected(color selectedColor) - - width: parent?.width ?? 0 - height: colorColumn.height + Theme.spacingM * 2 - - Column { - id: colorColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Color") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - Row { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: [ - { - id: "primary", - label: I18n.tr("Primary"), - color: Theme.primary - }, - { - id: "secondary", - label: I18n.tr("Secondary"), - color: Theme.secondary - }, - { - id: "custom", - label: I18n.tr("Custom"), - color: root.customColor - } - ] - - Rectangle { - required property var modelData - required property int index - - width: (parent.width - Theme.spacingS * 2) / 3 - height: 60 - radius: Theme.cornerRadius - color: root.colorMode === modelData.id ? Theme.primarySelected : Theme.surfaceHover - border.color: root.colorMode === modelData.id ? Theme.primary : "transparent" - border.width: 2 - - Column { - anchors.centerIn: parent - spacing: Theme.spacingXS - - Rectangle { - width: 24 - height: 24 - radius: 12 - color: modelData.color - border.color: Theme.outline - border.width: 1 - anchors.horizontalCenter: parent.horizontalCenter - - DankIcon { - visible: modelData.id === "custom" - anchors.centerIn: parent - name: "colorize" - size: 14 - color: Theme.background - } - } - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.horizontalCenter: parent.horizontalCenter - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: { - if (modelData.id !== "custom") { - root.colorModeSelected(modelData.id); - return; - } - PopoutService.colorPickerModal.selectedColor = root.customColor; - PopoutService.colorPickerModal.pickerTitle = root.pickerTitle; - PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { - root.customColorSelected(selectedColor); - root.colorModeSelected("custom"); - }; - PopoutService.colorPickerModal.show(); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDisplayPicker.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDisplayPicker.qml deleted file mode 100644 index ba453fd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDisplayPicker.qml +++ /dev/null @@ -1,103 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import Quickshell -import qs.Common -import qs.Widgets - -Item { - id: root - - property var displayPreferences: [] - - signal preferencesChanged(var preferences) - - property bool localAllDisplays: true - - onDisplayPreferencesChanged: { - if (!Array.isArray(displayPreferences) || displayPreferences.length === 0) { - localAllDisplays = true; - return; - } - localAllDisplays = displayPreferences.includes("all"); - } - - width: parent?.width ?? 0 - height: displayColumn.height + Theme.spacingM * 2 - - Column { - id: displayColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Displays") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - DankToggle { - width: parent.width - text: I18n.tr("All displays") - checked: root.localAllDisplays - onToggled: isChecked => { - root.localAllDisplays = isChecked; - if (isChecked) { - root.preferencesChanged(["all"]); - return; - } - var screens = []; - for (var i = 0; i < Quickshell.screens.length; i++) { - var s = Quickshell.screens[i]; - screens.push({ - name: s.name, - model: s.model || "" - }); - } - root.preferencesChanged(screens); - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: !root.localAllDisplays - - Repeater { - model: Quickshell.screens - - DankToggle { - required property var modelData - - property bool localChecked: { - const prefs = root.displayPreferences; - if (!Array.isArray(prefs) || prefs.includes("all")) - return true; - return prefs.some(p => p.name === modelData.name); - } - - width: parent.width - text: SettingsData.getScreenDisplayName(modelData) - description: modelData.width + "×" + modelData.height - checked: localChecked - onToggled: isChecked => { - localChecked = isChecked; - var prefs = JSON.parse(JSON.stringify(root.displayPreferences)); - if (!Array.isArray(prefs) || prefs.includes("all")) - prefs = []; - prefs = prefs.filter(p => p.name !== modelData.name); - if (isChecked) { - prefs.push({ - name: modelData.name, - model: modelData.model || "" - }); - } - root.preferencesChanged(prefs); - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDivider.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDivider.qml deleted file mode 100644 index 86d9fe7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDivider.qml +++ /dev/null @@ -1,11 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common - -Rectangle { - width: parent?.width ?? 0 - height: 1 - color: Theme.outline - opacity: 0.15 -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml deleted file mode 100644 index c5ec3a6..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml +++ /dev/null @@ -1,60 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankDropdown { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - property string settingKey: "" - - readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey - - width: parent?.width ?? 0 - addHorizontalPadding: true - usePopupTransparency: false - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0) - visible: root.isHighlighted - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - function findParentFlickable() { - let p = root.parent; - while (p) { - if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) - return p; - p = p.parent; - } - return null; - } - - Component.onCompleted: { - if (!settingKey) - return; - let flickable = findParentFlickable(); - if (flickable) - SettingsSearchService.registerCard(settingKey, root, flickable); - } - - Component.onDestruction: { - if (settingKey) - SettingsSearchService.unregisterCard(settingKey); - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml deleted file mode 100644 index 5bdd91a..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml +++ /dev/null @@ -1,108 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - - property string title: "" - property string description: "" - property string iconName: "" - property alias value: slider.value - property alias minimum: slider.minimum - property alias maximum: slider.maximum - property alias unit: slider.unit - property int defaultValue: -1 - - signal sliderValueChanged(int newValue) - signal sliderDragFinished(int finalValue) - width: parent?.width ?? 0 - height: Theme.spacingL * 2 + contentColumn.height - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: contentColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - spacing: Theme.spacingS - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - id: headerIcon - name: root.iconName - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - visible: root.iconName !== "" - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - width: parent.width - headerIcon.width - (root.defaultValue >= 0 ? resetButton.width + Theme.spacingS : 0) - Theme.spacingM - - StyledText { - text: root.title - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - width: parent.width - horizontalAlignment: Text.AlignLeft - visible: root.title !== "" - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - visible: root.description !== "" - } - } - - DankActionButton { - id: resetButton - anchors.verticalCenter: parent.verticalCenter - buttonSize: 36 - iconName: "restart_alt" - iconSize: 20 - visible: root.defaultValue >= 0 && slider.value !== root.defaultValue - backgroundColor: Theme.surfaceContainerHigh - iconColor: Theme.surfaceVariantText - onClicked: { - slider.value = root.defaultValue; - root.sliderValueChanged(root.defaultValue); - root.sliderDragFinished(root.defaultValue); - } - } - } - - DankSlider { - id: slider - width: parent.width - height: 32 - showValue: true - wheelEnabled: false - thumbOutlineColor: Theme.surfaceContainerHigh - onSliderValueChanged: newValue => root.sliderValueChanged(newValue) - onSliderDragFinished: finalValue => root.sliderDragFinished(finalValue) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml deleted file mode 100644 index b1ada84..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml +++ /dev/null @@ -1,148 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - property string settingKey: "" - - property string text: "" - property string description: "" - - readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey - - function findParentFlickable() { - let p = root.parent; - while (p) { - if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) - return p; - p = p.parent; - } - return null; - } - - Component.onCompleted: { - if (!settingKey) - return; - let flickable = findParentFlickable(); - if (flickable) - SettingsSearchService.registerCard(settingKey, root, flickable); - } - - Component.onDestruction: { - if (settingKey) - SettingsSearchService.unregisterCard(settingKey); - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0) - visible: root.isHighlighted - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - property alias value: slider.value - property alias minimum: slider.minimum - property alias maximum: slider.maximum - property alias step: slider.step - property alias unit: slider.unit - property alias wheelEnabled: slider.wheelEnabled - property alias thumbOutlineColor: slider.thumbOutlineColor - property int defaultValue: -1 - - signal sliderValueChanged(int newValue) - signal sliderDragFinished(int finalValue) - width: parent?.width ?? 0 - height: headerRow.height + Theme.spacingXS + slider.height - - Column { - id: contentColumn - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - Row { - id: headerRow - width: parent.width - height: labelColumn.height - spacing: Theme.spacingS - - Column { - id: labelColumn - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - width: parent.width - resetButtonContainer.width - Theme.spacingS - - StyledText { - text: root.text - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - visible: root.text !== "" - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - visible: root.description !== "" - horizontalAlignment: Text.AlignLeft - } - } - - Item { - id: resetButtonContainer - width: root.defaultValue >= 0 ? 36 : 0 - height: 36 - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - id: resetButton - anchors.centerIn: parent - buttonSize: 36 - iconName: "restart_alt" - iconSize: 20 - visible: root.defaultValue >= 0 && slider.value !== root.defaultValue - backgroundColor: Theme.surfaceContainerHigh - iconColor: Theme.surfaceVariantText - onClicked: { - slider.value = root.defaultValue; - root.sliderValueChanged(root.defaultValue); - root.sliderDragFinished(root.defaultValue); - } - } - } - } - - DankSlider { - id: slider - width: parent.width - height: 32 - showValue: true - wheelEnabled: false - thumbOutlineColor: Theme.surfaceContainerHigh - onSliderValueChanged: newValue => root.sliderValueChanged(newValue) - onSliderDragFinished: finalValue => root.sliderDragFinished(finalValue) - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml deleted file mode 100644 index c36fb7c..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml +++ /dev/null @@ -1,120 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Widgets - -StyledRect { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - - property string title: "" - property string description: "" - property string iconName: "" - property bool checked: false - property bool enabled: true - - default property alias content: expandedContent.children - readonly property bool hasContent: expandedContent.children.length > 0 - - signal toggled(bool checked) - - width: parent?.width ?? 0 - height: Theme.spacingL * 2 + mainColumn.height - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: mainColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - spacing: Theme.spacingM - - Item { - width: parent.width - height: headerColumn.height - - Column { - id: headerColumn - anchors.left: parent.left - anchors.right: toggleSwitch.left - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingXS - - Row { - spacing: Theme.spacingM - width: parent.width - - DankIcon { - id: headerIcon - name: root.iconName - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - visible: root.iconName !== "" - } - - StyledText { - id: headerText - text: root.title - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - visible: root.title !== "" - width: parent.width - (headerIcon.visible ? headerIcon.width + parent.spacing : 0) - horizontalAlignment: Text.AlignLeft - } - } - - StyledText { - id: descriptionText - text: root.description - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - visible: root.description !== "" - } - } - - DankToggle { - id: toggleSwitch - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - hideText: true - checked: root.checked - enabled: root.enabled - onToggled: checked => root.toggled(checked) - } - - StateLayer { - anchors.fill: parent - disabled: !root.enabled - stateColor: Theme.primary - cornerRadius: root.radius - onClicked: { - if (!root.enabled) - return; - root.toggled(!root.checked); - } - } - } - - Column { - id: expandedContent - width: parent.width - spacing: Theme.spacingM - visible: root.checked && root.hasContent - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml deleted file mode 100644 index 684b639..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml +++ /dev/null @@ -1,58 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankToggle { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property string tab: "" - property var tags: [] - property string settingKey: "" - - readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey - - width: parent?.width ?? 0 - - function findParentFlickable() { - let p = root.parent; - while (p) { - if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) - return p; - p = p.parent; - } - return null; - } - - Component.onCompleted: { - if (!settingKey) - return; - let flickable = findParentFlickable(); - if (flickable) - SettingsSearchService.registerCard(settingKey, root, flickable); - } - - Component.onDestruction: { - if (settingKey) - SettingsSearchService.unregisterCard(settingKey); - } - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: Theme.withAlpha(Theme.primary, root.isHighlighted ? 0.2 : 0) - visible: root.isHighlighted - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SystemMonitorVariantCard.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SystemMonitorVariantCard.qml deleted file mode 100644 index 1ecd451..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/Widgets/SystemMonitorVariantCard.qml +++ /dev/null @@ -1,390 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -Rectangle { - id: root - - property var variant: ({}) - property bool expanded: false - - signal expandToggled(bool isExpanded) - signal deleteRequested - signal nameChanged(string newName) - signal configChanged(string key, var value) - - readonly property var cfg: variant.config || {} - - function updateConfig(key, value) { - var newConfig = JSON.parse(JSON.stringify(cfg)); - newConfig[key] = value; - root.configChanged("config", newConfig); - } - - width: parent?.width ?? 0 - height: variantColumn.height - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - clip: true - - Column { - id: variantColumn - width: parent.width - spacing: 0 - - Item { - width: parent.width - height: headerContent.height + Theme.spacingM * 2 - - Row { - id: headerContent - x: Theme.spacingM - y: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - spacing: Theme.spacingM - - DankIcon { - name: root.expanded ? "expand_less" : "expand_more" - size: Theme.iconSize - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - deleteBtn.width - Theme.spacingM * 2 - anchors.verticalCenter: parent.verticalCenter - spacing: 0 - - StyledText { - text: root.variant.name || "Unnamed" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - width: parent.width - elide: Text.ElideRight - } - - StyledText { - property var features: { - var f = []; - if (root.cfg.showCpu) - f.push("CPU"); - if (root.cfg.showMemory) - f.push("RAM"); - if (root.cfg.showNetwork) - f.push("Net"); - if (root.cfg.showDisk) - f.push("Disk"); - if (root.cfg.showGpuTemp) - f.push("GPU"); - return f; - } - text: features.length > 0 ? features.join(", ") : I18n.tr("No features enabled") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: parent.width - elide: Text.ElideRight - } - } - - Rectangle { - id: deleteBtn - width: 32 - height: 32 - radius: 16 - color: deleteMouse.containsMouse ? Theme.error : "transparent" - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "delete" - size: 16 - color: deleteMouse.containsMouse ? Theme.background : Theme.surfaceVariantText - } - - MouseArea { - id: deleteMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.deleteRequested() - } - } - } - - MouseArea { - anchors.fill: parent - anchors.rightMargin: deleteBtn.width + Theme.spacingM - cursorShape: Qt.PointingHandCursor - onClicked: root.expandToggled(!root.expanded) - } - } - - Column { - width: parent.width - spacing: 0 - visible: root.expanded - - SettingsDivider {} - - Item { - width: parent.width - height: nameRow.height + Theme.spacingM * 2 - - Row { - id: nameRow - x: Theme.spacingM - y: Theme.spacingM - width: parent.width - Theme.spacingM * 2 - spacing: Theme.spacingM - - StyledText { - text: I18n.tr("Name") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - width: 80 - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: parent.width - 80 - Theme.spacingM - text: root.variant.name || "" - onEditingFinished: { - if (text !== root.variant.name) - root.nameChanged(text); - } - } - } - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Header") - checked: root.cfg.showHeader ?? true - onToggled: checked => root.updateConfig("showHeader", checked) - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show CPU") - checked: root.cfg.showCpu ?? true - onToggled: checked => root.updateConfig("showCpu", checked) - } - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show CPU Graph") - visible: root.cfg.showCpu - checked: root.cfg.showCpuGraph ?? true - onToggled: checked => root.updateConfig("showCpuGraph", checked) - } - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show CPU Temp") - visible: root.cfg.showCpu - checked: root.cfg.showCpuTemp ?? true - onToggled: checked => root.updateConfig("showCpuTemp", checked) - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Memory") - checked: root.cfg.showMemory ?? true - onToggled: checked => root.updateConfig("showMemory", checked) - } - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Memory Graph") - visible: root.cfg.showMemory - checked: root.cfg.showMemoryGraph ?? true - onToggled: checked => root.updateConfig("showMemoryGraph", checked) - } - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Memory in GB") - visible: root.cfg.showMemory - checked: root.cfg.showInGb ?? false - onToggled: checked => root.updateConfig("showInGb", checked) - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Network") - checked: root.cfg.showNetwork ?? true - onToggled: checked => root.updateConfig("showNetwork", checked) - } - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Network Graph") - visible: root.cfg.showNetwork - checked: root.cfg.showNetworkGraph ?? true - onToggled: checked => root.updateConfig("showNetworkGraph", checked) - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Disk") - checked: root.cfg.showDisk ?? true - onToggled: checked => root.updateConfig("showDisk", checked) - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show GPU Temperature") - checked: root.cfg.showGpuTemp ?? false - onToggled: checked => root.updateConfig("showGpuTemp", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: root.cfg.showGpuTemp && DgopService.availableGpus.length > 0 - - Item { - width: 1 - height: Theme.spacingS - } - - Repeater { - model: DgopService.availableGpus - - Rectangle { - required property var modelData - - width: (parent?.width ?? 0) - Theme.spacingM * 2 - x: Theme.spacingM - height: 40 - radius: Theme.cornerRadius - color: root.cfg.gpuPciId === modelData.pciId ? Theme.primarySelected : Theme.surfaceContainer - border.color: root.cfg.gpuPciId === modelData.pciId ? Theme.primary : "transparent" - border.width: 2 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - DankIcon { - name: "videocam" - size: Theme.iconSizeSmall - color: root.cfg.gpuPciId === modelData.pciId ? Theme.primary : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.displayName || "Unknown GPU" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - Theme.iconSizeSmall - Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - } - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: root.updateConfig("gpuPciId", modelData.pciId) - } - } - } - - Item { - width: 1 - height: Theme.spacingS - } - } - - SettingsDivider {} - - DankToggle { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - text: I18n.tr("Show Top Processes") - checked: root.cfg.showTopProcesses ?? false - onToggled: checked => root.updateConfig("showTopProcesses", checked) - } - - SettingsDivider {} - - Column { - width: parent.width - Theme.spacingM * 2 - x: Theme.spacingM - topPadding: Theme.spacingM - bottomPadding: Theme.spacingM - spacing: Theme.spacingS - - Row { - width: parent.width - - StyledText { - id: transparencyLabel - text: I18n.tr("Transparency") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - - Item { - width: parent.width - transparencyLabel.width - transparencyValue.width - height: 1 - } - - StyledText { - id: transparencyValue - text: transparencySlider.value + "%" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - DankSlider { - id: transparencySlider - width: parent.width - minimum: 0 - maximum: 100 - value: Math.round((root.cfg.transparency ?? 0.8) * 100) - showValue: false - wheelEnabled: false - onSliderDragFinished: finalValue => root.updateConfig("transparency", finalValue / 100) - } - } - - Item { - width: 1 - height: Theme.spacingM - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTab.qml deleted file mode 100644 index 86bc391..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTab.qml +++ /dev/null @@ -1,1145 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: widgetsTab - - property var parentModal: null - property string selectedBarId: "default" - - property var selectedBarConfig: { - selectedBarId; - SettingsData.barConfigs; - const index = SettingsData.barConfigs.findIndex(cfg => cfg.id === selectedBarId); - return index !== -1 ? SettingsData.barConfigs[index] : SettingsData.barConfigs[0]; - } - - property bool selectedBarIsVertical: { - selectedBarId; - const pos = selectedBarConfig?.position ?? SettingsData.Position.Top; - return pos === SettingsData.Position.Left || pos === SettingsData.Position.Right; - } - - property bool hasMultipleBars: SettingsData.barConfigs.length > 1 - - DankTooltipV2 { - id: sharedTooltip - } - - property var baseWidgetDefinitions: { - var coreWidgets = [ - { - "id": "layout", - "text": I18n.tr("Layout"), - "description": I18n.tr("Display and switch DWL layouts"), - "icon": "view_quilt", - "enabled": CompositorService.isDwl && DwlService.dwlAvailable, - "warning": !CompositorService.isDwl ? I18n.tr("Requires DWL compositor") : (!DwlService.dwlAvailable ? I18n.tr("DWL service not available") : undefined) - }, - { - "id": "launcherButton", - "text": I18n.tr("App Launcher"), - "description": I18n.tr("Quick access to application launcher"), - "icon": "apps", - "enabled": true - }, - { - "id": "workspaceSwitcher", - "text": I18n.tr("Workspace Switcher"), - "description": I18n.tr("Shows current workspace and allows switching"), - "icon": "view_module", - "enabled": true - }, - { - "id": "focusedWindow", - "text": I18n.tr("Focused Window"), - "description": I18n.tr("Display currently focused application title"), - "icon": "window", - "enabled": true - }, - { - "id": "runningApps", - "text": I18n.tr("Running Apps"), - "description": I18n.tr("Shows all running applications with focus indication"), - "icon": "apps", - "enabled": true - }, - { - "id": "appsDock", - "text": I18n.tr("Apps Dock"), - "description": I18n.tr("Pinned and running apps with drag-and-drop"), - "icon": "dock_to_bottom", - "enabled": true - }, - { - "id": "clock", - "text": I18n.tr("Clock"), - "description": I18n.tr("Current time and date display"), - "icon": "schedule", - "enabled": true - }, - { - "id": "weather", - "text": I18n.tr("Weather Widget"), - "description": I18n.tr("Current weather conditions and temperature"), - "icon": "wb_sunny", - "enabled": true - }, - { - "id": "music", - "text": I18n.tr("Media Controls"), - "description": I18n.tr("Control currently playing media"), - "icon": "music_note", - "enabled": true - }, - { - "id": "clipboard", - "text": I18n.tr("Clipboard Manager"), - "description": I18n.tr("Access clipboard history"), - "icon": "content_paste", - "enabled": true - }, - { - "id": "cpuUsage", - "text": I18n.tr("CPU Usage"), - "description": I18n.tr("CPU usage indicator"), - "icon": "memory", - "enabled": DgopService.dgopAvailable, - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined - }, - { - "id": "memUsage", - "text": I18n.tr("Memory Usage"), - "description": I18n.tr("Memory usage indicator"), - "icon": "developer_board", - "enabled": DgopService.dgopAvailable, - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined - }, - { - "id": "diskUsage", - "text": I18n.tr("Disk Usage"), - "description": I18n.tr("Percentage"), - "icon": "storage", - "enabled": DgopService.dgopAvailable, - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined - }, - { - "id": "cpuTemp", - "text": I18n.tr("CPU Temperature"), - "description": I18n.tr("CPU temperature display"), - "icon": "device_thermostat", - "enabled": DgopService.dgopAvailable, - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined - }, - { - "id": "gpuTemp", - "text": I18n.tr("GPU Temperature"), - "description": I18n.tr("GPU temperature display"), - "icon": "auto_awesome_mosaic", - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : I18n.tr("This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics."), - "enabled": DgopService.dgopAvailable - }, - { - "id": "systemTray", - "text": I18n.tr("System Tray"), - "description": I18n.tr("System notification area icons"), - "icon": "notifications", - "enabled": true - }, - { - "id": "privacyIndicator", - "text": I18n.tr("Privacy Indicator"), - "description": I18n.tr("Shows when microphone, camera, or screen sharing is active"), - "icon": "privacy_tip", - "enabled": true - }, - { - "id": "controlCenterButton", - "text": I18n.tr("Control Center"), - "description": I18n.tr("Access to system controls and settings"), - "icon": "settings", - "enabled": true - }, - { - "id": "notificationButton", - "text": I18n.tr("Notification Center"), - "description": I18n.tr("Access to notifications and do not disturb"), - "icon": "notifications", - "enabled": true - }, - { - "id": "battery", - "text": I18n.tr("Battery"), - "description": I18n.tr("Battery level and power management"), - "icon": "battery_std", - "enabled": true - }, - { - "id": "vpn", - "text": I18n.tr("VPN"), - "description": I18n.tr("VPN status and quick connect"), - "icon": "vpn_lock", - "enabled": true - }, - { - "id": "idleInhibitor", - "text": I18n.tr("Idle Inhibitor"), - "description": I18n.tr("Prevent screen timeout"), - "icon": "motion_sensor_active", - "enabled": true - }, - { - "id": "capsLockIndicator", - "text": I18n.tr("Caps Lock Indicator"), - "description": I18n.tr("Shows when caps lock is active"), - "icon": "shift_lock", - "enabled": true - }, - { - "id": "spacer", - "text": I18n.tr("Spacer"), - "description": I18n.tr("Customizable empty space"), - "icon": "more_horiz", - "enabled": true - }, - { - "id": "separator", - "text": I18n.tr("Separator"), - "description": I18n.tr("Visual divider between widgets"), - "icon": "remove", - "enabled": true - }, - { - "id": "network_speed_monitor", - "text": I18n.tr("Network Speed Monitor"), - "description": I18n.tr("Network download and upload speed display"), - "icon": "network_check", - "warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined, - "enabled": DgopService.dgopAvailable - }, - { - "id": "keyboard_layout_name", - "text": I18n.tr("Keyboard Layout Name"), - "description": I18n.tr("Displays the active keyboard layout and allows switching"), - "icon": "keyboard" - }, - { - "id": "notepadButton", - "text": I18n.tr("Notepad"), - "description": I18n.tr("Quick access to notepad"), - "icon": "assignment", - "enabled": true - }, - { - "id": "colorPicker", - "text": I18n.tr("Color Picker"), - "description": I18n.tr("Quick access to color picker"), - "icon": "palette", - "enabled": true - }, - { - "id": "systemUpdate", - "text": I18n.tr("System Update"), - "description": I18n.tr("Check for system updates"), - "icon": "update", - "enabled": SystemUpdateService.distributionSupported - }, - { - "id": "powerMenuButton", - "text": I18n.tr("Power"), - "description": I18n.tr("Display the power system menu"), - "icon": "power_settings_new", - "enabled": true - }, - ]; - - var allPluginVariants = PluginService.getAllPluginVariants(); - for (var i = 0; i < allPluginVariants.length; i++) { - var variant = allPluginVariants[i]; - coreWidgets.push({ - "id": variant.fullId, - "text": variant.name, - "description": variant.description, - "icon": variant.icon, - "enabled": variant.loaded, - "warning": !variant.loaded ? I18n.tr("Plugin is disabled - enable in Plugins settings to use") : undefined - }); - } - - return coreWidgets; - } - - property var defaultLeftWidgets: [ - { - "id": "launcherButton", - "enabled": true - }, - { - "id": "workspaceSwitcher", - "enabled": true - }, - { - "id": "focusedWindow", - "enabled": true - } - ] - property var defaultCenterWidgets: [ - { - "id": "music", - "enabled": true - }, - { - "id": "clock", - "enabled": true - }, - { - "id": "weather", - "enabled": true - } - ] - property var defaultRightWidgets: [ - { - "id": "systemTray", - "enabled": true - }, - { - "id": "clipboard", - "enabled": true - }, - { - "id": "notificationButton", - "enabled": true - }, - { - "id": "battery", - "enabled": true - }, - { - "id": "controlCenterButton", - "enabled": true - } - ] - - function getWidgetsForSection(sectionId) { - switch (sectionId) { - case "left": - return selectedBarConfig?.leftWidgets || []; - case "center": - return selectedBarConfig?.centerWidgets || []; - case "right": - return selectedBarConfig?.rightWidgets || []; - default: - return []; - } - } - - function setWidgetsForSection(sectionId, widgets) { - switch (sectionId) { - case "left": - SettingsData.updateBarConfig(selectedBarId, { - leftWidgets: widgets - }); - break; - case "center": - SettingsData.updateBarConfig(selectedBarId, { - centerWidgets: widgets - }); - break; - case "right": - SettingsData.updateBarConfig(selectedBarId, { - rightWidgets: widgets - }); - break; - } - } - - function getWidgetsForPopup() { - return baseWidgetDefinitions.filter(widget => { - if (widget.warning && widget.warning.includes("Plugin is disabled")) - return false; - if (widget.enabled === false) - return false; - return true; - }); - } - - function addWidgetToSection(widgetId, targetSection) { - var widgetObj = { - "id": widgetId, - "enabled": true - }; - if (widgetId === "spacer") - widgetObj.size = 20; - if (widgetId === "gpuTemp") { - widgetObj.selectedGpuIndex = 0; - widgetObj.pciId = ""; - } - if (widgetId === "controlCenterButton") { - widgetObj.showNetworkIcon = SettingsData.controlCenterShowNetworkIcon; - widgetObj.showBluetoothIcon = SettingsData.controlCenterShowBluetoothIcon; - widgetObj.showAudioIcon = SettingsData.controlCenterShowAudioIcon; - widgetObj.showAudioPercent = SettingsData.controlCenterShowAudioPercent; - widgetObj.showVpnIcon = SettingsData.controlCenterShowVpnIcon; - widgetObj.showBrightnessIcon = SettingsData.controlCenterShowBrightnessIcon; - widgetObj.showBrightnessPercent = SettingsData.controlCenterShowBrightnessPercent; - widgetObj.showMicIcon = SettingsData.controlCenterShowMicIcon; - widgetObj.showMicPercent = SettingsData.controlCenterShowMicPercent; - widgetObj.showBatteryIcon = SettingsData.controlCenterShowBatteryIcon; - widgetObj.showPrinterIcon = SettingsData.controlCenterShowPrinterIcon; - widgetObj.showScreenSharingIcon = SettingsData.controlCenterShowScreenSharingIcon; - widgetObj.controlCenterGroupOrder = ["network", "vpn", "bluetooth", "audio", "microphone", "brightness", "battery", "printer", "screenSharing"]; - } - if (widgetId === "runningApps") { - widgetObj.runningAppsCompactMode = SettingsData.runningAppsCompactMode; - widgetObj.runningAppsGroupByApp = SettingsData.runningAppsGroupByApp; - widgetObj.runningAppsCurrentWorkspace = SettingsData.runningAppsCurrentWorkspace; - widgetObj.runningAppsCurrentMonitor = false; - } - if (widgetId === "diskUsage") { - widgetObj.mountPath = "/"; - widgetObj.diskUsageMode = 0; - } - if (widgetId === "cpuUsage" || widgetId === "memUsage" || widgetId === "cpuTemp" || widgetId === "gpuTemp") - widgetObj.minimumWidth = true; - if (widgetId === "memUsage") - widgetObj.showInGb = false; - - var widgets = getWidgetsForSection(targetSection).slice(); - widgets.push(widgetObj); - setWidgetsForSection(targetSection, widgets); - } - - function removeWidgetFromSection(sectionId, widgetIndex) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex >= 0 && widgetIndex < widgets.length) - widgets.splice(widgetIndex, 1); - setWidgetsForSection(sectionId, widgets); - } - - function cloneWidgetData(widget) { - if (typeof widget === "string") - return { - "id": widget, - "enabled": true - }; - var result = { - "id": widget.id, - "enabled": widget.enabled - }; - var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "controlCenterGroupOrder", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge", "trayUseInlineExpansion"]; - for (var i = 0; i < keys.length; i++) { - if (widget[keys[i]] !== undefined) - result[keys[i]] = widget[keys[i]]; - } - return result; - } - - function handleItemEnabledChanged(sectionId, itemId, enabled) { - var widgets = getWidgetsForSection(sectionId).slice(); - for (var i = 0; i < widgets.length; i++) { - var widget = widgets[i]; - var widgetId = typeof widget === "string" ? widget : widget.id; - if (widgetId !== itemId) - continue; - var newWidget = cloneWidgetData(widget); - newWidget.enabled = enabled; - widgets[i] = newWidget; - break; - } - setWidgetsForSection(sectionId, widgets); - } - - function handleItemOrderChanged(sectionId, newOrder) { - setWidgetsForSection(sectionId, newOrder); - } - - function handleSpacerSizeChanged(sectionId, widgetIndex, newSize) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) - return; - var widget = widgets[widgetIndex]; - var widgetId = typeof widget === "string" ? widget : widget.id; - if (widgetId !== "spacer") - return; - var newWidget = cloneWidgetData(widget); - newWidget.size = newSize; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleGpuSelectionChanged(sectionId, widgetIndex, selectedGpuIndex) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) - return; - var pciId = DgopService.availableGpus && DgopService.availableGpus.length > selectedGpuIndex ? DgopService.availableGpus[selectedGpuIndex].pciId : ""; - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.selectedGpuIndex = selectedGpuIndex; - newWidget.pciId = pciId; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleDiskMountSelectionChanged(sectionId, widgetIndex, mountPath) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) - return; - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.mountPath = mountPath; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleControlCenterSettingChanged(sectionId, widgetIndex, settingName, value) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) - return; - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget[settingName] = value; - - if (!value) { - switch (settingName) { - case "showAudioIcon": - newWidget.showAudioPercent = false; - break; - case "showMicIcon": - newWidget.showMicPercent = false; - break; - case "showBrightnessIcon": - newWidget.showBrightnessPercent = false; - break; - } - } - - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleControlCenterGroupOrderChanged(sectionId, widgetIndex, groupOrder) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) - return; - var previousWidget = widgets[widgetIndex]; - var newWidget = cloneWidgetData(previousWidget); - newWidget.controlCenterGroupOrder = groupOrder.slice(); - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handlePrivacySettingChanged(sectionId, widgetIndex, settingName, value) { - switch (settingName) { - case "showMicIcon": - SettingsData.set("privacyShowMicIcon", value); - break; - case "showCameraIcon": - SettingsData.set("privacyShowCameraIcon", value); - break; - case "showScreenSharingIcon": - SettingsData.set("privacyShowScreenShareIcon", value); - break; - } - } - - function handleMinimumWidthChanged(sectionId, widgetIndex, enabled) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) { - setWidgetsForSection(sectionId, widgets); - return; - } - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.minimumWidth = enabled; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleShowSwapChanged(sectionId, widgetIndex, enabled) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) { - setWidgetsForSection(sectionId, widgets); - return; - } - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.showSwap = enabled; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleShowInGbChanged(sectionId, widgetIndex, enabled) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) { - setWidgetsForSection(sectionId, widgets); - return; - } - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.showInGb = enabled; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleDiskUsageModeChanged(sectionId, widgetIndex, mode) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) { - setWidgetsForSection(sectionId, widgets); - return; - } - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget.diskUsageMode = mode; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value) { - var widgets = getWidgetsForSection(sectionId).slice(); - if (widgetIndex < 0 || widgetIndex >= widgets.length) { - setWidgetsForSection(sectionId, widgets); - return; - } - var newWidget = cloneWidgetData(widgets[widgetIndex]); - newWidget[settingName] = value; - widgets[widgetIndex] = newWidget; - setWidgetsForSection(sectionId, widgets); - } - - function handleCompactModeChanged(sectionId, widgetId, value) { - var widgets = getWidgetsForSection(sectionId).slice(); - for (var i = 0; i < widgets.length; i++) { - var widget = widgets[i]; - var currentId = typeof widget === "string" ? widget : widget.id; - if (currentId !== widgetId) - continue; - - var newWidget = cloneWidgetData(widget); - switch (widgetId) { - case "music": - newWidget.mediaSize = value; - break; - case "clock": - newWidget.clockCompactMode = value; - break; - case "focusedWindow": - newWidget.focusedWindowCompactMode = value; - break; - case "runningApps": - newWidget.runningAppsCompactMode = value; - break; - case "keyboard_layout_name": - newWidget.keyboardLayoutNameCompactMode = value; - break; - } - widgets[i] = newWidget; - break; - } - setWidgetsForSection(sectionId, widgets); - } - - function getItemsForSection(sectionId) { - var widgets = []; - var widgetData = getWidgetsForSection(sectionId); - widgetData.forEach(widget => { - var isString = typeof widget === "string"; - var widgetId = isString ? widget : widget.id; - var widgetDef = baseWidgetDefinitions.find(w => w.id === widgetId); - if (!widgetDef) - return; - - var item = Object.assign({}, widgetDef); - item.enabled = isString ? true : widget.enabled; - if (!isString) { - if (widget.size !== undefined) - item.size = widget.size; - if (widget.selectedGpuIndex !== undefined) - item.selectedGpuIndex = widget.selectedGpuIndex; - if (widget.pciId !== undefined) - item.pciId = widget.pciId; - if (widget.mountPath !== undefined) - item.mountPath = widget.mountPath; - if (widget.diskUsageMode !== undefined) - item.diskUsageMode = widget.diskUsageMode; - if (widget.showNetworkIcon !== undefined) - item.showNetworkIcon = widget.showNetworkIcon; - if (widget.showBluetoothIcon !== undefined) - item.showBluetoothIcon = widget.showBluetoothIcon; - if (widget.showAudioIcon !== undefined) - item.showAudioIcon = widget.showAudioIcon; - if (widget.showAudioPercent !== undefined) - item.showAudioPercent = widget.showAudioPercent; - if (widget.showVpnIcon !== undefined) - item.showVpnIcon = widget.showVpnIcon; - if (widget.showBrightnessIcon !== undefined) - item.showBrightnessIcon = widget.showBrightnessIcon; - if (widget.showBrightnessPercent !== undefined) - item.showBrightnessPercent = widget.showBrightnessPercent; - if (widget.showMicIcon !== undefined) - item.showMicIcon = widget.showMicIcon; - if (widget.showMicPercent !== undefined) - item.showMicPercent = widget.showMicPercent; - if (widget.showBatteryIcon !== undefined) - item.showBatteryIcon = widget.showBatteryIcon; - if (widget.showPrinterIcon !== undefined) - item.showPrinterIcon = widget.showPrinterIcon; - if (widget.showScreenSharingIcon !== undefined) - item.showScreenSharingIcon = widget.showScreenSharingIcon; - if (widget.controlCenterGroupOrder !== undefined) - item.controlCenterGroupOrder = widget.controlCenterGroupOrder; - if (widget.minimumWidth !== undefined) - item.minimumWidth = widget.minimumWidth; - if (widget.showSwap !== undefined) - item.showSwap = widget.showSwap; - if (widget.showInGb !== undefined) - item.showInGb = widget.showInGb; - if (widget.mediaSize !== undefined) - item.mediaSize = widget.mediaSize; - if (widget.clockCompactMode !== undefined) - item.clockCompactMode = widget.clockCompactMode; - if (widget.focusedWindowCompactMode !== undefined) - item.focusedWindowCompactMode = widget.focusedWindowCompactMode; - if (widget.runningAppsCompactMode !== undefined) - item.runningAppsCompactMode = widget.runningAppsCompactMode; - if (widget.runningAppsGroupByApp !== undefined) - item.runningAppsGroupByApp = widget.runningAppsGroupByApp; - if (widget.runningAppsCurrentWorkspace !== undefined) - item.runningAppsCurrentWorkspace = widget.runningAppsCurrentWorkspace; - if (widget.runningAppsCurrentMonitor !== undefined) - item.runningAppsCurrentMonitor = widget.runningAppsCurrentMonitor; - if (widget.keyboardLayoutNameCompactMode !== undefined) - item.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode; - if (widget.barMaxVisibleApps !== undefined) - item.barMaxVisibleApps = widget.barMaxVisibleApps; - if (widget.barMaxVisibleRunningApps !== undefined) - item.barMaxVisibleRunningApps = widget.barMaxVisibleRunningApps; - if (widget.barShowOverflowBadge !== undefined) - item.barShowOverflowBadge = widget.barShowOverflowBadge; - if (widget.trayUseInlineExpansion !== undefined) - item.trayUseInlineExpansion = widget.trayUseInlineExpansion; - } - widgets.push(item); - }); - return widgets; - } - - Component.onCompleted: { - const leftWidgets = selectedBarConfig?.leftWidgets; - const centerWidgets = selectedBarConfig?.centerWidgets; - const rightWidgets = selectedBarConfig?.rightWidgets; - - if (!leftWidgets) - setWidgetsForSection("left", defaultLeftWidgets); - if (!centerWidgets) - setWidgetsForSection("center", defaultCenterWidgets); - if (!rightWidgets) - setWidgetsForSection("right", defaultRightWidgets); - - const sections = ["left", "center", "right"]; - sections.forEach(sectionId => { - var widgets = getWidgetsForSection(sectionId).slice(); - var updated = false; - for (var i = 0; i < widgets.length; i++) { - var widget = widgets[i]; - if (typeof widget === "object" && widget.id === "spacer" && !widget.size) { - widgets[i] = Object.assign({}, widget, { - "size": 20 - }); - updated = true; - } - } - if (updated) - setWidgetsForSection(sectionId, widgets); - }); - } - - LazyLoader { - id: widgetSelectionPopupLoader - active: false - - WidgetSelectionPopup { - id: widgetSelectionPopupItem - parentModal: widgetsTab.parentModal - onWidgetSelected: (widgetId, targetSection) => { - widgetsTab.addWidgetToSection(widgetId, targetSection); - } - } - } - - function showWidgetSelectionPopup(sectionId) { - widgetSelectionPopupLoader.active = true; - if (!widgetSelectionPopupLoader.item) - return; - widgetSelectionPopupLoader.item.targetSection = sectionId; - widgetSelectionPopupLoader.item.allWidgets = widgetsTab.getWidgetsForPopup(); - widgetSelectionPopupLoader.item.show(); - } - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - StyledRect { - width: parent.width - height: barSelectorContent.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - visible: hasMultipleBars - - Column { - id: barSelectorContent - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "toolbar" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Select Bar") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankButtonGroup { - id: barSelectorGroup - width: parent.width - model: SettingsData.barConfigs.map(cfg => cfg.name || ("Bar " + (SettingsData.barConfigs.indexOf(cfg) + 1))) - currentIndex: { - const idx = SettingsData.barConfigs.findIndex(cfg => cfg.id === selectedBarId); - return idx >= 0 ? idx : 0; - } - checkEnabled: false - onSelectionChanged: (index, selected) => { - if (!selected) - return; - if (index >= 0 && index < SettingsData.barConfigs.length) - selectedBarId = SettingsData.barConfigs[index].id; - } - } - } - } - - StyledRect { - width: parent.width - height: widgetManagementHeader.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: widgetManagementHeader - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - RowLayout { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "widgets" - size: Theme.iconSize - color: Theme.primary - Layout.alignment: Qt.AlignVCenter - } - - StyledText { - text: I18n.tr("Widget Management") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - Layout.alignment: Qt.AlignVCenter - } - - Item { - height: 1 - Layout.fillWidth: true - } - - Rectangle { - width: resetContentRow.implicitWidth + Theme.spacingM * 2 - height: 28 - radius: Theme.cornerRadius - color: resetArea.containsMouse ? Theme.surfacePressed : Theme.surfaceVariant - Layout.alignment: Qt.AlignVCenter - border.width: 0 - - Row { - id: resetContentRow - anchors.centerIn: parent - spacing: Theme.spacingXS - - DankIcon { - name: "refresh" - size: 14 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Reset") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: resetArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - setWidgetsForSection("left", defaultLeftWidgets); - setWidgetsForSection("center", defaultCenterWidgets); - setWidgetsForSection("right", defaultRightWidgets); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - StyledText { - width: parent.width - text: I18n.tr("Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingL - - StyledRect { - width: parent.width - height: leftSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - WidgetsTabSection { - id: leftSection - anchors.fill: parent - anchors.margins: Theme.spacingL - title: selectedBarIsVertical ? I18n.tr("Top Section") : I18n.tr("Left Section") - titleIcon: "format_align_left" - sectionId: "left" - allWidgets: widgetsTab.baseWidgetDefinitions - items: widgetsTab.getItemsForSection("left") - onItemEnabledChanged: (sectionId, itemId, enabled) => { - widgetsTab.handleItemEnabledChanged(sectionId, itemId, enabled); - } - onItemOrderChanged: newOrder => { - widgetsTab.handleItemOrderChanged(sectionId, newOrder); - } - onAddWidget: sectionId => { - showWidgetSelectionPopup(sectionId); - } - onRemoveWidget: (sectionId, index) => { - widgetsTab.removeWidgetFromSection(sectionId, index); - } - onSpacerSizeChanged: (sectionId, index, size) => { - widgetsTab.handleSpacerSizeChanged(sectionId, index, size); - } - onGpuSelectionChanged: (sectionId, index, gpuIndex) => { - widgetsTab.handleGpuSelectionChanged(sectionId, index, gpuIndex); - } - onDiskMountSelectionChanged: (sectionId, index, mountPath) => { - widgetsTab.handleDiskMountSelectionChanged(sectionId, index, mountPath); - } - onControlCenterSettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handleControlCenterSettingChanged(sectionId, index, setting, value); - } - onControlCenterGroupOrderChanged: (sectionId, index, groupOrder) => { - widgetsTab.handleControlCenterGroupOrderChanged(sectionId, index, groupOrder); - } - onPrivacySettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handlePrivacySettingChanged(sectionId, index, setting, value); - } - onMinimumWidthChanged: (sectionId, index, enabled) => { - widgetsTab.handleMinimumWidthChanged(sectionId, index, enabled); - } - onShowSwapChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowSwapChanged(sectionId, index, enabled); - } - onShowInGbChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowInGbChanged(sectionId, index, enabled); - } - onDiskUsageModeChanged: (sectionId, widgetIndex, mode) => { - widgetsTab.handleDiskUsageModeChanged(sectionId, widgetIndex, mode); - } - onCompactModeChanged: (widgetId, value) => { - widgetsTab.handleCompactModeChanged(sectionId, widgetId, value); - } - onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => { - widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value); - } - } - } - - StyledRect { - width: parent.width - height: centerSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - WidgetsTabSection { - id: centerSection - anchors.fill: parent - anchors.margins: Theme.spacingL - title: selectedBarIsVertical ? I18n.tr("Middle Section") : I18n.tr("Center Section") - titleIcon: "format_align_center" - sectionId: "center" - allWidgets: widgetsTab.baseWidgetDefinitions - items: widgetsTab.getItemsForSection("center") - onItemEnabledChanged: (sectionId, itemId, enabled) => { - widgetsTab.handleItemEnabledChanged(sectionId, itemId, enabled); - } - onItemOrderChanged: newOrder => { - widgetsTab.handleItemOrderChanged(sectionId, newOrder); - } - onAddWidget: sectionId => { - showWidgetSelectionPopup(sectionId); - } - onRemoveWidget: (sectionId, index) => { - widgetsTab.removeWidgetFromSection(sectionId, index); - } - onSpacerSizeChanged: (sectionId, index, size) => { - widgetsTab.handleSpacerSizeChanged(sectionId, index, size); - } - onGpuSelectionChanged: (sectionId, index, gpuIndex) => { - widgetsTab.handleGpuSelectionChanged(sectionId, index, gpuIndex); - } - onDiskMountSelectionChanged: (sectionId, index, mountPath) => { - widgetsTab.handleDiskMountSelectionChanged(sectionId, index, mountPath); - } - onControlCenterSettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handleControlCenterSettingChanged(sectionId, index, setting, value); - } - onControlCenterGroupOrderChanged: (sectionId, index, groupOrder) => { - widgetsTab.handleControlCenterGroupOrderChanged(sectionId, index, groupOrder); - } - onPrivacySettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handlePrivacySettingChanged(sectionId, index, setting, value); - } - onMinimumWidthChanged: (sectionId, index, enabled) => { - widgetsTab.handleMinimumWidthChanged(sectionId, index, enabled); - } - onShowSwapChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowSwapChanged(sectionId, index, enabled); - } - onShowInGbChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowInGbChanged(sectionId, index, enabled); - } - onDiskUsageModeChanged: (sectionId, widgetIndex, mode) => { - widgetsTab.handleDiskUsageModeChanged(sectionId, widgetIndex, mode); - } - onCompactModeChanged: (widgetId, value) => { - widgetsTab.handleCompactModeChanged(sectionId, widgetId, value); - } - onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => { - widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value); - } - } - } - - StyledRect { - width: parent.width - height: rightSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - WidgetsTabSection { - id: rightSection - anchors.fill: parent - anchors.margins: Theme.spacingL - title: selectedBarIsVertical ? I18n.tr("Bottom Section") : I18n.tr("Right Section") - titleIcon: "format_align_right" - sectionId: "right" - allWidgets: widgetsTab.baseWidgetDefinitions - items: widgetsTab.getItemsForSection("right") - onItemEnabledChanged: (sectionId, itemId, enabled) => { - widgetsTab.handleItemEnabledChanged(sectionId, itemId, enabled); - } - onItemOrderChanged: newOrder => { - widgetsTab.handleItemOrderChanged(sectionId, newOrder); - } - onAddWidget: sectionId => { - showWidgetSelectionPopup(sectionId); - } - onRemoveWidget: (sectionId, index) => { - widgetsTab.removeWidgetFromSection(sectionId, index); - } - onSpacerSizeChanged: (sectionId, index, size) => { - widgetsTab.handleSpacerSizeChanged(sectionId, index, size); - } - onGpuSelectionChanged: (sectionId, index, gpuIndex) => { - widgetsTab.handleGpuSelectionChanged(sectionId, index, gpuIndex); - } - onDiskMountSelectionChanged: (sectionId, index, mountPath) => { - widgetsTab.handleDiskMountSelectionChanged(sectionId, index, mountPath); - } - onControlCenterSettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handleControlCenterSettingChanged(sectionId, index, setting, value); - } - onControlCenterGroupOrderChanged: (sectionId, index, groupOrder) => { - widgetsTab.handleControlCenterGroupOrderChanged(sectionId, index, groupOrder); - } - onPrivacySettingChanged: (sectionId, index, setting, value) => { - widgetsTab.handlePrivacySettingChanged(sectionId, index, setting, value); - } - onMinimumWidthChanged: (sectionId, index, enabled) => { - widgetsTab.handleMinimumWidthChanged(sectionId, index, enabled); - } - onShowSwapChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowSwapChanged(sectionId, index, enabled); - } - onShowInGbChanged: (sectionId, index, enabled) => { - widgetsTab.handleShowInGbChanged(sectionId, index, enabled); - } - onDiskUsageModeChanged: (sectionId, widgetIndex, mode) => { - widgetsTab.handleDiskUsageModeChanged(sectionId, widgetIndex, mode); - } - onCompactModeChanged: (widgetId, value) => { - widgetsTab.handleCompactModeChanged(sectionId, widgetId, value); - } - onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => { - widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value); - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTabSection.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTabSection.qml deleted file mode 100644 index 88c1270..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WidgetsTabSection.qml +++ /dev/null @@ -1,2940 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets -import qs.Services - -Column { - id: root - - property var items: [] - property var allWidgets: [] - property string title: "" - property string titleIcon: "widgets" - property string sectionId: "" - - DankTooltipV2 { - id: sharedTooltip - } - - signal itemEnabledChanged(string sectionId, string itemId, bool enabled) - signal itemOrderChanged(var newOrder) - signal addWidget(string sectionId) - signal removeWidget(string sectionId, int widgetIndex) - signal spacerSizeChanged(string sectionId, int widgetIndex, int newSize) - signal compactModeChanged(string widgetId, var value) - signal gpuSelectionChanged(string sectionId, int widgetIndex, int selectedIndex) - signal diskMountSelectionChanged(string sectionId, int widgetIndex, string mountPath) - signal controlCenterSettingChanged(string sectionId, int widgetIndex, string settingName, bool value) - signal controlCenterGroupOrderChanged(string sectionId, int widgetIndex, var groupOrder) - signal privacySettingChanged(string sectionId, int widgetIndex, string settingName, bool value) - signal minimumWidthChanged(string sectionId, int widgetIndex, bool enabled) - signal showSwapChanged(string sectionId, int widgetIndex, bool enabled) - signal showInGbChanged(string sectionId, int widgetIndex, bool enabled) - signal diskUsageModeChanged(string sectionId, int widgetIndex, int mode) - signal overflowSettingChanged(string sectionId, int widgetIndex, string settingName, var value) - - function cloneWidgetData(widget) { - var result = { - "id": widget.id, - "enabled": widget.enabled - }; - var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "controlCenterGroupOrder", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge", "trayUseInlineExpansion"]; - for (var i = 0; i < keys.length; i++) { - if (widget[keys[i]] !== undefined) - result[keys[i]] = widget[keys[i]]; - } - return result; - } - - width: parent.width - height: implicitHeight - spacing: Theme.spacingM - - Row { - spacing: Theme.spacingM - - DankIcon { - name: root.titleIcon - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: root.title - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Column { - id: itemsList - - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: root.items - - delegate: Item { - id: delegateItem - - property bool held: dragArea.pressed - property real originalY: y - - width: itemsList.width - height: 70 - z: held ? 2 : 1 - - Rectangle { - id: itemBackground - - anchors.fill: parent - anchors.margins: 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.8) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - - DankIcon { - name: "drag_indicator" - size: Theme.iconSize - 4 - color: Theme.outline - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM + 8 - anchors.verticalCenter: parent.verticalCenter - opacity: 0.8 - } - - DankIcon { - name: modelData.icon - size: Theme.iconSize - color: modelData.enabled ? Theme.primary : Theme.outline - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM * 2 + 40 - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM * 3 + 40 + Theme.iconSize - anchors.right: actionButtons.left - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.text - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: modelData.enabled ? Theme.surfaceText : Theme.outline - elide: Text.ElideRight - width: parent.width - } - - StyledText { - text: { - if (modelData.id === "gpuTemp") { - var selectedIdx = modelData.selectedGpuIndex !== undefined ? modelData.selectedGpuIndex : 0; - if (DgopService.availableGpus && DgopService.availableGpus.length > selectedIdx) { - var gpu = DgopService.availableGpus[selectedIdx]; - return gpu.driver ? gpu.driver.toUpperCase() : ""; - } - return I18n.tr("No GPU detected"); - } - return modelData.description; - } - font.pixelSize: Theme.fontSizeSmall - color: modelData.enabled ? Theme.outline : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6) - elide: Text.ElideRight - width: parent.width - wrapMode: Text.WordWrap - } - } - - Row { - id: actionButtons - - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - DankActionButton { - id: gpuMenuButton - visible: modelData.id === "gpuTemp" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - gpuContextMenu.widgetData = modelData; - gpuContextMenu.sectionId = root.sectionId; - gpuContextMenu.widgetIndex = index; - - var buttonPos = gpuMenuButton.mapToItem(root, 0, 0); - var popupWidth = gpuContextMenu.width; - var popupHeight = gpuContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) { - xPos = buttonPos.x + gpuMenuButton.width + Theme.spacingS; - } - - var yPos = buttonPos.y - popupHeight / 2 + gpuMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - gpuContextMenu.x = xPos; - gpuContextMenu.y = yPos; - gpuContextMenu.open(); - } - } - - Item { - width: 120 - height: 32 - visible: modelData.id === "diskUsage" - DankDropdown { - id: diskMountDropdown - anchors.fill: parent - currentValue: { - const mountPath = modelData.mountPath || "/"; - if (mountPath === "/") { - return "root (/)"; - } - return mountPath; - } - options: { - if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) { - return ["root (/)"]; - } - return DgopService.diskMounts.map(mount => { - if (mount.mount === "/") { - return "root (/)"; - } - return mount.mount; - }); - } - onValueChanged: value => { - const newPath = value === "root (/)" ? "/" : value; - root.diskMountSelectionChanged(root.sectionId, index, newPath); - } - } - } - - DankActionButton { - id: diskMenuButton - visible: modelData.id === "diskUsage" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - diskUsageContextMenu.widgetData = modelData; - diskUsageContextMenu.sectionId = root.sectionId; - diskUsageContextMenu.widgetIndex = index; - - var buttonPos = diskMenuButton.mapToItem(root, 0, 0); - var xPos = buttonPos.x - diskUsageContextMenu.width - Theme.spacingS; - if (xPos < 0) - xPos = buttonPos.x + diskMenuButton.width + Theme.spacingS; - var yPos = buttonPos.y - diskUsageContextMenu.height / 2 + diskMenuButton.height / 2; - if (yPos < 0) - yPos = Theme.spacingS; - else if (yPos + diskUsageContextMenu.height > root.height) - yPos = root.height - diskUsageContextMenu.height - Theme.spacingS; - - diskUsageContextMenu.x = xPos; - diskUsageContextMenu.y = yPos; - diskUsageContextMenu.open(); - } - } - - Item { - width: 32 - height: 32 - visible: modelData.warning !== undefined && modelData.warning !== "" - - DankIcon { - name: "warning" - size: 20 - color: Theme.error - anchors.centerIn: parent - opacity: warningArea.containsMouse ? 1.0 : 0.8 - } - - MouseArea { - id: warningArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - } - - Rectangle { - id: warningTooltip - - property string warningText: (modelData.warning !== undefined && modelData.warning !== "") ? modelData.warning : "" - - width: Math.min(250, warningTooltipText.implicitWidth) + Theme.spacingM * 2 - height: warningTooltipText.implicitHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - border.color: Theme.outline - border.width: 0 - visible: warningArea.containsMouse && warningText !== "" - opacity: visible ? 1 : 0 - x: -width - Theme.spacingS - y: (parent.height - height) / 2 - z: 100 - - StyledText { - id: warningTooltipText - anchors.centerIn: parent - anchors.margins: Theme.spacingS - text: warningTooltip.warningText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: Math.min(250, implicitWidth) - wrapMode: Text.WordWrap - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - DankActionButton { - id: minimumWidthButton - buttonSize: 28 - visible: modelData.id === "cpuUsage" || modelData.id === "memUsage" || modelData.id === "cpuTemp" || modelData.id === "gpuTemp" - iconName: "straighten" - iconSize: 16 - iconColor: (modelData.minimumWidth !== undefined ? modelData.minimumWidth : true) ? Theme.primary : Theme.outline - onClicked: { - var currentEnabled = modelData.minimumWidth !== undefined ? modelData.minimumWidth : true; - root.minimumWidthChanged(root.sectionId, index, !currentEnabled); - } - onEntered: { - var currentEnabled = modelData.minimumWidth !== undefined ? modelData.minimumWidth : true; - const tooltipText = currentEnabled ? "Force Padding" : "Dynamic Width"; - sharedTooltip.show(tooltipText, minimumWidthButton, 0, 0, "bottom"); - } - onExited: { - sharedTooltip.hide(); - } - } - - DankActionButton { - id: memMenuButton - visible: modelData.id === "memUsage" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - memUsageContextMenu.widgetData = modelData; - memUsageContextMenu.sectionId = root.sectionId; - memUsageContextMenu.widgetIndex = index; - - var buttonPos = memMenuButton.mapToItem(root, 0, 0); - var popupWidth = memUsageContextMenu.width; - var popupHeight = memUsageContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) { - xPos = buttonPos.x + memMenuButton.width + Theme.spacingS; - } - - var yPos = buttonPos.y - popupHeight / 2 + memMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - memUsageContextMenu.x = xPos; - memUsageContextMenu.y = yPos; - memUsageContextMenu.open(); - } - } - - DankActionButton { - id: musicMenuButton - visible: modelData.id === "music" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - musicContextMenu.widgetData = modelData; - musicContextMenu.sectionId = root.sectionId; - musicContextMenu.widgetIndex = index; - - var buttonPos = musicMenuButton.mapToItem(root, 0, 0); - var popupWidth = musicContextMenu.width; - var popupHeight = musicContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) - xPos = buttonPos.x + musicMenuButton.width + Theme.spacingS; - - var yPos = buttonPos.y - popupHeight / 2 + musicMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - musicContextMenu.x = xPos; - musicContextMenu.y = yPos; - musicContextMenu.open(); - } - } - - DankActionButton { - id: runningAppsMenuButton - visible: modelData.id === "runningApps" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - runningAppsContextMenu.widgetData = modelData; - runningAppsContextMenu.sectionId = root.sectionId; - runningAppsContextMenu.widgetIndex = index; - - var buttonPos = runningAppsMenuButton.mapToItem(root, 0, 0); - var popupWidth = runningAppsContextMenu.width; - var popupHeight = runningAppsContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) - xPos = buttonPos.x + runningAppsMenuButton.width + Theme.spacingS; - - var yPos = buttonPos.y - popupHeight / 2 + runningAppsMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - runningAppsContextMenu.x = xPos; - runningAppsContextMenu.y = yPos; - runningAppsContextMenu.open(); - } - } - - Row { - spacing: Theme.spacingXS - visible: modelData.id === "clock" || modelData.id === "focusedWindow" || modelData.id === "keyboard_layout_name" || modelData.id === "appsDock" || modelData.id === "systemTray" - - DankActionButton { - id: compactModeButton - buttonSize: 28 - visible: modelData.id === "clock" || modelData.id === "focusedWindow" || modelData.id === "keyboard_layout_name" - iconName: { - const isCompact = (() => { - switch (modelData.id) { - case "clock": - return modelData.clockCompactMode !== undefined ? modelData.clockCompactMode : SettingsData.clockCompactMode; - case "focusedWindow": - return modelData.focusedWindowCompactMode !== undefined ? modelData.focusedWindowCompactMode : SettingsData.focusedWindowCompactMode; - case "keyboard_layout_name": - return modelData.keyboardLayoutNameCompactMode !== undefined ? modelData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode; - default: - return false; - } - })(); - return isCompact ? "zoom_out" : "zoom_in"; - } - iconSize: 16 - iconColor: { - const isCompact = (() => { - switch (modelData.id) { - case "clock": - return modelData.clockCompactMode !== undefined ? modelData.clockCompactMode : SettingsData.clockCompactMode; - case "focusedWindow": - return modelData.focusedWindowCompactMode !== undefined ? modelData.focusedWindowCompactMode : SettingsData.focusedWindowCompactMode; - case "keyboard_layout_name": - return modelData.keyboardLayoutNameCompactMode !== undefined ? modelData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode; - default: - return false; - } - })(); - return isCompact ? Theme.primary : Theme.outline; - } - onClicked: { - const currentValue = (() => { - switch (modelData.id) { - case "clock": - return modelData.clockCompactMode !== undefined ? modelData.clockCompactMode : SettingsData.clockCompactMode; - case "focusedWindow": - return modelData.focusedWindowCompactMode !== undefined ? modelData.focusedWindowCompactMode : SettingsData.focusedWindowCompactMode; - case "keyboard_layout_name": - return modelData.keyboardLayoutNameCompactMode !== undefined ? modelData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode; - default: - return false; - } - })(); - root.compactModeChanged(modelData.id, !currentValue); - } - onEntered: { - const isCompact = (() => { - switch (modelData.id) { - case "clock": - return modelData.clockCompactMode !== undefined ? modelData.clockCompactMode : SettingsData.clockCompactMode; - case "focusedWindow": - return modelData.focusedWindowCompactMode !== undefined ? modelData.focusedWindowCompactMode : SettingsData.focusedWindowCompactMode; - case "keyboard_layout_name": - return modelData.keyboardLayoutNameCompactMode !== undefined ? modelData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode; - default: - return false; - } - })(); - const tooltipText = isCompact ? "Full Size" : "Compact"; - sharedTooltip.show(tooltipText, compactModeButton, 0, 0, "bottom"); - } - onExited: { - sharedTooltip.hide(); - } - } - - DankActionButton { - id: appsDockMenuButton - buttonSize: 32 - visible: modelData.id === "appsDock" - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - appsDockContextMenu.widgetData = modelData; - appsDockContextMenu.sectionId = root.sectionId; - appsDockContextMenu.widgetIndex = index; - - var buttonPos = appsDockMenuButton.mapToItem(root, 0, 0); - var popupWidth = appsDockContextMenu.width; - var popupHeight = appsDockContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) - xPos = buttonPos.x + appsDockMenuButton.width + Theme.spacingS; - - var yPos = buttonPos.y - popupHeight / 2 + appsDockMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - appsDockContextMenu.x = xPos; - appsDockContextMenu.y = yPos; - appsDockContextMenu.open(); - } - } - - DankActionButton { - id: trayMenuButton - buttonSize: 32 - visible: modelData.id === "systemTray" - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - trayContextMenu.widgetData = modelData; - trayContextMenu.sectionId = root.sectionId; - trayContextMenu.widgetIndex = index; - - var buttonPos = trayMenuButton.mapToItem(root, 0, 0); - var popupWidth = trayContextMenu.width; - var popupHeight = trayContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) - xPos = buttonPos.x + trayMenuButton.width + Theme.spacingS; - - var yPos = buttonPos.y - popupHeight / 2 + trayMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - trayContextMenu.x = xPos; - trayContextMenu.y = yPos; - trayContextMenu.open(); - } - } - - Rectangle { - id: compactModeTooltip - width: tooltipText.contentWidth + Theme.spacingM * 2 - height: tooltipText.contentHeight + Theme.spacingS * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - border.color: Theme.outline - border.width: 0 - visible: false - opacity: visible ? 1 : 0 - x: -width - Theme.spacingS - y: (parent.height - height) / 2 - z: 100 - - StyledText { - id: tooltipText - anchors.centerIn: parent - text: I18n.tr("Compact Mode") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - DankActionButton { - id: ccMenuButton - visible: modelData.id === "controlCenterButton" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - controlCenterContextMenu.widgetData = modelData; - controlCenterContextMenu.sectionId = root.sectionId; - controlCenterContextMenu.widgetIndex = index; - controlCenterContextMenu.controlCenterGroups = controlCenterContextMenu.getOrderedControlCenterGroups(); - - var buttonPos = ccMenuButton.mapToItem(root, 0, 0); - var popupWidth = controlCenterContextMenu.width; - var popupHeight = controlCenterContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) { - xPos = buttonPos.x + ccMenuButton.width + Theme.spacingS; - } - - var yPos = buttonPos.y - popupHeight / 2 + ccMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - controlCenterContextMenu.x = xPos; - controlCenterContextMenu.y = yPos; - controlCenterContextMenu.open(); - } - } - - DankActionButton { - id: privacyMenuButton - visible: modelData.id === "privacyIndicator" - buttonSize: 32 - iconName: "more_vert" - iconSize: 18 - iconColor: Theme.outline - onClicked: { - privacyContextMenu.widgetData = modelData; - privacyContextMenu.sectionId = root.sectionId; - privacyContextMenu.widgetIndex = index; - - var buttonPos = privacyMenuButton.mapToItem(root, 0, 0); - var popupWidth = privacyContextMenu.width; - var popupHeight = privacyContextMenu.height; - - var xPos = buttonPos.x - popupWidth - Theme.spacingS; - if (xPos < 0) { - xPos = buttonPos.x + privacyMenuButton.width + Theme.spacingS; - } - - var yPos = buttonPos.y - popupHeight / 2 + privacyMenuButton.height / 2; - if (yPos < 0) { - yPos = Theme.spacingS; - } else if (yPos + popupHeight > root.height) { - yPos = root.height - popupHeight - Theme.spacingS; - } - - privacyContextMenu.x = xPos; - privacyContextMenu.y = yPos; - privacyContextMenu.open(); - } - } - - DankActionButton { - id: visibilityButton - visible: modelData.id !== "spacer" - buttonSize: 32 - iconName: modelData.enabled ? "visibility" : "visibility_off" - iconSize: 18 - iconColor: modelData.enabled ? Theme.primary : Theme.outline - onClicked: { - root.itemEnabledChanged(root.sectionId, modelData.id, !modelData.enabled); - } - onEntered: { - const tooltipText = modelData.enabled ? "Hide" : "Show"; - sharedTooltip.show(tooltipText, visibilityButton, 0, 0, "bottom"); - } - onExited: { - sharedTooltip.hide(); - } - } - - Row { - visible: modelData.id === "spacer" - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 24 - iconName: "remove" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var currentSize = modelData.size || 20; - var newSize = Math.max(5, currentSize - 5); - root.spacerSizeChanged(root.sectionId, index, newSize); - } - } - - StyledText { - text: (modelData.size || 20).toString() - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankActionButton { - buttonSize: 24 - iconName: "add" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var currentSize = modelData.size || 20; - var newSize = Math.min(5000, currentSize + 5); - root.spacerSizeChanged(root.sectionId, index, newSize); - } - } - } - - DankActionButton { - buttonSize: 32 - iconName: "close" - iconSize: 18 - iconColor: Theme.error - onClicked: { - root.removeWidget(root.sectionId, index); - } - } - } - - MouseArea { - id: dragArea - - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - width: 60 - hoverEnabled: true - cursorShape: Qt.SizeVerCursor - drag.target: held ? delegateItem : undefined - drag.axis: Drag.YAxis - drag.minimumY: -delegateItem.height - drag.maximumY: itemsList.height - preventStealing: true - onPressed: { - delegateItem.z = 2; - delegateItem.originalY = delegateItem.y; - } - onReleased: { - delegateItem.z = 1; - if (drag.active) { - var newIndex = Math.round(delegateItem.y / (delegateItem.height + itemsList.spacing)); - newIndex = Math.max(0, Math.min(newIndex, root.items.length - 1)); - if (newIndex !== index) { - var newItems = root.items.slice(); - var draggedItem = newItems.splice(index, 1)[0]; - newItems.splice(newIndex, 0, draggedItem); - root.itemOrderChanged(newItems.map(item => root.cloneWidgetData(item))); - } - } - delegateItem.x = 0; - delegateItem.y = delegateItem.originalY; - } - } - - Behavior on y { - enabled: !dragArea.held && !dragArea.drag.active - - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - - Rectangle { - width: 200 - height: 40 - radius: Theme.cornerRadius - color: addButtonArea.containsMouse ? Theme.primaryContainer : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 0 - anchors.horizontalCenter: parent.horizontalCenter - - StyledText { - text: I18n.tr("Add Widget") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - anchors.centerIn: parent - } - - MouseArea { - id: addButtonArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.addWidget(root.sectionId); - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Popup { - id: memUsageContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - width: 200 - height: 80 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: swapToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "swap_horiz" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Show Swap") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: swapToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: memUsageContextMenu.widgetData?.showSwap ?? false - onToggled: { - root.showSwapChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, toggled); - } - } - - MouseArea { - id: swapToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - swapToggle.checked = !swapToggle.checked; - root.showSwapChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, swapToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: gbToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "straighten" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Show in GB") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: gbToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: memUsageContextMenu.widgetData?.showInGb ?? false - onToggled: { - root.showInGbChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, toggled); - } - } - - MouseArea { - id: gbToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - gbToggle.checked = !gbToggle.checked; - root.showInGbChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, gbToggle.checked); - } - } - } - } - } - } - - Popup { - id: trayContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - readonly property var currentWidgetData: (widgetIndex >= 0 && widgetIndex < root.items.length) ? root.items[widgetIndex] : widgetData - - width: 220 - height: contentColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: contentColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: trayOverflowArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "arrow_selector_tool" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Use Inline Expansion") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: trayOverflowToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: trayContextMenu.currentWidgetData?.trayUseInlineExpansion ?? false - } - - MouseArea { - id: trayOverflowArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - const newValue = !(trayContextMenu.currentWidgetData?.trayUseInlineExpansion ?? false); - root.overflowSettingChanged(trayContextMenu.sectionId, trayContextMenu.widgetIndex, "trayUseInlineExpansion", newValue); - } - } - } - } - } - } - - Popup { - id: diskUsageContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - readonly property var currentWidgetData: (widgetIndex >= 0 && widgetIndex < root.items.length) ? root.items[widgetIndex] : widgetData - - width: 240 - height: diskMenuColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: diskMenuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Disk Usage Display") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - } - - Repeater { - model: [ - { - label: I18n.tr("Percentage"), - mode: 0, - icon: "percent" - }, - { - label: I18n.tr("Total"), - mode: 1, - icon: "storage" - }, - { - label: I18n.tr("Remaining"), - mode: 2, - icon: "hourglass_empty" - }, - { - label: I18n.tr("Remaining / Total"), - mode: 3, - icon: "pie_chart" - } - ] - - delegate: Rectangle { - required property var modelData - required property int index - - width: diskMenuColumn.width - height: 32 - radius: Theme.cornerRadius - color: diskOptionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - function isSelected() { - return (diskUsageContextMenu.currentWidgetData?.diskUsageMode ?? 0) === modelData.mode; - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: modelData.icon - size: 16 - color: isSelected() ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: isSelected() ? Theme.primary : Theme.surfaceText - font.weight: isSelected() ? Font.Medium : Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankIcon { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - name: "check" - size: 16 - color: Theme.primary - visible: isSelected() - } - - MouseArea { - id: diskOptionArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.diskUsageModeChanged(diskUsageContextMenu.sectionId, diskUsageContextMenu.widgetIndex, modelData.mode); - diskUsageContextMenu.close(); - } - } - } - } - } - } - } - - Popup { - id: controlCenterContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - readonly property real minimumContentWidth: controlCenterContentMetrics.implicitWidth + Theme.spacingS * 2 - readonly property real controlCenterRowHeight: 32 - readonly property real controlCenterRowSpacing: 1 - readonly property real controlCenterGroupVerticalPadding: Theme.spacingXS * 2 - readonly property real controlCenterMenuSpacing: 2 - width: Math.max(220, minimumContentWidth) - height: getControlCenterPopupHeight(controlCenterGroups) - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - onClosed: { - cancelControlCenterDrag(); - } - - readonly property var defaultControlCenterGroups: [ - { - id: "network", - rows: [ - { - icon: "lan", - label: I18n.tr("Network"), - setting: "showNetworkIcon" - } - ] - }, - { - id: "vpn", - rows: [ - { - icon: "vpn_lock", - label: I18n.tr("VPN"), - setting: "showVpnIcon" - } - ] - }, - { - id: "bluetooth", - rows: [ - { - icon: "bluetooth", - label: I18n.tr("Bluetooth"), - setting: "showBluetoothIcon" - } - ] - }, - { - id: "audio", - rows: [ - { - icon: "volume_up", - label: I18n.tr("Audio"), - setting: "showAudioIcon" - }, - { - icon: "percent", - label: I18n.tr("Volume"), - setting: "showAudioPercent" - } - ] - }, - { - id: "microphone", - rows: [ - { - icon: "mic", - label: I18n.tr("Microphone"), - setting: "showMicIcon" - }, - { - icon: "percent", - label: I18n.tr("Microphone Volume"), - setting: "showMicPercent" - } - ] - }, - { - id: "brightness", - rows: [ - { - icon: "brightness_high", - label: I18n.tr("Brightness"), - setting: "showBrightnessIcon" - }, - { - icon: "percent", - label: I18n.tr("Brightness Value"), - setting: "showBrightnessPercent" - } - ] - }, - { - id: "battery", - rows: [ - { - icon: "battery_full", - label: I18n.tr("Battery"), - setting: "showBatteryIcon" - } - ] - }, - { - id: "printer", - rows: [ - { - icon: "print", - label: I18n.tr("Printer"), - setting: "showPrinterIcon" - } - ] - }, - { - id: "screenSharing", - rows: [ - { - icon: "screen_record", - label: I18n.tr("Screen Sharing"), - setting: "showScreenSharingIcon" - } - ] - } - ] - property var controlCenterGroups: defaultControlCenterGroups - property int draggedControlCenterGroupIndex: -1 - property int controlCenterGroupDropIndex: -1 - - function updateControlCenterGroupDropIndex(draggedIndex, localY) { - const totalGroups = controlCenterGroups.length; - let dropIndex = totalGroups; - - for (let i = 0; i < totalGroups; i++) { - const delegate = groupRepeater.itemAt(i); - if (!delegate) - continue; - - const midpoint = delegate.y + delegate.height / 2; - if (localY < midpoint) { - dropIndex = i; - break; - } - } - - controlCenterGroupDropIndex = Math.max(0, Math.min(totalGroups, dropIndex)); - draggedControlCenterGroupIndex = draggedIndex; - } - - function finishControlCenterDrag() { - if (draggedControlCenterGroupIndex < 0) { - controlCenterGroupDropIndex = -1; - return; - } - - const fromIndex = draggedControlCenterGroupIndex; - let toIndex = controlCenterGroupDropIndex; - - draggedControlCenterGroupIndex = -1; - controlCenterGroupDropIndex = -1; - - if (toIndex < 0 || toIndex > controlCenterGroups.length || toIndex === fromIndex || toIndex === fromIndex + 1) - return; - - const groups = controlCenterGroups.slice(); - const moved = groups.splice(fromIndex, 1)[0]; - - if (toIndex > fromIndex) - toIndex -= 1; - - groups.splice(toIndex, 0, moved); - controlCenterGroups = groups; - const reorderedGroupIds = groups.map(group => group.id); - root.controlCenterGroupOrderChanged(sectionId, widgetIndex, reorderedGroupIds); - } - - function cancelControlCenterDrag() { - draggedControlCenterGroupIndex = -1; - controlCenterGroupDropIndex = -1; - } - - function getControlCenterGroupHeight(group) { - const rowCount = group?.rows?.length ?? 0; - if (rowCount <= 0) - return controlCenterGroupVerticalPadding; - - return rowCount * controlCenterRowHeight + Math.max(0, rowCount - 1) * controlCenterRowSpacing + controlCenterGroupVerticalPadding; - } - - function getControlCenterPopupHeight(groups) { - const orderedGroups = groups || []; - let totalHeight = Theme.spacingS * 2; - - for (let i = 0; i < orderedGroups.length; i++) { - totalHeight += getControlCenterGroupHeight(orderedGroups[i]); - if (i < orderedGroups.length - 1) - totalHeight += controlCenterMenuSpacing; - } - - return totalHeight; - } - - function getOrderedControlCenterGroups() { - const baseGroups = defaultControlCenterGroups.slice(); - const currentWidget = contentItem.getCurrentWidgetData(); - const savedOrder = currentWidget?.controlCenterGroupOrder; - if (!savedOrder || !savedOrder.length) - return baseGroups; - - const groupMap = {}; - for (let i = 0; i < baseGroups.length; i++) - groupMap[baseGroups[i].id] = baseGroups[i]; - - const orderedGroups = []; - for (let i = 0; i < savedOrder.length; i++) { - const groupId = savedOrder[i]; - const group = groupMap[groupId]; - if (group) { - orderedGroups.push(group); - delete groupMap[groupId]; - } - } - - for (let i = 0; i < baseGroups.length; i++) { - const group = baseGroups[i]; - if (groupMap[group.id]) - orderedGroups.push(group); - } - - return orderedGroups; - } - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - function getCurrentWidgetData() { - const widgets = root.items || []; - if (controlCenterContextMenu.widgetIndex >= 0 && controlCenterContextMenu.widgetIndex < widgets.length) - return widgets[controlCenterContextMenu.widgetIndex]; - return controlCenterContextMenu.widgetData; - } - - Column { - id: menuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Item { - id: controlCenterContentMetrics - visible: false - implicitWidth: 16 + Theme.spacingS + 16 + Theme.spacingS + longestControlCenterLabelMetrics.advanceWidth + Theme.spacingM + 40 + Theme.spacingS * 2 + Theme.spacingM - } - - TextMetrics { - id: longestControlCenterLabelMetrics - font.pixelSize: Theme.fontSizeSmall - text: { - const labels = [I18n.tr("Network"), I18n.tr("VPN"), I18n.tr("Bluetooth"), I18n.tr("Audio"), I18n.tr("Volume"), I18n.tr("Microphone"), I18n.tr("Microphone Volume"), I18n.tr("Brightness"), I18n.tr("Brightness Value"), I18n.tr("Battery"), I18n.tr("Printer"), I18n.tr("Screen Sharing")]; - let longest = ""; - for (let i = 0; i < labels.length; i++) { - if (labels[i].length > longest.length) - longest = labels[i]; - } - return longest; - } - } - - Repeater { - id: groupRepeater - model: controlCenterContextMenu.controlCenterGroups - - delegate: Item { - id: delegateRoot - - required property var modelData - required property int index - - function getCheckedState(settingName) { - const wd = controlCenterContextMenu.contentItem.getCurrentWidgetData(); - switch (settingName) { - case "showNetworkIcon": - return wd?.showNetworkIcon ?? SettingsData.controlCenterShowNetworkIcon; - case "showVpnIcon": - return wd?.showVpnIcon ?? SettingsData.controlCenterShowVpnIcon; - case "showBluetoothIcon": - return wd?.showBluetoothIcon ?? SettingsData.controlCenterShowBluetoothIcon; - case "showAudioIcon": - return wd?.showAudioIcon ?? SettingsData.controlCenterShowAudioIcon; - case "showAudioPercent": - return wd?.showAudioPercent ?? SettingsData.controlCenterShowAudioPercent; - case "showMicIcon": - return wd?.showMicIcon ?? SettingsData.controlCenterShowMicIcon; - case "showMicPercent": - return wd?.showMicPercent ?? SettingsData.controlCenterShowMicPercent; - case "showBrightnessIcon": - return wd?.showBrightnessIcon ?? SettingsData.controlCenterShowBrightnessIcon; - case "showBrightnessPercent": - return wd?.showBrightnessPercent ?? SettingsData.controlCenterShowBrightnessPercent; - case "showBatteryIcon": - return wd?.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon; - case "showPrinterIcon": - return wd?.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon; - case "showScreenSharingIcon": - return wd?.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon; - default: - return false; - } - } - - readonly property string rootSetting: modelData.rows[0]?.setting ?? "" - readonly property bool rootEnabled: rootSetting ? getCheckedState(rootSetting) : true - readonly property bool isDragged: controlCenterContextMenu.draggedControlCenterGroupIndex === index - readonly property bool showDropIndicatorAbove: controlCenterContextMenu.controlCenterGroupDropIndex === index - readonly property bool showDropIndicatorBelow: controlCenterContextMenu.controlCenterGroupDropIndex === controlCenterContextMenu.controlCenterGroups.length && index === controlCenterContextMenu.controlCenterGroups.length - 1 - - width: menuColumn.width - height: groupBackground.height - - Rectangle { - id: groupBackground - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: groupContent.implicitHeight + Theme.spacingXS * 2 - radius: Theme.cornerRadius - color: isDragged ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.18) : (groupHoverArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent") - opacity: isDragged ? 0.75 : 1.0 - } - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: -1 - height: 2 - radius: 1 - color: Theme.primary - visible: showDropIndicatorAbove - z: 3 - } - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.bottomMargin: -1 - height: 2 - radius: 1 - color: Theme.primary - visible: showDropIndicatorBelow - z: 3 - } - - Item { - id: groupContent - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: Theme.spacingXS - implicitHeight: groupColumn.implicitHeight - - Column { - id: groupColumn - anchors.left: parent.left - anchors.right: parent.right - spacing: 1 - - Repeater { - id: groupColumnRepeater - model: modelData.rows - - delegate: Rectangle { - required property var modelData - required property int index - - readonly property var rowData: modelData - readonly property bool isFirstRow: index === 0 - readonly property bool rowEnabled: isFirstRow ? true : delegateRoot.rootEnabled - readonly property bool computedCheckedState: rowEnabled ? getCheckedState(rowData.setting) : false - readonly property bool rowHovered: rowEnabled && (toggleArea.containsMouse || (isFirstRow && groupDragHandleArea.containsMouse)) - - width: groupColumn.width - height: 32 - radius: Theme.cornerRadius - opacity: rowEnabled ? 1.0 : 0.5 - color: rowHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: toggle.left - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - Item { - width: 16 - height: 16 - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - anchors.centerIn: parent - name: "drag_indicator" - size: 16 - color: groupDragHandleArea.pressed || isDragged ? Theme.primary : Theme.outline - visible: isFirstRow - } - - MouseArea { - id: groupDragHandleArea - anchors.fill: parent - hoverEnabled: true - preventStealing: true - enabled: isFirstRow - cursorShape: pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor - - onPressed: mouse => { - mouse.accepted = true; - const point = mapToItem(menuColumn, mouse.x, mouse.y); - controlCenterContextMenu.updateControlCenterGroupDropIndex(delegateRoot.index, point.y); - } - onPositionChanged: mouse => { - if (!pressed) - return; - mouse.accepted = true; - const point = mapToItem(menuColumn, mouse.x, mouse.y); - controlCenterContextMenu.updateControlCenterGroupDropIndex(delegateRoot.index, point.y); - } - onReleased: mouse => { - mouse.accepted = true; - const point = mapToItem(menuColumn, mouse.x, mouse.y); - controlCenterContextMenu.updateControlCenterGroupDropIndex(delegateRoot.index, point.y); - controlCenterContextMenu.finishControlCenterDrag(); - } - onCanceled: { - controlCenterContextMenu.cancelControlCenterDrag(); - } - } - } - - DankIcon { - name: rowData.icon - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: rowData.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: toggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - enabled: rowEnabled - checked: computedCheckedState - - onToggled: { - if (!rowEnabled) - return; - root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, rowData.setting, toggled); - } - } - - MouseArea { - id: toggleArea - anchors.fill: parent - anchors.leftMargin: 16 + Theme.spacingS * 2 - hoverEnabled: true - cursorShape: rowEnabled ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: rowEnabled && controlCenterContextMenu.draggedControlCenterGroupIndex < 0 - onPressed: { - if (!rowEnabled) - return; - root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, rowData.setting, !computedCheckedState); - } - } - } - } - } - - MouseArea { - id: groupHoverArea - anchors.fill: parent - hoverEnabled: true - enabled: false - } - } - } - } - } - } - } - - Popup { - id: privacyContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - width: 200 - height: 160 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - onOpened: { - console.log("Privacy context menu opened"); - } - - onClosed: { - console.log("Privacy Center context menu closed"); - } - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - - Column { - id: menuPrivacyColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Always on icons") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: micToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "mic" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Microphone") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: micToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.privacyShowMicIcon - onToggled: toggled => { - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showMicIcon", toggled); - } - } - - MouseArea { - id: micToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - micToggle.checked = !micToggle.checked; - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showMicIcon", micToggle.checked); - } - } - } - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: cameraToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "camera_video" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Camera") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: cameraToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.privacyShowCameraIcon - onToggled: toggled => { - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showCameraIcon", toggled); - } - } - - MouseArea { - id: cameraToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - cameraToggle.checked = !cameraToggle.checked; - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showCameraIcon", cameraToggle.checked); - } - } - } - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: screenshareToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "screen_share" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Screen sharing") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: screenshareToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.privacyShowScreenShareIcon - onToggled: toggled => { - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showScreenSharingIcon", toggled); - } - } - - MouseArea { - id: screenshareToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - screenshareToggle.checked = !screenshareToggle.checked; - root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showScreenSharingIcon", screenshareToggle.checked); - } - } - } - } - } - } - - Popup { - id: gpuContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - width: 250 - height: gpuMenuColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: gpuMenuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Repeater { - model: DgopService.availableGpus || [] - - delegate: Rectangle { - required property var modelData - required property int index - - width: gpuMenuColumn.width - height: 40 - radius: Theme.cornerRadius - color: gpuOptionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - property bool isSelected: { - var selectedIdx = gpuContextMenu.widgetData ? (gpuContextMenu.widgetData.selectedGpuIndex !== undefined ? gpuContextMenu.widgetData.selectedGpuIndex : 0) : 0; - return index === selectedIdx; - } - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.right: checkIcon.left - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "memory" - size: 18 - color: isSelected ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - Column { - anchors.verticalCenter: parent.verticalCenter - spacing: 2 - - StyledText { - text: modelData.driver ? modelData.driver.toUpperCase() : "" - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: isSelected ? Theme.primary : Theme.surfaceText - } - - StyledText { - text: modelData.displayName || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - width: 180 - } - } - } - - DankIcon { - id: checkIcon - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - name: "check" - size: 18 - color: Theme.primary - visible: isSelected - } - - MouseArea { - id: gpuOptionArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.gpuSelectionChanged(gpuContextMenu.sectionId, gpuContextMenu.widgetIndex, index); - gpuContextMenu.close(); - } - } - } - } - } - } - } - - Popup { - id: musicContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - width: 180 - height: musicMenuColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: musicMenuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Repeater { - model: [ - { - icon: "photo_size_select_small", - label: I18n.tr("Small"), - sizeValue: 0 - }, - { - icon: "photo_size_select_actual", - label: I18n.tr("Medium"), - sizeValue: 1 - }, - { - icon: "photo_size_select_large", - label: I18n.tr("Large"), - sizeValue: 2 - }, - { - icon: "fit_screen", - label: I18n.tr("Largest"), - sizeValue: 3 - } - ] - - delegate: Rectangle { - required property var modelData - required property int index - - function isSelected() { - var wd = musicContextMenu.widgetData; - var currentSize = wd?.mediaSize ?? SettingsData.mediaSize; - return currentSize === modelData.sizeValue; - } - - width: musicMenuColumn.width - height: Math.max(18, Theme.fontSizeSmall) + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: musicOptionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: modelData.icon - size: 18 - color: isSelected() ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - font.weight: isSelected() ? Font.Medium : Font.Normal - color: isSelected() ? Theme.primary : Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankIcon { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - name: "check" - size: 16 - color: Theme.primary - visible: isSelected() - } - - MouseArea { - id: musicOptionArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - root.compactModeChanged("music", modelData.sizeValue); - musicContextMenu.close(); - } - } - } - } - } - } - } - - Popup { - id: runningAppsContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - readonly property var currentWidgetData: (widgetIndex >= 0 && widgetIndex < root.items.length) ? root.items[widgetIndex] : widgetData - - width: 240 - height: runningAppsMenuColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: runningAppsMenuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: 2 - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: "transparent" - - StyledText { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - text: I18n.tr("Running Apps Settings") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: raCompactArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "zoom_in" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Compact Mode") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: raCompactToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: runningAppsContextMenu.currentWidgetData?.runningAppsCompactMode ?? SettingsData.runningAppsCompactMode - onToggled: { - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCompactMode", toggled); - } - } - - MouseArea { - id: raCompactArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - raCompactToggle.checked = !raCompactToggle.checked; - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCompactMode", raCompactToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: raGroupArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "apps" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Group by App") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: raGroupToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: runningAppsContextMenu.currentWidgetData?.runningAppsGroupByApp ?? SettingsData.runningAppsGroupByApp - onToggled: { - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsGroupByApp", toggled); - } - } - - MouseArea { - id: raGroupArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - raGroupToggle.checked = !raGroupToggle.checked; - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsGroupByApp", raGroupToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: raWorkspaceArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "workspaces" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Current Workspace", "Running apps filter: only show apps from the active workspace") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: raWorkspaceToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: runningAppsContextMenu.currentWidgetData?.runningAppsCurrentWorkspace ?? SettingsData.runningAppsCurrentWorkspace - onToggled: { - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCurrentWorkspace", toggled); - } - } - - MouseArea { - id: raWorkspaceArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - raWorkspaceToggle.checked = !raWorkspaceToggle.checked; - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCurrentWorkspace", raWorkspaceToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: raDisplayArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "monitor" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Current Monitor", "Running apps filter: only show apps from the same monitor") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: raDisplayToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: runningAppsContextMenu.currentWidgetData?.runningAppsCurrentMonitor ?? SettingsData.runningAppsCurrentMonitor - onToggled: { - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCurrentMonitor", toggled); - } - } - - MouseArea { - id: raDisplayArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - raDisplayToggle.checked = !raDisplayToggle.checked; - root.overflowSettingChanged(runningAppsContextMenu.sectionId, runningAppsContextMenu.widgetIndex, "runningAppsCurrentMonitor", raDisplayToggle.checked); - } - } - } - } - } - } - - Popup { - id: appsDockContextMenu - - property var widgetData: null - property string sectionId: "" - property int widgetIndex: -1 - - // Dynamically get current widget data from the items list - readonly property var currentWidgetData: (widgetIndex >= 0 && widgetIndex < root.items.length) ? root.items[widgetIndex] : widgetData - - width: 320 - height: appsDockMenuColumn.implicitHeight + Theme.spacingS * 2 - padding: 0 - modal: true - focus: true - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - background: Rectangle { - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) - border.width: 0 - } - - contentItem: Item { - Column { - id: appsDockMenuColumn - anchors.fill: parent - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Apps Dock Settings") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - leftPadding: Theme.spacingS - } - - StyledText { - text: I18n.tr("Overflow") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - leftPadding: Theme.spacingS - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Max Pinned Apps") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 120 - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 24 - iconName: "remove" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = appsDockContextMenu.currentWidgetData?.barMaxVisibleApps ?? SettingsData.barMaxVisibleApps; - var newVal = Math.max(0, current - 1); - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barMaxVisibleApps", newVal); - } - } - - StyledText { - text: { - var val = appsDockContextMenu.currentWidgetData?.barMaxVisibleApps ?? SettingsData.barMaxVisibleApps; - return val === 0 ? I18n.tr("All") : val; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignHCenter - width: 30 - } - - DankActionButton { - buttonSize: 24 - iconName: "add" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = appsDockContextMenu.currentWidgetData?.barMaxVisibleApps ?? SettingsData.barMaxVisibleApps; - var newVal = current + 1; - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barMaxVisibleApps", newVal); - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Max Running Apps") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 120 - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 24 - iconName: "remove" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = appsDockContextMenu.currentWidgetData?.barMaxVisibleRunningApps ?? SettingsData.barMaxVisibleRunningApps; - var newVal = Math.max(0, current - 1); - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barMaxVisibleRunningApps", newVal); - } - } - - StyledText { - text: { - var val = appsDockContextMenu.currentWidgetData?.barMaxVisibleRunningApps ?? SettingsData.barMaxVisibleRunningApps; - return val === 0 ? I18n.tr("All") : val; - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignHCenter - width: 30 - } - - DankActionButton { - buttonSize: 24 - iconName: "add" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = appsDockContextMenu.currentWidgetData?.barMaxVisibleRunningApps ?? SettingsData.barMaxVisibleRunningApps; - var newVal = current + 1; - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barMaxVisibleRunningApps", newVal); - } - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: badgeToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "notifications" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Show Badge") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: badgeToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: appsDockContextMenu.currentWidgetData?.barShowOverflowBadge ?? SettingsData.barShowOverflowBadge - onToggled: { - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barShowOverflowBadge", toggled); - } - } - - MouseArea { - id: badgeToggleArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - badgeToggle.checked = !badgeToggle.checked; - root.overflowSettingChanged(appsDockContextMenu.sectionId, appsDockContextMenu.widgetIndex, "barShowOverflowBadge", badgeToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - StyledText { - text: I18n.tr("Visual Effects") - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - leftPadding: Theme.spacingS - topPadding: Theme.spacingXS - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: hideIndicatorsArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "visibility_off" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Hide Indicators") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: hideIndicatorsToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.appsDockHideIndicators - onToggled: { - SettingsData.set("appsDockHideIndicators", toggled); - } - } - - MouseArea { - id: hideIndicatorsArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - hideIndicatorsToggle.checked = !hideIndicatorsToggle.checked; - SettingsData.set("appsDockHideIndicators", hideIndicatorsToggle.checked); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: colorizeActiveArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "palette" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Colorize Active") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: colorizeActiveToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.appsDockColorizeActive - onToggled: { - SettingsData.set("appsDockColorizeActive", toggled); - } - } - - MouseArea { - id: colorizeActiveArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - colorizeActiveToggle.checked = !colorizeActiveToggle.checked; - SettingsData.set("appsDockColorizeActive", colorizeActiveToggle.checked); - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: SettingsData.appsDockColorizeActive - leftPadding: Theme.spacingL + Theme.spacingS - - StyledText { - text: I18n.tr("Active Color") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 90 - } - - DankButtonGroup { - anchors.verticalCenter: parent.verticalCenter - model: ["pri", "sec", "pc", "err", "ok"] - buttonHeight: 22 - minButtonWidth: 32 - buttonPadding: 4 - checkIconSize: 10 - textSize: 9 - spacing: 1 - currentIndex: { - switch (SettingsData.appsDockActiveColorMode) { - case "secondary": - return 1; - case "primaryContainer": - return 2; - case "error": - return 3; - case "success": - return 4; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["primary", "secondary", "primaryContainer", "error", "success"]; - SettingsData.set("appsDockActiveColorMode", modes[index]); - } - } - } - - Rectangle { - width: parent.width - height: 32 - radius: Theme.cornerRadius - color: enlargeOnHoverArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" - - Row { - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankIcon { - name: "zoom_in" - size: 16 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Enlarge on Hover") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - anchors.verticalCenter: parent.verticalCenter - } - } - - DankToggle { - id: enlargeOnHoverToggle - anchors.right: parent.right - anchors.rightMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - width: 40 - height: 20 - checked: SettingsData.appsDockEnlargeOnHover - onToggled: { - SettingsData.set("appsDockEnlargeOnHover", toggled); - } - } - - MouseArea { - id: enlargeOnHoverArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onPressed: { - enlargeOnHoverToggle.checked = !enlargeOnHoverToggle.checked; - SettingsData.set("appsDockEnlargeOnHover", enlargeOnHoverToggle.checked); - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - visible: SettingsData.appsDockEnlargeOnHover - - StyledText { - text: I18n.tr("Enlargement %") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 120 - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 24 - iconName: "remove" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = SettingsData.appsDockEnlargePercentage; - var newVal = Math.max(100, current - 5); - SettingsData.set("appsDockEnlargePercentage", newVal); - } - } - - StyledText { - text: SettingsData.appsDockEnlargePercentage + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignHCenter - width: 50 - } - - DankActionButton { - buttonSize: 24 - iconName: "add" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = SettingsData.appsDockEnlargePercentage; - var newVal = Math.min(150, current + 5); - SettingsData.set("appsDockEnlargePercentage", newVal); - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Icon Size %") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 120 - } - - Row { - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - DankActionButton { - buttonSize: 24 - iconName: "remove" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = SettingsData.appsDockIconSizePercentage; - var newVal = Math.max(50, current - 5); - SettingsData.set("appsDockIconSizePercentage", newVal); - } - } - - StyledText { - text: SettingsData.appsDockIconSizePercentage + "%" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignHCenter - width: 50 - } - - DankActionButton { - buttonSize: 24 - iconName: "add" - iconSize: 14 - iconColor: Theme.outline - onClicked: { - var current = SettingsData.appsDockIconSizePercentage; - var newVal = Math.min(200, current + 5); - SettingsData.set("appsDockIconSizePercentage", newVal); - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WindowRulesTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WindowRulesTab.qml deleted file mode 100644 index 5e1310e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WindowRulesTab.qml +++ /dev/null @@ -1,685 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtCore -import QtQuick -import QtQuick.Layouts -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - - LayoutMirroring.enabled: I18n.isRtl - LayoutMirroring.childrenInherit: true - - property var parentModal: null - property var windowRulesIncludeStatus: ({ - "exists": false, - "included": false - }) - property bool checkingInclude: false - property bool fixingInclude: false - property var windowRules: [] - property var activeWindows: getActiveWindows() - - signal rulesChanged - - function getActiveWindows() { - const toplevels = ToplevelManager.toplevels?.values || []; - return toplevels.map(t => ({ - appId: t.appId || "", - title: t.title || "" - })); - } - - Connections { - target: ToplevelManager.toplevels - function onValuesChanged() { - root.activeWindows = root.getActiveWindows(); - } - } - - function getWindowRulesConfigPaths() { - const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); - switch (CompositorService.compositor) { - case "niri": - return { - "configFile": configDir + "/niri/config.kdl", - "rulesFile": configDir + "/niri/dms/windowrules.kdl", - "grepPattern": 'include.*"dms/windowrules.kdl"', - "includeLine": 'include "dms/windowrules.kdl"' - }; - case "hyprland": - return { - "configFile": configDir + "/hypr/hyprland.conf", - "rulesFile": configDir + "/hypr/dms/windowrules.conf", - "grepPattern": 'source.*dms/windowrules.conf', - "includeLine": "source = ./dms/windowrules.conf" - }; - default: - return null; - } - } - - function loadWindowRules() { - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland") { - windowRules = []; - return; - } - - Proc.runCommand("load-windowrules", ["dms", "config", "windowrules", "list", compositor], (output, exitCode) => { - if (exitCode !== 0) { - windowRules = []; - return; - } - try { - const result = JSON.parse(output.trim()); - const allRules = result.rules || []; - windowRules = allRules.filter(r => (r.source || "").includes("dms/windowrules")); - if (result.dmsStatus) { - windowRulesIncludeStatus = { - "exists": result.dmsStatus.exists, - "included": result.dmsStatus.included - }; - } - } catch (e) { - windowRules = []; - } - }); - } - - function removeRule(ruleId) { - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland") - return; - - Proc.runCommand("remove-windowrule", ["dms", "config", "windowrules", "remove", compositor, ruleId], (output, exitCode) => { - if (exitCode === 0) { - loadWindowRules(); - rulesChanged(); - } - }); - } - - function reorderRules(fromIndex, toIndex) { - if (fromIndex === toIndex) - return; - - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland") - return; - - let ids = windowRules.map(r => r.id); - const [moved] = ids.splice(fromIndex, 1); - ids.splice(toIndex, 0, moved); - - Proc.runCommand("reorder-windowrules", ["dms", "config", "windowrules", "reorder", compositor, JSON.stringify(ids)], (output, exitCode) => { - if (exitCode === 0) { - loadWindowRules(); - rulesChanged(); - } - }); - } - - function checkWindowRulesIncludeStatus() { - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland") { - windowRulesIncludeStatus = { - "exists": false, - "included": false - }; - return; - } - - const filename = (compositor === "niri") ? "windowrules.kdl" : "windowrules.conf"; - checkingInclude = true; - Proc.runCommand("check-windowrules-include", ["dms", "config", "resolve-include", compositor, filename], (output, exitCode) => { - checkingInclude = false; - if (exitCode !== 0) { - windowRulesIncludeStatus = { - "exists": false, - "included": false - }; - return; - } - try { - windowRulesIncludeStatus = JSON.parse(output.trim()); - } catch (e) { - windowRulesIncludeStatus = { - "exists": false, - "included": false - }; - } - }); - } - - function fixWindowRulesInclude() { - const paths = getWindowRulesConfigPaths(); - if (!paths) - return; - fixingInclude = true; - const rulesDir = paths.rulesFile.substring(0, paths.rulesFile.lastIndexOf("/")); - const unixTime = Math.floor(Date.now() / 1000); - const backupFile = paths.configFile + ".backup" + unixTime; - Proc.runCommand("fix-windowrules-include", ["sh", "-c", `cp "${paths.configFile}" "${backupFile}" 2>/dev/null; ` + `mkdir -p "${rulesDir}" && ` + `touch "${paths.rulesFile}" && ` + `if ! grep -v '^[[:space:]]*\\(//\\|#\\)' "${paths.configFile}" 2>/dev/null | grep -q '${paths.grepPattern}'; then ` + `echo '' >> "${paths.configFile}" && ` + `echo '${paths.includeLine}' >> "${paths.configFile}"; fi`], (output, exitCode) => { - fixingInclude = false; - if (exitCode !== 0) - return; - checkWindowRulesIncludeStatus(); - loadWindowRules(); - }); - } - - function openRuleModal(window) { - if (!PopoutService.windowRuleModalLoader) - return; - PopoutService.windowRuleModalLoader.active = true; - if (PopoutService.windowRuleModalLoader.item) { - PopoutService.windowRuleModalLoader.item.onRuleSubmitted.connect(loadWindowRules); - PopoutService.windowRuleModalLoader.item.show(window || null); - } - } - - function editRule(rule) { - if (!PopoutService.windowRuleModalLoader) - return; - PopoutService.windowRuleModalLoader.active = true; - if (PopoutService.windowRuleModalLoader.item) { - PopoutService.windowRuleModalLoader.item.onRuleSubmitted.connect(loadWindowRules); - PopoutService.windowRuleModalLoader.item.showEdit(rule); - } - } - - Component.onCompleted: { - if (CompositorService.isNiri || CompositorService.isHyprland) { - checkWindowRulesIncludeStatus(); - loadWindowRules(); - } - } - - DankFlickable { - id: flickable - anchors.fill: parent - clip: true - contentWidth: width - contentHeight: contentColumn.implicitHeight - - Column { - id: contentColumn - width: flickable.width - spacing: Theme.spacingL - topPadding: Theme.spacingXL - bottomPadding: Theme.spacingXL - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: headerSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: headerSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - RowLayout { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "select_window" - size: Theme.iconSize - color: Theme.primary - Layout.alignment: Qt.AlignVCenter - } - - ColumnLayout { - Layout.fillWidth: true - spacing: Theme.spacingXS - - StyledText { - text: I18n.tr("Window Rules") - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - Layout.fillWidth: true - } - - StyledText { - text: I18n.tr("Define rules for window behavior. Saves to %1").arg(CompositorService.isNiri ? "dms/windowrules.kdl" : "dms/windowrules.conf") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - Layout.fillWidth: true - } - } - - DankActionButton { - Layout.preferredWidth: 40 - Layout.preferredHeight: 40 - circular: false - iconName: "add" - iconSize: Theme.iconSize - iconColor: Theme.primary - onClicked: root.openRuleModal() - } - } - - RowLayout { - width: parent.width - spacing: Theme.spacingM - visible: root.activeWindows.length > 0 - - StyledText { - text: I18n.tr("Create rule for:") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - Layout.alignment: Qt.AlignVCenter - } - - DankDropdown { - id: windowSelector - Layout.fillWidth: true - dropdownWidth: 400 - compactMode: true - emptyText: I18n.tr("Select a window...") - options: root.activeWindows.map(w => { - const label = w.appId + (w.title ? " - " + w.title : ""); - return label.length > 60 ? label.substring(0, 57) + "..." : label; - }) - onValueChanged: value => { - if (!value) - return; - const index = options.indexOf(value); - if (index < 0 || index >= root.activeWindows.length) - return; - const window = root.activeWindows[index]; - root.openRuleModal(window); - currentValue = ""; - } - } - } - } - } - - StyledRect { - id: warningBox - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: warningSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - - readonly property bool showError: root.windowRulesIncludeStatus.exists && !root.windowRulesIncludeStatus.included - readonly property bool showSetup: !root.windowRulesIncludeStatus.exists && !root.windowRulesIncludeStatus.included - - color: (showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.15) : "transparent" - border.color: (showError || showSetup) ? Theme.withAlpha(Theme.warning, 0.3) : "transparent" - border.width: 1 - visible: (showError || showSetup) && !root.checkingInclude && (CompositorService.isNiri || CompositorService.isHyprland) - - Row { - id: warningSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - DankIcon { - name: "warning" - size: Theme.iconSize - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - (fixButton.visible ? fixButton.width + Theme.spacingM : 0) - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: warningBox.showSetup ? I18n.tr("Window Rules Not Configured") : I18n.tr("Window Rules Include Missing") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.warning - width: parent.width - horizontalAlignment: Text.AlignLeft - } - - StyledText { - readonly property string rulesFile: CompositorService.isNiri ? "dms/windowrules.kdl" : "dms/windowrules.conf" - text: warningBox.showSetup ? I18n.tr("Click 'Setup' to create %1 and add include to your compositor config.").arg(rulesFile) : I18n.tr("%1 exists but is not included. Window rules won't apply.").arg(rulesFile) - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - horizontalAlignment: Text.AlignLeft - } - } - - DankButton { - id: fixButton - visible: warningBox.showError || warningBox.showSetup - text: root.fixingInclude ? I18n.tr("Fixing...") : (warningBox.showSetup ? I18n.tr("Setup") : I18n.tr("Fix Now")) - backgroundColor: Theme.warning - textColor: Theme.background - enabled: !root.fixingInclude - anchors.verticalCenter: parent.verticalCenter - onClicked: root.fixWindowRulesInclude() - } - } - } - - StyledRect { - width: Math.min(650, parent.width - Theme.spacingL * 2) - height: rulesSection.implicitHeight + Theme.spacingL * 2 - anchors.horizontalCenter: parent.horizontalCenter - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - - Column { - id: rulesSection - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - RowLayout { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "list" - size: Theme.iconSize - color: Theme.primary - Layout.alignment: Qt.AlignVCenter - } - - StyledText { - text: I18n.tr("Rules (%1)").arg(root.windowRules?.length ?? 0) - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - Layout.fillWidth: true - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: !root.windowRules || root.windowRules.length === 0 - - Item { - width: 1 - height: Theme.spacingM - } - - DankIcon { - name: "select_window" - size: 40 - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - opacity: 0.5 - } - - StyledText { - text: I18n.tr("No window rules configured") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.horizontalCenter: parent.horizontalCenter - } - - Item { - width: 1 - height: Theme.spacingM - } - } - - Column { - id: rulesListColumn - width: parent.width - spacing: Theme.spacingXS - visible: root.windowRules && root.windowRules.length > 0 - - Repeater { - model: ScriptModel { - objectProp: "id" - values: root.windowRules || [] - } - - delegate: Item { - id: ruleDelegateItem - required property var modelData - required property int index - - property bool held: ruleDragArea.pressed - property real originalY: y - - readonly property string ruleIdRef: modelData.id - readonly property var liveRuleData: { - const rules = root.windowRules || []; - return rules.find(r => r.id === ruleIdRef) ?? modelData; - } - readonly property string displayName: { - const name = liveRuleData.name || ""; - if (name) - return name; - const m = liveRuleData.matchCriteria || {}; - return m.appId || m.title || I18n.tr("Unnamed Rule"); - } - - width: rulesListColumn.width - height: ruleCard.height - z: held ? 2 : 1 - - Rectangle { - id: ruleCard - width: parent.width - height: ruleContent.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: ruleDelegateItem.liveRuleData.enabled !== false ? Theme.surfaceContainer : Theme.withAlpha(Theme.surfaceContainer, 0.4) - - RowLayout { - id: ruleContent - anchors.fill: parent - anchors.margins: Theme.spacingM - anchors.leftMargin: 28 - spacing: Theme.spacingM - - ColumnLayout { - Layout.fillWidth: true - spacing: 2 - - StyledText { - text: ruleDelegateItem.displayName - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: ruleDelegateItem.liveRuleData.enabled !== false ? Theme.surfaceText : Theme.surfaceVariantText - elide: Text.ElideRight - Layout.fillWidth: true - } - - StyledText { - text: { - const m = ruleDelegateItem.liveRuleData.matchCriteria || {}; - let parts = []; - if (m.appId) - parts.push(m.appId); - if (m.title) - parts.push("title: " + m.title); - return parts.length > 0 ? parts.join(" · ") : I18n.tr("No match criteria"); - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - Layout.fillWidth: true - } - - Flow { - Layout.fillWidth: true - Layout.topMargin: 4 - spacing: Theme.spacingXS - visible: { - const a = ruleDelegateItem.liveRuleData.actions || {}; - return Object.keys(a).some(k => a[k] !== undefined && a[k] !== null && a[k] !== ""); - } - - Repeater { - model: { - const a = ruleDelegateItem.liveRuleData.actions || {}; - const labels = { - "opacity": I18n.tr("Opacity"), - "openFloating": I18n.tr("Float"), - "openMaximized": I18n.tr("Maximize"), - "openMaximizedToEdges": I18n.tr("Max Edges"), - "openFullscreen": I18n.tr("Fullscreen"), - "openFocused": I18n.tr("Focus"), - "openOnOutput": I18n.tr("Output"), - "openOnWorkspace": I18n.tr("Workspace"), - "defaultColumnWidth": I18n.tr("Width"), - "defaultWindowHeight": I18n.tr("Height"), - "variableRefreshRate": I18n.tr("VRR"), - "blockOutFrom": I18n.tr("Block Out"), - "defaultColumnDisplay": I18n.tr("Display"), - "scrollFactor": I18n.tr("Scroll"), - "cornerRadius": I18n.tr("Radius"), - "clipToGeometry": I18n.tr("Clip"), - "tiledState": I18n.tr("Tiled"), - "minWidth": I18n.tr("Min W"), - "maxWidth": I18n.tr("Max W"), - "minHeight": I18n.tr("Min H"), - "maxHeight": I18n.tr("Max H"), - "tile": I18n.tr("Tile"), - "nofocus": I18n.tr("No Focus"), - "noborder": I18n.tr("No Border"), - "noshadow": I18n.tr("No Shadow"), - "nodim": I18n.tr("No Dim"), - "noblur": I18n.tr("No Blur"), - "noanim": I18n.tr("No Anim"), - "norounding": I18n.tr("No Round"), - "pin": I18n.tr("Pin"), - "opaque": I18n.tr("Opaque"), - "size": I18n.tr("Size"), - "move": I18n.tr("Move"), - "monitor": I18n.tr("Monitor"), - "workspace": I18n.tr("Workspace") - }; - return Object.keys(a).filter(k => a[k] !== undefined && a[k] !== null && a[k] !== "").map(k => { - const val = a[k]; - if (typeof val === "boolean") - return labels[k] || k; - return (labels[k] || k) + ": " + val; - }); - } - - delegate: Rectangle { - required property string modelData - width: chipText.implicitWidth + Theme.spacingS * 2 - height: 20 - radius: 10 - color: Theme.withAlpha(Theme.primary, 0.15) - - StyledText { - id: chipText - anchors.centerIn: parent - text: modelData - font.pixelSize: Theme.fontSizeSmall - 2 - color: Theme.primary - } - } - } - } - } - - RowLayout { - Layout.alignment: Qt.AlignVCenter - spacing: 2 - - DankActionButton { - buttonSize: 28 - iconName: "edit" - iconSize: 16 - backgroundColor: "transparent" - iconColor: Theme.surfaceVariantText - onClicked: root.editRule(ruleDelegateItem.liveRuleData) - } - - DankActionButton { - id: deleteBtn - buttonSize: 28 - iconName: "delete" - iconSize: 16 - backgroundColor: "transparent" - iconColor: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText - - MouseArea { - id: deleteArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.removeRule(ruleDelegateItem.ruleIdRef) - } - } - } - } - } - - MouseArea { - id: ruleDragArea - anchors.left: parent.left - anchors.top: parent.top - width: 40 - height: ruleCard.height - hoverEnabled: true - cursorShape: Qt.SizeVerCursor - drag.target: ruleDelegateItem.held ? ruleDelegateItem : undefined - drag.axis: Drag.YAxis - preventStealing: true - - onPressed: { - ruleDelegateItem.z = 2; - ruleDelegateItem.originalY = ruleDelegateItem.y; - } - onReleased: { - ruleDelegateItem.z = 1; - if (!drag.active) { - ruleDelegateItem.y = ruleDelegateItem.originalY; - return; - } - const spacing = Theme.spacingXS; - const itemH = ruleDelegateItem.height + spacing; - var newIndex = Math.round(ruleDelegateItem.y / itemH); - newIndex = Math.max(0, Math.min(newIndex, (root.windowRules?.length ?? 1) - 1)); - if (newIndex !== ruleDelegateItem.index) - root.reorderRules(ruleDelegateItem.index, newIndex); - ruleDelegateItem.y = ruleDelegateItem.originalY; - } - } - - DankIcon { - x: Theme.spacingM - 2 - y: (ruleCard.height / 2) - (size / 2) - name: "drag_indicator" - size: 18 - color: Theme.outline - opacity: ruleDragArea.containsMouse || ruleDragArea.pressed ? 1 : 0.5 - } - - Behavior on y { - enabled: !ruleDragArea.pressed && !ruleDragArea.drag.active - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WorkspacesTab.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WorkspacesTab.qml deleted file mode 100644 index 99955fd..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Settings/WorkspacesTab.qml +++ /dev/null @@ -1,526 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Settings.Widgets - -Item { - id: root - - DankFlickable { - anchors.fill: parent - clip: true - contentHeight: mainColumn.height + Theme.spacingXL - contentWidth: width - - Column { - id: mainColumn - topPadding: 4 - width: Math.min(550, parent.width - Theme.spacingL * 2) - anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXL - - SettingsCard { - width: parent.width - iconName: "view_module" - title: I18n.tr("Workspace Settings") - settingKey: "workspaceSettings" - - SettingsToggleRow { - settingKey: "showWorkspaceIndex" - tags: ["workspace", "index", "numbers", "labels"] - text: I18n.tr("Workspace Index Numbers") - description: I18n.tr("Show workspace index numbers in the top bar workspace switcher") - checked: SettingsData.showWorkspaceIndex - onToggled: checked => SettingsData.set("showWorkspaceIndex", checked) - } - - SettingsToggleRow { - settingKey: "showWorkspaceName" - tags: ["workspace", "name", "labels"] - text: I18n.tr("Workspace Names") - description: I18n.tr("Show workspace name on horizontal bars, and first letter on vertical bars") - checked: SettingsData.showWorkspaceName - onToggled: checked => SettingsData.set("showWorkspaceName", checked) - } - - SettingsToggleRow { - settingKey: "showWorkspacePadding" - tags: ["workspace", "padding", "minimum"] - text: I18n.tr("Workspace Padding") - description: I18n.tr("Always show a minimum of 3 workspaces, even if fewer are available") - checked: SettingsData.showWorkspacePadding - onToggled: checked => SettingsData.set("showWorkspacePadding", checked) - } - - SettingsToggleRow { - settingKey: "showWorkspaceApps" - tags: ["workspace", "apps", "icons", "applications"] - text: I18n.tr("Show Workspace Apps") - description: I18n.tr("Display application icons in workspace indicators") - checked: SettingsData.showWorkspaceApps - visible: CompositorService.isNiri || CompositorService.isHyprland - onToggled: checked => SettingsData.set("showWorkspaceApps", checked) - } - - Item { - width: parent.width - height: maxAppsColumn.height - visible: SettingsData.showWorkspaceApps - opacity: visible ? 1 : 0 - - Column { - id: maxAppsColumn - x: Theme.spacingL - width: 120 - spacing: Theme.spacingS - - StyledText { - text: I18n.tr("Max apps to show") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Medium - horizontalAlignment: Text.AlignLeft - } - - DankTextField { - width: 100 - height: 28 - placeholderText: "3" - text: SettingsData.maxWorkspaceIcons - maximumLength: 2 - font.pixelSize: Theme.fontSizeSmall - topPadding: Theme.spacingXS - bottomPadding: Theme.spacingXS - onEditingFinished: SettingsData.set("maxWorkspaceIcons", parseInt(text, 10)) - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - - SettingsSliderRow { - visible: SettingsData.showWorkspaceApps - text: I18n.tr("Icon Size") - value: SettingsData.workspaceAppIconSizeOffset - minimum: 0 - maximum: 10 - unit: "px" - defaultValue: 0 - onSliderValueChanged: newValue => SettingsData.set("workspaceAppIconSizeOffset", newValue) - } - - SettingsToggleRow { - settingKey: "groupWorkspaceApps" - tags: ["workspace", "apps", "icons", "group", "grouped", "collapse"] - text: I18n.tr("Group Workspace Apps") - description: I18n.tr("Group repeated application icons in unfocused workspaces") - checked: SettingsData.groupWorkspaceApps - visible: SettingsData.showWorkspaceApps - onToggled: checked => SettingsData.set("groupWorkspaceApps", checked) - } - - SettingsToggleRow { - settingKey: "workspaceActiveAppHighlightEnabled" - tags: ["workspace", "apps", "icons", "highlight", "active", "focused"] - text: I18n.tr("Highlight Active Workspace App") - description: I18n.tr("Highlight the currently focused app inside workspace indicators") - checked: SettingsData.workspaceActiveAppHighlightEnabled - visible: SettingsData.showWorkspaceApps - onToggled: checked => SettingsData.set("workspaceActiveAppHighlightEnabled", checked) - } - - SettingsToggleRow { - settingKey: "workspaceFollowFocus" - tags: ["workspace", "focus", "follow", "monitor"] - text: I18n.tr("Follow Monitor Focus") - description: I18n.tr("Show workspaces of the currently focused monitor") - checked: SettingsData.workspaceFollowFocus - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle - onToggled: checked => SettingsData.set("workspaceFollowFocus", checked) - } - - SettingsToggleRow { - settingKey: "showOccupiedWorkspacesOnly" - tags: ["workspace", "occupied", "active", "windows"] - text: I18n.tr("Show Occupied Workspaces Only") - description: I18n.tr("Display only workspaces that contain windows") - checked: SettingsData.showOccupiedWorkspacesOnly - visible: CompositorService.isNiri || CompositorService.isHyprland - onToggled: checked => SettingsData.set("showOccupiedWorkspacesOnly", checked) - } - - SettingsToggleRow { - settingKey: "reverseScrolling" - tags: ["workspace", "scroll", "scrolling", "reverse", "direction"] - text: I18n.tr("Reverse Scrolling Direction") - description: I18n.tr("Reverse workspace switch direction when scrolling over the bar") - checked: SettingsData.reverseScrolling - visible: CompositorService.isNiri || CompositorService.isHyprland - onToggled: checked => SettingsData.set("reverseScrolling", checked) - } - - SettingsToggleRow { - settingKey: "workspaceDragReorder" - tags: ["workspace", "drag", "reorder", "sort", "move"] - text: I18n.tr("Drag to Reorder") - description: I18n.tr("Drag workspace indicators to reorder them") - checked: SettingsData.workspaceDragReorder - visible: CompositorService.isNiri - onToggled: checked => SettingsData.set("workspaceDragReorder", checked) - } - - SettingsToggleRow { - settingKey: "dwlShowAllTags" - tags: ["dwl", "tags", "workspace"] - text: I18n.tr("Show All Tags") - description: I18n.tr("Show all 9 tags instead of only occupied tags (DWL only)") - checked: SettingsData.dwlShowAllTags - visible: CompositorService.isDwl - onToggled: checked => SettingsData.set("dwlShowAllTags", checked) - } - } - - SettingsCard { - width: parent.width - iconName: "palette" - title: I18n.tr("Workspace Appearance") - settingKey: "workspaceAppearance" - - SettingsButtonGroupRow { - text: I18n.tr("Focused Color") - model: ["pri", "s", "sc", "sch", "none"] - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceColorMode) { - case "s": - return 1; - case "sc": - return 2; - case "sch": - return 3; - case "none": - return 4; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["default", "s", "sc", "sch", "none"]; - SettingsData.set("workspaceColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsButtonGroupRow { - text: I18n.tr("Occupied Color") - model: ["none", "sec", "s", "sc", "sch", "schh"] - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceOccupiedColorMode) { - case "sec": - return 1; - case "s": - return 2; - case "sc": - return 3; - case "sch": - return 4; - case "schh": - return 5; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["none", "sec", "s", "sc", "sch", "schh"]; - SettingsData.set("workspaceOccupiedColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl - } - - SettingsButtonGroupRow { - text: I18n.tr("Unfocused Color") - model: ["def", "s", "sc", "sch"] - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceUnfocusedColorMode) { - case "s": - return 1; - case "sc": - return 2; - case "sch": - return 3; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["default", "s", "sc", "sch"]; - SettingsData.set("workspaceUnfocusedColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle - } - - SettingsButtonGroupRow { - text: I18n.tr("Urgent Color") - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle - model: ["err", "pri", "sec", "s", "sc"] - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceUrgentColorMode) { - case "primary": - return 1; - case "secondary": - return 2; - case "s": - return 3; - case "sc": - return 4; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["default", "primary", "secondary", "s", "sc"]; - SettingsData.set("workspaceUrgentColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - settingKey: "workspaceFocusedBorderEnabled" - tags: ["workspace", "border", "outline", "focused", "ring"] - text: I18n.tr("Focused Border") - description: I18n.tr("Show an outline ring around the focused workspace indicator") - checked: SettingsData.workspaceFocusedBorderEnabled - onToggled: checked => SettingsData.set("workspaceFocusedBorderEnabled", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: SettingsData.workspaceFocusedBorderEnabled - leftPadding: Theme.spacingM - - SettingsButtonGroupRow { - width: parent.width - parent.leftPadding - text: I18n.tr("Border Color") - model: [I18n.tr("Surface"), I18n.tr("Secondary"), I18n.tr("Primary")] - currentIndex: { - switch (SettingsData.workspaceFocusedBorderColor) { - case "surfaceText": - return 0; - case "secondary": - return 1; - case "primary": - return 2; - default: - return 2; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let newColor = "primary"; - switch (index) { - case 0: - newColor = "surfaceText"; - break; - case 1: - newColor = "secondary"; - break; - case 2: - newColor = "primary"; - break; - } - SettingsData.set("workspaceFocusedBorderColor", newColor); - } - } - - SettingsSliderRow { - width: parent.width - parent.leftPadding - text: I18n.tr("Thickness") - value: SettingsData.workspaceFocusedBorderThickness - minimum: 1 - maximum: 6 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("workspaceFocusedBorderThickness", newValue) - } - } - } - - SettingsCard { - width: parent.width - iconName: "label" - title: I18n.tr("Named Workspace Icons") - settingKey: "workspaceIcons" - visible: SettingsData.hasNamedWorkspaces() - - StyledText { - width: parent.width - text: I18n.tr("Configure icons for named workspaces. Icons take priority over numbers when both are enabled.") - font.pixelSize: Theme.fontSizeSmall - color: Theme.outline - wrapMode: Text.WordWrap - } - - Repeater { - model: SettingsData.getNamedWorkspaces() - - Rectangle { - width: parent.width - height: workspaceIconRow.implicitHeight + Theme.spacingM - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.5) - border.width: 0 - - Row { - id: workspaceIconRow - - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - spacing: Theme.spacingM - - StyledText { - text: "\"" + modelData + "\"" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - width: 150 - elide: Text.ElideRight - } - - DankIconPicker { - id: iconPicker - anchors.verticalCenter: parent.verticalCenter - - Component.onCompleted: { - var iconData = SettingsData.getWorkspaceNameIcon(modelData); - if (iconData) { - setIcon(iconData.value, iconData.type); - } - } - - onIconSelected: (iconName, iconType) => { - SettingsData.setWorkspaceNameIcon(modelData, { - "type": iconType, - "value": iconName - }); - setIcon(iconName, iconType); - } - - Connections { - target: SettingsData - function onWorkspaceIconsUpdated() { - var iconData = SettingsData.getWorkspaceNameIcon(modelData); - if (iconData) { - iconPicker.setIcon(iconData.value, iconData.type); - } else { - iconPicker.setIcon("", "icon"); - } - } - } - } - - Rectangle { - width: 28 - height: 28 - radius: Theme.cornerRadius - color: clearMouseArea.containsMouse ? Theme.errorHover : Theme.surfaceContainer - border.width: 0 - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: "close" - size: 16 - color: clearMouseArea.containsMouse ? Theme.error : Theme.outline - anchors.centerIn: parent - } - - MouseArea { - id: clearMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: SettingsData.removeWorkspaceNameIcon(modelData) - } - } - - Item { - width: parent.width - 150 - 240 - 28 - Theme.spacingM * 4 - height: 1 - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/SystemUpdatePopout.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/SystemUpdatePopout.qml deleted file mode 100644 index 49cdb93..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/SystemUpdatePopout.qml +++ /dev/null @@ -1,329 +0,0 @@ -import QtQuick -import qs.Common -import qs.Services -import qs.Widgets - -DankPopout { - id: systemUpdatePopout - - layerNamespace: "dms:system-update" - - property var parentWidget: null - property var triggerScreen: null - - Ref { - service: SystemUpdateService - } - - popupWidth: 400 - popupHeight: 500 - triggerWidth: 55 - positioning: "" - screen: triggerScreen - shouldBeVisible: false - - onBackgroundClicked: close() - - onShouldBeVisibleChanged: { - if (shouldBeVisible) { - if (SystemUpdateService.updateCount === 0 && !SystemUpdateService.isChecking) { - SystemUpdateService.checkForUpdates(); - } - } - } - - content: Component { - Rectangle { - id: updaterPanel - - color: "transparent" - - Column { - width: parent.width - Theme.spacingL * 2 - height: parent.height - Theme.spacingL * 2 - x: Theme.spacingL - y: Theme.spacingL - spacing: Theme.spacingL - - Item { - width: parent.width - height: 40 - - StyledText { - text: I18n.tr("System Updates") - font.pixelSize: Theme.fontSizeLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - Row { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - anchors.verticalCenter: parent.verticalCenter - text: { - if (SystemUpdateService.isChecking) - return I18n.tr("Checking..."); - if (SystemUpdateService.hasError) - return I18n.tr("Error"); - if (SystemUpdateService.updateCount === 0) - return I18n.tr("Up to date"); - return SystemUpdateService.updateCount === 1 - ? I18n.tr("%1 update").arg(SystemUpdateService.updateCount) - : I18n.tr("%1 updates").arg(SystemUpdateService.updateCount); - } - font.pixelSize: Theme.fontSizeMedium - color: { - if (SystemUpdateService.hasError) - return Theme.error; - return Theme.surfaceText; - } - } - - DankActionButton { - id: checkForUpdatesButton - buttonSize: 28 - iconName: "refresh" - iconSize: 18 - z: 15 - iconColor: Theme.surfaceText - enabled: !SystemUpdateService.isChecking - opacity: enabled ? 1.0 : 0.5 - onClicked: { - SystemUpdateService.checkForUpdates(); - } - - RotationAnimation { - target: checkForUpdatesButton - property: "rotation" - from: 0 - to: 360 - duration: 1000 - running: SystemUpdateService.isChecking - loops: Animation.Infinite - - onRunningChanged: { - if (!running) { - checkForUpdatesButton.rotation = 0; - } - } - } - } - } - } - - Rectangle { - width: parent.width - height: { - let usedHeight = 40 + Theme.spacingL; - usedHeight += 48 + Theme.spacingL; - return parent.height - usedHeight; - } - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.1) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05) - border.width: 0 - - Column { - anchors.fill: parent - anchors.margins: Theme.spacingM - anchors.rightMargin: 0 - - StyledText { - id: statusText - width: parent.width - text: { - if (SystemUpdateService.hasError) { - return I18n.tr("Failed to check for updates:\n%1").arg(SystemUpdateService.errorMessage); - } - if (!SystemUpdateService.helperAvailable) { - return I18n.tr("No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates."); - } - if (SystemUpdateService.isChecking) { - return I18n.tr("Checking for updates..."); - } - if (SystemUpdateService.updateCount === 0) { - return I18n.tr("Your system is up to date!"); - } - return SystemUpdateService.updateCount === 1 - ? I18n.tr("Found %1 package to update:").arg(SystemUpdateService.updateCount) - : I18n.tr("Found %1 packages to update:").arg(SystemUpdateService.updateCount); - } - font.pixelSize: Theme.fontSizeMedium - color: { - if (SystemUpdateService.hasError) - return Theme.errorText; - return Theme.surfaceText; - } - wrapMode: Text.WordWrap - visible: SystemUpdateService.updateCount === 0 || SystemUpdateService.hasError || SystemUpdateService.isChecking - } - - DankListView { - id: packagesList - - width: parent.width - height: parent.height - (SystemUpdateService.updateCount === 0 || SystemUpdateService.hasError || SystemUpdateService.isChecking ? statusText.height + Theme.spacingM : 0) - visible: SystemUpdateService.updateCount > 0 && !SystemUpdateService.isChecking && !SystemUpdateService.hasError - clip: true - spacing: Theme.spacingXS - - model: SystemUpdateService.availableUpdates - - delegate: Rectangle { - width: ListView.view.width - Theme.spacingM - height: 48 - radius: Theme.cornerRadius - color: packageMouseArea.containsMouse ? Theme.primaryHoverLight : "transparent" - border.color: Theme.outlineLight - border.width: 0 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - Column { - anchors.verticalCenter: parent.verticalCenter - width: parent.width - Theme.spacingM - spacing: 2 - - StyledText { - width: parent.width - text: modelData.name || "" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - elide: Text.ElideRight - } - - StyledText { - width: parent.width - text: `${modelData.currentVersion} → ${modelData.newVersion}` - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - elide: Text.ElideRight - } - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - MouseArea { - id: packageMouseArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - } - } - } - } - } - - Row { - width: parent.width - height: 48 - spacing: Theme.spacingM - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: parent.height - radius: Theme.cornerRadius - color: updateMouseArea.containsMouse ? Theme.primaryHover : Theme.secondaryHover - opacity: SystemUpdateService.updateCount > 0 ? 1.0 : 0.5 - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "system_update_alt" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Update All") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: updateMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - enabled: SystemUpdateService.updateCount > 0 - onClicked: { - SystemUpdateService.runUpdates(); - systemUpdatePopout.close(); - } - } - } - - Rectangle { - width: (parent.width - Theme.spacingM) / 2 - height: parent.height - radius: Theme.cornerRadius - color: closeMouseArea.containsMouse ? Theme.errorPressed : Theme.secondaryHover - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - } - } - - Row { - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "close" - size: Theme.iconSize - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Close") - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - systemUpdatePopout.close(); - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Toast.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Toast.qml deleted file mode 100644 index 2d1356e..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/Toast.qml +++ /dev/null @@ -1,444 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Services -import qs.Widgets - -PanelWindow { - id: root - - WlrLayershell.namespace: "dms:toast" - - property var modelData - property bool shouldBeVisible: false - property real frozenWidth: 0 - readonly property string copiedText: I18n.tr("Copied!") - - readonly property real dpr: modelData ? CompositorService.getScreenScale(modelData) : 1 - readonly property real shadowBuffer: 5 - readonly property real toastY: Theme.barHeight - 4 + (SettingsData.barConfigs[0]?.spacing ?? 4) + 2 - - Connections { - target: ToastService - function onToastVisibleChanged() { - if (ToastService.toastVisible) { - shouldBeVisible = true; - visible = true; - } else { - frozenWidth = toast.width; - shouldBeVisible = false; - closeTimer.restart(); - } - } - } - - Timer { - id: closeTimer - interval: Theme.mediumDuration + 50 - onTriggered: { - if (!shouldBeVisible) { - visible = false; - } - } - } - - screen: modelData - visible: shouldBeVisible - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - - readonly property real toastWidth: shouldBeVisible ? Math.min(900, messageText.implicitWidth + statusIcon.width + Theme.spacingM + (ToastService.hasDetails ? (expandButton.width + closeButton.width + 4) : (ToastService.currentLevel === ToastService.levelError ? closeButton.width + Theme.spacingS : 0)) + Theme.spacingL * 2 + Theme.spacingM * 2) : frozenWidth - readonly property real toastHeight: toastContent.height + Theme.spacingL * 2 - - anchors { - top: true - left: true - } - - WlrLayershell.margins { - left: Math.max(0, Theme.snap((modelData?.width ?? 1920) / 2 - toastWidth / 2 - shadowBuffer, dpr)) - top: Math.max(0, Theme.snap(toastY - shadowBuffer, dpr)) - } - - implicitWidth: toastWidth + (shadowBuffer * 2) - implicitHeight: toastHeight + (shadowBuffer * 2) - - Rectangle { - id: toast - - property bool expanded: false - - Connections { - target: ToastService - function onResetToastState() { - toast.expanded = false; - } - } - - x: shadowBuffer - y: shadowBuffer - width: root.toastWidth - height: root.toastHeight - color: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - return Theme.error; - case ToastService.levelWarn: - return Theme.warning; - case ToastService.levelInfo: - return Theme.surfaceContainer; - default: - return Theme.surfaceContainer; - } - } - radius: Theme.cornerRadius - opacity: shouldBeVisible ? 1 : 0 - - Column { - id: toastContent - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: Theme.spacingL - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - spacing: Theme.spacingS - - Item { - width: parent.width - height: Math.max(Theme.iconSize + 8, messageText.implicitHeight) - - DankIcon { - id: statusIcon - name: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - return "error"; - case ToastService.levelWarn: - return "warning"; - case ToastService.levelInfo: - return "info"; - default: - return "info"; - } - } - size: Theme.iconSize - color: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: messageText - text: ToastService.currentMessage - font.pixelSize: Theme.fontSizeMedium - color: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - font.weight: Font.Medium - anchors.left: statusIcon.right - anchors.leftMargin: Theme.spacingM - anchors.right: ToastService.hasDetails ? expandButton.left : parent.right - anchors.rightMargin: ToastService.hasDetails ? Theme.spacingS : 0 - anchors.verticalCenter: parent.verticalCenter - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - DankActionButton { - id: expandButton - iconName: toast.expanded ? "expand_less" : "expand_more" - iconSize: Theme.iconSize - iconColor: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - buttonSize: Theme.iconSize + 8 - anchors.right: closeButton.left - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - visible: ToastService.hasDetails - - onClicked: { - toast.expanded = !toast.expanded; - if (toast.expanded) { - ToastService.stopTimer(); - } else { - ToastService.restartTimer(); - } - } - } - - DankActionButton { - id: closeButton - iconName: "close" - iconSize: Theme.iconSize - iconColor: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - buttonSize: Theme.iconSize + 8 - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - visible: ToastService.hasDetails || ToastService.currentLevel === ToastService.levelError - - onClicked: { - ToastService.hideToast(); - } - } - } - - Rectangle { - width: parent.width - height: detailsColumn.height + Theme.spacingS * 2 - color: ToastService.currentDetails.length > 0 ? Qt.rgba(0, 0, 0, 0.2) : "transparent" - radius: Theme.cornerRadius / 2 - visible: toast.expanded && ToastService.hasDetails - anchors.horizontalCenter: parent.horizontalCenter - - Column { - id: detailsColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Theme.spacingS - spacing: Theme.spacingS - - Item { - width: parent.width - Theme.spacingS * 2 - height: detailsText.implicitHeight - anchors.horizontalCenter: parent.horizontalCenter - visible: ToastService.currentDetails.length > 0 - - StyledText { - id: detailsText - text: ToastService.currentDetails - font.pixelSize: Theme.fontSizeSmall - color: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - anchors.left: parent.left - anchors.right: copyDetailsButton.left - anchors.rightMargin: Theme.spacingS - wrapMode: Text.Wrap - } - - DankActionButton { - id: copyDetailsButton - iconName: "content_copy" - iconSize: Theme.iconSizeSmall - iconColor: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - buttonSize: Theme.iconSizeSmall + 8 - anchors.right: parent.right - anchors.top: parent.top - - property bool showTooltip: false - - onClicked: { - Quickshell.execDetached(["dms", "cl", "copy", ToastService.currentDetails]); - showTooltip = true; - detailsTooltipTimer.start(); - } - - Timer { - id: detailsTooltipTimer - interval: 1500 - onTriggered: copyDetailsButton.showTooltip = false - } - - Rectangle { - visible: copyDetailsButton.showTooltip - width: detailsTooltipLabel.implicitWidth + 16 - height: detailsTooltipLabel.implicitHeight + 8 - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.width: 1 - border.color: Theme.outlineMedium - y: -height - 4 - x: -width / 2 + copyDetailsButton.width / 2 - - StyledText { - id: detailsTooltipLabel - anchors.centerIn: parent - text: root.copiedText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - } - } - - Rectangle { - width: parent.width - Theme.spacingS * 2 - height: commandText.height + Theme.spacingS - anchors.horizontalCenter: parent.horizontalCenter - color: Qt.rgba(0, 0, 0, 0.3) - radius: Theme.cornerRadius / 2 - visible: ToastService.currentCommand.length > 0 - - StyledText { - id: commandText - text: ToastService.currentCommand - font.pixelSize: Theme.fontSizeSmall - color: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - isMonospace: true - anchors.left: parent.left - anchors.right: copyButton.visible ? copyButton.left : parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Theme.spacingS / 2 - anchors.rightMargin: Theme.spacingS / 2 - wrapMode: Text.Wrap - } - - DankActionButton { - id: copyButton - iconName: "content_copy" - iconSize: Theme.iconSizeSmall - iconColor: { - switch (ToastService.currentLevel) { - case ToastService.levelError: - case ToastService.levelWarn: - return SessionData.isLightMode ? Theme.surfaceText : Theme.background; - default: - return Theme.surfaceText; - } - } - buttonSize: Theme.iconSizeSmall + 8 - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.rightMargin: Theme.spacingS / 2 - visible: ToastService.currentCommand.length > 0 - - property bool showTooltip: false - - onClicked: { - Quickshell.execDetached(["dms", "cl", "copy", ToastService.currentCommand]); - showTooltip = true; - tooltipTimer.start(); - } - - Timer { - id: tooltipTimer - interval: 1500 - onTriggered: copyButton.showTooltip = false - } - - Rectangle { - visible: copyButton.showTooltip - width: tooltipLabel.implicitWidth + 16 - height: tooltipLabel.implicitHeight + 8 - color: Theme.surfaceContainer - radius: Theme.cornerRadius - border.width: 1 - border.color: Theme.outlineMedium - y: -height - 4 - x: -width / 2 + copyButton.width / 2 - - StyledText { - id: tooltipLabel - anchors.centerIn: parent - text: root.copiedText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - } - } - } - } - } - } - } - - MouseArea { - anchors.fill: parent - visible: !ToastService.hasDetails - onClicked: ToastService.hideToast() - } - - ElevationShadow { - anchors.fill: parent - z: -1 - level: Theme.elevationLevel3 - fallbackOffset: 6 - targetRadius: toast.radius - targetColor: toast.color - shadowOpacity: Theme.elevationLevel3 && Theme.elevationLevel3.alpha !== undefined ? Theme.elevationLevel3.alpha : 0.3 - shadowEnabled: Theme.elevationEnabled - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on height { - enabled: false - } - - Behavior on width { - enabled: false - } - } - - mask: Region { - item: toast - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WallpaperBackground.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WallpaperBackground.qml deleted file mode 100644 index 8430b01..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WallpaperBackground.qml +++ /dev/null @@ -1,658 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Widgets -import qs.Services - -Variants { - model: { - if (SessionData.isGreeterMode) { - return Quickshell.screens; - } - return SettingsData.getFilteredScreens("wallpaper"); - } - - PanelWindow { - id: wallpaperWindow - - required property var modelData - - screen: modelData - - WlrLayershell.layer: WlrLayer.Background - WlrLayershell.exclusionMode: ExclusionMode.Ignore - - anchors.top: true - anchors.bottom: true - anchors.left: true - anchors.right: true - - color: "transparent" - - mask: Region { - item: Item {} - } - - Item { - id: root - anchors.fill: parent - - function encodeFileUrl(path) { - if (!path) - return ""; - return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/'); - } - - property string source: SessionData.getMonitorWallpaper(modelData.name) || "" - property bool isColorSource: source.startsWith("#") - property string transitionType: SessionData.wallpaperTransition - property string actualTransitionType: transitionType - property bool isInitialized: false - - Connections { - target: SessionData - function onIsLightModeChanged() { - if (SessionData.perModeWallpaper) { - var newSource = SessionData.getMonitorWallpaper(modelData.name) || ""; - if (newSource !== root.source) { - root.source = newSource; - } - } - } - } - onTransitionTypeChanged: { - if (transitionType !== "random") { - actualTransitionType = transitionType; - return; - } - actualTransitionType = SessionData.includedTransitions.length === 0 ? "none" : SessionData.includedTransitions[Math.floor(Math.random() * SessionData.includedTransitions.length)]; - } - - property real transitionProgress: 0 - property real shaderFillMode: getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name)) - property vector4d fillColor: Qt.vector4d(0, 0, 0, 1) - property real edgeSmoothness: 0.1 - - property real wipeDirection: 0 - property real discCenterX: 0.5 - property real discCenterY: 0.5 - property real stripesCount: 16 - property real stripesAngle: 0 - - readonly property bool transitioning: transitionAnimation.running - property bool effectActive: false - property bool _renderSettling: true - property bool _overviewBlurSettling: false - property bool useNextForEffect: false - property string pendingWallpaper: "" - property string _deferredSource: "" - readonly property bool overviewBlurActive: CompositorService.isNiri && SettingsData.blurWallpaperOnOverview && NiriService.inOverview && currentWallpaper.source !== "" - - Connections { - target: currentWallpaper - function onStatusChanged() { - if (currentWallpaper.status !== Image.Ready && currentWallpaper.status !== Image.Error) - return; - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - function _recheckScreenScale() { - const newScale = CompositorService.getScreenScale(modelData); - if (newScale !== root.screenScale) { - console.info("WallpaperBackground: screen scale corrected for", modelData.name + ":", root.screenScale, "->", newScale); - root.screenScale = newScale; - } - } - - Connections { - target: wallpaperWindow - function onWidthChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - function onHeightChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: Quickshell - function onScreensChanged() { - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: NiriService - function onDisplayScalesChanged() { - root._recheckScreenScale(); - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: WlrOutputService - function onWlrOutputAvailableChanged() { - root._recheckScreenScale(); - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - - Connections { - target: NiriService - function onInOverviewChanged() { - root._overviewBlurSettling = true; - overviewBlurSettleTimer.restart(); - } - } - - Connections { - target: SettingsData - function onBlurWallpaperOnOverviewChanged() { - root._overviewBlurSettling = true; - overviewBlurSettleTimer.restart(); - } - } - - Connections { - target: CompositorService - function onRandrDataReady() { - if (root._deferredSource) { - const src = root._deferredSource; - root._deferredSource = ""; - root.setWallpaperImmediate(src); - } else { - root._recheckScreenScale(); - } - } - } - - Connections { - target: IdleService - function onIsShellLockedChanged() { - if (!IdleService.isShellLocked) { - root._renderSettling = true; - renderSettleTimer.restart(); - } - } - } - - Timer { - id: renderSettleTimer - interval: 1000 - onTriggered: root._renderSettling = false - } - - Timer { - id: overviewBlurSettleTimer - interval: 150 - onTriggered: root._overviewBlurSettling = false - } - - function getFillMode(modeName) { - switch (modeName) { - case "Stretch": - return Image.Stretch; - case "Fit": - case "PreserveAspectFit": - return Image.PreserveAspectFit; - case "Fill": - case "PreserveAspectCrop": - return Image.PreserveAspectCrop; - case "Tile": - return Image.Tile; - case "TileVertically": - return Image.TileVertically; - case "TileHorizontally": - return Image.TileHorizontally; - case "Pad": - return Image.Pad; - default: - return Image.PreserveAspectCrop; - } - } - - Component.onCompleted: { - if (typeof wallpaperWindow.updatesEnabled !== "undefined") - wallpaperWindow.updatesEnabled = Qt.binding(() => !root.source || root.effectActive || root._renderSettling || root.overviewBlurActive || root._overviewBlurSettling || root.pendingWallpaper !== "" || root._deferredSource !== "" || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading); - - if (!source) { - root._renderSettling = false; - } - isInitialized = true; - } - - onSourceChanged: { - if (!source || source.startsWith("#")) { - setWallpaperImmediate(""); - return; - } - - const formattedSource = source.startsWith("file://") ? source : encodeFileUrl(source); - - if (!isInitialized || !currentWallpaper.source) { - if (!CompositorService.randrReady) { - _deferredSource = formattedSource; - return; - } - setWallpaperImmediate(formattedSource); - return; - } - if (CompositorService.isNiri && SessionData.isSwitchingMode) { - setWallpaperImmediate(formattedSource); - return; - } - changeWallpaper(formattedSource); - } - - function setWallpaperImmediate(newSource) { - transitionAnimation.stop(); - root.transitionProgress = 0.0; - root.effectActive = false; - root._renderSettling = true; - renderSettleTimer.restart(); - root.screenScale = CompositorService.getScreenScale(modelData); - currentWallpaper.source = newSource; - nextWallpaper.source = ""; - } - - function startTransition() { - currentWallpaper.layer.enabled = true; - nextWallpaper.layer.enabled = true; - root.useNextForEffect = true; - root.effectActive = true; - if (srcCurrent.scheduleUpdate) - srcCurrent.scheduleUpdate(); - if (srcNext.scheduleUpdate) - srcNext.scheduleUpdate(); - transitionDelayTimer.start(); - } - - Timer { - id: transitionDelayTimer - interval: 16 - repeat: false - onTriggered: transitionAnimation.start() - } - - function changeWallpaper(newPath, force) { - if (!force && newPath === currentWallpaper.source) - return; - if (!newPath || newPath.startsWith("#")) - return; - root.screenScale = CompositorService.getScreenScale(modelData); - if (root.transitioning || root.effectActive) { - root.pendingWallpaper = newPath; - return; - } - if (!currentWallpaper.source) { - setWallpaperImmediate(newPath); - return; - } - - if (root.transitionType === "random") { - root.actualTransitionType = SessionData.includedTransitions.length === 0 ? "none" : SessionData.includedTransitions[Math.floor(Math.random() * SessionData.includedTransitions.length)]; - } - - if (root.actualTransitionType === "none") { - setWallpaperImmediate(newPath); - return; - } - - switch (root.actualTransitionType) { - case "wipe": - root.wipeDirection = Math.random() * 4; - break; - case "disc": - case "pixelate": - case "portal": - root.discCenterX = Math.random(); - root.discCenterY = Math.random(); - break; - case "stripes": - root.stripesCount = Math.round(Math.random() * 20 + 4); - root.stripesAngle = Math.random() * 360; - break; - } - - root._renderSettling = true; - renderSettleTimer.restart(); - - nextWallpaper.source = newPath; - - if (nextWallpaper.status === Image.Ready) - root.startTransition(); - } - - Loader { - anchors.fill: parent - active: !root.source || root.isColorSource - asynchronous: true - - sourceComponent: DankBackdrop { - screenName: modelData.name - } - } - - readonly property int maxTextureSize: 8192 - property real screenScale: 1 - property int textureWidth: Math.min(Math.round(modelData.width * screenScale), maxTextureSize) - property int textureHeight: Math.min(Math.round(modelData.height * screenScale), maxTextureSize) - - Image { - id: currentWallpaper - anchors.fill: parent - visible: true - opacity: 1 - layer.enabled: false - asynchronous: true - retainWhileLoading: true - smooth: true - cache: true - sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name)) - } - - Image { - id: nextWallpaper - anchors.fill: parent - visible: source !== "" - opacity: 0 - layer.enabled: false - asynchronous: true - retainWhileLoading: true - smooth: true - cache: true - sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name)) - - onStatusChanged: { - if (status !== Image.Ready) - return; - if (root.actualTransitionType === "none") { - root._renderSettling = true; - renderSettleTimer.restart(); - currentWallpaper.source = source; - nextWallpaper.source = ""; - root.transitionProgress = 0.0; - } else if (!root.transitioning) { - root.startTransition(); - } - } - } - - ShaderEffectSource { - id: srcCurrent - sourceItem: root.effectActive ? currentWallpaper : null - hideSource: root.effectActive - live: root.effectActive - mipmap: false - recursive: false - textureSize: Qt.size(root.textureWidth, root.textureHeight) - } - - ShaderEffectSource { - id: srcNext - sourceItem: root.effectActive ? nextWallpaper : null - hideSource: root.effectActive - live: root.effectActive - mipmap: false - recursive: false - textureSize: Qt.size(root.textureWidth, root.textureHeight) - } - - Rectangle { - id: dummyRect - width: 1 - height: 1 - visible: false - color: "transparent" - } - - ShaderEffectSource { - id: srcDummy - sourceItem: dummyRect - hideSource: true - live: false - mipmap: false - recursive: false - } - - Loader { - id: effectLoader - anchors.fill: parent - active: root.effectActive - - function getTransitionComponent(type) { - switch (type) { - case "fade": - return fadeComp; - case "wipe": - return wipeComp; - case "disc": - return discComp; - case "stripes": - return stripesComp; - case "iris bloom": - return irisComp; - case "pixelate": - return pixelateComp; - case "portal": - return portalComp; - default: - return null; - } - } - - sourceComponent: getTransitionComponent(root.actualTransitionType) - } - - Component { - id: fadeComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_fade.frag.qsb") - } - } - - Component { - id: wipeComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real direction: root.wipeDirection - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_wipe.frag.qsb") - } - } - - Component { - id: discComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real aspectRatio: root.width / root.height - property real centerX: root.discCenterX - property real centerY: root.discCenterY - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_disc.frag.qsb") - } - } - - Component { - id: stripesComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real aspectRatio: root.width / root.height - property real stripeCount: root.stripesCount - property real angle: root.stripesAngle - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_stripes.frag.qsb") - } - } - - Component { - id: irisComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real centerX: 0.5 - property real centerY: 0.5 - property real aspectRatio: root.width / root.height - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_iris_bloom.frag.qsb") - } - } - - Component { - id: pixelateComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - property real centerX: root.discCenterX - property real centerY: root.discCenterY - property real aspectRatio: root.width / root.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_pixelate.frag.qsb") - } - } - - Component { - id: portalComp - ShaderEffect { - anchors.fill: parent - property variant source1: srcCurrent - property variant source2: root.useNextForEffect ? srcNext : srcDummy - property real progress: root.transitionProgress - property real smoothness: root.edgeSmoothness - property real aspectRatio: root.width / root.height - property real centerX: root.discCenterX - property real centerY: root.discCenterY - property real fillMode: root.shaderFillMode - property vector4d fillColor: root.fillColor - property real imageWidth1: modelData.width - property real imageHeight1: modelData.height - property real imageWidth2: modelData.width - property real imageHeight2: modelData.height - property real screenWidth: modelData.width - property real screenHeight: modelData.height - fragmentShader: Qt.resolvedUrl("../Shaders/qsb/wp_portal.frag.qsb") - } - } - - NumberAnimation { - id: transitionAnimation - target: root - property: "transitionProgress" - from: 0.0 - to: 1.0 - duration: root.actualTransitionType === "none" ? 0 : 1000 - easing.type: Easing.InOutCubic - onFinished: { - if (nextWallpaper.source && nextWallpaper.status === Image.Ready) { - currentWallpaper.source = nextWallpaper.source; - } - root.useNextForEffect = false; - nextWallpaper.source = ""; - root.transitionProgress = 0.0; - currentWallpaper.layer.enabled = false; - nextWallpaper.layer.enabled = false; - root._renderSettling = true; - renderSettleTimer.restart(); - root.effectActive = false; - - if (!root.pendingWallpaper) - return; - var pending = root.pendingWallpaper; - root.pendingWallpaper = ""; - Qt.callLater(() => root.changeWallpaper(pending, true)); - } - } - - Loader { - id: overviewBlurLoader - anchors.fill: parent - active: root.overviewBlurActive - - sourceComponent: MultiEffect { - anchors.fill: parent - source: effectLoader.active ? effectLoader.item : currentWallpaper - blurEnabled: true - blur: 0.8 - blurMax: 75 - autoPaddingEnabled: false - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml deleted file mode 100644 index 1933035..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml +++ /dev/null @@ -1,291 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland -import Quickshell.Hyprland -import qs.Common -import qs.Services - -Scope { - id: overviewScope - - property bool overviewOpen: false - - Loader { - id: hyprlandLoader - active: overviewScope.overviewOpen - asynchronous: false - - sourceComponent: Variants { - id: overviewVariants - model: Quickshell.screens - - PanelWindow { - id: root - required property var modelData - readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen) - property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor?.id) - - screen: modelData - visible: overviewScope.overviewOpen - color: "transparent" - - WlrLayershell.namespace: "dms:workspace-overview" - WlrLayershell.layer: WlrLayer.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: { - if (!overviewScope.overviewOpen) - return WlrKeyboardFocus.None; - if (CompositorService.useHyprlandFocusGrab) - return WlrKeyboardFocus.OnDemand; - return WlrKeyboardFocus.Exclusive; - } - - anchors { - top: true - left: true - right: true - bottom: true - } - - HyprlandFocusGrab { - id: grab - windows: [root] - active: false - property bool hasBeenActivated: false - onActiveChanged: { - if (active) { - hasBeenActivated = true - } - } - onCleared: () => { - if (hasBeenActivated && overviewScope.overviewOpen) { - overviewScope.overviewOpen = false - } - } - } - - Connections { - target: overviewScope - function onOverviewOpenChanged() { - if (overviewScope.overviewOpen) { - grab.hasBeenActivated = false - if (CompositorService.useHyprlandFocusGrab) - delayedGrabTimer.start() - } else { - delayedGrabTimer.stop() - grab.active = false - grab.hasBeenActivated = false - } - } - } - - Connections { - target: root - function onMonitorIsFocusedChanged() { - if (!CompositorService.useHyprlandFocusGrab) - return; - if (overviewScope.overviewOpen && root.monitorIsFocused && !grab.active) { - grab.hasBeenActivated = false - grab.active = true - } else if (overviewScope.overviewOpen && !root.monitorIsFocused && grab.active) { - grab.active = false - } - } - } - - Timer { - id: delayedGrabTimer - interval: 150 - repeat: false - onTriggered: { - if (CompositorService.useHyprlandFocusGrab && overviewScope.overviewOpen && root.monitorIsFocused) { - grab.active = true - } - } - } - - Timer { - id: closeTimer - interval: Theme.expressiveDurations.expressiveDefaultSpatial + 120 - onTriggered: { - root.visible = false - } - } - - Rectangle { - id: background - anchors.fill: parent - color: "black" - opacity: overviewScope.overviewOpen ? 0.5 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - - MouseArea { - anchors.fill: parent - onClicked: mouse => { - const localPos = mapToItem(contentContainer, mouse.x, mouse.y) - if (localPos.x < 0 || localPos.x > contentContainer.width || localPos.y < 0 || localPos.y > contentContainer.height) { - overviewScope.overviewOpen = false - closeTimer.restart() - } - } - } - } - - Item { - id: contentContainer - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.topMargin: 100 - width: childrenRect.width - height: childrenRect.height - - opacity: overviewScope.overviewOpen ? 1 : 0 - transform: [scaleTransform, motionTransform] - - Scale { - id: scaleTransform - origin.x: contentContainer.width / 2 - origin.y: contentContainer.height / 2 - xScale: overviewScope.overviewOpen ? 1 : 0.96 - yScale: overviewScope.overviewOpen ? 1 : 0.96 - - Behavior on xScale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - - Behavior on yScale { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - } - - Translate { - id: motionTransform - x: 0 - y: overviewScope.overviewOpen ? 0 : Theme.spacingL - - Behavior on y { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: overviewScope.overviewOpen ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized - } - } - - Loader { - id: overviewLoader - active: overviewScope.overviewOpen - asynchronous: false - - sourceComponent: OverviewWidget { - panelWindow: root - overviewOpen: overviewScope.overviewOpen - } - } - } - - FocusScope { - id: focusScope - anchors.fill: parent - visible: overviewScope.overviewOpen - focus: overviewScope.overviewOpen && root.monitorIsFocused - - Keys.onEscapePressed: event => { - if (!root.monitorIsFocused) return - overviewScope.overviewOpen = false - closeTimer.restart() - event.accepted = true - } - - Keys.onPressed: event => { - if (!root.monitorIsFocused) return - - if (event.key === Qt.Key_Left || event.key === Qt.Key_Right) { - if (!overviewLoader.item) return - - const thisMonitorWorkspaceIds = overviewLoader.item.thisMonitorWorkspaceIds - if (thisMonitorWorkspaceIds.length === 0) return - - const currentId = root.monitor.activeWorkspace?.id ?? thisMonitorWorkspaceIds[0] - const currentIndex = thisMonitorWorkspaceIds.indexOf(currentId) - - let targetIndex - if (event.key === Qt.Key_Left) { - targetIndex = currentIndex - 1 - if (targetIndex < 0) targetIndex = thisMonitorWorkspaceIds.length - 1 - } else { - targetIndex = currentIndex + 1 - if (targetIndex >= thisMonitorWorkspaceIds.length) targetIndex = 0 - } - - const targetId = thisMonitorWorkspaceIds[targetIndex] - Hyprland.dispatch("workspace " + targetId) - event.accepted = true - } - } - - onVisibleChanged: { - if (visible && overviewScope.overviewOpen && root.monitorIsFocused) { - Qt.callLater(() => focusScope.forceActiveFocus()) - } - } - - Connections { - target: root - function onMonitorIsFocusedChanged() { - if (root.monitorIsFocused && overviewScope.overviewOpen) { - Qt.callLater(() => focusScope.forceActiveFocus()) - } - } - } - } - - onVisibleChanged: { - if (visible && overviewScope.overviewOpen) { - Qt.callLater(() => focusScope.forceActiveFocus()) - } else if (!visible) { - grab.active = false - } - } - - Connections { - target: overviewScope - function onOverviewOpenChanged() { - if (overviewScope.overviewOpen) { - closeTimer.stop() - root.visible = true - Qt.callLater(() => focusScope.forceActiveFocus()) - } else { - closeTimer.restart() - grab.active = false - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml deleted file mode 100644 index c7b1bf7..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml +++ /dev/null @@ -1,322 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland -import qs.Common -import qs.Modals.DankLauncherV2 -import qs.Services - -Scope { - id: niriOverviewScope - - property bool searchActive: false - property string searchActiveScreen: "" - property bool isClosing: false - property bool releaseKeyboard: false - readonly property bool spotlightModalOpen: PopoutService.dankLauncherV2Modal?.spotlightOpen ?? false - property bool overlayActive: NiriService.inOverview || searchActive - - function showSpotlight(screenName) { - isClosing = false; - releaseKeyboard = false; - searchActive = true; - searchActiveScreen = screenName; - } - - function hideSpotlight() { - if (!searchActive) - return; - isClosing = true; - } - - function hideAndReleaseKeyboard() { - releaseKeyboard = true; - hideSpotlight(); - } - - function resetState() { - searchActive = false; - searchActiveScreen = ""; - isClosing = false; - releaseKeyboard = false; - } - - Connections { - target: NiriService - function onInOverviewChanged() { - if (NiriService.inOverview) { - resetState(); - return; - } - if (!searchActive) { - resetState(); - return; - } - isClosing = true; - } - - function onCurrentOutputChanged() { - if (!NiriService.inOverview || !searchActive || searchActiveScreen === "" || searchActiveScreen === NiriService.currentOutput) - return; - hideSpotlight(); - } - } - - onSpotlightModalOpenChanged: { - if (spotlightModalOpen && searchActive) - hideSpotlight(); - } - - Loader { - id: niriOverlayLoader - active: overlayActive || isClosing - asynchronous: false - sourceComponent: Variants { - id: overlayVariants - model: Quickshell.screens - - PanelWindow { - id: overlayWindow - required property var modelData - - readonly property real dpr: CompositorService.getScreenScale(screen) - readonly property bool isActiveScreen: screen.name === NiriService.currentOutput - readonly property bool shouldShowSpotlight: niriOverviewScope.searchActive && screen.name === niriOverviewScope.searchActiveScreen && !niriOverviewScope.isClosing - readonly property bool isSpotlightScreen: screen.name === niriOverviewScope.searchActiveScreen - readonly property bool overlayVisible: NiriService.inOverview || niriOverviewScope.isClosing - property bool hasActivePopout: !!PopoutManager.currentPopoutsByScreen[screen.name] - property bool hasActiveModal: !!ModalManager.currentModalsByScreen[screen.name] - - Connections { - target: PopoutManager - function onPopoutChanged() { - overlayWindow.hasActivePopout = !!PopoutManager.currentPopoutsByScreen[overlayWindow.screen.name]; - } - } - - Connections { - target: ModalManager - function onModalChanged() { - overlayWindow.hasActiveModal = !!ModalManager.currentModalsByScreen[overlayWindow.screen.name]; - } - } - - screen: modelData - visible: overlayVisible - color: "transparent" - - WlrLayershell.namespace: "dms:niri-overview-spotlight" - WlrLayershell.layer: WlrLayer.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: { - if (!NiriService.inOverview) - return WlrKeyboardFocus.None; - if (!isActiveScreen) - return WlrKeyboardFocus.None; - if (niriOverviewScope.releaseKeyboard) - return WlrKeyboardFocus.None; - if (hasActivePopout || hasActiveModal) - return WlrKeyboardFocus.None; - return WlrKeyboardFocus.Exclusive; - } - - mask: Region { - item: overlayVisible && spotlightContainer.visible ? spotlightContainer : null - } - - onShouldShowSpotlightChanged: { - if (shouldShowSpotlight) { - if (launcherContent?.controller) { - launcherContent.controller.searchMode = SessionData.niriOverviewLastMode || "apps"; - launcherContent.controller.performSearch(); - } - return; - } - if (!isActiveScreen) - return; - Qt.callLater(() => keyboardFocusScope.forceActiveFocus()); - } - - anchors { - top: true - left: true - right: true - bottom: true - } - - FocusScope { - id: keyboardFocusScope - anchors.fill: parent - focus: true - - Keys.onPressed: event => { - if (overlayWindow.shouldShowSpotlight || niriOverviewScope.isClosing) - return; - if ([Qt.Key_Escape, Qt.Key_Return].includes(event.key)) { - NiriService.toggleOverview(); - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Left) { - NiriService.moveColumnLeft(); - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Right) { - NiriService.moveColumnRight(); - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Up) { - NiriService.moveWorkspaceUp(); - event.accepted = true; - return; - } - - if (event.key === Qt.Key_Down) { - NiriService.moveWorkspaceDown(); - event.accepted = true; - return; - } - - if (event.modifiers & (Qt.ControlModifier | Qt.MetaModifier) || [Qt.Key_Delete, Qt.Key_Backspace].includes(event.key)) { - event.accepted = false; - return; - } - - if (event.isAutoRepeat || !event.text) - return; - if (!launcherContent?.searchField) - return; - const trimmedText = event.text.trim(); - launcherContent.searchField.text = trimmedText; - launcherContent.controller.setSearchQuery(trimmedText); - niriOverviewScope.showSpotlight(overlayWindow.screen.name); - Qt.callLater(() => launcherContent.searchField.forceActiveFocus()); - event.accepted = true; - } - } - - Item { - id: spotlightContainer - x: Theme.snap((parent.width - width) / 2, overlayWindow.dpr) - y: Theme.snap((parent.height - height) / 2, overlayWindow.dpr) - - readonly property int baseWidth: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 500; - case "medium": - return 720; - case "large": - return 860; - default: - return 620; - } - } - readonly property int baseHeight: { - switch (SettingsData.dankLauncherV2Size) { - case "micro": - return 480; - case "medium": - return 720; - case "large": - return 860; - default: - return 600; - } - } - width: Math.min(baseWidth, overlayWindow.screen.width - 100) - height: Math.min(baseHeight, overlayWindow.screen.height - 100) - - readonly property bool animatingOut: niriOverviewScope.isClosing && overlayWindow.isSpotlightScreen - - scale: overlayWindow.shouldShowSpotlight ? 1.0 : 0.96 - opacity: overlayWindow.shouldShowSpotlight ? 1 : 0 - visible: overlayWindow.shouldShowSpotlight || animatingOut - enabled: overlayWindow.shouldShowSpotlight - - layer.enabled: visible - layer.smooth: false - layer.textureSize: layer.enabled ? Qt.size(Math.round(width * overlayWindow.dpr), Math.round(height * overlayWindow.dpr)) : Qt.size(0, 0) - - Behavior on scale { - id: scaleAnimation - NumberAnimation { - duration: Theme.expressiveDurations.fast - easing.type: Easing.BezierSpline - easing.bezierCurve: spotlightContainer.visible ? Theme.expressiveCurves.expressiveFastSpatial : Theme.expressiveCurves.standardAccel - onRunningChanged: { - if (running || !spotlightContainer.animatingOut) - return; - niriOverviewScope.resetState(); - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.expressiveDurations.fast - easing.type: Easing.BezierSpline - easing.bezierCurve: spotlightContainer.visible ? Theme.expressiveCurves.expressiveFastSpatial : Theme.expressiveCurves.standardAccel - } - } - - Rectangle { - anchors.fill: parent - color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) - radius: Theme.cornerRadius - border.color: Theme.outlineMedium - border.width: 1 - } - - LauncherContent { - id: launcherContent - anchors.fill: parent - anchors.margins: 0 - - property var fakeParentModal: QtObject { - property bool spotlightOpen: spotlightContainer.visible - property bool isClosing: niriOverviewScope.isClosing - function hide() { - if (niriOverviewScope.searchActive) { - niriOverviewScope.hideSpotlight(); - return; - } - NiriService.toggleOverview(); - } - } - - Connections { - target: launcherContent.searchField - function onTextChanged() { - if (launcherContent.searchField.text.length > 0 || !niriOverviewScope.searchActive) - return; - niriOverviewScope.hideSpotlight(); - } - } - - Component.onCompleted: { - parentModal = fakeParentModal; - } - - Connections { - target: launcherContent.controller - function onItemExecuted() { - niriOverviewScope.releaseKeyboard = true; - } - function onModeChanged(mode) { - if (launcherContent.controller.autoSwitchedToFiles) - return; - SessionData.setNiriOverviewLastMode(mode); - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml deleted file mode 100644 index 03d39fb..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml +++ /dev/null @@ -1,443 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Quickshell -import Quickshell.Hyprland -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: root - required property var panelWindow - required property bool overviewOpen - readonly property HyprlandMonitor monitor: Hyprland.monitorFor(panelWindow.screen) - readonly property real dpr: CompositorService.getScreenScale(panelWindow.screen) - readonly property int workspacesShown: SettingsData.overviewRows * SettingsData.overviewColumns - - readonly property var allWorkspaces: Hyprland.workspaces?.values || [] - readonly property var allWorkspaceIds: { - const workspaces = allWorkspaces; - if (!workspaces || workspaces.length === 0) - return []; - try { - const ids = workspaces.map(ws => ws?.id).filter(id => id !== null && id !== undefined); - return ids.sort((a, b) => a - b); - } catch (e) { - return []; - } - } - - readonly property var thisMonitorWorkspaceIds: { - const workspaces = allWorkspaces; - const mon = monitor; - if (!workspaces || workspaces.length === 0 || !mon) - return []; - try { - const filtered = workspaces.filter(ws => ws?.monitor?.name === mon.name); - return filtered.map(ws => ws?.id).filter(id => id !== null && id !== undefined).sort((a, b) => a - b); - } catch (e) { - return []; - } - } - - readonly property var displayedWorkspaceIds: { - if (!allWorkspaceIds || allWorkspaceIds.length === 0) { - const result = []; - for (let i = 1; i <= workspacesShown; i++) { - result.push(i); - } - return result; - } - - try { - const maxExisting = Math.max(...allWorkspaceIds); - const totalNeeded = Math.max(workspacesShown, allWorkspaceIds.length); - const result = []; - - for (let i = 1; i <= maxExisting; i++) { - result.push(i); - } - - let nextId = maxExisting + 1; - while (result.length < totalNeeded) { - result.push(nextId); - nextId++; - } - - return result; - } catch (e) { - const result = []; - for (let i = 1; i <= workspacesShown; i++) { - result.push(i); - } - return result; - } - } - - readonly property int minWorkspaceId: displayedWorkspaceIds.length > 0 ? displayedWorkspaceIds[0] : 1 - readonly property int maxWorkspaceId: displayedWorkspaceIds.length > 0 ? displayedWorkspaceIds[displayedWorkspaceIds.length - 1] : workspacesShown - readonly property int displayWorkspaceCount: displayedWorkspaceIds.length - - readonly property int effectiveColumns: SettingsData.overviewColumns - readonly property int effectiveRows: Math.max(SettingsData.overviewRows, Math.ceil(displayWorkspaceCount / effectiveColumns)) - - function getWorkspaceMonitorName(workspaceId) { - if (!allWorkspaces || !workspaceId) - return ""; - try { - const ws = allWorkspaces.find(w => w?.id === workspaceId); - return ws?.monitor?.name ?? ""; - } catch (e) { - return ""; - } - } - - function workspaceHasWindows(workspaceId) { - if (!workspaceId) - return false; - try { - const workspace = allWorkspaces.find(ws => ws?.id === workspaceId); - if (!workspace) - return false; - const toplevels = workspace?.toplevels?.values || []; - return toplevels.length > 0; - } catch (e) { - return false; - } - } - - property bool monitorIsFocused: monitor?.focused ?? false - property real scale: SettingsData.overviewScale - property color activeBorderColor: Theme.primary - - readonly property real monitorPhysicalWidth: panelWindow.screen ? (panelWindow.screen.width / root.dpr) : (monitor?.width ?? 1920) - readonly property real monitorPhysicalHeight: panelWindow.screen ? (panelWindow.screen.height / root.dpr) : (monitor?.height ?? 1080) - property real workspaceImplicitWidth: monitorPhysicalWidth * root.scale - property real workspaceImplicitHeight: monitorPhysicalHeight * root.scale - - property int workspaceZ: 0 - property int windowZ: 1 - property int monitorLabelZ: 2 - property int windowDraggingZ: 99999 - property real workspaceSpacing: 5 - - property int draggingFromWorkspace: -1 - property int draggingTargetWorkspace: -1 - - implicitWidth: overviewBackground.implicitWidth + Theme.spacingL * 2 - implicitHeight: overviewBackground.implicitHeight + Theme.spacingL * 2 - - Component.onCompleted: { - Hyprland.refreshToplevels(); - Hyprland.refreshWorkspaces(); - Hyprland.refreshMonitors(); - } - - onOverviewOpenChanged: { - if (overviewOpen) { - Hyprland.refreshToplevels(); - Hyprland.refreshWorkspaces(); - Hyprland.refreshMonitors(); - } - } - - Rectangle { - id: overviewBackground - property real padding: 10 - anchors.fill: parent - anchors.margins: Theme.spacingL - - implicitWidth: workspaceColumnLayout.implicitWidth + padding * 2 - implicitHeight: workspaceColumnLayout.implicitHeight + padding * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - - ElevationShadow { - anchors.fill: parent - z: -1 - level: Theme.elevationLevel2 - fallbackOffset: 4 - targetRadius: Theme.cornerRadius - targetColor: Theme.surfaceContainer - shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 - shadowEnabled: Theme.elevationEnabled - } - - ColumnLayout { - id: workspaceColumnLayout - - z: root.workspaceZ - anchors.centerIn: parent - spacing: workspaceSpacing - - Repeater { - model: root.effectiveRows - delegate: RowLayout { - id: row - property int rowIndex: index - spacing: workspaceSpacing - - Repeater { - model: root.effectiveColumns - Rectangle { - id: workspace - property int colIndex: index - property int workspaceIndex: rowIndex * root.effectiveColumns + colIndex - property int workspaceValue: (root.displayedWorkspaceIds && workspaceIndex < root.displayedWorkspaceIds.length) ? root.displayedWorkspaceIds[workspaceIndex] : -1 - property bool workspaceExists: (root.allWorkspaceIds && workspaceValue > 0) ? root.allWorkspaceIds.includes(workspaceValue) : false - property var workspaceObj: (workspaceExists && Hyprland.workspaces?.values) ? Hyprland.workspaces.values.find(ws => ws?.id === workspaceValue) : null - property bool isActive: workspaceObj?.active ?? false - property bool isOnThisMonitor: (workspaceObj && root.monitor) ? (workspaceObj.monitor?.name === root.monitor.name) : true - property bool hasWindows: (workspaceValue > 0) ? root.workspaceHasWindows(workspaceValue) : false - property string workspaceMonitorName: (workspaceValue > 0) ? root.getWorkspaceMonitorName(workspaceValue) : "" - property color defaultWorkspaceColor: workspaceExists ? Theme.surfaceContainer : Theme.withAlpha(Theme.surfaceContainer, 0.3) - property color hoveredWorkspaceColor: Qt.lighter(defaultWorkspaceColor, 1.1) - property color hoveredBorderColor: Theme.surfaceVariant - property bool hoveredWhileDragging: false - property bool shouldShowActiveIndicator: isActive && isOnThisMonitor && hasWindows - - visible: workspaceValue !== -1 - - implicitWidth: root.workspaceImplicitWidth - implicitHeight: root.workspaceImplicitHeight - color: hoveredWhileDragging ? hoveredWorkspaceColor : defaultWorkspaceColor - radius: Theme.cornerRadius - border.width: 2 - border.color: hoveredWhileDragging ? hoveredBorderColor : (shouldShowActiveIndicator ? root.activeBorderColor : "transparent") - - StyledText { - anchors.centerIn: parent - text: workspaceValue - font.pixelSize: Theme.fontSizeXLarge * 6 - font.weight: Font.DemiBold - color: Theme.withAlpha(Theme.surfaceText, workspaceExists ? 0.2 : 0.1) - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - - MouseArea { - id: workspaceArea - anchors.fill: parent - acceptedButtons: Qt.LeftButton - onClicked: { - if (root.draggingTargetWorkspace === -1) { - root.overviewOpen = false; - Hyprland.dispatch(`workspace ${workspaceValue}`); - } - } - } - - DropArea { - anchors.fill: parent - onEntered: { - root.draggingTargetWorkspace = workspaceValue; - if (root.draggingFromWorkspace == root.draggingTargetWorkspace) - return; - hoveredWhileDragging = true; - } - onExited: { - hoveredWhileDragging = false; - if (root.draggingTargetWorkspace == workspaceValue) - root.draggingTargetWorkspace = -1; - } - } - } - } - } - } - } - - Item { - id: windowSpace - anchors.centerIn: parent - implicitWidth: workspaceColumnLayout.implicitWidth - implicitHeight: workspaceColumnLayout.implicitHeight - - Repeater { - model: ScriptModel { - values: { - const workspaces = root.allWorkspaces; - const minId = root.minWorkspaceId; - const maxId = root.maxWorkspaceId; - - if (!workspaces || workspaces.length === 0) - return []; - - try { - const result = []; - for (const workspace of workspaces) { - const wsId = workspace?.id ?? -1; - if (wsId >= minId && wsId <= maxId) { - const toplevels = workspace?.toplevels?.values || []; - for (const toplevel of toplevels) { - result.push(toplevel); - } - } - } - return result; - } catch (e) { - console.error("OverviewWidget filter error:", e); - return []; - } - } - } - delegate: OverviewWindow { - id: window - required property var modelData - - overviewOpen: root.overviewOpen - readonly property int windowWorkspaceId: modelData?.workspace?.id ?? -1 - - function getWorkspaceIndex() { - if (!root.displayedWorkspaceIds || root.displayedWorkspaceIds.length === 0) - return 0; - if (!windowWorkspaceId || windowWorkspaceId < 0) - return 0; - try { - for (let i = 0; i < root.displayedWorkspaceIds.length; i++) { - if (root.displayedWorkspaceIds[i] === windowWorkspaceId) { - return i; - } - } - return 0; - } catch (e) { - return 0; - } - } - - readonly property int workspaceIndex: getWorkspaceIndex() - readonly property int workspaceColIndex: workspaceIndex % root.effectiveColumns - readonly property int workspaceRowIndex: Math.floor(workspaceIndex / root.effectiveColumns) - - toplevel: modelData - scale: root.scale - monitorDpr: root.dpr - availableWorkspaceWidth: root.workspaceImplicitWidth - availableWorkspaceHeight: root.workspaceImplicitHeight - widgetMonitorId: root.monitor.id - - xOffset: (root.workspaceImplicitWidth + workspaceSpacing) * workspaceColIndex - yOffset: (root.workspaceImplicitHeight + workspaceSpacing) * workspaceRowIndex - - z: atInitPosition ? root.windowZ : root.windowDraggingZ - property bool atInitPosition: (initX == x && initY == y) - - Drag.hotSpot.x: width / 2 - Drag.hotSpot.y: height / 2 - - MouseArea { - id: dragArea - anchors.fill: parent - hoverEnabled: true - onEntered: window.hovered = true - onExited: window.hovered = false - acceptedButtons: Qt.LeftButton | Qt.MiddleButton - drag.target: parent - - onPressed: mouse => { - root.draggingFromWorkspace = windowData?.workspace.id; - window.pressed = true; - window.Drag.active = true; - window.Drag.source = window; - window.Drag.hotSpot.x = mouse.x; - window.Drag.hotSpot.y = mouse.y; - } - - onReleased: { - const targetWorkspace = root.draggingTargetWorkspace; - window.pressed = false; - window.Drag.active = false; - root.draggingFromWorkspace = -1; - root.draggingTargetWorkspace = -1; - - if (targetWorkspace !== -1 && targetWorkspace !== windowData?.workspace.id) { - Hyprland.dispatch(`movetoworkspacesilent ${targetWorkspace},address:${windowData?.address}`); - Qt.callLater(() => { - Hyprland.refreshToplevels(); - Hyprland.refreshWorkspaces(); - Qt.callLater(() => { - window.x = window.initX; - window.y = window.initY; - }); - }); - } else { - window.x = window.initX; - window.y = window.initY; - } - } - - onClicked: event => { - if (!windowData || !windowData.address) - return; - if (event.button === Qt.LeftButton) { - root.overviewOpen = false; - Hyprland.dispatch(`focuswindow address:${windowData.address}`); - event.accepted = true; - } else if (event.button === Qt.MiddleButton) { - Hyprland.dispatch(`closewindow address:${windowData.address}`); - event.accepted = true; - } - } - } - } - } - } - - Item { - id: monitorLabelSpace - anchors.centerIn: parent - implicitWidth: workspaceColumnLayout.implicitWidth - implicitHeight: workspaceColumnLayout.implicitHeight - z: root.monitorLabelZ - - Repeater { - model: root.effectiveRows - delegate: Item { - id: labelRow - property int rowIndex: index - y: (root.workspaceImplicitHeight + workspaceSpacing) * rowIndex - width: parent.width - height: root.workspaceImplicitHeight - - Repeater { - model: root.effectiveColumns - delegate: Item { - id: labelItem - property int colIndex: index - property int workspaceIndex: labelRow.rowIndex * root.effectiveColumns + colIndex - property int workspaceValue: (root.displayedWorkspaceIds && workspaceIndex < root.displayedWorkspaceIds.length) ? root.displayedWorkspaceIds[workspaceIndex] : -1 - property bool workspaceExists: (root.allWorkspaceIds && workspaceValue > 0) ? root.allWorkspaceIds.includes(workspaceValue) : false - property string workspaceMonitorName: (workspaceValue > 0) ? root.getWorkspaceMonitorName(workspaceValue) : "" - - x: (root.workspaceImplicitWidth + workspaceSpacing) * colIndex - width: root.workspaceImplicitWidth - height: root.workspaceImplicitHeight - - Rectangle { - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: Theme.spacingS - width: monitorNameText.contentWidth + Theme.spacingS * 2 - height: monitorNameText.contentHeight + Theme.spacingXS * 2 - radius: Theme.cornerRadius - color: Theme.surface - visible: labelItem.workspaceExists && labelItem.workspaceMonitorName !== "" - - StyledText { - id: monitorNameText - anchors.centerIn: parent - text: labelItem.workspaceMonitorName - font.pixelSize: Theme.fontSizeSmall - font.weight: Font.Medium - color: Theme.surfaceText - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - } - } - } - } - } - } - } -} diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWindow.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWindow.qml deleted file mode 100644 index 4389971..0000000 --- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/WorkspaceOverlays/OverviewWindow.qml +++ /dev/null @@ -1,142 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import Quickshell -import Quickshell.Wayland -import qs.Common - -Item { - id: root - property var toplevel - property var scale - required property bool overviewOpen - property var availableWorkspaceWidth - property var availableWorkspaceHeight - property bool restrictToWorkspace: true - property real monitorDpr: 1 - - readonly property var windowData: toplevel?.lastIpcObject || null - readonly property var monitorObj: toplevel?.monitor - readonly property var monitorData: monitorObj?.lastIpcObject || null - readonly property real effectiveScale: root.scale / root.monitorDpr - - property real initX: Math.max(((windowData?.at?.[0] ?? 0) - (monitorData?.x ?? 0) - (monitorData?.reserved?.[0] ?? 0)) * effectiveScale, 0) + xOffset - property real initY: Math.max(((windowData?.at?.[1] ?? 0) - (monitorData?.y ?? 0) - (monitorData?.reserved?.[1] ?? 0)) * effectiveScale, 0) + yOffset - property real xOffset: 0 - property real yOffset: 0 - property int widgetMonitorId: 0 - - property var targetWindowWidth: (windowData?.size?.[0] ?? 100) * effectiveScale - property var targetWindowHeight: (windowData?.size?.[1] ?? 100) * effectiveScale - property bool hovered: false - property bool pressed: false - - property var iconToWindowRatio: 0.25 - property var iconToWindowRatioCompact: 0.45 - property var entry: DesktopEntries.heuristicLookup(Paths.moddedAppId(windowData?.class ?? "")) - property var iconPath: Paths.getAppIcon(windowData?.class ?? "", entry) || Quickshell.iconPath("application-x-executable", "image-missing") - property bool compactMode: Theme.fontSizeSmall * 4 > targetWindowHeight || Theme.fontSizeSmall * 4 > targetWindowWidth - - x: initX - y: initY - width: Math.min((windowData?.size?.[0] ?? 100) * effectiveScale, availableWorkspaceWidth) - height: Math.min((windowData?.size?.[1] ?? 100) * effectiveScale, availableWorkspaceHeight) - opacity: (monitorObj?.id ?? -1) == widgetMonitorId ? 1 : 0.4 - - Rectangle { - id: maskRect - width: root.width - height: root.height - radius: Theme.cornerRadius - visible: false - layer.enabled: true - } - - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskSource: maskRect - maskSpreadAtMin: 1 - maskThresholdMin: 0.5 - } - - Behavior on x { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - Behavior on y { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - Behavior on width { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - Behavior on height { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - - ScreencopyView { - id: windowPreview - anchors.fill: parent - captureSource: root.overviewOpen ? root.toplevel?.wayland : null - live: true - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: pressed ? Theme.withAlpha(Theme.surfaceContainerHigh, 0.5) : - hovered ? Theme.withAlpha(Theme.surfaceVariant, 0.3) : - Theme.withAlpha(Theme.surfaceContainer, 0.1) - border.color: Theme.withAlpha(Theme.outline, 0.3) - border.width: 1 - } - - ColumnLayout { - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.right: parent.right - spacing: Theme.fontSizeSmall * 0.5 - - Image { - id: windowIcon - property var iconSize: { - return Math.min(targetWindowWidth, targetWindowHeight) * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) / (root.monitorData?.scale ?? 1) - } - Layout.alignment: Qt.AlignHCenter - source: root.iconPath - width: iconSize - height: iconSize - sourceSize: Qt.size(iconSize, iconSize) - - Behavior on width { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - Behavior on height { - NumberAnimation { - duration: Theme.expressiveDurations.expressiveDefaultSpatial - easing.type: Easing.BezierSpline - easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel - } - } - } - } - } -} -- cgit v1.3