1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-05 21:15:38 -05:00

modules cleanup and qmlfmt everywhere

- throw in 24H clock fix and app drawer fix too
This commit is contained in:
bbedward
2025-09-03 23:26:07 -04:00
parent 178ccd3634
commit 21867c842f
55 changed files with 2720 additions and 3236 deletions

View File

@@ -64,8 +64,7 @@ quickshell -p shell.qml
qs -p . qs -p .
# Code formatting and linting # Code formatting and linting
./qmlformat-all.sh # Format all QML files using project script qmlfmt -t 4 -i 4 -b 250 -w /path/to/file.qml # Format a QML file (requires qmlfmt, do not use qmlformat)
qmlformat -i **/*.qml # Format all QML files in place
qmllint **/*.qml # Lint all QML files for syntax errors qmllint **/*.qml # Lint all QML files for syntax errors
``` ```
@@ -221,6 +220,8 @@ shell.qml # Main entry point (minimal orchestration)
- Properties before signal handlers before child components - Properties before signal handlers before child components
- Prefer property bindings over imperative code - Prefer property bindings over imperative code
- **CRITICAL**: NEVER add comments unless absolutely essential for complex logic understanding. Code should be self-documenting through clear naming and structure. Comments are a code smell indicating unclear implementation. - **CRITICAL**: NEVER add comments unless absolutely essential for complex logic understanding. Code should be self-documenting through clear naming and structure. Comments are a code smell indicating unclear implementation.
- Use guard statements, example `if (abc) { something() return;} somethingElse();`
- Don't use crazy ternary stuff, but use it for simple if else only. `propertyVal: a ? b : c`
2. **Naming Conventions**: 2. **Naming Conventions**:
- **Services**: Use `Singleton` type with `id: root` - **Services**: Use `Singleton` type with `id: root`
@@ -228,9 +229,7 @@ shell.qml # Main entry point (minimal orchestration)
- **Properties**: camelCase for properties, PascalCase for types - **Properties**: camelCase for properties, PascalCase for types
3. **Null-Safe Operations**: 3. **Null-Safe Operations**:
- **Do NOT use** `?.` operator (not supported by qmlformat) - **Use** `object?.property`
- **Use** `object && object.property` instead of `object?.property`
- **Example**: `activePlayer && activePlayer.trackTitle` instead of `activePlayer?.trackTitle`
4. **Component Structure**: 4. **Component Structure**:
```qml ```qml

24
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,24 @@
# Contributing
Contributions are welcome and encourages.
## Formatting
The preferred tool for formatting files is [qmlfmt](https://github.com/jesperhh/qmlfmt) (also available on aur as qmlfmt-git). It actually kinda sucks, but `qmlformat` doesn't work with null safe operators and ternarys and pragma statements and a bunch of other things that are supported.
We need some consistent style, so this at least gives the same formatter that Qt Creator uses.
You can configure it to format on save in vscode by configuring the "custom local formatters" extension then adding this to settings json.
```json
"customLocalFormatters.formatters": [
{
"command": "sh -c \"qmlfmt -t 4 -i 4 -b 250 | sed 's/pragma ComponentBehavior$/pragma ComponentBehavior: Bound/g'\"",
"languages": ["qml"]
}
],
"[qml]": {
"editor.defaultFormatter": "jkillian.custom-local-formatters",
"editor.formatOnSave": true
},
```

View File

@@ -1,4 +1,5 @@
pragma Singleton pragma Singleton
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtCore import QtCore
@@ -98,18 +99,14 @@ Singleton {
property var screenPreferences: ({}) property var screenPreferences: ({})
readonly property string defaultFontFamily: "Inter Variable" readonly property string defaultFontFamily: "Inter Variable"
readonly property string defaultMonoFontFamily: "Fira Code" readonly property string defaultMonoFontFamily: "Fira Code"
readonly property string _homeUrl: StandardPaths.writableLocation( readonly property string _homeUrl: StandardPaths.writableLocation(StandardPaths.HomeLocation)
StandardPaths.HomeLocation) readonly property string _configUrl: StandardPaths.writableLocation(StandardPaths.ConfigLocation)
readonly property string _configUrl: StandardPaths.writableLocation( readonly property string _configDir: _configUrl.startsWith("file://") ? _configUrl.substring(7) : _configUrl
StandardPaths.ConfigLocation)
readonly property string _configDir: _configUrl.startsWith(
"file://") ? _configUrl.substring(
7) : _configUrl
signal forceTopBarLayoutRefresh signal forceTopBarLayoutRefresh
signal widgetDataChanged signal widgetDataChanged
signal workspaceIconsUpdated signal workspaceIconsUpdated
function getEffectiveTimeFormat() { function getEffectiveTimeFormat() {
if (use24HourClock) { if (use24HourClock) {
return Locale.ShortFormat return Locale.ShortFormat
@@ -117,11 +114,11 @@ Singleton {
return "h:mm AP" return "h:mm AP"
} }
} }
function getEffectiveClockDateFormat() { function getEffectiveClockDateFormat() {
return clockDateFormat && clockDateFormat.length > 0 ? clockDateFormat : "ddd d" return clockDateFormat && clockDateFormat.length > 0 ? clockDateFormat : "ddd d"
} }
function getEffectiveLockDateFormat() { function getEffectiveLockDateFormat() {
return lockDateFormat && lockDateFormat.length > 0 ? lockDateFormat : Locale.LongFormat return lockDateFormat && lockDateFormat.length > 0 ? lockDateFormat : Locale.LongFormat
} }
@@ -139,7 +136,7 @@ Singleton {
leftWidgetsModel.append(dummyItem) leftWidgetsModel.append(dummyItem)
centerWidgetsModel.append(dummyItem) centerWidgetsModel.append(dummyItem)
rightWidgetsModel.append(dummyItem) rightWidgetsModel.append(dummyItem)
updateListModel(leftWidgetsModel, topBarLeftWidgets) updateListModel(leftWidgetsModel, topBarLeftWidgets)
updateListModel(centerWidgetsModel, topBarCenterWidgets) updateListModel(centerWidgetsModel, topBarCenterWidgets)
updateListModel(rightWidgetsModel, topBarRightWidgets) updateListModel(rightWidgetsModel, topBarRightWidgets)
@@ -166,42 +163,20 @@ Singleton {
currentThemeName = settings.currentThemeName !== undefined ? settings.currentThemeName : "blue" currentThemeName = settings.currentThemeName !== undefined ? settings.currentThemeName : "blue"
} }
customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : "" customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : ""
topBarTransparency = settings.topBarTransparency topBarTransparency = settings.topBarTransparency !== undefined ? (settings.topBarTransparency > 1 ? settings.topBarTransparency / 100 : settings.topBarTransparency) : 0.75
!== undefined ? (settings.topBarTransparency topBarWidgetTransparency = settings.topBarWidgetTransparency !== undefined ? (settings.topBarWidgetTransparency > 1 ? settings.topBarWidgetTransparency / 100 : settings.topBarWidgetTransparency) : 0.85
> 1 ? settings.topBarTransparency popupTransparency = settings.popupTransparency !== undefined ? (settings.popupTransparency > 1 ? settings.popupTransparency / 100 : settings.popupTransparency) : 0.92
/ 100 : settings.topBarTransparency) : 0.75 dockTransparency = settings.dockTransparency !== undefined ? (settings.dockTransparency > 1 ? settings.dockTransparency / 100 : settings.dockTransparency) : 1
topBarWidgetTransparency = settings.topBarWidgetTransparency use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true
!== undefined ? (settings.topBarWidgetTransparency useFahrenheit = settings.useFahrenheit !== undefined ? settings.useFahrenheit : false
> 1 ? settings.topBarWidgetTransparency nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false
/ 100 : settings.topBarWidgetTransparency) : 0.85 weatherLocation = settings.weatherLocation !== undefined ? settings.weatherLocation : "New York, NY"
popupTransparency = settings.popupTransparency weatherCoordinates = settings.weatherCoordinates !== undefined ? settings.weatherCoordinates : "40.7128,-74.0060"
!== undefined ? (settings.popupTransparency useAutoLocation = settings.useAutoLocation !== undefined ? settings.useAutoLocation : false
> 1 ? settings.popupTransparency weatherEnabled = settings.weatherEnabled !== undefined ? settings.weatherEnabled : true
/ 100 : settings.popupTransparency) : 0.92 showLauncherButton = settings.showLauncherButton !== undefined ? settings.showLauncherButton : true
dockTransparency = settings.dockTransparency showWorkspaceSwitcher = settings.showWorkspaceSwitcher !== undefined ? settings.showWorkspaceSwitcher : true
!== undefined ? (settings.dockTransparency showFocusedWindow = settings.showFocusedWindow !== undefined ? settings.showFocusedWindow : true
> 1 ? settings.dockTransparency
/ 100 : settings.dockTransparency) : 1
use24HourClock = settings.use24HourClock
!== undefined ? settings.use24HourClock : true
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
showLauncherButton = settings.showLauncherButton
!== undefined ? settings.showLauncherButton : true
showWorkspaceSwitcher = settings.showWorkspaceSwitcher
!== undefined ? settings.showWorkspaceSwitcher : true
showFocusedWindow = settings.showFocusedWindow
!== undefined ? settings.showFocusedWindow : true
showWeather = settings.showWeather !== undefined ? settings.showWeather : true showWeather = settings.showWeather !== undefined ? settings.showWeather : true
showMusic = settings.showMusic !== undefined ? settings.showMusic : true showMusic = settings.showMusic !== undefined ? settings.showMusic : true
showClipboard = settings.showClipboard !== undefined ? settings.showClipboard : true showClipboard = settings.showClipboard !== undefined ? settings.showClipboard : true
@@ -209,68 +184,42 @@ Singleton {
showMemUsage = settings.showMemUsage !== undefined ? settings.showMemUsage : true showMemUsage = settings.showMemUsage !== undefined ? settings.showMemUsage : true
showCpuTemp = settings.showCpuTemp !== undefined ? settings.showCpuTemp : true showCpuTemp = settings.showCpuTemp !== undefined ? settings.showCpuTemp : true
showGpuTemp = settings.showGpuTemp !== undefined ? settings.showGpuTemp : true showGpuTemp = settings.showGpuTemp !== undefined ? settings.showGpuTemp : true
selectedGpuIndex = settings.selectedGpuIndex selectedGpuIndex = settings.selectedGpuIndex !== undefined ? settings.selectedGpuIndex : 0
!== undefined ? settings.selectedGpuIndex : 0 enabledGpuPciIds = settings.enabledGpuPciIds !== undefined ? settings.enabledGpuPciIds : []
enabledGpuPciIds = settings.enabledGpuPciIds showSystemTray = settings.showSystemTray !== undefined ? settings.showSystemTray : true
!== undefined ? settings.enabledGpuPciIds : []
showSystemTray = settings.showSystemTray
!== undefined ? settings.showSystemTray : true
showClock = settings.showClock !== undefined ? settings.showClock : true showClock = settings.showClock !== undefined ? settings.showClock : true
showNotificationButton = settings.showNotificationButton showNotificationButton = settings.showNotificationButton !== undefined ? settings.showNotificationButton : true
!== undefined ? settings.showNotificationButton : true
showBattery = settings.showBattery !== undefined ? settings.showBattery : true showBattery = settings.showBattery !== undefined ? settings.showBattery : true
showControlCenterButton = settings.showControlCenterButton showControlCenterButton = settings.showControlCenterButton !== undefined ? settings.showControlCenterButton : true
!== undefined ? settings.showControlCenterButton : true controlCenterShowNetworkIcon = settings.controlCenterShowNetworkIcon !== undefined ? settings.controlCenterShowNetworkIcon : true
controlCenterShowNetworkIcon = settings.controlCenterShowNetworkIcon controlCenterShowBluetoothIcon = settings.controlCenterShowBluetoothIcon !== undefined ? settings.controlCenterShowBluetoothIcon : true
!== undefined ? settings.controlCenterShowNetworkIcon : true controlCenterShowAudioIcon = settings.controlCenterShowAudioIcon !== undefined ? settings.controlCenterShowAudioIcon : true
controlCenterShowBluetoothIcon = settings.controlCenterShowBluetoothIcon showWorkspaceIndex = settings.showWorkspaceIndex !== undefined ? settings.showWorkspaceIndex : false
!== undefined ? settings.controlCenterShowBluetoothIcon : true showWorkspacePadding = settings.showWorkspacePadding !== undefined ? settings.showWorkspacePadding : false
controlCenterShowAudioIcon = settings.controlCenterShowAudioIcon showWorkspaceApps = settings.showWorkspaceApps !== undefined ? settings.showWorkspaceApps : false
!== undefined ? settings.controlCenterShowAudioIcon : true maxWorkspaceIcons = settings.maxWorkspaceIcons !== undefined ? settings.maxWorkspaceIcons : 3
showWorkspaceIndex = settings.showWorkspaceIndex workspaceNameIcons = settings.workspaceNameIcons !== undefined ? settings.workspaceNameIcons : ({})
!== undefined ? settings.showWorkspaceIndex : false clockCompactMode = settings.clockCompactMode !== undefined ? settings.clockCompactMode : false
showWorkspacePadding = settings.showWorkspacePadding focusedWindowCompactMode = settings.focusedWindowCompactMode !== undefined ? settings.focusedWindowCompactMode : false
!== undefined ? settings.showWorkspacePadding : false runningAppsCompactMode = settings.runningAppsCompactMode !== undefined ? settings.runningAppsCompactMode : true
showWorkspaceApps = settings.showWorkspaceApps runningAppsCurrentWorkspace = settings.runningAppsCurrentWorkspace !== undefined ? settings.runningAppsCurrentWorkspace : false
!== undefined ? settings.showWorkspaceApps : false clockDateFormat = settings.clockDateFormat !== undefined ? settings.clockDateFormat : ""
maxWorkspaceIcons = settings.maxWorkspaceIcons lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : ""
!== undefined ? settings.maxWorkspaceIcons : 3
workspaceNameIcons = settings.workspaceNameIcons
!== undefined ? settings.workspaceNameIcons : ({})
clockCompactMode = settings.clockCompactMode
!== undefined ? settings.clockCompactMode : false
focusedWindowCompactMode = settings.focusedWindowCompactMode
!== undefined ? settings.focusedWindowCompactMode : false
runningAppsCompactMode = settings.runningAppsCompactMode
!== undefined ? settings.runningAppsCompactMode : true
runningAppsCurrentWorkspace = settings.runningAppsCurrentWorkspace
!== undefined ? settings.runningAppsCurrentWorkspace : false
clockDateFormat = settings.clockDateFormat
!== undefined ? settings.clockDateFormat : ""
lockDateFormat = settings.lockDateFormat
!== undefined ? settings.lockDateFormat : ""
mediaSize = settings.mediaSize !== undefined ? settings.mediaSize : (settings.mediaCompactMode !== undefined ? (settings.mediaCompactMode ? 0 : 1) : 1) mediaSize = settings.mediaSize !== undefined ? settings.mediaSize : (settings.mediaCompactMode !== undefined ? (settings.mediaCompactMode ? 0 : 1) : 1)
if (settings.topBarWidgetOrder) { if (settings.topBarWidgetOrder) {
topBarLeftWidgets = settings.topBarWidgetOrder.filter(w => { topBarLeftWidgets = settings.topBarWidgetOrder.filter(w => {
return ["launcherButton", "workspaceSwitcher", "focusedWindow"].includes(w) return ["launcherButton", "workspaceSwitcher", "focusedWindow"].includes(w)
}) })
topBarCenterWidgets = settings.topBarWidgetOrder.filter( topBarCenterWidgets = settings.topBarWidgetOrder.filter(w => {
w => { return ["clock", "music", "weather"].includes(w)
return ["clock", "music", "weather"].includes( })
w) topBarRightWidgets = settings.topBarWidgetOrder.filter(w => {
}) return ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"].includes(w)
topBarRightWidgets = settings.topBarWidgetOrder.filter( })
w => {
return ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"].includes(
w)
})
} else { } else {
var leftWidgets = settings.topBarLeftWidgets var leftWidgets = settings.topBarLeftWidgets !== undefined ? settings.topBarLeftWidgets : ["launcherButton", "workspaceSwitcher", "focusedWindow"]
!== undefined ? settings.topBarLeftWidgets : ["launcherButton", "workspaceSwitcher", "focusedWindow"] var centerWidgets = settings.topBarCenterWidgets !== undefined ? settings.topBarCenterWidgets : ["music", "clock", "weather"]
var centerWidgets = settings.topBarCenterWidgets var rightWidgets = settings.topBarRightWidgets !== undefined ? settings.topBarRightWidgets : ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
!== undefined ? settings.topBarCenterWidgets : ["music", "clock", "weather"]
var rightWidgets = settings.topBarRightWidgets
!== undefined ? settings.topBarRightWidgets : ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
topBarLeftWidgets = leftWidgets topBarLeftWidgets = leftWidgets
topBarCenterWidgets = centerWidgets topBarCenterWidgets = centerWidgets
topBarRightWidgets = rightWidgets topBarRightWidgets = rightWidgets
@@ -278,54 +227,35 @@ Singleton {
updateListModel(centerWidgetsModel, centerWidgets) updateListModel(centerWidgetsModel, centerWidgets)
updateListModel(rightWidgetsModel, rightWidgets) updateListModel(rightWidgetsModel, rightWidgets)
} }
appLauncherViewMode = settings.appLauncherViewMode appLauncherViewMode = settings.appLauncherViewMode !== undefined ? settings.appLauncherViewMode : "list"
!== undefined ? settings.appLauncherViewMode : "list" spotlightModalViewMode = settings.spotlightModalViewMode !== undefined ? settings.spotlightModalViewMode : "list"
spotlightModalViewMode = settings.spotlightModalViewMode networkPreference = settings.networkPreference !== undefined ? settings.networkPreference : "auto"
!== undefined ? settings.spotlightModalViewMode : "list"
networkPreference = settings.networkPreference
!== undefined ? settings.networkPreference : "auto"
iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default" iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default"
useOSLogo = settings.useOSLogo !== undefined ? settings.useOSLogo : false useOSLogo = settings.useOSLogo !== undefined ? settings.useOSLogo : false
osLogoColorOverride = settings.osLogoColorOverride osLogoColorOverride = settings.osLogoColorOverride !== undefined ? settings.osLogoColorOverride : ""
!== undefined ? settings.osLogoColorOverride : "" osLogoBrightness = settings.osLogoBrightness !== undefined ? settings.osLogoBrightness : 0.5
osLogoBrightness = settings.osLogoBrightness
!== undefined ? settings.osLogoBrightness : 0.5
osLogoContrast = settings.osLogoContrast !== undefined ? settings.osLogoContrast : 1 osLogoContrast = settings.osLogoContrast !== undefined ? settings.osLogoContrast : 1
wallpaperDynamicTheming = settings.wallpaperDynamicTheming wallpaperDynamicTheming = settings.wallpaperDynamicTheming !== undefined ? settings.wallpaperDynamicTheming : true
!== undefined ? settings.wallpaperDynamicTheming : true fontFamily = settings.fontFamily !== undefined ? settings.fontFamily : defaultFontFamily
fontFamily = settings.fontFamily monoFontFamily = settings.monoFontFamily !== undefined ? settings.monoFontFamily : defaultMonoFontFamily
!== undefined ? settings.fontFamily : defaultFontFamily
monoFontFamily = settings.monoFontFamily
!== undefined ? settings.monoFontFamily : defaultMonoFontFamily
fontWeight = settings.fontWeight !== undefined ? settings.fontWeight : Font.Normal fontWeight = settings.fontWeight !== undefined ? settings.fontWeight : Font.Normal
gtkThemingEnabled = settings.gtkThemingEnabled gtkThemingEnabled = settings.gtkThemingEnabled !== undefined ? settings.gtkThemingEnabled : false
!== undefined ? settings.gtkThemingEnabled : false qtThemingEnabled = settings.qtThemingEnabled !== undefined ? settings.qtThemingEnabled : false
qtThemingEnabled = settings.qtThemingEnabled
!== undefined ? settings.qtThemingEnabled : false
showDock = settings.showDock !== undefined ? settings.showDock : false showDock = settings.showDock !== undefined ? settings.showDock : false
dockAutoHide = settings.dockAutoHide !== undefined ? settings.dockAutoHide : false dockAutoHide = settings.dockAutoHide !== undefined ? settings.dockAutoHide : false
cornerRadius = settings.cornerRadius !== undefined ? settings.cornerRadius : 12 cornerRadius = settings.cornerRadius !== undefined ? settings.cornerRadius : 12
notificationOverlayEnabled = settings.notificationOverlayEnabled notificationOverlayEnabled = settings.notificationOverlayEnabled !== undefined ? settings.notificationOverlayEnabled : false
!== undefined ? settings.notificationOverlayEnabled : false topBarAutoHide = settings.topBarAutoHide !== undefined ? settings.topBarAutoHide : false
topBarAutoHide = settings.topBarAutoHide topBarVisible = settings.topBarVisible !== undefined ? settings.topBarVisible : true
!== undefined ? settings.topBarAutoHide : false notificationTimeoutLow = settings.notificationTimeoutLow !== undefined ? settings.notificationTimeoutLow : 5000
topBarVisible = settings.topBarVisible notificationTimeoutNormal = settings.notificationTimeoutNormal !== undefined ? settings.notificationTimeoutNormal : 5000
!== undefined ? settings.topBarVisible : true notificationTimeoutCritical = settings.notificationTimeoutCritical !== undefined ? settings.notificationTimeoutCritical : 0
notificationTimeoutLow = settings.notificationTimeoutLow
!== undefined ? settings.notificationTimeoutLow : 5000
notificationTimeoutNormal = settings.notificationTimeoutNormal
!== undefined ? settings.notificationTimeoutNormal : 5000
notificationTimeoutCritical = settings.notificationTimeoutCritical
!== undefined ? settings.notificationTimeoutCritical : 0
topBarSpacing = settings.topBarSpacing !== undefined ? settings.topBarSpacing : 4 topBarSpacing = settings.topBarSpacing !== undefined ? settings.topBarSpacing : 4
topBarBottomGap = settings.topBarBottomGap !== undefined ? settings.topBarBottomGap : 0 topBarBottomGap = settings.topBarBottomGap !== undefined ? settings.topBarBottomGap : 0
topBarInnerPadding = settings.topBarInnerPadding !== undefined ? settings.topBarInnerPadding : 8 topBarInnerPadding = settings.topBarInnerPadding !== undefined ? settings.topBarInnerPadding : 8
topBarSquareCorners = settings.topBarSquareCorners topBarSquareCorners = settings.topBarSquareCorners !== undefined ? settings.topBarSquareCorners : false
!== undefined ? settings.topBarSquareCorners : false topBarNoBackground = settings.topBarNoBackground !== undefined ? settings.topBarNoBackground : false
topBarNoBackground = settings.topBarNoBackground screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({})
!== undefined ? settings.topBarNoBackground : false
screenPreferences = settings.screenPreferences
!== undefined ? settings.screenPreferences : ({})
applyStoredTheme() applyStoredTheme()
detectAvailableIconThemes() detectAvailableIconThemes()
detectQtTools() detectQtTools()
@@ -434,7 +364,7 @@ Singleton {
showWorkspaceApps = enabled showWorkspaceApps = enabled
saveSettings() saveSettings()
} }
function setMaxWorkspaceIcons(maxIcons) { function setMaxWorkspaceIcons(maxIcons) {
maxWorkspaceIcons = maxIcons maxWorkspaceIcons = maxIcons
saveSettings() saveSettings()
@@ -526,7 +456,7 @@ Singleton {
else else
Qt.callLater(() => { Qt.callLater(() => {
if (typeof Theme !== "undefined") if (typeof Theme !== "undefined")
Theme.switchTheme(currentThemeName, false) Theme.switchTheme(currentThemeName, false)
}) })
} }
@@ -706,8 +636,7 @@ Singleton {
var widgetId = typeof order[i] === "string" ? order[i] : order[i].id var widgetId = typeof order[i] === "string" ? order[i] : order[i].id
var enabled = typeof order[i] === "string" ? true : order[i].enabled var enabled = typeof order[i] === "string" ? true : order[i].enabled
var size = typeof order[i] === "string" ? undefined : order[i].size var size = typeof order[i] === "string" ? undefined : order[i].size
var selectedGpuIndex = typeof order[i] var selectedGpuIndex = typeof order[i] === "string" ? undefined : order[i].selectedGpuIndex
=== "string" ? undefined : order[i].selectedGpuIndex
var pciId = typeof order[i] === "string" ? undefined : order[i].pciId var pciId = typeof order[i] === "string" ? undefined : order[i].pciId
var item = { var item = {
"widgetId": widgetId, "widgetId": widgetId,
@@ -834,8 +763,7 @@ Singleton {
+ " print \"icon_theme=\" theme; icon_theme_added = 1 \n" + " } \n" + " in_appearance = 0; print; next \n" + " }\n" + " in_appearance && /^icon_theme=/ { \n" + " if (!icon_theme_added) { \n" + " print \"icon_theme=\" theme; icon_theme_added = 1 \n" + " } \n" + " print \"icon_theme=\" theme; icon_theme_added = 1 \n" + " } \n" + " in_appearance = 0; print; next \n" + " }\n" + " in_appearance && /^icon_theme=/ { \n" + " if (!icon_theme_added) { \n" + " print \"icon_theme=\" theme; icon_theme_added = 1 \n" + " } \n"
+ " next \n" + " }\n" + " { print }\n" + " END { if (in_appearance && !icon_theme_added) print \"icon_theme=\" theme }\n" + " ' \"$config_file\" > \"$config_file.tmp\" && mv \"$config_file.tmp\" \"$config_file\"\n" + " else\n" + " printf '\\n[Appearance]\\nicon_theme=%s\\n' \"$theme_name\" >> \"$config_file\"\n" + " fi\n" + " next \n" + " }\n" + " { print }\n" + " END { if (in_appearance && !icon_theme_added) print \"icon_theme=\" theme }\n" + " ' \"$config_file\" > \"$config_file.tmp\" && mv \"$config_file.tmp\" \"$config_file\"\n" + " else\n" + " printf '\\n[Appearance]\\nicon_theme=%s\\n' \"$theme_name\" >> \"$config_file\"\n" + " fi\n"
+ " else\n" + " printf '[Appearance]\\nicon_theme=%s\\n' \"$theme_name\" > \"$config_file\"\n" + " fi\n" + "}\n" + "update_qt_config " + _configDir + "/qt5ct/qt5ct.conf " + _shq( + " else\n" + " printf '[Appearance]\\nicon_theme=%s\\n' \"$theme_name\" > \"$config_file\"\n" + " fi\n" + "}\n" + "update_qt_config " + _configDir + "/qt5ct/qt5ct.conf " + _shq(
qtThemeName) + "\n" + "update_qt_config " + _configDir + "/qt6ct/qt6ct.conf " + _shq(qtThemeName) + "\n" qtThemeName) + "\n" + "update_qt_config " + _configDir + "/qt6ct/qt6ct.conf " + _shq(qtThemeName) + "\n" + "rm -rf " + home + "/.cache/icon-cache " + home + "/.cache/thumbnails 2>/dev/null || true\n"
+ "rm -rf " + home + "/.cache/icon-cache " + home + "/.cache/thumbnails 2>/dev/null || true\n"
Quickshell.execDetached(["sh", "-lc", script]) Quickshell.execDetached(["sh", "-lc", script])
} }
@@ -1018,17 +946,14 @@ Singleton {
onTriggered: { onTriggered: {
var availableFonts = Qt.fontFamilies() var availableFonts = Qt.fontFamilies()
var missingFonts = [] var missingFonts = []
if (fontFamily === defaultFontFamily && !availableFonts.includes( if (fontFamily === defaultFontFamily && !availableFonts.includes(defaultFontFamily))
defaultFontFamily)) missingFonts.push(defaultFontFamily)
missingFonts.push(defaultFontFamily)
if (monoFontFamily === defaultMonoFontFamily if (monoFontFamily === defaultMonoFontFamily && !availableFonts.includes(defaultMonoFontFamily))
&& !availableFonts.includes(defaultMonoFontFamily)) missingFonts.push(defaultMonoFontFamily)
missingFonts.push(defaultMonoFontFamily)
if (missingFonts.length > 0) { if (missingFonts.length > 0) {
var message = "Missing fonts: " + missingFonts.join( var message = "Missing fonts: " + missingFonts.join(", ") + ". Using system defaults."
", ") + ". Using system defaults."
ToastService.showWarning(message) ToastService.showWarning(message)
} }
} }
@@ -1039,8 +964,7 @@ Singleton {
FileView { FileView {
id: settingsFile id: settingsFile
path: StandardPaths.writableLocation( path: StandardPaths.writableLocation(StandardPaths.ConfigLocation) + "/DankMaterialShell/settings.json"
StandardPaths.ConfigLocation) + "/DankMaterialShell/settings.json"
blockLoading: true blockLoading: true
blockWrites: true blockWrites: true
watchChanges: true watchChanges: true
@@ -1049,13 +973,13 @@ Singleton {
hasTriedDefaultSettings = false hasTriedDefaultSettings = false
} }
onLoadFailed: error => { onLoadFailed: error => {
if (!hasTriedDefaultSettings) { if (!hasTriedDefaultSettings) {
hasTriedDefaultSettings = true hasTriedDefaultSettings = true
defaultSettingsCheckProcess.running = true defaultSettingsCheckProcess.running = true
} else { } else {
applyStoredTheme() applyStoredTheme()
} }
} }
} }
Process { Process {
@@ -1064,12 +988,12 @@ Singleton {
command: ["sh", "-c", "gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | sed \"s/'//g\" || echo ''"] command: ["sh", "-c", "gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | sed \"s/'//g\" || echo ''"]
running: false running: false
onExited: exitCode => { onExited: exitCode => {
if (exitCode === 0 && stdout && stdout.length > 0) if (exitCode === 0 && stdout && stdout.length > 0)
systemDefaultIconTheme = stdout.trim() systemDefaultIconTheme = stdout.trim()
else else
systemDefaultIconTheme = "" systemDefaultIconTheme = ""
iconThemeDetectionProcess.running = true iconThemeDetectionProcess.running = true
} }
} }
Process { Process {
@@ -1085,9 +1009,8 @@ Singleton {
var themes = text.trim().split('\n') var themes = text.trim().split('\n')
for (var i = 0; i < themes.length; i++) { for (var i = 0; i < themes.length; i++) {
var theme = themes[i].trim() var theme = themes[i].trim()
if (theme && theme !== "" && theme !== "default" if (theme && theme !== "" && theme !== "default" && theme !== "hicolor" && theme !== "locolor")
&& theme !== "hicolor" && theme !== "locolor") detectedThemes.push(theme)
detectedThemes.push(theme)
} }
} }
availableIconThemes = detectedThemes availableIconThemes = detectedThemes
@@ -1108,11 +1031,11 @@ Singleton {
for (var i = 0; i < lines.length; i++) { for (var i = 0; i < lines.length; i++) {
var line = lines[i] var line = lines[i]
if (line.startsWith('qt5ct:')) if (line.startsWith('qt5ct:'))
qt5ctAvailable = line.split(':')[1] === 'true' qt5ctAvailable = line.split(':')[1] === 'true'
else if (line.startsWith('qt6ct:')) else if (line.startsWith('qt6ct:'))
qt6ctAvailable = line.split(':')[1] === 'true' qt6ctAvailable = line.split(':')[1] === 'true'
else if (line.startsWith('gtk:')) else if (line.startsWith('gtk:'))
gtkAvailable = line.split(':')[1] === 'true' gtkAvailable = line.split(':')[1] === 'true'
} }
} }
} }
@@ -1122,17 +1045,18 @@ Singleton {
Process { Process {
id: defaultSettingsCheckProcess id: defaultSettingsCheckProcess
command: ["sh", "-c", "CONFIG_DIR=\"" + _configDir + "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-settings.json\" ] && [ ! -f \"$CONFIG_DIR/settings.json\" ]; then cp \"$CONFIG_DIR/default-settings.json\" \"$CONFIG_DIR/settings.json\" && echo 'copied'; else echo 'not_found'; fi"] command: ["sh", "-c", "CONFIG_DIR=\"" + _configDir
+ "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-settings.json\" ] && [ ! -f \"$CONFIG_DIR/settings.json\" ]; then cp \"$CONFIG_DIR/default-settings.json\" \"$CONFIG_DIR/settings.json\" && echo 'copied'; else echo 'not_found'; fi"]
running: false running: false
onExited: exitCode => { onExited: exitCode => {
if (exitCode === 0) { if (exitCode === 0) {
console.log("Copied default-settings.json to settings.json") console.log("Copied default-settings.json to settings.json")
settingsFile.reload() settingsFile.reload()
} else { } else {
// No default settings file found, just apply stored theme // No default settings file found, just apply stored theme
applyStoredTheme() applyStoredTheme()
} }
} }
} }
IpcHandler { IpcHandler {
@@ -1157,5 +1081,4 @@ Singleton {
target: "bar" target: "bar"
} }
} }

View File

@@ -17,10 +17,6 @@ DankPopout {
function show() { function show() {
open() open()
appLauncher.searchQuery = ""
appLauncher.selectedIndex = 0
appLauncher.setCategory("All")
appLauncher.keyboardNavigationActive = false
} }
function setTriggerPosition(x, y, width, section, screen) { function setTriggerPosition(x, y, width, section, screen) {
@@ -40,12 +36,18 @@ DankPopout {
WlrLayershell.namespace: "quickshell-launcher" WlrLayershell.namespace: "quickshell-launcher"
screen: triggerScreen screen: triggerScreen
onOpened: { onShouldBeVisibleChanged: {
Qt.callLater(() => { if (shouldBeVisible) {
if (contentLoader.item && contentLoader.item.searchField) { appLauncher.searchQuery = ""
contentLoader.item.searchField.forceActiveFocus() appLauncher.selectedIndex = 0
} appLauncher.setCategory("All")
}) Qt.callLater(() => {
if (contentLoader.item && contentLoader.item.searchField) {
contentLoader.item.searchField.text = ""
contentLoader.item.searchField.forceActiveFocus()
}
})
}
} }
AppLauncher { AppLauncher {

View File

@@ -120,7 +120,7 @@ Item {
anchors.top: parent.top anchors.top: parent.top
text: { text: {
if (SettingsData.use24HourClock) { if (SettingsData.use24HourClock) {
return systemClock.date.toLocaleTimeString(Qt.locale(), Locale.ShortFormat) return systemClock.date.toLocaleTimeString(Qt.locale(), "HH:mm")
} else { } else {
return systemClock.date.toLocaleTimeString(Qt.locale(), "h:mm AP") return systemClock.date.toLocaleTimeString(Qt.locale(), "h:mm AP")
} }

View File

@@ -9,10 +9,15 @@ DankListView {
property var keyboardController: null property var keyboardController: null
property bool keyboardActive: false property bool keyboardActive: false
property bool autoScrollDisabled: false property bool autoScrollDisabled: false
property alias count: listView.count
property alias listContentHeight: listView.contentHeight
clip: true
model: NotificationService.groupedNotifications
spacing: Theme.spacingL
onIsUserScrollingChanged: { onIsUserScrollingChanged: {
if (isUserScrolling && keyboardController if (isUserScrolling && keyboardController && keyboardController.keyboardNavigationActive) {
&& keyboardController.keyboardNavigationActive) {
autoScrollDisabled = true autoScrollDisabled = true
} }
} }
@@ -21,24 +26,13 @@ DankListView {
autoScrollDisabled = false autoScrollDisabled = false
} }
property alias count: listView.count
property alias listContentHeight: listView.contentHeight
clip: true
model: NotificationService.groupedNotifications
spacing: Theme.spacingL
Timer { Timer {
id: positionPreservationTimer id: positionPreservationTimer
interval: 200 interval: 200
running: keyboardController running: keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled
&& keyboardController.keyboardNavigationActive
&& !autoScrollDisabled
repeat: true repeat: true
onTriggered: { onTriggered: {
if (keyboardController if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) {
&& keyboardController.keyboardNavigationActive
&& !autoScrollDisabled) {
keyboardController.ensureVisible() keyboardController.ensureVisible()
} }
} }
@@ -50,107 +44,94 @@ DankListView {
} }
onModelChanged: { onModelChanged: {
if (keyboardController && keyboardController.keyboardNavigationActive) { if (!keyboardController || !keyboardController.keyboardNavigationActive) {
keyboardController.rebuildFlatNavigation() return
Qt.callLater(function () {
if (keyboardController
&& keyboardController.keyboardNavigationActive
&& !autoScrollDisabled) {
keyboardController.ensureVisible()
}
})
} }
keyboardController.rebuildFlatNavigation()
Qt.callLater(() => {
if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) {
keyboardController.ensureVisible()
}
})
} }
delegate: Item { delegate: Item {
required property var modelData required property var modelData
required property int index required property int index
readonly property bool isExpanded: NotificationService.expandedGroups[modelData?.key] readonly property bool isExpanded: (NotificationService.expandedGroups[modelData && modelData.key] || false)
|| false
width: ListView.view.width width: ListView.view.width
height: notificationCardWrapper.height height: notificationCard.height
Item { NotificationCard {
id: notificationCardWrapper id: notificationCard
width: parent.width width: parent.width
height: notificationCard.height notificationGroup: modelData
keyboardNavigationActive: listView.keyboardActive
NotificationCard { isGroupSelected: {
id: notificationCard if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive) {
width: parent.width return false
notificationGroup: modelData }
keyboardController.selectionVersion
const selection = keyboardController.getCurrentSelection()
return selection.type === "group" && selection.groupIndex === index
}
isGroupSelected: { selectedNotificationIndex: {
if (!keyboardController if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive) {
|| !keyboardController.keyboardNavigationActive) return -1
return false
keyboardController.selectionVersion
if (!listView.keyboardActive)
return false
const selection = keyboardController.getCurrentSelection()
return selection.type === "group"
&& selection.groupIndex === index
} }
selectedNotificationIndex: { keyboardController.selectionVersion
if (!keyboardController const selection = keyboardController.getCurrentSelection()
|| !keyboardController.keyboardNavigationActive) return (selection.type === "notification" && selection.groupIndex === index) ? selection.notificationIndex : -1
return -1
keyboardController.selectionVersion
if (!listView.keyboardActive)
return -1
const selection = keyboardController.getCurrentSelection()
return (selection.type === "notification"
&& selection.groupIndex === index) ? selection.notificationIndex : -1
}
keyboardNavigationActive: listView.keyboardActive
} }
} }
} }
Connections { Connections {
target: NotificationService
function onGroupedNotificationsChanged() { function onGroupedNotificationsChanged() {
if (keyboardController) { if (!keyboardController) {
if (keyboardController.isTogglingGroup) { return
keyboardController.rebuildFlatNavigation() }
return
}
if (keyboardController.isTogglingGroup) {
keyboardController.rebuildFlatNavigation() keyboardController.rebuildFlatNavigation()
return
}
if (keyboardController.keyboardNavigationActive) { keyboardController.rebuildFlatNavigation()
Qt.callLater(function () {
if (!autoScrollDisabled) { if (keyboardController.keyboardNavigationActive) {
keyboardController.ensureVisible() Qt.callLater(() => {
} if (!autoScrollDisabled) {
}) keyboardController.ensureVisible()
} }
})
} }
} }
function onExpandedGroupsChanged() { function onExpandedGroupsChanged() {
if (keyboardController if (keyboardController && keyboardController.keyboardNavigationActive) {
&& keyboardController.keyboardNavigationActive) { Qt.callLater(() => {
Qt.callLater(function () { if (!autoScrollDisabled) {
if (!autoScrollDisabled) { keyboardController.ensureVisible()
keyboardController.ensureVisible() }
} })
})
} }
} }
function onExpandedMessagesChanged() { function onExpandedMessagesChanged() {
if (keyboardController if (keyboardController && keyboardController.keyboardNavigationActive) {
&& keyboardController.keyboardNavigationActive) { Qt.callLater(() => {
Qt.callLater(function () { if (!autoScrollDisabled) {
if (!autoScrollDisabled) { keyboardController.ensureVisible()
keyboardController.ensureVisible() }
} })
})
} }
} }
target: NotificationService
} }
} }

View File

@@ -11,13 +11,11 @@ Rectangle {
id: root id: root
property var notificationGroup property var notificationGroup
property bool expanded: NotificationService.expandedGroups[notificationGroup?.key] property bool expanded: (NotificationService.expandedGroups[notificationGroup && notificationGroup.key] || false)
|| false property bool descriptionExpanded: (NotificationService.expandedMessages[(notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.notification
property bool descriptionExpanded: NotificationService.expandedMessages[notificationGroup?.latestNotification?.notification?.id + "_desc"] && notificationGroup.latestNotification.notification.id) ? (notificationGroup.latestNotification.notification.id + "_desc") : ""] || false)
|| false
property bool userInitiatedExpansion: false property bool userInitiatedExpansion: false
// Selection properties for keyboard navigation
property bool isGroupSelected: false property bool isGroupSelected: false
property int selectedNotificationIndex: -1 property int selectedNotificationIndex: -1
property bool keyboardNavigationActive: false property bool keyboardNavigationActive: false
@@ -29,8 +27,7 @@ Rectangle {
} }
const baseHeight = 116 const baseHeight = 116
if (descriptionExpanded) { if (descriptionExpanded) {
return baseHeight + descriptionText.contentHeight return baseHeight + descriptionText.contentHeight - (descriptionText.font.pixelSize * 1.2 * 2)
- (descriptionText.font.pixelSize * 1.2 * 2)
} }
return baseHeight return baseHeight
} }
@@ -51,50 +48,33 @@ Rectangle {
} }
color: { color: {
// Keyboard selection highlighting for groups (both collapsed and expanded)
if (isGroupSelected && keyboardNavigationActive) { if (isGroupSelected && keyboardNavigationActive) {
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2)
Theme.surfaceVariant.b, 0.2)
} }
// Very subtle group highlighting when navigating within expanded group if (keyboardNavigationActive && expanded && selectedNotificationIndex >= 0) {
if (keyboardNavigationActive && expanded return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12)
&& selectedNotificationIndex >= 0) {
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.12)
} }
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.1)
Theme.surfaceVariant.b, 0.1)
} }
border.color: { border.color: {
// Keyboard selection highlighting for groups (both collapsed and expanded)
if (isGroupSelected && keyboardNavigationActive) { if (isGroupSelected && keyboardNavigationActive) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.5)
Theme.primary.b, 0.5)
} }
// Subtle group border when navigating within expanded group if (keyboardNavigationActive && expanded && selectedNotificationIndex >= 0) {
if (keyboardNavigationActive && expanded return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2)
&& selectedNotificationIndex >= 0) {
return Qt.rgba(Theme.primary.r, Theme.primary.g,
Theme.primary.b, 0.2)
} }
// Critical notification styling
if (notificationGroup?.latestNotification?.urgency === NotificationUrgency.Critical) { if (notificationGroup?.latestNotification?.urgency === NotificationUrgency.Critical) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3)
Theme.primary.b, 0.3)
} }
return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05) return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
} }
border.width: { border.width: {
// Keyboard selection highlighting for groups (both collapsed and expanded)
if (isGroupSelected && keyboardNavigationActive) { if (isGroupSelected && keyboardNavigationActive) {
return 1.5 return 1.5
} }
// Subtle group border when navigating within expanded group if (keyboardNavigationActive && expanded && selectedNotificationIndex >= 0) {
if (keyboardNavigationActive && expanded
&& selectedNotificationIndex >= 0) {
return 1 return 1
} }
// Critical notification styling
if (notificationGroup?.latestNotification?.urgency === NotificationUrgency.Critical) { if (notificationGroup?.latestNotification?.urgency === NotificationUrgency.Critical) {
return 2 return 2
} }
@@ -142,8 +122,7 @@ Rectangle {
width: 55 width: 55
height: 55 height: 55
radius: 27.5 radius: 27.5
color: Qt.rgba(Theme.primary.r, Theme.primary.g, color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
Theme.primary.b, 0.1)
border.color: "transparent" border.color: "transparent"
border.width: 0 border.width: 0
anchors.left: parent.left anchors.left: parent.left
@@ -158,9 +137,7 @@ Rectangle {
return notificationGroup.latestNotification.cleanImage return notificationGroup.latestNotification.cleanImage
if (notificationGroup?.latestNotification?.appIcon) { if (notificationGroup?.latestNotification?.appIcon) {
const appIcon = notificationGroup.latestNotification.appIcon const appIcon = notificationGroup.latestNotification.appIcon
if (appIcon.startsWith("file://") || appIcon.startsWith( if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://"))
"http://") || appIcon.startsWith(
"https://"))
return appIcon return appIcon
return Quickshell.iconPath(appIcon, true) return Quickshell.iconPath(appIcon, true)
} }
@@ -171,9 +148,7 @@ Rectangle {
StyledText { StyledText {
anchors.centerIn: parent anchors.centerIn: parent
visible: !parent.hasNotificationImage visible: !parent.hasNotificationImage && (!notificationGroup?.latestNotification?.appIcon || notificationGroup.latestNotification.appIcon === "")
&& (!notificationGroup?.latestNotification?.appIcon
|| notificationGroup.latestNotification.appIcon === "")
text: { text: {
const appName = notificationGroup?.appName || "?" const appName = notificationGroup?.appName || "?"
return appName.charAt(0).toUpperCase() return appName.charAt(0).toUpperCase()
@@ -196,9 +171,7 @@ Rectangle {
StyledText { StyledText {
anchors.centerIn: parent anchors.centerIn: parent
text: (notificationGroup?.count text: (notificationGroup?.count || 0) > 99 ? "99+" : (notificationGroup?.count || 0).toString()
|| 0) > 99 ? "99+" : (notificationGroup?.count
|| 0).toString()
color: Theme.primaryText color: Theme.primaryText
font.pixelSize: 9 font.pixelSize: 9
font.weight: Font.Bold font.weight: Font.Bold
@@ -231,13 +204,9 @@ Rectangle {
StyledText { StyledText {
width: parent.width width: parent.width
text: { text: {
const timeStr = notificationGroup?.latestNotification?.timeStr const timeStr = (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.timeStr) || ""
|| "" const appName = (notificationGroup && notificationGroup.appName) || ""
if (timeStr.length > 0) return timeStr.length > 0 ? `${appName} ${timeStr}` : appName
return (notificationGroup?.appName
|| "") + " • " + timeStr
else
return notificationGroup?.appName || ""
} }
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
@@ -247,8 +216,7 @@ Rectangle {
} }
StyledText { StyledText {
text: notificationGroup?.latestNotification?.summary text: (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.summary) || ""
|| ""
color: Theme.surfaceText color: Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium font.weight: Font.Medium
@@ -260,8 +228,7 @@ Rectangle {
StyledText { StyledText {
id: descriptionText id: descriptionText
property string fullText: notificationGroup?.latestNotification?.htmlBody property string fullText: (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.htmlBody) || ""
|| ""
property bool hasMoreText: truncated property bool hasMoreText: truncated
text: fullText text: fullText
@@ -280,12 +247,10 @@ Rectangle {
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (parent.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (parent.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: mouse => { onClicked: mouse => {
if (!parent.hoveredLink if (!parent.hoveredLink && (parent.hasMoreText || descriptionExpanded)) {
&& (parent.hasMoreText const messageId = (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.notification
|| descriptionExpanded)) { && notificationGroup.latestNotification.notification.id) ? (notificationGroup.latestNotification.notification.id + "_desc") : ""
const messageId = notificationGroup?.latestNotification?.notification?.id + "_desc" NotificationService.toggleMessageExpansion(messageId)
NotificationService.toggleMessageExpansion(
messageId)
} }
} }
@@ -350,9 +315,7 @@ Rectangle {
StyledText { StyledText {
anchors.centerIn: parent anchors.centerIn: parent
text: (notificationGroup?.count text: (notificationGroup?.count || 0) > 99 ? "99+" : (notificationGroup?.count || 0).toString()
|| 0) > 99 ? "99+" : (notificationGroup?.count
|| 0).toString()
color: Theme.primaryText color: Theme.primaryText
font.pixelSize: 9 font.pixelSize: 9
font.weight: Font.Bold font.weight: Font.Bold
@@ -371,8 +334,7 @@ Rectangle {
delegate: Rectangle { delegate: Rectangle {
required property var modelData required property var modelData
required property int index required property int index
readonly property bool messageExpanded: NotificationService.expandedMessages[modelData?.notification?.id] readonly property bool messageExpanded: NotificationService.expandedMessages[modelData?.notification?.id] || false
|| false
readonly property bool isSelected: root.selectedNotificationIndex === index readonly property bool isSelected: root.selectedNotificationIndex === index
width: parent.width width: parent.width
@@ -388,17 +350,8 @@ Rectangle {
return baseHeight return baseHeight
} }
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: isSelected ? Qt.rgba(Theme.surfaceVariant.r, color: isSelected ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.25) : "transparent"
Theme.surfaceVariant.g, 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)
Theme.surfaceVariant.b,
0.25) : "transparent"
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: isSelected ? 1 : 1 border.width: isSelected ? 1 : 1
Behavior on color { Behavior on color {
@@ -427,8 +380,7 @@ Rectangle {
Rectangle { Rectangle {
id: messageIcon id: messageIcon
readonly property bool hasNotificationImage: modelData?.image readonly property bool hasNotificationImage: modelData?.image && modelData.image !== ""
&& modelData.image !== ""
width: 32 width: 32
height: 32 height: 32
@@ -436,11 +388,8 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 32 anchors.topMargin: 32
color: Qt.rgba(Theme.primary.r, Theme.primary.g, color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
Theme.primary.b, 0.1) border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2)
border.color: Qt.rgba(Theme.primary.r,
Theme.primary.g,
Theme.primary.b, 0.2)
border.width: 1 border.width: 1
IconImage { IconImage {
@@ -452,10 +401,7 @@ Rectangle {
if (modelData?.appIcon) { if (modelData?.appIcon) {
const appIcon = modelData.appIcon const appIcon = modelData.appIcon
if (appIcon.startsWith("file://") if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://"))
|| appIcon.startsWith("http://")
|| appIcon.startsWith(
"https://"))
return appIcon return appIcon
return Quickshell.iconPath(appIcon, true) return Quickshell.iconPath(appIcon, true)
@@ -467,9 +413,7 @@ Rectangle {
StyledText { StyledText {
anchors.centerIn: parent anchors.centerIn: parent
visible: !parent.hasNotificationImage visible: !parent.hasNotificationImage && (!modelData?.appIcon || modelData.appIcon === "")
&& (!modelData?.appIcon
|| modelData.appIcon === "")
text: { text: {
const appName = modelData?.appName || "?" const appName = modelData?.appName || "?"
return appName.charAt(0).toUpperCase() return appName.charAt(0).toUpperCase()
@@ -531,19 +475,14 @@ Rectangle {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
visible: text.length > 0 visible: text.length > 0
linkColor: Theme.primary linkColor: Theme.primary
onLinkActivated: link => Qt.openUrlExternally( onLinkActivated: link => Qt.openUrlExternally(link)
link)
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (bodyText.hasMoreText || messageExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (bodyText.hasMoreText || messageExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: mouse => { onClicked: mouse => {
if (!parent.hoveredLink if (!parent.hoveredLink && (bodyText.hasMoreText || messageExpanded)) {
&& (bodyText.hasMoreText NotificationService.toggleMessageExpansion(modelData?.notification?.id || "")
|| messageExpanded)) {
NotificationService.toggleMessageExpansion(
modelData?.notification?.id
|| "")
} }
} }
@@ -580,26 +519,16 @@ Rectangle {
Rectangle { Rectangle {
property bool isHovered: false property bool isHovered: false
width: Math.max( width: Math.max(actionText.implicitWidth + 12, 50)
actionText.implicitWidth + 12,
50)
height: 24 height: 24
radius: 4 radius: 4
color: isHovered ? Qt.rgba( color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.1) : "transparent"
StyledText { StyledText {
id: actionText id: actionText
text: { text: {
const baseText = modelData.text const baseText = modelData.text || "View"
|| "View" if (keyboardNavigationActive && (isGroupSelected || selectedNotificationIndex >= 0)) {
if (keyboardNavigationActive
&& (isGroupSelected
|| selectedNotificationIndex
>= 0)) {
return `${baseText} (${index + 1})` return `${baseText} (${index + 1})`
} }
return baseText return baseText
@@ -618,8 +547,7 @@ Rectangle {
onEntered: parent.isHovered = true onEntered: parent.isHovered = true
onExited: parent.isHovered = false onExited: parent.isHovered = false
onClicked: { onClicked: {
if (modelData if (modelData && modelData.invoke) {
&& modelData.invoke) {
modelData.invoke() modelData.invoke()
} }
} }
@@ -630,16 +558,10 @@ Rectangle {
Rectangle { Rectangle {
property bool isHovered: false property bool isHovered: false
width: Math.max( width: Math.max(clearText.implicitWidth + 12, 50)
clearText.implicitWidth + 12,
50)
height: 24 height: 24
radius: 4 radius: 4
color: isHovered ? Qt.rgba( color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.1) : "transparent"
StyledText { StyledText {
id: clearText id: clearText
@@ -656,8 +578,7 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onEntered: parent.isHovered = true onEntered: parent.isHovered = true
onExited: parent.isHovered = false onExited: parent.isHovered = false
onClicked: NotificationService.dismissNotification( onClicked: NotificationService.dismissNotification(modelData)
modelData)
} }
} }
} }
@@ -686,8 +607,7 @@ Rectangle {
width: Math.max(actionText.implicitWidth + 12, 50) width: Math.max(actionText.implicitWidth + 12, 50)
height: 24 height: 24
radius: 4 radius: 4
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
Theme.primary.b, 0.1) : "transparent"
StyledText { StyledText {
id: actionText id: actionText
@@ -734,8 +654,7 @@ Rectangle {
width: clearText.width + 16 width: clearText.width + 16
height: clearText.height + 8 height: clearText.height + 8
radius: 6 radius: 6
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
Theme.primary.b, 0.1) : "transparent"
StyledText { StyledText {
id: clearText id: clearText
@@ -752,19 +671,16 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onEntered: clearButton.isHovered = true onEntered: clearButton.isHovered = true
onExited: clearButton.isHovered = false onExited: clearButton.isHovered = false
onClicked: NotificationService.dismissGroup( onClicked: NotificationService.dismissGroup(notificationGroup?.key || "")
notificationGroup?.key || "")
} }
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
visible: !expanded && (notificationGroup?.count || 0) > 1 visible: !expanded && (notificationGroup?.count || 0) > 1 && !descriptionExpanded
&& !descriptionExpanded
onClicked: { onClicked: {
root.userInitiatedExpansion = true root.userInitiatedExpansion = true
NotificationService.toggleGroupExpansion( NotificationService.toggleGroupExpansion(notificationGroup?.key || "")
notificationGroup?.key || "")
} }
z: -1 z: -1
} }
@@ -787,8 +703,7 @@ Rectangle {
buttonSize: 28 buttonSize: 28
onClicked: { onClicked: {
root.userInitiatedExpansion = true root.userInitiatedExpansion = true
NotificationService.toggleGroupExpansion( NotificationService.toggleGroupExpansion(notificationGroup?.key || "")
notificationGroup?.key || "")
} }
} }
@@ -798,8 +713,7 @@ Rectangle {
iconName: "close" iconName: "close"
iconSize: 18 iconSize: 18
buttonSize: 28 buttonSize: 28
onClicked: NotificationService.dismissGroup( onClicked: NotificationService.dismissGroup(notificationGroup?.key || "")
notificationGroup?.key || "")
} }
} }

View File

@@ -20,9 +20,9 @@ DankPopout {
id: keyboardController id: keyboardController
listView: null listView: null
isOpen: notificationHistoryVisible isOpen: notificationHistoryVisible
onClose: function () { onClose: () => {
notificationHistoryVisible = false notificationHistoryVisible = false
} }
} }
function setTriggerPosition(x, y, width, section, screen) { function setTriggerPosition(x, y, width, section, screen) {
@@ -55,32 +55,27 @@ DankPopout {
onShouldBeVisibleChanged: { onShouldBeVisibleChanged: {
if (shouldBeVisible) { if (shouldBeVisible) {
NotificationService.onOverlayOpen() NotificationService.onOverlayOpen()
// Set up keyboard controller when content is loaded Qt.callLater(() => {
Qt.callLater(function () { if (contentLoader.item) {
if (contentLoader.item) { contentLoader.item.externalKeyboardController = keyboardController
contentLoader.item.externalKeyboardController = keyboardController
// Find the notification list and set up the connection const notificationList = findChild(contentLoader.item, "notificationList")
var notificationList = findChild(contentLoader.item, const notificationHeader = findChild(contentLoader.item, "notificationHeader")
"notificationList")
var notificationHeader = findChild(contentLoader.item,
"notificationHeader")
if (notificationList) { if (notificationList) {
keyboardController.listView = notificationList keyboardController.listView = notificationList
notificationList.keyboardController = keyboardController notificationList.keyboardController = keyboardController
} }
if (notificationHeader) { if (notificationHeader) {
notificationHeader.keyboardController = keyboardController notificationHeader.keyboardController = keyboardController
} }
keyboardController.reset() keyboardController.reset()
keyboardController.rebuildFlatNavigation() keyboardController.rebuildFlatNavigation()
} }
}) })
} else { } else {
NotificationService.onOverlayClose() NotificationService.onOverlayClose()
// Reset keyboard state when closing
keyboardController.keyboardNavigationActive = false keyboardController.keyboardNavigationActive = false
} }
} }
@@ -89,9 +84,9 @@ DankPopout {
if (parent.objectName === objectName) { if (parent.objectName === objectName) {
return parent return parent
} }
for (var i = 0; i < parent.children.length; i++) { for (let i = 0; i < parent.children.length; i++) {
var child = parent.children[i] const child = parent.children[i]
var result = findChild(child, objectName) const result = findChild(child, objectName)
if (result) { if (result) {
return result return result
} }
@@ -112,44 +107,44 @@ DankPopout {
baseHeight += (notificationSettings.expanded ? notificationSettings.contentHeight : 0) baseHeight += (notificationSettings.expanded ? notificationSettings.contentHeight : 0)
baseHeight += Theme.spacingM * 2 baseHeight += Theme.spacingM * 2
let listHeight = notificationList.listContentHeight let listHeight = notificationList.listContentHeight
if (NotificationService.groupedNotifications.length === 0) if (NotificationService.groupedNotifications.length === 0) {
listHeight = 200 listHeight = 200
}
baseHeight += Math.min(listHeight, 600) baseHeight += Math.min(listHeight, 600)
return Math.max( const maxHeight = root.screen ? root.screen.height * 0.8 : Screen.height * 0.8
300, Math.min( return Math.max(300, Math.min(baseHeight, maxHeight))
baseHeight,
root.screen ? root.screen.height * 0.8 : Screen.height * 0.8))
} }
color: Theme.popupBackground() color: Theme.popupBackground()
radius: Theme.cornerRadius radius: Theme.cornerRadius
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
Theme.outline.b, 0.08)
border.width: 1 border.width: 1
focus: true focus: true
Component.onCompleted: { Component.onCompleted: {
if (root.shouldBeVisible) if (root.shouldBeVisible) {
forceActiveFocus() forceActiveFocus()
}
Keys.onPressed: function (event) {
if (event.key === Qt.Key_Escape) {
root.close()
event.accepted = true
} else if (externalKeyboardController) {
externalKeyboardController.handleKey(event)
} }
} }
Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
root.close()
event.accepted = true
} else if (externalKeyboardController) {
externalKeyboardController.handleKey(event)
}
}
Connections { Connections {
function onShouldBeVisibleChanged() { function onShouldBeVisibleChanged() {
if (root.shouldBeVisible) if (root.shouldBeVisible) {
Qt.callLater(function () { Qt.callLater(() => {
notificationContent.forceActiveFocus() notificationContent.forceActiveFocus()
}) })
else } else {
notificationContent.focus = false notificationContent.focus = false
}
} }
target: root target: root
} }
@@ -182,8 +177,7 @@ DankPopout {
objectName: "notificationList" objectName: "notificationList"
width: parent.width width: parent.width
height: parent.height - notificationContent.cachedHeaderHeight height: parent.height - notificationContent.cachedHeaderHeight - notificationSettings.height - contentColumnInner.spacing * 2
- notificationSettings.height - contentColumnInner.spacing * 2
} }
} }
} }
@@ -194,7 +188,7 @@ DankPopout {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.margins: Theme.spacingL anchors.margins: Theme.spacingL
showHints: externalKeyboardController ? externalKeyboardController.showKeyboardHints : false showHints: (externalKeyboardController && externalKeyboardController.showKeyboardHints) || false
z: 200 z: 200
} }

View File

@@ -19,16 +19,14 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
name: "notifications_none" name: "notifications_none"
size: Theme.iconSizeLarge + 16 size: Theme.iconSizeLarge + 16
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
Theme.surfaceText.b, 0.3)
} }
StyledText { StyledText {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
text: "Nothing to see here" text: "Nothing to see here"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
Theme.surfaceText.b, 0.3)
font.weight: Font.Medium font.weight: Font.Medium
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }

View File

@@ -47,7 +47,7 @@ Item {
anchors.bottom: parent.top anchors.bottom: parent.top
anchors.bottomMargin: Theme.spacingS anchors.bottomMargin: Theme.spacingS
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: doNotDisturbButton.children[1].containsMouse // Access StateLayer's containsMouse visible: doNotDisturbButton.children[1].containsMouse
opacity: visible ? 1 : 0 opacity: visible ? 1 : 0
StyledText { StyledText {
@@ -76,12 +76,10 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS spacing: Theme.spacingXS
// Keyboard help button
DankActionButton { DankActionButton {
id: helpButton id: helpButton
iconName: "info" iconName: "info"
iconColor: keyboardController iconColor: (keyboardController && keyboardController.showKeyboardHints) ? Theme.primary : Theme.surfaceText
&& keyboardController.showKeyboardHints ? Theme.primary : Theme.surfaceText
buttonSize: 28 buttonSize: 28
visible: keyboardController !== null visible: keyboardController !== null
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@@ -92,7 +90,6 @@ Item {
} }
} }
// Settings button
DankActionButton { DankActionButton {
id: settingsButton id: settingsButton
iconName: "settings" iconName: "settings"
@@ -109,17 +106,8 @@ Item {
height: 28 height: 28
radius: Theme.cornerRadius radius: Theme.cornerRadius
visible: NotificationService.notifications.length > 0 visible: NotificationService.notifications.length > 0
color: clearArea.containsMouse ? Qt.rgba(Theme.primary.r, color: clearArea.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.3)
Theme.primary.g, border.color: clearArea.containsMouse ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
Theme.primary.b,
0.12) : Qt.rgba(
Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: clearArea.containsMouse ? Theme.primary : Qt.rgba(
Theme.outline.r,
Theme.outline.g,
Theme.outline.b, 0.08)
border.width: 1 border.width: 1
Row { Row {

View File

@@ -25,15 +25,13 @@ QtObject {
function rebuildFlatNavigation() { function rebuildFlatNavigation() {
isRebuilding = true isRebuilding = true
var nav = [] const nav = []
var groups = NotificationService.groupedNotifications const groups = NotificationService.groupedNotifications
for (var i = 0; i < groups.length; i++) { for (let i = 0; i < groups.length; i++) {
var group = groups[i] const group = groups[i]
var isExpanded = NotificationService.expandedGroups[group.key] const isExpanded = NotificationService.expandedGroups[group.key] || false
|| false
// Add the group itself
nav.push({ nav.push({
"type": "group", "type": "group",
"groupIndex": i, "groupIndex": i,
@@ -42,12 +40,10 @@ QtObject {
"notificationId": "" "notificationId": ""
}) })
// If expanded, add individual notifications
if (isExpanded) { if (isExpanded) {
var notifications = group.notifications || [] const notifications = group.notifications || []
for (var j = 0; j < notifications.length; j++) { for (let j = 0; j < notifications.length; j++) {
var notifId = String( const notifId = String(notifications[j] && notifications[j].notification && notifications[j].notification.id ? notifications[j].notification.id : "")
notifications[j]?.notification?.id || "")
nav.push({ nav.push({
"type": "notification", "type": "notification",
"groupIndex": i, "groupIndex": i,
@@ -65,22 +61,18 @@ QtObject {
} }
function updateSelectedIndexFromId() { function updateSelectedIndexFromId() {
if (!keyboardNavigationActive) if (!keyboardNavigationActive) {
return return
}
// Find the index that matches our selected ID/key for (let i = 0; i < flatNavigation.length; i++) {
for (var i = 0; i < flatNavigation.length; i++) { const item = flatNavigation[i]
var item = flatNavigation[i]
if (selectedItemType === "group" && item.type === "group" if (selectedItemType === "group" && item.type === "group" && item.groupKey === selectedGroupKey) {
&& item.groupKey === selectedGroupKey) {
selectedFlatIndex = i selectedFlatIndex = i
selectionVersion++ // Trigger UI update selectionVersion++ // Trigger UI update
return return
} else if (selectedItemType === "notification" } else if (selectedItemType === "notification" && item.type === "notification" && String(item.notificationId) === String(selectedNotificationId)) {
&& item.type === "notification" && String(
item.notificationId) === String(
selectedNotificationId)) {
selectedFlatIndex = i selectedFlatIndex = i
selectionVersion++ // Trigger UI update selectionVersion++ // Trigger UI update
return return
@@ -89,10 +81,9 @@ QtObject {
// If not found, try to find the same group but select the group header instead // If not found, try to find the same group but select the group header instead
if (selectedItemType === "notification") { if (selectedItemType === "notification") {
for (var j = 0; j < flatNavigation.length; j++) { for (let j = 0; j < flatNavigation.length; j++) {
var groupItem = flatNavigation[j] const groupItem = flatNavigation[j]
if (groupItem.type === "group" if (groupItem.type === "group" && groupItem.groupKey === selectedGroupKey) {
&& groupItem.groupKey === selectedGroupKey) {
selectedFlatIndex = j selectedFlatIndex = j
selectedItemType = "group" selectedItemType = "group"
selectedNotificationId = "" selectedNotificationId = ""
@@ -104,8 +95,7 @@ QtObject {
// If still not found, clamp to valid range and update // If still not found, clamp to valid range and update
if (flatNavigation.length > 0) { if (flatNavigation.length > 0) {
selectedFlatIndex = Math.min(selectedFlatIndex, selectedFlatIndex = Math.min(selectedFlatIndex, flatNavigation.length - 1)
flatNavigation.length - 1)
selectedFlatIndex = Math.max(selectedFlatIndex, 0) selectedFlatIndex = Math.max(selectedFlatIndex, 0)
updateSelectedIdFromIndex() updateSelectedIdFromIndex()
selectionVersion++ // Trigger UI update selectionVersion++ // Trigger UI update
@@ -113,9 +103,8 @@ QtObject {
} }
function updateSelectedIdFromIndex() { function updateSelectedIdFromIndex() {
if (selectedFlatIndex >= 0 if (selectedFlatIndex >= 0 && selectedFlatIndex < flatNavigation.length) {
&& selectedFlatIndex < flatNavigation.length) { const item = flatNavigation[selectedFlatIndex]
var item = flatNavigation[selectedFlatIndex]
selectedItemType = item.type selectedItemType = item.type
selectedGroupKey = item.groupKey selectedGroupKey = item.groupKey
selectedNotificationId = item.notificationId selectedNotificationId = item.notificationId
@@ -143,8 +132,7 @@ QtObject {
listView.enableAutoScroll() listView.enableAutoScroll()
} }
selectedFlatIndex = Math.min(selectedFlatIndex + 1, selectedFlatIndex = Math.min(selectedFlatIndex + 1, flatNavigation.length - 1)
flatNavigation.length - 1)
updateSelectedIdFromIndex() updateSelectedIdFromIndex()
selectionVersion++ selectionVersion++
ensureVisible() ensureVisible()
@@ -167,8 +155,7 @@ QtObject {
} }
function toggleGroupExpanded() { function toggleGroupExpanded() {
if (flatNavigation.length === 0 if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length)
|| selectedFlatIndex >= flatNavigation.length)
return return
const currentItem = flatNavigation[selectedFlatIndex] const currentItem = flatNavigation[selectedFlatIndex]
@@ -182,8 +169,7 @@ QtObject {
if (notificationCount < 2) if (notificationCount < 2)
return return
const wasExpanded = NotificationService.expandedGroups[group.key] const wasExpanded = NotificationService.expandedGroups[group.key] || false
|| false
const groupIndex = currentItem.groupIndex const groupIndex = currentItem.groupIndex
isTogglingGroup = true isTogglingGroup = true
@@ -193,18 +179,16 @@ QtObject {
// Smart selection after toggle // Smart selection after toggle
if (!wasExpanded) { if (!wasExpanded) {
// Just expanded - move to first notification in the group // Just expanded - move to first notification in the group
for (var i = 0; i < flatNavigation.length; i++) { for (let i = 0; i < flatNavigation.length; i++) {
if (flatNavigation[i].type === "notification" if (flatNavigation[i].type === "notification" && flatNavigation[i].groupIndex === groupIndex) {
&& flatNavigation[i].groupIndex === groupIndex) {
selectedFlatIndex = i selectedFlatIndex = i
break break
} }
} }
} else { } else {
// Just collapsed - stay on the group header // Just collapsed - stay on the group header
for (var i = 0; i < flatNavigation.length; i++) { for (let i = 0; i < flatNavigation.length; i++) {
if (flatNavigation[i].type === "group" if (flatNavigation[i].type === "group" && flatNavigation[i].groupIndex === groupIndex) {
&& flatNavigation[i].groupIndex === groupIndex) {
selectedFlatIndex = i selectedFlatIndex = i
break break
} }
@@ -216,8 +200,7 @@ QtObject {
} }
function handleEnterKey() { function handleEnterKey() {
if (flatNavigation.length === 0 if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length)
|| selectedFlatIndex >= flatNavigation.length)
return return
const currentItem = flatNavigation[selectedFlatIndex] const currentItem = flatNavigation[selectedFlatIndex]
@@ -239,8 +222,7 @@ QtObject {
} }
function toggleTextExpanded() { function toggleTextExpanded() {
if (flatNavigation.length === 0 if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length)
|| selectedFlatIndex >= flatNavigation.length)
return return
const currentItem = flatNavigation[selectedFlatIndex] const currentItem = flatNavigation[selectedFlatIndex]
@@ -249,15 +231,12 @@ QtObject {
if (!group) if (!group)
return return
var messageId = "" let messageId = ""
if (currentItem.type === "group") { if (currentItem.type === "group") {
messageId = group.latestNotification?.notification?.id + "_desc" messageId = group.latestNotification?.notification?.id + "_desc"
} else if (currentItem.type === "notification" } else if (currentItem.type === "notification" && currentItem.notificationIndex >= 0 && currentItem.notificationIndex < group.notifications.length) {
&& currentItem.notificationIndex >= 0 messageId = group.notifications[currentItem.notificationIndex]?.notification?.id + "_desc"
&& currentItem.notificationIndex < group.notifications.length) {
messageId = group.notifications[currentItem.notificationIndex]?.notification?.id
+ "_desc"
} }
if (messageId) { if (messageId) {
@@ -266,8 +245,7 @@ QtObject {
} }
function executeAction(actionIndex) { function executeAction(actionIndex) {
if (flatNavigation.length === 0 if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length)
|| selectedFlatIndex >= flatNavigation.length)
return return
const currentItem = flatNavigation[selectedFlatIndex] const currentItem = flatNavigation[selectedFlatIndex]
@@ -276,15 +254,12 @@ QtObject {
if (!group) if (!group)
return return
var actions = [] let actions = []
if (currentItem.type === "group") { if (currentItem.type === "group") {
actions = group.latestNotification?.actions || [] actions = group.latestNotification?.actions || []
} else if (currentItem.type === "notification" } else if (currentItem.type === "notification" && currentItem.notificationIndex >= 0 && currentItem.notificationIndex < group.notifications.length) {
&& currentItem.notificationIndex >= 0 actions = group.notifications[currentItem.notificationIndex]?.actions || []
&& currentItem.notificationIndex < group.notifications.length) {
actions = group.notifications[currentItem.notificationIndex]?.actions
|| []
} }
if (actionIndex >= 0 && actionIndex < actions.length) { if (actionIndex >= 0 && actionIndex < actions.length) {
@@ -298,8 +273,7 @@ QtObject {
} }
function clearSelected() { function clearSelected() {
if (flatNavigation.length === 0 if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length)
|| selectedFlatIndex >= flatNavigation.length)
return return
const currentItem = flatNavigation[selectedFlatIndex] const currentItem = flatNavigation[selectedFlatIndex]
@@ -330,24 +304,20 @@ QtObject {
} }
function ensureVisible() { function ensureVisible() {
if (flatNavigation.length === 0 if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length || !listView)
|| selectedFlatIndex >= flatNavigation.length || !listView)
return return
const currentItem = flatNavigation[selectedFlatIndex] const currentItem = flatNavigation[selectedFlatIndex]
if (keyboardNavigationActive && currentItem if (keyboardNavigationActive && currentItem && currentItem.groupIndex >= 0) {
&& currentItem.groupIndex >= 0) {
// Always center the selected item for better visibility // Always center the selected item for better visibility
// This ensures the selected item stays in view even when new notifications arrive // This ensures the selected item stays in view even when new notifications arrive
if (currentItem.type === "notification") { if (currentItem.type === "notification") {
// For individual notifications, center on the group but bias towards the notification // For individual notifications, center on the group but bias towards the notification
listView.positionViewAtIndex(currentItem.groupIndex, listView.positionViewAtIndex(currentItem.groupIndex, ListView.Center)
ListView.Center)
} else { } else {
// For group headers, center on the group // For group headers, center on the group
listView.positionViewAtIndex(currentItem.groupIndex, listView.positionViewAtIndex(currentItem.groupIndex, ListView.Center)
ListView.Center)
} }
// Force immediate update // Force immediate update
@@ -356,8 +326,7 @@ QtObject {
} }
function handleKey(event) { function handleKey(event) {
if ((event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) if ((event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) && (event.modifiers & Qt.ShiftModifier)) {
&& (event.modifiers & Qt.ShiftModifier)) {
NotificationService.clearAllNotifications() NotificationService.clearAllNotifications()
rebuildFlatNavigation() rebuildFlatNavigation()
if (flatNavigation.length === 0) { if (flatNavigation.length === 0) {
@@ -430,15 +399,13 @@ QtObject {
if (event.key === Qt.Key_Space) { if (event.key === Qt.Key_Space) {
toggleGroupExpanded() toggleGroupExpanded()
event.accepted = true event.accepted = true
} else if (event.key === Qt.Key_Return } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|| event.key === Qt.Key_Enter) {
handleEnterKey() handleEnterKey()
event.accepted = true event.accepted = true
} else if (event.key === Qt.Key_E) { } else if (event.key === Qt.Key_E) {
toggleTextExpanded() toggleTextExpanded()
event.accepted = true event.accepted = true
} else if (event.key === Qt.Key_Delete } else if (event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) {
|| event.key === Qt.Key_Backspace) {
clearSelected() clearSelected()
event.accepted = true event.accepted = true
} else if (event.key >= Qt.Key_1 && event.key <= Qt.Key_9) { } else if (event.key >= Qt.Key_1 && event.key <= Qt.Key_9) {
@@ -456,8 +423,7 @@ QtObject {
// Get current selection info for UI // Get current selection info for UI
function getCurrentSelection() { function getCurrentSelection() {
if (!keyboardNavigationActive || selectedFlatIndex < 0 if (!keyboardNavigationActive || selectedFlatIndex < 0 || selectedFlatIndex >= flatNavigation.length) {
|| selectedFlatIndex >= flatNavigation.length) {
return { return {
"type": "", "type": "",
"groupIndex": -1, "groupIndex": -1,

View File

@@ -9,8 +9,7 @@ Rectangle {
height: 80 height: 80
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95)
Theme.surfaceContainer.b, 0.95)
border.color: Theme.primary border.color: Theme.primary
border.width: 2 border.width: 2
opacity: showHints ? 1 : 0 opacity: showHints ? 1 : 0

View File

@@ -15,10 +15,8 @@ Rectangle {
visible: expanded visible: expanded
clip: true clip: true
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3)
Theme.surfaceContainer.b, 0.3) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.1)
border.width: 1 border.width: 1
Behavior on height { Behavior on height {
@@ -29,7 +27,6 @@ Rectangle {
} }
} }
// Ensure smooth opacity transition
opacity: expanded ? 1 : 0 opacity: expanded ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
@@ -82,17 +79,20 @@ Rectangle {
return "5 seconds" return "5 seconds"
} }
for (var i = 0; i < timeoutOptions.length; i++) { for (let i = 0; i < timeoutOptions.length; i++) {
if (timeoutOptions[i].value === value) { if (timeoutOptions[i].value === value) {
return timeoutOptions[i].text return timeoutOptions[i].text
} }
} }
if (value === 0) if (value === 0) {
return "Never" return "Never"
if (value < 1000) }
if (value < 1000) {
return value + "ms" return value + "ms"
if (value < 60000) }
if (value < 60000) {
return Math.round(value / 1000) + " seconds" return Math.round(value / 1000) + " seconds"
}
return Math.round(value / 60000) + " minutes" return Math.round(value / 60000) + " minutes"
} }
@@ -139,16 +139,14 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
checked: SessionData.doNotDisturb checked: SessionData.doNotDisturb
onToggled: SessionData.setDoNotDisturb( onToggled: SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
!SessionData.doNotDisturb)
} }
} }
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 1 height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
Theme.outline.b, 0.1)
} }
StyledText { StyledText {
@@ -165,10 +163,9 @@ Rectangle {
currentValue: getTimeoutText(SettingsData.notificationTimeoutLow) currentValue: getTimeoutText(SettingsData.notificationTimeoutLow)
options: timeoutOptions.map(opt => opt.text) options: timeoutOptions.map(opt => opt.text)
onValueChanged: value => { onValueChanged: value => {
for (var i = 0; i < timeoutOptions.length; i++) { for (let i = 0; i < timeoutOptions.length; i++) {
if (timeoutOptions[i].text === value) { if (timeoutOptions[i].text === value) {
SettingsData.setNotificationTimeoutLow( SettingsData.setNotificationTimeoutLow(timeoutOptions[i].value)
timeoutOptions[i].value)
break break
} }
} }
@@ -182,10 +179,9 @@ Rectangle {
currentValue: getTimeoutText(SettingsData.notificationTimeoutNormal) currentValue: getTimeoutText(SettingsData.notificationTimeoutNormal)
options: timeoutOptions.map(opt => opt.text) options: timeoutOptions.map(opt => opt.text)
onValueChanged: value => { onValueChanged: value => {
for (var i = 0; i < timeoutOptions.length; i++) { for (let i = 0; i < timeoutOptions.length; i++) {
if (timeoutOptions[i].text === value) { if (timeoutOptions[i].text === value) {
SettingsData.setNotificationTimeoutNormal( SettingsData.setNotificationTimeoutNormal(timeoutOptions[i].value)
timeoutOptions[i].value)
break break
} }
} }
@@ -196,14 +192,12 @@ Rectangle {
width: parent.width width: parent.width
text: "Critical Priority" text: "Critical Priority"
description: "Timeout for critical priority notifications" description: "Timeout for critical priority notifications"
currentValue: getTimeoutText( currentValue: getTimeoutText(SettingsData.notificationTimeoutCritical)
SettingsData.notificationTimeoutCritical)
options: timeoutOptions.map(opt => opt.text) options: timeoutOptions.map(opt => opt.text)
onValueChanged: value => { onValueChanged: value => {
for (var i = 0; i < timeoutOptions.length; i++) { for (let i = 0; i < timeoutOptions.length; i++) {
if (timeoutOptions[i].text === value) { if (timeoutOptions[i].text === value) {
SettingsData.setNotificationTimeoutCritical( SettingsData.setNotificationTimeoutCritical(timeoutOptions[i].value)
timeoutOptions[i].value)
break break
} }
} }
@@ -213,8 +207,7 @@ Rectangle {
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 1 height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
Theme.outline.b, 0.1)
} }
Item { Item {
@@ -255,8 +248,7 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.notificationOverlayEnabled checked: SettingsData.notificationOverlayEnabled
onToggled: toggled => SettingsData.setNotificationOverlayEnabled( onToggled: toggled => SettingsData.setNotificationOverlayEnabled(toggled)
toggled)
} }
} }
} }

View File

@@ -13,8 +13,7 @@ PanelWindow {
required property var notificationData required property var notificationData
required property string notificationId required property string notificationId
readonly property bool hasValidData: notificationData readonly property bool hasValidData: notificationData && notificationData.notification
&& notificationData.notification
property int screenY: 0 property int screenY: 0
property bool exiting: false property bool exiting: false
property bool _isDestroying: false property bool _isDestroying: false
@@ -24,20 +23,20 @@ PanelWindow {
signal exitFinished signal exitFinished
function startExit() { function startExit() {
if (exiting || _isDestroying) if (exiting || _isDestroying) {
return return
}
exiting = true exiting = true
exitAnim.restart() exitAnim.restart()
exitWatchdog.restart() exitWatchdog.restart()
if (NotificationService.removeFromVisibleNotifications) if (NotificationService.removeFromVisibleNotifications)
NotificationService.removeFromVisibleNotifications( NotificationService.removeFromVisibleNotifications(win.notificationData)
win.notificationData)
} }
function forceExit() { function forceExit() {
if (_isDestroying) if (_isDestroying) {
return return
}
_isDestroying = true _isDestroying = true
exiting = true exiting = true
visible = false visible = false
@@ -46,8 +45,9 @@ PanelWindow {
} }
function finalizeExit(reason) { function finalizeExit(reason) {
if (_finalized) if (_finalized) {
return return
}
_finalized = true _finalized = true
_isDestroying = true _isDestroying = true
@@ -64,8 +64,7 @@ PanelWindow {
SettingsData.notificationOverlayEnabled SettingsData.notificationOverlayEnabled
const shouldUseOverlay = (SettingsData.notificationOverlayEnabled) const shouldUseOverlay = (SettingsData.notificationOverlayEnabled) || (notificationData.urgency === NotificationUrgency.Critical)
|| (notificationData.urgency === NotificationUrgency.Critical)
return shouldUseOverlay ? WlrLayershell.Overlay : WlrLayershell.Top return shouldUseOverlay ? WlrLayershell.Overlay : WlrLayershell.Top
} }
@@ -77,38 +76,33 @@ PanelWindow {
onScreenYChanged: margins.top = Theme.barHeight - 4 + SettingsData.topBarSpacing + 4 + screenY onScreenYChanged: margins.top = Theme.barHeight - 4 + SettingsData.topBarSpacing + 4 + screenY
onHasValidDataChanged: { onHasValidDataChanged: {
if (!hasValidData && !exiting && !_isDestroying) { if (!hasValidData && !exiting && !_isDestroying) {
forceExit() forceExit()
} }
} }
Component.onCompleted: { Component.onCompleted: {
if (hasValidData) { if (hasValidData) {
Qt.callLater(() => { Qt.callLater(() => enterX.restart())
return enterX.restart()
})
} else { } else {
forceExit() forceExit()
} }
} }
onNotificationDataChanged: { onNotificationDataChanged: {
if (!_isDestroying) { if (!_isDestroying) {
wrapperConn.target = win.notificationData || null wrapperConn.target = win.notificationData || null
notificationConn.target = (win.notificationData notificationConn.target = (win.notificationData && win.notificationData.notification && win.notificationData.notification.Retainable) || null
&& win.notificationData.notification
&& win.notificationData.notification.Retainable)
|| null
} }
} }
onEntered: { onEntered: {
if (!_isDestroying) if (!_isDestroying) {
enterDelay.start() enterDelay.start()
}
} }
Component.onDestruction: { Component.onDestruction: {
_isDestroying = true _isDestroying = true
exitWatchdog.stop() exitWatchdog.stop()
if (notificationData && notificationData.timer) if (notificationData && notificationData.timer) {
notificationData.timer.stop() notificationData.timer.stop()
}
} }
anchors { anchors {
@@ -136,18 +130,8 @@ PanelWindow {
anchors.margins: 4 anchors.margins: 4
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Theme.popupBackground() color: Theme.popupBackground()
border.color: notificationData && notificationData.urgency border.color: notificationData && notificationData.urgency === NotificationUrgency.Critical ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
=== NotificationUrgency.Critical ? Qt.rgba( border.width: notificationData && notificationData.urgency === NotificationUrgency.Critical ? 2 : 1
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.3) : Qt.rgba(
Theme.outline.r,
Theme.outline.g,
Theme.outline.b,
0.08)
border.width: notificationData
&& notificationData.urgency === NotificationUrgency.Critical ? 2 : 1
clip: true clip: true
Rectangle { Rectangle {
@@ -179,8 +163,7 @@ PanelWindow {
anchors.fill: parent anchors.fill: parent
color: "transparent" color: "transparent"
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
Theme.outline.b, 0.12)
border.width: 1 border.width: 1
radius: parent.radius radius: parent.radius
z: -1 z: -1
@@ -189,8 +172,7 @@ PanelWindow {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
radius: parent.radius radius: parent.radius
visible: notificationData visible: notificationData && notificationData.urgency === NotificationUrgency.Critical
&& notificationData.urgency === NotificationUrgency.Critical
opacity: 1 opacity: 1
gradient: Gradient { gradient: Gradient {
@@ -227,15 +209,12 @@ PanelWindow {
Rectangle { Rectangle {
id: iconContainer id: iconContainer
readonly property bool hasNotificationImage: notificationData readonly property bool hasNotificationImage: notificationData && notificationData.image && notificationData.image !== ""
&& notificationData.image
&& notificationData.image !== ""
width: 55 width: 55
height: 55 height: 55
radius: 27.5 radius: 27.5
color: Qt.rgba(Theme.primary.r, Theme.primary.g, color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
Theme.primary.b, 0.1)
border.color: "transparent" border.color: "transparent"
border.width: 0 border.width: 0
anchors.left: parent.left anchors.left: parent.left
@@ -256,9 +235,7 @@ PanelWindow {
if (notificationData.appIcon) { if (notificationData.appIcon) {
const appIcon = notificationData.appIcon const appIcon = notificationData.appIcon
if (appIcon.startsWith("file://") if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://"))
|| appIcon.startsWith("http://")
|| appIcon.startsWith("https://"))
return appIcon return appIcon
return Quickshell.iconPath(appIcon, true) return Quickshell.iconPath(appIcon, true)
@@ -270,13 +247,9 @@ PanelWindow {
StyledText { StyledText {
anchors.centerIn: parent anchors.centerIn: parent
visible: !parent.hasNotificationImage visible: !parent.hasNotificationImage && (!notificationData || !notificationData.appIcon || notificationData.appIcon === "")
&& (!notificationData
|| !notificationData.appIcon
|| notificationData.appIcon === "")
text: { text: {
const appName = notificationData const appName = notificationData && notificationData.appName ? notificationData.appName : "?"
&& notificationData.appName ? notificationData.appName : "?"
return appName.charAt(0).toUpperCase() return appName.charAt(0).toUpperCase()
} }
font.pixelSize: 20 font.pixelSize: 20
@@ -313,10 +286,8 @@ PanelWindow {
if (!notificationData) if (!notificationData)
return "" return ""
const appName = notificationData.appName const appName = notificationData.appName || ""
|| "" const timeStr = notificationData.timeStr || ""
const timeStr = notificationData.timeStr
|| ""
if (timeStr.length > 0) if (timeStr.length > 0)
return appName + " • " + timeStr return appName + " • " + timeStr
else else
@@ -330,8 +301,7 @@ PanelWindow {
} }
StyledText { StyledText {
text: notificationData ? (notificationData.summary text: notificationData ? (notificationData.summary || "") : ""
|| "") : ""
color: Theme.surfaceText color: Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium font.weight: Font.Medium
@@ -342,8 +312,7 @@ PanelWindow {
} }
StyledText { StyledText {
text: notificationData ? (notificationData.htmlBody text: notificationData ? (notificationData.htmlBody || "") : ""
|| "") : ""
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
width: parent.width width: parent.width
@@ -353,8 +322,7 @@ PanelWindow {
visible: text.length > 0 visible: text.length > 0
linkColor: Theme.primary linkColor: Theme.primary
onLinkActivated: link => { onLinkActivated: link => {
return Qt.openUrlExternally( return Qt.openUrlExternally(link)
link)
} }
MouseArea { MouseArea {
@@ -394,8 +362,7 @@ PanelWindow {
z: 20 z: 20
Repeater { Repeater {
model: notificationData ? (notificationData.actions model: notificationData ? (notificationData.actions || []) : []
|| []) : []
Rectangle { Rectangle {
property bool isHovered: false property bool isHovered: false
@@ -403,10 +370,7 @@ PanelWindow {
width: Math.max(actionText.implicitWidth + 12, 50) width: Math.max(actionText.implicitWidth + 12, 50)
height: 24 height: 24
radius: 4 radius: 4
color: isHovered ? Qt.rgba(Theme.primary.r, color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
Theme.primary.g,
Theme.primary.b,
0.1) : "transparent"
StyledText { StyledText {
id: actionText id: actionText
@@ -450,8 +414,7 @@ PanelWindow {
width: Math.max(clearText.implicitWidth + 12, 50) width: Math.max(clearText.implicitWidth + 12, 50)
height: 24 height: 24
radius: 4 radius: 4
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
Theme.primary.b, 0.1) : "transparent"
z: 20 z: 20
StyledText { StyledText {
@@ -473,8 +436,7 @@ PanelWindow {
onExited: clearButton.isHovered = false onExited: clearButton.isHovered = false
onClicked: { onClicked: {
if (notificationData && !win.exiting) if (notificationData && !win.exiting)
NotificationService.dismissNotification( NotificationService.dismissNotification(notificationData)
notificationData)
} }
} }
} }
@@ -492,8 +454,7 @@ PanelWindow {
notificationData.timer.stop() notificationData.timer.stop()
} }
onExited: { onExited: {
if (notificationData && notificationData.popup if (notificationData && notificationData.popup && notificationData.timer)
&& notificationData.timer)
notificationData.timer.restart() notificationData.timer.restart()
} }
onClicked: { onClicked: {
@@ -587,8 +548,7 @@ PanelWindow {
forceExit() forceExit()
} }
target: (win.notificationData && win.notificationData.notification target: (win.notificationData && win.notificationData.notification && win.notificationData.notification.Retainable) || null
&& win.notificationData.notification.Retainable) || null
ignoreUnknownSignals: true ignoreUnknownSignals: true
enabled: !win._isDestroying enabled: !win._isDestroying
} }
@@ -599,8 +559,7 @@ PanelWindow {
interval: 160 interval: 160
repeat: false repeat: false
onTriggered: { onTriggered: {
if (notificationData && notificationData.timer && !exiting if (notificationData && notificationData.timer && !exiting && !_isDestroying)
&& !_isDestroying)
notificationData.timer.start() notificationData.timer.start()
} }
} }

View File

@@ -38,125 +38,120 @@ QtObject {
running: false running: false
repeat: true repeat: true
onTriggered: { onTriggered: {
let toRemove = [] const toRemove = []
for (let p of popupWindows) { for (const p of popupWindows) {
if (!p) { toRemove.push(p); continue } if (!p) {
const isZombie = toRemove.push(p)
p.status === Component.Null || continue
(!p.visible && !p.exiting) || }
(!p.notificationData && !p._isDestroying) || const isZombie = p.status === Component.Null || (!p.visible && !p.exiting) || (!p.notificationData && !p._isDestroying) || (!p.hasValidData && !p._isDestroying)
(!p.hasValidData && !p._isDestroying)
if (isZombie) { if (isZombie) {
toRemove.push(p) toRemove.push(p)
if (p.forceExit) p.forceExit() if (p.forceExit) {
else if (p.destroy) { try { p.destroy() } catch(e) {} } p.forceExit()
} else if (p.destroy) {
try {
p.destroy()
} catch (e) {
}
}
} }
} }
if (toRemove.length) { if (toRemove.length) {
popupWindows = popupWindows.filter(p => toRemove.indexOf(p) === -1) popupWindows = popupWindows.filter(p => toRemove.indexOf(p) === -1)
const survivors = _active().sort((a,b)=>a.screenY-b.screenY) const survivors = _active().sort((a, b) => a.screenY - b.screenY)
for (var k=0; k<survivors.length; ++k) for (let k = 0; k < survivors.length; ++k) {
survivors[k].screenY = topMargin + k * baseNotificationHeight survivors[k].screenY = topMargin + k * baseNotificationHeight
}
}
if (popupWindows.length === 0) {
sweeper.stop()
} }
if (popupWindows.length === 0) sweeper.stop()
} }
} }
function _hasWindowFor(w) { function _hasWindowFor(w) {
return popupWindows.some(p => { return popupWindows.some(p => p && p.notificationData === w && !p._isDestroying && p.status !== Component.Null)
return p && p.notificationData === w
&& !p._isDestroying
&& p.status !== Component.Null
})
} }
function _isValidWindow(p) { function _isValidWindow(p) {
return p && p.status !== Component.Null && !p._isDestroying return p && p.status !== Component.Null && !p._isDestroying && p.hasValidData
&& p.hasValidData
} }
function _canMakeRoomFor(wrapper) { function _canMakeRoomFor(wrapper) {
const activeWindows = _active() const activeWindows = _active()
if (activeWindows.length < maxTargetNotifications) if (activeWindows.length < maxTargetNotifications) {
return true return true
}
if (!wrapper || !wrapper.notification) if (!wrapper || !wrapper.notification) {
return false return false
}
const incomingUrgency = wrapper.notification.urgency || 0 const incomingUrgency = wrapper.notification.urgency || 0
for (const p of activeWindows) {
for (let p of activeWindows) { if (!p.notificationData || !p.notificationData.notification) {
if (!p.notificationData || !p.notificationData.notification)
continue continue
}
const existingUrgency = p.notificationData.notification.urgency || 0 const existingUrgency = p.notificationData.notification.urgency || 0
if (existingUrgency < incomingUrgency) {
if (existingUrgency < incomingUrgency)
return true return true
}
if (existingUrgency === incomingUrgency) { if (existingUrgency === incomingUrgency) {
const timer = p.notificationData.timer const timer = p.notificationData.timer
if (timer && !timer.running) if (timer && !timer.running) {
return true return true
}
} }
} }
return false return false
} }
function _makeRoomForNew(wrapper) { function _makeRoomForNew(wrapper) {
const activeWindows = _active() const activeWindows = _active()
if (activeWindows.length < maxTargetNotifications) if (activeWindows.length < maxTargetNotifications) {
return return
}
const toRemove = _selectPopupToRemove(activeWindows, wrapper) const toRemove = _selectPopupToRemove(activeWindows, wrapper)
if (toRemove && !toRemove.exiting) { if (toRemove && !toRemove.exiting) {
toRemove.notificationData.removedByLimit = true toRemove.notificationData.removedByLimit = true
toRemove.notificationData.popup = false toRemove.notificationData.popup = false
if (toRemove.notificationData.timer) if (toRemove.notificationData.timer) {
toRemove.notificationData.timer.stop() toRemove.notificationData.timer.stop()
}
} }
} }
function _selectPopupToRemove(activeWindows, incomingWrapper) { function _selectPopupToRemove(activeWindows, incomingWrapper) {
const incomingUrgency = (incomingWrapper && incomingWrapper.notification) const incomingUrgency = (incomingWrapper && incomingWrapper.notification) ? incomingWrapper.notification.urgency || 0 : 0
? incomingWrapper.notification.urgency || 0 : 0
const sortedWindows = activeWindows.slice().sort((a, b) => { const sortedWindows = activeWindows.slice().sort((a, b) => {
const aUrgency = (a.notificationData && a.notificationData.notification) const aUrgency = (a.notificationData && a.notificationData.notification) ? a.notificationData.notification.urgency || 0 : 0
? a.notificationData.notification.urgency || 0 : 0 const bUrgency = (b.notificationData && b.notificationData.notification) ? b.notificationData.notification.urgency || 0 : 0
const bUrgency = (b.notificationData && b.notificationData.notification) if (aUrgency !== bUrgency) {
? b.notificationData.notification.urgency || 0 : 0 return aUrgency - bUrgency
}
if (aUrgency !== bUrgency) const aTimer = a.notificationData && a.notificationData.timer
return aUrgency - bUrgency const bTimer = b.notificationData && b.notificationData.timer
const aRunning = aTimer && aTimer.running
const aTimer = a.notificationData && a.notificationData.timer const bRunning = bTimer && bTimer.running
const bTimer = b.notificationData && b.notificationData.timer if (aRunning !== bRunning) {
const aRunning = aTimer && aTimer.running return aRunning ? 1 : -1
const bRunning = bTimer && bTimer.running }
return b.screenY - a.screenY
if (aRunning !== bRunning) })
return aRunning ? 1 : -1
return b.screenY - a.screenY
})
return sortedWindows[0] return sortedWindows[0]
} }
function _sync(newWrappers) { function _sync(newWrappers) {
for (let w of newWrappers) { for (const w of newWrappers) {
if (w && !_hasWindowFor(w)) if (w && !_hasWindowFor(w)) {
insertNewestAtTop(w) insertNewestAtTop(w)
}
} }
for (const p of popupWindows.slice()) {
for (let p of popupWindows.slice()) { if (!_isValidWindow(p)) {
if (!_isValidWindow(p))
continue continue
}
if (p.notificationData && newWrappers.indexOf( if (p.notificationData && newWrappers.indexOf(p.notificationData) === -1 && !p.exiting) {
p.notificationData) === -1 && !p.exiting) {
p.notificationData.removedByLimit = true p.notificationData.removedByLimit = true
p.notificationData.popup = false p.notificationData.popup = false
} }
@@ -165,21 +160,18 @@ QtObject {
function insertNewestAtTop(wrapper) { function insertNewestAtTop(wrapper) {
if (!wrapper) { if (!wrapper) {
return return
} }
for (const p of popupWindows) {
for (let p of popupWindows) { if (!_isValidWindow(p)) {
if (!_isValidWindow(p))
continue continue
}
if (p.exiting) if (p.exiting) {
continue continue
}
p.screenY = p.screenY + baseNotificationHeight p.screenY = p.screenY + baseNotificationHeight
} }
const notificationId = wrapper const notificationId = wrapper && wrapper.notification ? wrapper.notification.id : ""
&& wrapper.notification ? wrapper.notification.id : ""
const win = popupComponent.createObject(null, { const win = popupComponent.createObject(null, {
"notificationData": wrapper, "notificationData": wrapper,
"notificationId": notificationId, "notificationId": notificationId,
@@ -187,30 +179,26 @@ QtObject {
"screen": manager.modelData "screen": manager.modelData
}) })
if (!win) { if (!win) {
return return
} }
if (!win.hasValidData) { if (!win.hasValidData) {
win.destroy() win.destroy()
return return
} }
popupWindows.push(win) popupWindows.push(win)
if (!sweeper.running) if (!sweeper.running) {
sweeper.start() sweeper.start()
}
} }
function _active() { function _active() {
return popupWindows.filter(p => { return popupWindows.filter(p => _isValidWindow(p) && p.notificationData && p.notificationData.popup && !p.exiting)
return _isValidWindow(p)
&& p.notificationData
&& p.notificationData.popup && !p.exiting
})
} }
function _bottom() { function _bottom() {
let b = null, maxY = -1 let b = null
for (let p of _active()) { let maxY = -1
for (const p of _active()) {
if (p.screenY > maxY) { if (p.screenY > maxY) {
maxY = p.screenY maxY = p.screenY
b = p b = p
@@ -219,26 +207,25 @@ QtObject {
return b return b
} }
function _onPopupEntered(p) { function _onPopupEntered(p) {}
}
function _onPopupExitFinished(p) { function _onPopupExitFinished(p) {
if (!p) if (!p) {
return return
}
const windowId = p.toString() const windowId = p.toString()
if (destroyingWindows.has(windowId)) if (destroyingWindows.has(windowId)) {
return return
}
destroyingWindows.add(windowId) destroyingWindows.add(windowId)
const i = popupWindows.indexOf(p) const i = popupWindows.indexOf(p)
if (i !== -1) { if (i !== -1) {
popupWindows.splice(i, 1) popupWindows.splice(i, 1)
popupWindows = popupWindows.slice() popupWindows = popupWindows.slice()
} }
if (NotificationService.releaseWrapper && p.notificationData) if (NotificationService.releaseWrapper && p.notificationData) {
NotificationService.releaseWrapper(p.notificationData) NotificationService.releaseWrapper(p.notificationData)
}
Qt.callLater(() => { Qt.callLater(() => {
if (p && p.destroy) { if (p && p.destroy) {
try { try {
@@ -247,27 +234,24 @@ QtObject {
} }
} }
Qt.callLater(() => { Qt.callLater(() => destroyingWindows.delete(windowId))
destroyingWindows.delete(windowId)
})
}) })
const survivors = _active().sort((a, b) => { const survivors = _active().sort((a, b) => a.screenY - b.screenY)
return a.screenY - b.screenY for (let k = 0; k < survivors.length; ++k) {
})
for (var k = 0; k < survivors.length; ++k) {
survivors[k].screenY = topMargin + k * baseNotificationHeight survivors[k].screenY = topMargin + k * baseNotificationHeight
} }
} }
function cleanupAllWindows() { function cleanupAllWindows() {
sweeper.stop() sweeper.stop()
for (let p of popupWindows.slice()) { for (const p of popupWindows.slice()) {
if (p) { if (p) {
try { try {
if (p.forceExit) if (p.forceExit) {
p.forceExit() p.forceExit()
else if (p.destroy) } else if (p.destroy) {
p.destroy() p.destroy()
}
} catch (e) { } catch (e) {
} }
@@ -278,9 +262,10 @@ QtObject {
} }
onPopupWindowsChanged: { onPopupWindowsChanged: {
if (popupWindows.length > 0 && !sweeper.running) if (popupWindows.length > 0 && !sweeper.running) {
sweeper.start() sweeper.start()
else if (popupWindows.length === 0 && sweeper.running) } else if (popupWindows.length === 0 && sweeper.running) {
sweeper.stop() sweeper.stop()
}
} }
} }

View File

@@ -24,7 +24,6 @@ DankOSD {
} }
} }
Connections { Connections {
target: DisplayService target: DisplayService
function onBrightnessChanged() { function onBrightnessChanged() {
@@ -54,12 +53,13 @@ DankOSD {
anchors.centerIn: parent anchors.centerIn: parent
name: { name: {
const deviceInfo = DisplayService.getCurrentDeviceInfo() const deviceInfo = DisplayService.getCurrentDeviceInfo()
if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") {
return "brightness_medium" return "brightness_medium"
else if (deviceInfo.name.includes("kbd")) } else if (deviceInfo.name.includes("kbd")) {
return "keyboard" return "keyboard"
else } else {
return "lightbulb" return "lightbulb"
}
} }
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
@@ -80,40 +80,43 @@ DankOSD {
unit: "%" unit: "%"
Component.onCompleted: { Component.onCompleted: {
if (DisplayService.brightnessAvailable)
value = DisplayService.brightnessLevel
}
onSliderValueChanged: function(newValue) {
if (DisplayService.brightnessAvailable) { if (DisplayService.brightnessAvailable) {
root.brightnessDebounceTimer.pendingValue = newValue value = DisplayService.brightnessLevel
root.brightnessDebounceTimer.restart()
resetHideTimer()
} }
} }
onSliderValueChanged: newValue => {
if (DisplayService.brightnessAvailable) {
root.brightnessDebounceTimer.pendingValue = newValue
root.brightnessDebounceTimer.restart()
resetHideTimer()
}
}
onContainsMouseChanged: { onContainsMouseChanged: {
setChildHovered(containsMouse) setChildHovered(containsMouse)
} }
onSliderDragFinished: function(finalValue) { onSliderDragFinished: finalValue => {
if (DisplayService.brightnessAvailable) { if (DisplayService.brightnessAvailable) {
root.brightnessDebounceTimer.stop() root.brightnessDebounceTimer.stop()
DisplayService.setBrightnessInternal(finalValue, DisplayService.lastIpcDevice) DisplayService.setBrightnessInternal(finalValue, DisplayService.lastIpcDevice)
} }
} }
Connections { Connections {
target: DisplayService target: DisplayService
function onBrightnessChanged() { function onBrightnessChanged() {
if (!brightnessSlider.pressed) if (!brightnessSlider.pressed) {
brightnessSlider.value = DisplayService.brightnessLevel brightnessSlider.value = DisplayService.brightnessLevel
}
} }
function onDeviceSwitched() { function onDeviceSwitched() {
if (!brightnessSlider.pressed) if (!brightnessSlider.pressed) {
brightnessSlider.value = DisplayService.brightnessLevel brightnessSlider.value = DisplayService.brightnessLevel
}
} }
} }
} }
@@ -122,9 +125,10 @@ DankOSD {
onOsdShown: { onOsdShown: {
if (DisplayService.brightnessAvailable && contentLoader.item) { if (DisplayService.brightnessAvailable && contentLoader.item) {
let slider = contentLoader.item.children[0].children[1] const slider = contentLoader.item.children[0].children[1]
if (slider) if (slider) {
slider.value = DisplayService.brightnessLevel slider.value = DisplayService.brightnessLevel
}
} }
} }
} }

View File

@@ -24,4 +24,4 @@ DankOSD {
size: Theme.iconSize size: Theme.iconSize
color: SessionService.idleInhibited ? Theme.primary : Theme.outline color: SessionService.idleInhibited ? Theme.primary : Theme.outline
} }
} }

View File

@@ -24,4 +24,4 @@ DankOSD {
size: Theme.iconSize size: Theme.iconSize
color: AudioService.source && AudioService.source.audio && AudioService.source.audio.muted ? Theme.error : Theme.primary color: AudioService.source && AudioService.source.audio && AudioService.source.audio.muted ? Theme.error : Theme.primary
} }
} }

View File

@@ -11,7 +11,6 @@ DankOSD {
autoHideInterval: 3000 autoHideInterval: 3000
enableMouseInteraction: true enableMouseInteraction: true
Connections { Connections {
target: AudioService target: AudioService
@@ -20,8 +19,9 @@ DankOSD {
} }
function onSinkChanged() { function onSinkChanged() {
if (root.shouldBeVisible) if (root.shouldBeVisible) {
root.show() root.show()
}
} }
} }
@@ -80,17 +80,18 @@ DankOSD {
unit: "%" unit: "%"
Component.onCompleted: { Component.onCompleted: {
if (AudioService.sink && AudioService.sink.audio)
value = Math.round(AudioService.sink.audio.volume * 100)
}
onSliderValueChanged: function(newValue) {
if (AudioService.sink && AudioService.sink.audio) { if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.volume = newValue / 100 value = Math.round(AudioService.sink.audio.volume * 100)
resetHideTimer()
} }
} }
onSliderValueChanged: newValue => {
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.volume = newValue / 100
resetHideTimer()
}
}
onContainsMouseChanged: { onContainsMouseChanged: {
setChildHovered(containsMouse || muteButton.containsMouse) setChildHovered(containsMouse || muteButton.containsMouse)
} }
@@ -99,8 +100,9 @@ DankOSD {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
function onVolumeChanged() { function onVolumeChanged() {
if (volumeSlider && !volumeSlider.pressed) if (volumeSlider && !volumeSlider.pressed) {
volumeSlider.value = Math.round(AudioService.sink.audio.volume * 100) volumeSlider.value = Math.round(AudioService.sink.audio.volume * 100)
}
} }
} }
} }
@@ -109,9 +111,10 @@ DankOSD {
onOsdShown: { onOsdShown: {
if (AudioService.sink && AudioService.sink.audio && contentLoader.item) { if (AudioService.sink && AudioService.sink.audio && contentLoader.item) {
let slider = contentLoader.item.children[0].children[1] const slider = contentLoader.item.children[0].children[1]
if (slider) if (slider) {
slider.value = Math.round(AudioService.sink.audio.volume * 100) slider.value = Math.round(AudioService.sink.audio.volume * 100)
}
} }
} }
} }

View File

@@ -6,42 +6,42 @@ import qs.Widgets
Column { Column {
function formatNetworkSpeed(bytesPerSec) { function formatNetworkSpeed(bytesPerSec) {
if (bytesPerSec < 1024) if (bytesPerSec < 1024) {
return bytesPerSec.toFixed(0) + " B/s" return bytesPerSec.toFixed(0) + " B/s";
else if (bytesPerSec < 1024 * 1024) } else if (bytesPerSec < 1024 * 1024) {
return (bytesPerSec / 1024).toFixed(1) + " KB/s" return (bytesPerSec / 1024).toFixed(1) + " KB/s";
else if (bytesPerSec < 1024 * 1024 * 1024) } else if (bytesPerSec < 1024 * 1024 * 1024) {
return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s" return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s";
else } else {
return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(1) + " GB/s" return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(1) + " GB/s";
}
} }
function formatDiskSpeed(bytesPerSec) { function formatDiskSpeed(bytesPerSec) {
if (bytesPerSec < 1024 * 1024) if (bytesPerSec < 1024 * 1024) {
return (bytesPerSec / 1024).toFixed(1) + " KB/s" return (bytesPerSec / 1024).toFixed(1) + " KB/s";
else if (bytesPerSec < 1024 * 1024 * 1024) } else if (bytesPerSec < 1024 * 1024 * 1024) {
return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s" return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s";
else } else {
return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(1) + " GB/s" return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(1) + " GB/s";
}
} }
anchors.fill: parent anchors.fill: parent
spacing: Theme.spacingM spacing: Theme.spacingM
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["cpu", "memory", "network", "disk"]) DgopService.addRef(["cpu", "memory", "network", "disk"]);
} }
Component.onDestruction: { Component.onDestruction: {
DgopService.removeRef(["cpu", "memory", "network", "disk"]) DgopService.removeRef(["cpu", "memory", "network", "disk"]);
} }
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 200 height: 200
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.04)
Theme.surfaceVariant.b, 0.04) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.06)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.06)
border.width: 1 border.width: 1
Column { Column {
@@ -66,17 +66,17 @@ Column {
width: 80 width: 80
height: 24 height: 24
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.primary.r, Theme.primary.g, color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
Theme.primary.b, 0.12)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
StyledText { StyledText {
text: DgopService.cpuUsage.toFixed(1) + "%" text: `${DgopService.cpuUsage.toFixed(1)}%`
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.primary color: Theme.primary
anchors.centerIn: parent anchors.centerIn: parent
} }
} }
Item { Item {
@@ -85,11 +85,12 @@ Column {
} }
StyledText { StyledText {
text: DgopService.cpuCores + " cores" text: `${DgopService.cpuCores} cores`
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
DankFlickable { DankFlickable {
@@ -100,6 +101,7 @@ Column {
Column { Column {
id: coreUsageColumn id: coreUsageColumn
width: parent.width width: parent.width
spacing: 6 spacing: 6
@@ -112,7 +114,7 @@ Column {
spacing: Theme.spacingS spacing: Theme.spacingS
StyledText { StyledText {
text: "C" + index text: `C${index}`
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
width: 24 width: 24
@@ -123,38 +125,37 @@ Column {
width: parent.width - 80 width: parent.width - 80
height: 6 height: 6
radius: 3 radius: 3
color: Qt.rgba(Theme.outline.r, color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
Theme.outline.g,
Theme.outline.b, 0.2)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
Rectangle { Rectangle {
width: parent.width * Math.min( width: parent.width * Math.min(1, modelData / 100)
1, modelData / 100)
height: parent.height height: parent.height
radius: parent.radius radius: parent.radius
color: { color: {
const usage = modelData const usage = modelData;
if (usage > 80) if (usage > 80) {
return Theme.error return Theme.error;
}
if (usage > 60) if (usage > 60) {
return Theme.warning return Theme.warning;
}
return Theme.primary return Theme.primary;
} }
Behavior on width { Behavior on width {
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
} }
StyledText { StyledText {
text: modelData ? modelData.toFixed( text: modelData ? `${modelData.toFixed(0)}%` : "0%"
0) + "%" : "0%"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.surfaceText color: Theme.surfaceText
@@ -162,21 +163,25 @@ Column {
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
} }
} }
} }
} }
} }
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 80 height: 80
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.04)
Theme.surfaceVariant.b, 0.04) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.06)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.06)
border.width: 1 border.width: 1
Row { Row {
@@ -196,12 +201,11 @@ Column {
} }
StyledText { StyledText {
text: DgopService.formatSystemMemory( text: `${DgopService.formatSystemMemory(DgopService.usedMemoryKB)} / ${DgopService.formatSystemMemory(DgopService.totalMemoryKB)}`
DgopService.usedMemoryKB) + " / " + DgopService.formatSystemMemory(
DgopService.totalMemoryKB)
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
} }
} }
Item { Item {
@@ -218,45 +222,41 @@ Column {
width: parent.width width: parent.width
height: 16 height: 16
radius: 8 radius: 8
color: Qt.rgba(Theme.outline.r, Theme.outline.g, color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
Theme.outline.b, 0.2)
Rectangle { Rectangle {
width: DgopService.totalMemoryKB width: DgopService.totalMemoryKB > 0 ? parent.width * (DgopService.usedMemoryKB / DgopService.totalMemoryKB) : 0
> 0 ? parent.width * (DgopService.usedMemoryKB
/ DgopService.totalMemoryKB) : 0
height: parent.height height: parent.height
radius: parent.radius radius: parent.radius
color: { color: {
const usage = DgopService.totalMemoryKB const usage = DgopService.totalMemoryKB > 0 ? (DgopService.usedMemoryKB / DgopService.totalMemoryKB) : 0;
> 0 ? (DgopService.usedMemoryKB if (usage > 0.9) {
/ DgopService.totalMemoryKB) : 0 return Theme.error;
if (usage > 0.9) }
return Theme.error if (usage > 0.7) {
return Theme.warning;
if (usage > 0.7) }
return Theme.warning return Theme.secondary;
return Theme.secondary
} }
Behavior on width { Behavior on width {
NumberAnimation { NumberAnimation {
duration: Theme.mediumDuration duration: Theme.mediumDuration
} }
} }
} }
} }
StyledText { StyledText {
text: DgopService.totalMemoryKB text: DgopService.totalMemoryKB > 0 ? `${((DgopService.usedMemoryKB / DgopService.totalMemoryKB) * 100).toFixed(1)}% used` : "No data"
> 0 ? ((DgopService.usedMemoryKB
/ DgopService.totalMemoryKB) * 100).toFixed(
1) + "% used" : "No data"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText color: Theme.surfaceText
} }
} }
Item { Item {
@@ -276,14 +276,11 @@ Column {
} }
StyledText { StyledText {
text: DgopService.totalSwapKB text: DgopService.totalSwapKB > 0 ? `${DgopService.formatSystemMemory(DgopService.usedSwapKB)} / ${DgopService.formatSystemMemory(DgopService.totalSwapKB)}` : "No swap configured"
> 0 ? DgopService.formatSystemMemory(
DgopService.usedSwapKB) + " / "
+ DgopService.formatSystemMemory(
DgopService.totalSwapKB) : "No swap configured"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
} }
} }
Item { Item {
@@ -300,49 +297,48 @@ Column {
width: parent.width width: parent.width
height: 16 height: 16
radius: 8 radius: 8
color: Qt.rgba(Theme.outline.r, Theme.outline.g, color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
Theme.outline.b, 0.2)
Rectangle { Rectangle {
width: DgopService.totalSwapKB width: DgopService.totalSwapKB > 0 ? parent.width * (DgopService.usedSwapKB / DgopService.totalSwapKB) : 0
> 0 ? parent.width * (DgopService.usedSwapKB
/ DgopService.totalSwapKB) : 0
height: parent.height height: parent.height
radius: parent.radius radius: parent.radius
color: { color: {
if (!DgopService.totalSwapKB) if (!DgopService.totalSwapKB) {
return Qt.rgba(Theme.surfaceText.r, return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3);
Theme.surfaceText.g, }
Theme.surfaceText.b, 0.3) const usage = DgopService.usedSwapKB / DgopService.totalSwapKB;
if (usage > 0.9) {
const usage = DgopService.usedSwapKB / DgopService.totalSwapKB return Theme.error;
if (usage > 0.9) }
return Theme.error if (usage > 0.7) {
return Theme.warning;
if (usage > 0.7) }
return Theme.warning return Theme.info;
return Theme.info
} }
Behavior on width { Behavior on width {
NumberAnimation { NumberAnimation {
duration: Theme.mediumDuration duration: Theme.mediumDuration
} }
} }
} }
} }
StyledText { StyledText {
text: DgopService.totalSwapKB text: DgopService.totalSwapKB > 0 ? `${((DgopService.usedSwapKB / DgopService.totalSwapKB) * 100).toFixed(1)}% used` : "Not available"
> 0 ? ((DgopService.usedSwapKB / DgopService.totalSwapKB) * 100).toFixed(
1) + "% used" : "Not available"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText color: Theme.surfaceText
} }
} }
} }
} }
Row { Row {
@@ -354,10 +350,8 @@ Column {
width: (parent.width - Theme.spacingM) / 2 width: (parent.width - Theme.spacingM) / 2
height: 80 height: 80
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.04)
Theme.surfaceVariant.b, 0.04) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.06)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.06)
border.width: 1 border.width: 1
Column { Column {
@@ -386,13 +380,12 @@ Column {
} }
StyledText { StyledText {
text: DgopService.networkRxRate text: DgopService.networkRxRate > 0 ? formatNetworkSpeed(DgopService.networkRxRate) : "0 B/s"
> 0 ? formatNetworkSpeed(
DgopService.networkRxRate) : "0 B/s"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText color: Theme.surfaceText
} }
} }
Row { Row {
@@ -405,26 +398,26 @@ Column {
} }
StyledText { StyledText {
text: DgopService.networkTxRate text: DgopService.networkTxRate > 0 ? formatNetworkSpeed(DgopService.networkTxRate) : "0 B/s"
> 0 ? formatNetworkSpeed(
DgopService.networkTxRate) : "0 B/s"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText color: Theme.surfaceText
} }
} }
} }
} }
} }
Rectangle { Rectangle {
width: (parent.width - Theme.spacingM) / 2 width: (parent.width - Theme.spacingM) / 2
height: 80 height: 80
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.04)
Theme.surfaceVariant.b, 0.04) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.06)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.06)
border.width: 1 border.width: 1
Column { Column {
@@ -458,6 +451,7 @@ Column {
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText color: Theme.surfaceText
} }
} }
Row { Row {
@@ -475,9 +469,15 @@ Column {
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText color: Theme.surfaceText
} }
} }
} }
} }
} }
} }
} }

View File

@@ -12,25 +12,27 @@ Popup {
property var processData: null property var processData: null
function show(x, y) { function show(x, y) {
if (!processContextMenu.parent && typeof Overlay !== "undefined" if (!processContextMenu.parent && typeof Overlay !== "undefined" && Overlay.overlay) {
&& Overlay.overlay) processContextMenu.parent = Overlay.overlay;
processContextMenu.parent = Overlay.overlay }
const menuWidth = 180 const menuWidth = 180;
const menuHeight = menuColumn.implicitHeight + Theme.spacingS * 2 const menuHeight = menuColumn.implicitHeight + Theme.spacingS * 2;
const screenWidth = Screen.width const screenWidth = Screen.width;
const screenHeight = Screen.height const screenHeight = Screen.height;
let finalX = x let finalX = x;
let finalY = y let finalY = y;
if (x + menuWidth > screenWidth - 20) if (x + menuWidth > screenWidth - 20) {
finalX = x - menuWidth finalX = x - menuWidth;
}
if (y + menuHeight > screenHeight - 20) if (y + menuHeight > screenHeight - 20) {
finalY = y - menuHeight finalY = y - menuHeight;
}
processContextMenu.x = Math.max(20, finalX) processContextMenu.x = Math.max(20, finalX);
processContextMenu.y = Math.max(20, finalY) processContextMenu.y = Math.max(20, finalY);
open() open();
} }
width: 180 width: 180
@@ -39,10 +41,10 @@ Popup {
modal: false modal: false
closePolicy: Popup.CloseOnEscape closePolicy: Popup.CloseOnEscape
onClosed: { onClosed: {
closePolicy = Popup.CloseOnEscape closePolicy = Popup.CloseOnEscape;
} }
onOpened: { onOpened: {
outsideClickTimer.start() outsideClickTimer.start();
} }
Timer { Timer {
@@ -50,7 +52,7 @@ Popup {
interval: 100 interval: 100
onTriggered: { onTriggered: {
processContextMenu.closePolicy = Popup.CloseOnEscape | Popup.CloseOnPressOutside processContextMenu.closePolicy = Popup.CloseOnEscape | Popup.CloseOnPressOutside;
} }
} }
@@ -63,8 +65,7 @@ Popup {
color: Theme.popupBackground() color: Theme.popupBackground()
radius: Theme.cornerRadius radius: Theme.cornerRadius
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
Theme.outline.b, 0.08)
border.width: 1 border.width: 1
Column { Column {
@@ -78,10 +79,7 @@ Popup {
width: parent.width width: parent.width
height: 28 height: 28
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: copyPidArea.containsMouse ? Qt.rgba(Theme.primary.r, color: copyPidArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
StyledText { StyledText {
anchors.left: parent.left anchors.left: parent.left
@@ -100,25 +98,21 @@ Popup {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if (processContextMenu.processData) if (processContextMenu.processData) {
Quickshell.execDetached( Quickshell.execDetached(["wl-copy", processContextMenu.processData.pid.toString()]);
["wl-copy", processContextMenu.processData.pid.toString( }
)])
processContextMenu.close() processContextMenu.close();
} }
} }
} }
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 28 height: 28
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: copyNameArea.containsMouse ? Qt.rgba( color: copyNameArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
StyledText { StyledText {
anchors.left: parent.left anchors.left: parent.left
@@ -138,13 +132,13 @@ Popup {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if (processContextMenu.processData) { if (processContextMenu.processData) {
let processName = processContextMenu.processData.displayName const processName = processContextMenu.processData.displayName || processContextMenu.processData.command;
|| processContextMenu.processData.command Quickshell.execDetached(["wl-copy", processName]);
Quickshell.execDetached(["wl-copy", processName])
} }
processContextMenu.close() processContextMenu.close();
} }
} }
} }
Rectangle { Rectangle {
@@ -157,19 +151,16 @@ Popup {
anchors.centerIn: parent anchors.centerIn: parent
width: parent.width width: parent.width
height: 1 height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
Theme.outline.b, 0.2)
} }
} }
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 28 height: 28
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: killArea.containsMouse ? Qt.rgba(Theme.error.r, color: killArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent"
Theme.error.g,
Theme.error.b,
0.12) : "transparent"
enabled: processContextMenu.processData enabled: processContextMenu.processData
opacity: enabled ? 1 : 0.5 opacity: enabled ? 1 : 0.5
@@ -179,10 +170,7 @@ Popup {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "Kill Process" text: "Kill Process"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: parent.enabled ? (killArea.containsMouse ? Theme.error : Theme.surfaceText) : Qt.rgba( color: parent.enabled ? (killArea.containsMouse ? Theme.error : Theme.surfaceText) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b, 0.5)
font.weight: Font.Normal font.weight: Font.Normal
} }
@@ -194,27 +182,22 @@ Popup {
cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
enabled: parent.enabled enabled: parent.enabled
onClicked: { onClicked: {
if (processContextMenu.processData) if (processContextMenu.processData) {
Quickshell.execDetached( Quickshell.execDetached(["kill", processContextMenu.processData.pid.toString()]);
["kill", processContextMenu.processData.pid.toString( }
)])
processContextMenu.close() processContextMenu.close();
} }
} }
} }
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 28 height: 28
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: forceKillArea.containsMouse ? Qt.rgba( color: forceKillArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent"
Theme.error.r, enabled: processContextMenu.processData && processContextMenu.processData.pid > 1000
Theme.error.g,
Theme.error.b,
0.12) : "transparent"
enabled: processContextMenu.processData
&& processContextMenu.processData.pid > 1000
opacity: enabled ? 1 : 0.5 opacity: enabled ? 1 : 0.5
StyledText { StyledText {
@@ -223,10 +206,7 @@ Popup {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "Force Kill Process" text: "Force Kill Process"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: parent.enabled ? (forceKillArea.containsMouse ? Theme.error : Theme.surfaceText) : Qt.rgba( color: parent.enabled ? (forceKillArea.containsMouse ? Theme.error : Theme.surfaceText) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b, 0.5)
font.weight: Font.Normal font.weight: Font.Normal
} }
@@ -238,15 +218,18 @@ Popup {
cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
enabled: parent.enabled enabled: parent.enabled
onClicked: { onClicked: {
if (processContextMenu.processData) if (processContextMenu.processData) {
Quickshell.execDetached( Quickshell.execDetached(["kill", "-9", processContextMenu.processData.pid.toString()]);
["kill", "-9", processContextMenu.processData.pid.toString( }
)])
processContextMenu.close() processContextMenu.close();
} }
} }
} }
} }
} }
} }

View File

@@ -12,14 +12,8 @@ Rectangle {
width: parent ? parent.width : 0 width: parent ? parent.width : 0
height: 40 height: 40
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
Theme.primary.g, border.color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Theme.primary.b,
0.08) : "transparent"
border.color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
border.width: 1 border.width: 1
MouseArea { MouseArea {
@@ -29,25 +23,21 @@ Rectangle {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: mouse => { onClicked: (mouse) => {
if (mouse.button === Qt.RightButton) { if (mouse.button === Qt.RightButton) {
if (process && process.pid > 0 && contextMenu) { if (process && process.pid > 0 && contextMenu) {
contextMenu.processData = process contextMenu.processData = process;
let globalPos = processMouseArea.mapToGlobal( const globalPos = processMouseArea.mapToGlobal(mouse.x, mouse.y);
mouse.x, mouse.y) const localPos = contextMenu.parent ? contextMenu.parent.mapFromGlobal(globalPos.x, globalPos.y) : globalPos;
let localPos = contextMenu.parent ? contextMenu.parent.mapFromGlobal( contextMenu.show(localPos.x, localPos.y);
globalPos.x, }
globalPos.y) : globalPos }
contextMenu.show(localPos.x, localPos.y) }
}
}
}
onPressAndHold: { onPressAndHold: {
if (process && process.pid > 0 && contextMenu) { if (process && process.pid > 0 && contextMenu) {
contextMenu.processData = process contextMenu.processData = process;
let globalPos = processMouseArea.mapToGlobal( const globalPos = processMouseArea.mapToGlobal(processMouseArea.width / 2, processMouseArea.height / 2);
processMouseArea.width / 2, processMouseArea.height / 2) contextMenu.show(globalPos.x, globalPos.y);
contextMenu.show(globalPos.x, globalPos.y)
} }
} }
} }
@@ -62,10 +52,10 @@ Rectangle {
name: DgopService.getProcessIcon(process ? process.command : "") name: DgopService.getProcessIcon(process ? process.command : "")
size: Theme.iconSize - 4 size: Theme.iconSize - 4
color: { color: {
if (process && process.cpu > 80) if (process && process.cpu > 80) {
return Theme.error return Theme.error;
}
return Theme.surfaceText return Theme.surfaceText;
} }
opacity: 0.8 opacity: 0.8
anchors.left: parent.left anchors.left: parent.left
@@ -92,12 +82,10 @@ Rectangle {
height: 20 height: 20
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: { color: {
if (process && process.cpu > 80) if (process && process.cpu > 80) {
return Qt.rgba(Theme.error.r, Theme.error.g, return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12);
Theme.error.b, 0.12) }
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08);
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.08)
} }
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 194 anchors.rightMargin: 194
@@ -109,13 +97,14 @@ Rectangle {
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
font.weight: Font.Bold font.weight: Font.Bold
color: { color: {
if (process && process.cpu > 80) if (process && process.cpu > 80) {
return Theme.error return Theme.error;
}
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.centerIn: parent anchors.centerIn: parent
} }
} }
Rectangle { Rectangle {
@@ -125,31 +114,29 @@ Rectangle {
height: 20 height: 20
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: { color: {
if (process && process.memoryKB > 1024 * 1024) if (process && process.memoryKB > 1024 * 1024) {
return Qt.rgba(Theme.error.r, Theme.error.g, return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12);
Theme.error.b, 0.12) }
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08);
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.08)
} }
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 102 anchors.rightMargin: 102
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
StyledText { StyledText {
text: DgopService.formatMemoryUsage( text: DgopService.formatMemoryUsage(process ? process.memoryKB : 0)
process ? process.memoryKB : 0)
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
font.weight: Font.Bold font.weight: Font.Bold
color: { color: {
if (process && process.memoryKB > 1024 * 1024) if (process && process.memoryKB > 1024 * 1024) {
return Theme.error return Theme.error;
}
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.centerIn: parent anchors.centerIn: parent
} }
} }
StyledText { StyledText {
@@ -171,10 +158,7 @@ Rectangle {
width: 28 width: 28
height: 28 height: 28
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: menuButtonArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, color: menuButtonArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
Theme.surfaceText.g,
Theme.surfaceText.b,
0.08) : "transparent"
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@@ -194,13 +178,10 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if (process && process.pid > 0 && contextMenu) { if (process && process.pid > 0 && contextMenu) {
contextMenu.processData = process contextMenu.processData = process;
let globalPos = menuButtonArea.mapToGlobal( const globalPos = menuButtonArea.mapToGlobal(menuButtonArea.width / 2, menuButtonArea.height);
menuButtonArea.width / 2, menuButtonArea.height) const localPos = contextMenu.parent ? contextMenu.parent.mapFromGlobal(globalPos.x, globalPos.y) : globalPos;
let localPos = contextMenu.parent ? contextMenu.parent.mapFromGlobal( contextMenu.show(localPos.x, localPos.y);
globalPos.x,
globalPos.y) : globalPos
contextMenu.show(localPos.x, localPos.y)
} }
} }
} }
@@ -209,7 +190,11 @@ Rectangle {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
} }
} }

View File

@@ -19,21 +19,22 @@ DankPopout {
property var triggerScreen: null property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) { function setTriggerPosition(x, y, width, section, screen) {
triggerX = x triggerX = x;
triggerY = y triggerY = y;
triggerWidth = width triggerWidth = width;
triggerSection = section triggerSection = section;
triggerScreen = screen triggerScreen = screen;
} }
function hide() { function hide() {
close() close();
if (processContextMenu.visible) if (processContextMenu.visible) {
processContextMenu.close() processContextMenu.close();
}
} }
function show() { function show() {
open() open();
} }
popupWidth: 600 popupWidth: 600
@@ -51,39 +52,43 @@ DankPopout {
service: DgopService service: DgopService
} }
ProcessContextMenu {
id: processContextMenu
}
content: Component { content: Component {
Rectangle { Rectangle {
id: processListContent id: processListContent
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Theme.popupBackground() color: Theme.popupBackground()
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
Theme.outline.b, 0.08)
border.width: 1 border.width: 1
clip: true clip: true
antialiasing: true antialiasing: true
smooth: true smooth: true
focus: true focus: true
Component.onCompleted: { Component.onCompleted: {
if (processListPopout.shouldBeVisible) if (processListPopout.shouldBeVisible) {
forceActiveFocus() forceActiveFocus();
}
} }
Keys.onPressed: (event) => {
Keys.onPressed: function (event) {
if (event.key === Qt.Key_Escape) { if (event.key === Qt.Key_Escape) {
processListPopout.close() processListPopout.close();
event.accepted = true event.accepted = true;
} }
} }
Connections { Connections {
function onShouldBeVisibleChanged() { function onShouldBeVisibleChanged() {
if (processListPopout.shouldBeVisible) if (processListPopout.shouldBeVisible) {
Qt.callLater(function () { Qt.callLater(() => {
processListContent.forceActiveFocus() processListContent.forceActiveFocus();
}) });
}
} }
target: processListPopout target: processListPopout
} }
@@ -96,11 +101,8 @@ DankPopout {
Layout.fillWidth: true Layout.fillWidth: true
height: systemOverview.height + Theme.spacingM * 2 height: systemOverview.height + Theme.spacingM * 2
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2)
Theme.surfaceVariant.g, border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
Theme.surfaceVariant.b, 0.2)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.08)
border.width: 1 border.width: 1
SystemOverview { SystemOverview {
@@ -109,17 +111,15 @@ DankPopout {
anchors.centerIn: parent anchors.centerIn: parent
width: parent.width - Theme.spacingM * 2 width: parent.width - Theme.spacingM * 2
} }
} }
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.1)
Theme.surfaceVariant.g, border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
Theme.surfaceVariant.b, 0.1)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.05)
border.width: 1 border.width: 1
ProcessListView { ProcessListView {
@@ -127,12 +127,13 @@ DankPopout {
anchors.margins: Theme.spacingS anchors.margins: Theme.spacingS
contextMenu: processContextMenu contextMenu: processContextMenu
} }
} }
} }
} }
} }
ProcessContextMenu {
id: processContextMenu
}
} }

View File

@@ -10,10 +10,10 @@ Column {
property var contextMenu: null property var contextMenu: null
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["processes"]) DgopService.addRef(["processes"]);
} }
Component.onDestruction: { Component.onDestruction: {
DgopService.removeRef(["processes"]) DgopService.removeRef(["processes"]);
} }
Item { Item {
@@ -28,14 +28,9 @@ Column {
height: 20 height: 20
color: { color: {
if (DgopService.currentSort === "name") { if (DgopService.currentSort === "name") {
return Qt.rgba(Theme.primary.r, Theme.primary.g, return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
Theme.primary.b, 0.12)
} }
return processHeaderArea.containsMouse ? Qt.rgba( return processHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent";
Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b,
0.08) : "transparent"
} }
radius: Theme.cornerRadius radius: Theme.cornerRadius
anchors.left: parent.left anchors.left: parent.left
@@ -59,7 +54,7 @@ Column {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
DgopService.setSortBy("name") DgopService.setSortBy("name");
} }
} }
@@ -67,7 +62,9 @@ Column {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
Rectangle { Rectangle {
@@ -75,14 +72,9 @@ Column {
height: 20 height: 20
color: { color: {
if (DgopService.currentSort === "cpu") { if (DgopService.currentSort === "cpu") {
return Qt.rgba(Theme.primary.r, Theme.primary.g, return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
Theme.primary.b, 0.12)
} }
return cpuHeaderArea.containsMouse ? Qt.rgba( return cpuHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent";
Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b,
0.08) : "transparent"
} }
radius: Theme.cornerRadius radius: Theme.cornerRadius
anchors.right: parent.right anchors.right: parent.right
@@ -106,7 +98,7 @@ Column {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
DgopService.setSortBy("cpu") DgopService.setSortBy("cpu");
} }
} }
@@ -114,7 +106,9 @@ Column {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
Rectangle { Rectangle {
@@ -122,14 +116,9 @@ Column {
height: 20 height: 20
color: { color: {
if (DgopService.currentSort === "memory") { if (DgopService.currentSort === "memory") {
return Qt.rgba(Theme.primary.r, Theme.primary.g, return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
Theme.primary.b, 0.12)
} }
return memoryHeaderArea.containsMouse ? Qt.rgba( return memoryHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent";
Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b,
0.08) : "transparent"
} }
radius: Theme.cornerRadius radius: Theme.cornerRadius
anchors.right: parent.right anchors.right: parent.right
@@ -153,7 +142,7 @@ Column {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
DgopService.setSortBy("memory") DgopService.setSortBy("memory");
} }
} }
@@ -161,7 +150,9 @@ Column {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
Rectangle { Rectangle {
@@ -169,14 +160,9 @@ Column {
height: 20 height: 20
color: { color: {
if (DgopService.currentSort === "pid") { if (DgopService.currentSort === "pid") {
return Qt.rgba(Theme.primary.r, Theme.primary.g, return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
Theme.primary.b, 0.12)
} }
return pidHeaderArea.containsMouse ? Qt.rgba( return pidHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent";
Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b,
0.08) : "transparent"
} }
radius: Theme.cornerRadius radius: Theme.cornerRadius
anchors.right: parent.right anchors.right: parent.right
@@ -201,7 +187,7 @@ Column {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
DgopService.setSortBy("pid") DgopService.setSortBy("pid");
} }
} }
@@ -209,17 +195,16 @@ Column {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
Rectangle { Rectangle {
width: 28 width: 28
height: 28 height: 28
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: sortOrderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, color: sortOrderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
Theme.surfaceText.g,
Theme.surfaceText.b,
0.08) : "transparent"
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 8 anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@@ -232,14 +217,14 @@ Column {
} }
MouseArea { MouseArea {
// TODO: Re-implement sort order toggle
id: sortOrderArea id: sortOrderArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
// ! TODO - we lost this with dgop
} }
} }
@@ -247,8 +232,11 @@ Column {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
} }
DankListView { DankListView {
@@ -266,5 +254,7 @@ Column {
process: modelData process: modelData
contextMenu: root.contextMenu contextMenu: root.contextMenu
} }
} }
} }

View File

@@ -19,7 +19,7 @@ ColumnLayout {
ProcessListView { ProcessListView {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
contextMenu: processesTab.contextMenu || localContextMenu contextMenu: processesTab.contextMenu
} }
ProcessContextMenu { ProcessContextMenu {

View File

@@ -8,10 +8,10 @@ Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["cpu", "memory", "system"]) DgopService.addRef(["cpu", "memory", "system"]);
} }
Component.onDestruction: { Component.onDestruction: {
DgopService.removeRef(["cpu", "memory", "system"]) DgopService.removeRef(["cpu", "memory", "system"]);
} }
Rectangle { Rectangle {
@@ -19,23 +19,15 @@ Row {
height: 80 height: 80
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: { color: {
if (DgopService.sortBy === "cpu") if (DgopService.sortBy === "cpu") {
return Qt.rgba(Theme.primary.r, Theme.primary.g, return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16);
Theme.primary.b, 0.16) } else if (cpuCardMouseArea.containsMouse) {
else if (cpuCardMouseArea.containsMouse) return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
return Qt.rgba(Theme.primary.r, Theme.primary.g, } else {
Theme.primary.b, 0.12) return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
else }
return Qt.rgba(Theme.primary.r, Theme.primary.g,
Theme.primary.b, 0.08)
} }
border.color: DgopService.sortBy === "cpu" ? Qt.rgba(Theme.primary.r, border.color: DgopService.sortBy === "cpu" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.4) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2)
Theme.primary.g,
Theme.primary.b,
0.4) : Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b, 0.2)
border.width: DgopService.sortBy === "cpu" ? 2 : 1 border.width: DgopService.sortBy === "cpu" ? 2 : 1
MouseArea { MouseArea {
@@ -44,7 +36,9 @@ Row {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: DgopService.setSortBy("cpu") onClicked: {
DgopService.setSortBy("cpu");
}
} }
Column { Column {
@@ -66,10 +60,10 @@ Row {
StyledText { StyledText {
text: { text: {
if (DgopService.cpuUsage === undefined if (DgopService.cpuUsage === undefined || DgopService.cpuUsage === null) {
|| DgopService.cpuUsage === null) return "--%";
return "--%" }
return DgopService.cpuUsage.toFixed(1) + "%" return DgopService.cpuUsage.toFixed(1) + "%";
} }
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
@@ -81,56 +75,58 @@ Row {
Rectangle { Rectangle {
width: 1 width: 1
height: 20 height: 20
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
Theme.surfaceText.b, 0.3)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: { text: {
if (DgopService.cpuTemperature === undefined if (DgopService.cpuTemperature === undefined || DgopService.cpuTemperature === null || DgopService.cpuTemperature <= 0) {
|| DgopService.cpuTemperature === null return "--°";
|| DgopService.cpuTemperature <= 0) }
return "--°" return Math.round(DgopService.cpuTemperature) + "°";
return Math.round(DgopService.cpuTemperature) + "°"
} }
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
font.weight: Font.Medium font.weight: Font.Medium
color: { color: {
if (DgopService.cpuTemperature > 80) if (DgopService.cpuTemperature > 80) {
return Theme.error return Theme.error;
}
if (DgopService.cpuTemperature > 60) if (DgopService.cpuTemperature > 60) {
return Theme.warning return Theme.warning;
}
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
StyledText { StyledText {
text: DgopService.cpuCores + " cores" text: `${DgopService.cpuCores} cores`
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: Theme.surfaceText color: Theme.surfaceText
opacity: 0.7 opacity: 0.7
} }
} }
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
Behavior on border.color { Behavior on border.color {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
Rectangle { Rectangle {
@@ -138,25 +134,15 @@ Row {
height: 80 height: 80
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: { color: {
if (DgopService.sortBy === "memory") if (DgopService.sortBy === "memory") {
return Qt.rgba(Theme.primary.r, Theme.primary.g, return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16);
Theme.primary.b, 0.16) } else if (memoryCardMouseArea.containsMouse) {
else if (memoryCardMouseArea.containsMouse) return Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.12);
return Qt.rgba(Theme.secondary.r, Theme.secondary.g, } else {
Theme.secondary.b, 0.12) return Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08);
else }
return Qt.rgba(Theme.secondary.r, Theme.secondary.g,
Theme.secondary.b, 0.08)
} }
border.color: DgopService.sortBy === "memory" ? Qt.rgba( border.color: DgopService.sortBy === "memory" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.4) : Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.2)
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.4) : Qt.rgba(
Theme.secondary.r,
Theme.secondary.g,
Theme.secondary.b,
0.2)
border.width: DgopService.sortBy === "memory" ? 2 : 1 border.width: DgopService.sortBy === "memory" ? 2 : 1
MouseArea { MouseArea {
@@ -165,7 +151,9 @@ Row {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: DgopService.setSortBy("memory") onClicked: {
DgopService.setSortBy("memory");
}
} }
Column { Column {
@@ -186,8 +174,7 @@ Row {
spacing: Theme.spacingS spacing: Theme.spacingS
StyledText { StyledText {
text: DgopService.formatSystemMemory( text: DgopService.formatSystemMemory(DgopService.usedMemoryKB)
DgopService.usedMemoryKB)
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
font.weight: Font.Bold font.weight: Font.Bold
@@ -198,15 +185,13 @@ Row {
Rectangle { Rectangle {
width: 1 width: 1
height: 20 height: 20
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
Theme.surfaceText.b, 0.3)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: DgopService.totalSwapKB > 0 visible: DgopService.totalSwapKB > 0
} }
StyledText { StyledText {
text: DgopService.totalSwapKB > 0 ? DgopService.formatSystemMemory( text: DgopService.totalSwapKB > 0 ? DgopService.formatSystemMemory(DgopService.usedSwapKB) : ""
DgopService.usedSwapKB) : ""
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
font.weight: Font.Medium font.weight: Font.Medium
@@ -214,35 +199,38 @@ Row {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: DgopService.totalSwapKB > 0 visible: DgopService.totalSwapKB > 0
} }
} }
StyledText { StyledText {
text: { text: {
if (DgopService.totalSwapKB > 0) if (DgopService.totalSwapKB > 0) {
return "of " + DgopService.formatSystemMemory( return "of " + DgopService.formatSystemMemory(DgopService.totalMemoryKB) + " + swap";
DgopService.totalMemoryKB) + " + swap" }
return "of " + DgopService.formatSystemMemory(DgopService.totalMemoryKB);
return "of " + DgopService.formatSystemMemory(
DgopService.totalMemoryKB)
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: Theme.surfaceText color: Theme.surfaceText
opacity: 0.7 opacity: 0.7
} }
} }
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
Behavior on border.color { Behavior on border.color {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
Rectangle { Rectangle {
@@ -250,74 +238,54 @@ Row {
height: 80 height: 80
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: { color: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) { if (gpuCardMouseArea.containsMouse && DgopService.availableGpus.length > 1) {
if (gpuCardMouseArea.containsMouse return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.16);
&& DgopService.availableGpus.length > 1) } else {
return Qt.rgba(Theme.surfaceVariant.r, return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
Theme.surfaceVariant.g, }
Theme.surfaceVariant.b, 0.16)
else
return Qt.rgba(Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.08)
} }
var gpu = DgopService.availableGpus[Math.min( const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
SessionData.selectedGpuIndex, const vendor = gpu.vendor.toLowerCase();
DgopService.availableGpus.length - 1)]
var vendor = gpu.vendor.toLowerCase()
if (vendor.includes("nvidia")) { if (vendor.includes("nvidia")) {
if (gpuCardMouseArea.containsMouse if (gpuCardMouseArea.containsMouse && DgopService.availableGpus.length > 1) {
&& DgopService.availableGpus.length > 1) return Qt.rgba(Theme.success.r, Theme.success.g, Theme.success.b, 0.2);
return Qt.rgba(Theme.success.r, Theme.success.g, } else {
Theme.success.b, 0.2) return Qt.rgba(Theme.success.r, Theme.success.g, Theme.success.b, 0.12);
else }
return Qt.rgba(Theme.success.r, Theme.success.g,
Theme.success.b, 0.12)
} else if (vendor.includes("amd")) { } else if (vendor.includes("amd")) {
if (gpuCardMouseArea.containsMouse if (gpuCardMouseArea.containsMouse && DgopService.availableGpus.length > 1) {
&& DgopService.availableGpus.length > 1) return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.2);
return Qt.rgba(Theme.error.r, Theme.error.g, } else {
Theme.error.b, 0.2) return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12);
else }
return Qt.rgba(Theme.error.r, Theme.error.g,
Theme.error.b, 0.12)
} else if (vendor.includes("intel")) { } else if (vendor.includes("intel")) {
if (gpuCardMouseArea.containsMouse if (gpuCardMouseArea.containsMouse && DgopService.availableGpus.length > 1) {
&& DgopService.availableGpus.length > 1) return Qt.rgba(Theme.info.r, Theme.info.g, Theme.info.b, 0.2);
return Qt.rgba(Theme.info.r, Theme.info.g, } else {
Theme.info.b, 0.2) return Qt.rgba(Theme.info.r, Theme.info.g, Theme.info.b, 0.12);
else }
return Qt.rgba(Theme.info.r, Theme.info.g, }
Theme.info.b, 0.12) if (gpuCardMouseArea.containsMouse && DgopService.availableGpus.length > 1) {
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.16);
} else {
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
} }
if (gpuCardMouseArea.containsMouse
&& DgopService.availableGpus.length > 1)
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.16)
else
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.08)
} }
border.color: { border.color: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2);
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, }
Theme.surfaceVariant.b, 0.2) const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
const vendor = gpu.vendor.toLowerCase();
var gpu = DgopService.availableGpus[Math.min( if (vendor.includes("nvidia")) {
SessionData.selectedGpuIndex, return Qt.rgba(Theme.success.r, Theme.success.g, Theme.success.b, 0.3);
DgopService.availableGpus.length - 1)] } else if (vendor.includes("amd")) {
var vendor = gpu.vendor.toLowerCase() return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3);
if (vendor.includes("nvidia")) } else if (vendor.includes("intel")) {
return Qt.rgba(Theme.success.r, Theme.success.g, return Qt.rgba(Theme.info.r, Theme.info.g, Theme.info.b, 0.3);
Theme.success.b, 0.3) }
else if (vendor.includes("amd")) return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2);
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3)
else if (vendor.includes("intel"))
return Qt.rgba(Theme.info.r, Theme.info.g, Theme.info.b, 0.3)
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.2)
} }
border.width: 1 border.width: 1
@@ -327,19 +295,17 @@ Row {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
cursorShape: DgopService.availableGpus.length cursorShape: DgopService.availableGpus.length > 1 ? Qt.PointingHandCursor : Qt.ArrowCursor
> 1 ? Qt.PointingHandCursor : Qt.ArrowCursor onClicked: (mouse) => {
onClicked: mouse => { if (mouse.button === Qt.LeftButton) {
if (mouse.button === Qt.LeftButton) { if (DgopService.availableGpus.length > 1) {
if (DgopService.availableGpus.length > 1) { const nextIndex = (SessionData.selectedGpuIndex + 1) % DgopService.availableGpus.length;
var nextIndex = (SessionData.selectedGpuIndex + 1) SessionData.setSelectedGpuIndex(nextIndex);
% DgopService.availableGpus.length }
SessionData.setSelectedGpuIndex(nextIndex) } else if (mouse.button === Qt.RightButton) {
} gpuContextMenu.popup();
} else if (mouse.button === Qt.RightButton) { }
gpuContextMenu.popup() }
}
}
} }
Column { Column {
@@ -358,69 +324,54 @@ Row {
StyledText { StyledText {
text: { text: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) return "No GPU";
return "No GPU" }
const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
var gpu = DgopService.availableGpus[Math.min(
SessionData.selectedGpuIndex,
DgopService.availableGpus.length - 1)]
// Check if temperature monitoring is enabled for this GPU // Check if temperature monitoring is enabled for this GPU
var tempEnabled = SessionData.enabledGpuPciIds const tempEnabled = SessionData.enabledGpuPciIds && SessionData.enabledGpuPciIds.indexOf(gpu.pciId) !== -1;
&& SessionData.enabledGpuPciIds.indexOf( const temp = gpu.temperature;
gpu.pciId) !== -1 const hasTemp = tempEnabled && temp !== undefined && temp !== null && temp !== 0;
var temp = gpu.temperature if (hasTemp) {
var hasTemp = tempEnabled && temp !== undefined return Math.round(temp) + "°";
&& temp !== null && temp !== 0 } else {
if (hasTemp) return gpu.vendor;
return Math.round(temp) + "°" }
else
return gpu.vendor
} }
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
font.weight: Font.Bold font.weight: Font.Bold
color: { color: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) return Theme.surfaceText;
return Theme.surfaceText }
const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
var gpu = DgopService.availableGpus[Math.min( const tempEnabled = SessionData.enabledGpuPciIds && SessionData.enabledGpuPciIds.indexOf(gpu.pciId) !== -1;
SessionData.selectedGpuIndex, const temp = gpu.temperature || 0;
DgopService.availableGpus.length - 1)] if (tempEnabled && temp > 80) {
var tempEnabled = SessionData.enabledGpuPciIds return Theme.error;
&& SessionData.enabledGpuPciIds.indexOf( }
gpu.pciId) !== -1 if (tempEnabled && temp > 60) {
var temp = gpu.temperature || 0 return Theme.warning;
if (tempEnabled && temp > 80) }
return Theme.error return Theme.surfaceText;
if (tempEnabled && temp > 60)
return Theme.warning
return Theme.surfaceText
} }
} }
StyledText { StyledText {
text: { text: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) return "No GPUs detected";
return "No GPUs detected" }
const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
var gpu = DgopService.availableGpus[Math.min( const tempEnabled = SessionData.enabledGpuPciIds && SessionData.enabledGpuPciIds.indexOf(gpu.pciId) !== -1;
SessionData.selectedGpuIndex, const temp = gpu.temperature;
DgopService.availableGpus.length - 1)] const hasTemp = tempEnabled && temp !== undefined && temp !== null && temp !== 0;
var tempEnabled = SessionData.enabledGpuPciIds if (hasTemp) {
&& SessionData.enabledGpuPciIds.indexOf( return gpu.vendor + " " + gpu.displayName;
gpu.pciId) !== -1 } else {
var temp = gpu.temperature return gpu.displayName;
var hasTemp = tempEnabled && temp !== undefined }
&& temp !== null && temp !== 0
if (hasTemp)
return gpu.vendor + " " + gpu.displayName
else
return gpu.displayName
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
@@ -430,6 +381,7 @@ Row {
elide: Text.ElideRight elide: Text.ElideRight
maximumLineCount: 1 maximumLineCount: 1
} }
} }
Menu { Menu {
@@ -439,53 +391,45 @@ Row {
text: "Enable GPU Temperature" text: "Enable GPU Temperature"
checkable: true checkable: true
checked: { checked: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) { return false;
return false
} }
const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
var gpu = DgopService.availableGpus[Math.min( if (!gpu.pciId) {
SessionData.selectedGpuIndex, return false;
DgopService.availableGpus.length - 1)] }
if (!gpu.pciId) return SessionData.enabledGpuPciIds ? SessionData.enabledGpuPciIds.indexOf(gpu.pciId) !== -1 : false;
return false
return SessionData.enabledGpuPciIds ? SessionData.enabledGpuPciIds.indexOf(
gpu.pciId) !== -1 : false
} }
onTriggered: { onTriggered: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) { return;
return
} }
const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
var gpu = DgopService.availableGpus[Math.min( if (!gpu.pciId) {
SessionData.selectedGpuIndex, return;
DgopService.availableGpus.length - 1)] }
if (!gpu.pciId) const enabledIds = SessionData.enabledGpuPciIds ? SessionData.enabledGpuPciIds.slice() : [];
return const index = enabledIds.indexOf(gpu.pciId);
var enabledIds = SessionData.enabledGpuPciIds ? SessionData.enabledGpuPciIds.slice(
) : []
var index = enabledIds.indexOf(gpu.pciId)
if (checked && index === -1) { if (checked && index === -1) {
enabledIds.push(gpu.pciId) enabledIds.push(gpu.pciId);
DgopService.addGpuPciId(gpu.pciId) DgopService.addGpuPciId(gpu.pciId);
} else if (!checked && index !== -1) { } else if (!checked && index !== -1) {
enabledIds.splice(index, 1) enabledIds.splice(index, 1);
DgopService.removeGpuPciId(gpu.pciId) DgopService.removeGpuPciId(gpu.pciId);
} }
SessionData.setEnabledGpuPciIds(enabledIds);
SessionData.setEnabledGpuPciIds(enabledIds)
} }
} }
} }
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
} }

View File

@@ -8,14 +8,15 @@ DankFlickable {
anchors.fill: parent anchors.fill: parent
contentHeight: systemColumn.implicitHeight contentHeight: systemColumn.implicitHeight
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["system", "hardware", "diskmounts"]) DgopService.addRef(["system", "hardware", "diskmounts"]);
} }
Component.onDestruction: { Component.onDestruction: {
DgopService.removeRef(["system", "hardware", "diskmounts"]) DgopService.removeRef(["system", "hardware", "diskmounts"]);
} }
Column { Column {
id: systemColumn id: systemColumn
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
@@ -23,8 +24,7 @@ DankFlickable {
width: parent.width width: parent.width
height: systemInfoColumn.implicitHeight + 2 * Theme.spacingL height: systemInfoColumn.implicitHeight + 2 * Theme.spacingL
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.6)
Theme.surfaceContainer.b, 0.6)
border.width: 0 border.width: 0
Column { Column {
@@ -60,46 +60,37 @@ DankFlickable {
} }
StyledText { StyledText {
text: DgopService.distribution + " • " + DgopService.architecture text: `${DgopService.distribution} ${DgopService.architecture} ${DgopService.kernelVersion}`
+ " • " + DgopService.kernelVersion
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: Qt.rgba(Theme.surfaceText.r, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
Theme.surfaceText.g,
Theme.surfaceText.b, 0.7)
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
StyledText { StyledText {
text: "Up " + UserInfoService.uptime + " • Boot: " text: `Up ${UserInfoService.uptime} Boot: ${DgopService.bootTime}`
+ DgopService.bootTime
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: Qt.rgba(Theme.surfaceText.r, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
Theme.surfaceText.g,
Theme.surfaceText.b, 0.6)
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
StyledText { StyledText {
text: "Load: " + DgopService.loadAverage + " • " text: `Load: ${DgopService.loadAverage} ${DgopService.processCount} processes, ${DgopService.threadCount} threads`
+ DgopService.processCount + " processes, "
+ DgopService.threadCount + " threads"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: Qt.rgba(Theme.surfaceText.r, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
Theme.surfaceText.g,
Theme.surfaceText.b, 0.6)
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
} }
} }
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 1 height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
Theme.outline.b, 0.2)
} }
Row { Row {
@@ -110,12 +101,9 @@ DankFlickable {
width: (parent.width - Theme.spacingXL) / 2 width: (parent.width - Theme.spacingXL) / 2
height: hardwareColumn.implicitHeight + Theme.spacingL height: hardwareColumn.implicitHeight + Theme.spacingL
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainerHigh.r, color: Qt.rgba(Theme.surfaceContainerHigh.r, Theme.surfaceContainerHigh.g, Theme.surfaceContainerHigh.b, 0.4)
Theme.surfaceContainerHigh.g,
Theme.surfaceContainerHigh.b, 0.4)
border.width: 1 border.width: 1
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
Theme.outline.b, 0.1)
Column { Column {
id: hardwareColumn id: hardwareColumn
@@ -145,6 +133,7 @@ DankFlickable {
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
StyledText { StyledText {
@@ -164,9 +153,7 @@ DankFlickable {
text: DgopService.motherboard text: DgopService.motherboard
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: Qt.rgba(Theme.surfaceText.r, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8)
Theme.surfaceText.g,
Theme.surfaceText.b, 0.8)
width: parent.width width: parent.width
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
@@ -175,30 +162,27 @@ DankFlickable {
} }
StyledText { StyledText {
text: "BIOS " + DgopService.biosVersion text: `BIOS ${DgopService.biosVersion}`
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: Qt.rgba(Theme.surfaceText.r, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
Theme.surfaceText.g,
Theme.surfaceText.b, 0.7)
width: parent.width width: parent.width
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
StyledText { StyledText {
text: DgopService.formatSystemMemory( text: `${DgopService.formatSystemMemory(DgopService.totalMemoryKB)} RAM`
DgopService.totalMemoryKB) + " RAM"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: Qt.rgba(Theme.surfaceText.r, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8)
Theme.surfaceText.g,
Theme.surfaceText.b, 0.8)
width: parent.width width: parent.width
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
} }
} }
Rectangle { Rectangle {
@@ -206,100 +190,58 @@ DankFlickable {
height: gpuColumn.implicitHeight + Theme.spacingL height: gpuColumn.implicitHeight + Theme.spacingL
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: { color: {
var baseColor = Qt.rgba( const baseColor = Qt.rgba(Theme.surfaceContainerHigh.r, Theme.surfaceContainerHigh.g, Theme.surfaceContainerHigh.b, 0.4);
Theme.surfaceContainerHigh.r, const hoverColor = Qt.rgba(Theme.surfaceContainerHigh.r, Theme.surfaceContainerHigh.g, Theme.surfaceContainerHigh.b, 0.6);
Theme.surfaceContainerHigh.g, if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
Theme.surfaceContainerHigh.b, 0.4) return gpuCardMouseArea.containsMouse && DgopService.availableGpus.length > 1 ? hoverColor : baseColor;
var hoverColor = Qt.rgba(
Theme.surfaceContainerHigh.r,
Theme.surfaceContainerHigh.g,
Theme.surfaceContainerHigh.b, 0.6)
if (!DgopService.availableGpus
|| DgopService.availableGpus.length === 0) {
return gpuCardMouseArea.containsMouse
&& DgopService.availableGpus.length
> 1 ? hoverColor : baseColor
} }
var gpu = DgopService.availableGpus[Math.min( const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
SessionData.selectedGpuIndex, const vendor = gpu.fullName.split(' ')[0].toLowerCase();
DgopService.availableGpus.length let tintColor;
- 1)]
var vendor = gpu.fullName.split(
' ')[0].toLowerCase()
var tintColor
if (vendor.includes("nvidia")) { if (vendor.includes("nvidia")) {
tintColor = Theme.success tintColor = Theme.success;
} else if (vendor.includes("amd")) { } else if (vendor.includes("amd")) {
tintColor = Theme.error tintColor = Theme.error;
} else if (vendor.includes("intel")) { } else if (vendor.includes("intel")) {
tintColor = Theme.info tintColor = Theme.info;
} else { } else {
return gpuCardMouseArea.containsMouse return gpuCardMouseArea.containsMouse && DgopService.availableGpus.length > 1 ? hoverColor : baseColor;
&& DgopService.availableGpus.length
> 1 ? hoverColor : baseColor
} }
if (gpuCardMouseArea.containsMouse && DgopService.availableGpus.length > 1) {
if (gpuCardMouseArea.containsMouse return Qt.rgba((hoverColor.r + tintColor.r * 0.1) / 1.1, (hoverColor.g + tintColor.g * 0.1) / 1.1, (hoverColor.b + tintColor.b * 0.1) / 1.1, 0.6);
&& DgopService.availableGpus.length > 1) {
return Qt.rgba(
(hoverColor.r + tintColor.r * 0.1) / 1.1,
(hoverColor.g + tintColor.g * 0.1) / 1.1,
(hoverColor.b + tintColor.b * 0.1) / 1.1,
0.6)
} else { } else {
return Qt.rgba( return Qt.rgba((baseColor.r + tintColor.r * 0.08) / 1.08, (baseColor.g + tintColor.g * 0.08) / 1.08, (baseColor.b + tintColor.b * 0.08) / 1.08, 0.4);
(baseColor.r + tintColor.r * 0.08) / 1.08,
(baseColor.g + tintColor.g * 0.08) / 1.08,
(baseColor.b + tintColor.b * 0.08) / 1.08,
0.4)
} }
} }
border.width: 1 border.width: 1
border.color: { border.color: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) { return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1);
return Qt.rgba(Theme.outline.r,
Theme.outline.g,
Theme.outline.b, 0.1)
} }
var gpu = DgopService.availableGpus[Math.min( const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
SessionData.selectedGpuIndex, const vendor = gpu.fullName.split(' ')[0].toLowerCase();
DgopService.availableGpus.length
- 1)]
var vendor = gpu.fullName.split(
' ')[0].toLowerCase()
if (vendor.includes("nvidia")) { if (vendor.includes("nvidia")) {
return Qt.rgba(Theme.success.r, return Qt.rgba(Theme.success.r, Theme.success.g, Theme.success.b, 0.3);
Theme.success.g,
Theme.success.b, 0.3)
} else if (vendor.includes("amd")) { } else if (vendor.includes("amd")) {
return Qt.rgba(Theme.error.r, Theme.error.g, return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3);
Theme.error.b, 0.3)
} else if (vendor.includes("intel")) { } else if (vendor.includes("intel")) {
return Qt.rgba(Theme.info.r, Theme.info.g, return Qt.rgba(Theme.info.r, Theme.info.g, Theme.info.b, 0.3);
Theme.info.b, 0.3)
} }
return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1);
return Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.1)
} }
MouseArea { MouseArea {
id: gpuCardMouseArea id: gpuCardMouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: DgopService.availableGpus.length cursorShape: DgopService.availableGpus.length > 1 ? Qt.PointingHandCursor : Qt.ArrowCursor
> 1 ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: { onClicked: {
if (DgopService.availableGpus.length > 1) { if (DgopService.availableGpus.length > 1) {
var nextIndex = (SessionData.selectedGpuIndex + 1) const nextIndex = (SessionData.selectedGpuIndex + 1) % DgopService.availableGpus.length;
% DgopService.availableGpus.length SessionData.setSelectedGpuIndex(nextIndex);
SessionData.setSelectedGpuIndex(nextIndex)
} }
} }
} }
@@ -332,17 +274,17 @@ DankFlickable {
color: Theme.secondary color: Theme.secondary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
StyledText { StyledText {
text: { text: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) { return "No GPUs detected";
return "No GPUs detected"
} }
var gpu = DgopService.availableGpus[Math.min(
SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)] const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
return gpu.fullName return gpu.fullName;
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
@@ -356,19 +298,16 @@ DankFlickable {
StyledText { StyledText {
text: { text: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) { return "Device: N/A";
return "Device: N/A"
} }
var gpu = DgopService.availableGpus[Math.min(
SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)] const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
return "Device: " + gpu.pciId return `Device: ${gpu.pciId}`;
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: Qt.rgba(Theme.surfaceText.r, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8)
Theme.surfaceText.g,
Theme.surfaceText.b, 0.8)
width: parent.width width: parent.width
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
@@ -377,19 +316,16 @@ DankFlickable {
StyledText { StyledText {
text: { text: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) { return "Driver: N/A";
return "Driver: N/A"
} }
var gpu = DgopService.availableGpus[Math.min(
SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)] const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
return "Driver: " + gpu.driver return `Driver: ${gpu.driver}`;
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: Qt.rgba(Theme.surfaceText.r, color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8)
Theme.surfaceText.g,
Theme.surfaceText.b, 0.8)
width: parent.width width: parent.width
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
@@ -397,60 +333,60 @@ DankFlickable {
StyledText { StyledText {
text: { text: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) { return "Temp: --°";
return "Temp: --°"
} }
var gpu = DgopService.availableGpus[Math.min(
SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)] const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
var temp = gpu.temperature const temp = gpu.temperature;
return "Temp: " + ((temp === undefined return `Temp: ${(temp === undefined || temp === null || temp === 0) ? '--°' : `${Math.round(temp)}°C`}`;
|| temp === null
|| temp === 0) ? "--°" : Math.round(
temp) + "°C")
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: { color: {
if (!DgopService.availableGpus if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|| DgopService.availableGpus.length === 0) { return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7);
return Qt.rgba(Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b, 0.7)
} }
var gpu = DgopService.availableGpus[Math.min(
SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)] const gpu = DgopService.availableGpus[Math.min(SessionData.selectedGpuIndex, DgopService.availableGpus.length - 1)];
var temp = gpu.temperature || 0 const temp = gpu.temperature || 0;
if (temp > 80) if (temp > 80) {
return Theme.error return Theme.error;
if (temp > 60) }
return Theme.warning
return Qt.rgba(Theme.surfaceText.r, if (temp > 60) {
Theme.surfaceText.g, return Theme.warning;
Theme.surfaceText.b, 0.7) }
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7);
} }
width: parent.width width: parent.width
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
} }
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
} }
} }
} }
Rectangle { Rectangle {
width: parent.width width: parent.width
height: storageColumn.implicitHeight + 2 * Theme.spacingL height: storageColumn.implicitHeight + 2 * Theme.spacingL
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.6)
Theme.surfaceContainer.b, 0.6)
border.width: 0 border.width: 0
Column { Column {
@@ -481,6 +417,7 @@ DankFlickable {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Column { Column {
@@ -557,6 +494,7 @@ DankFlickable {
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
} }
Repeater { Repeater {
@@ -568,11 +506,7 @@ DankFlickable {
width: parent.width width: parent.width
height: 24 height: 24
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: diskMouseArea.containsMouse ? Qt.rgba( color: diskMouseArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.04) : "transparent"
Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b,
0.04) : "transparent"
MouseArea { MouseArea {
id: diskMouseArea id: diskMouseArea
@@ -645,26 +579,35 @@ DankFlickable {
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: { color: {
const percent = parseInt( const percent = parseInt(modelData.percent);
modelData.percent) if (percent > 90) {
if (percent > 90) return Theme.error;
return Theme.error }
if (percent > 75) if (percent > 75) {
return Theme.warning return Theme.warning;
}
return Theme.surfaceText return Theme.surfaceText;
} }
width: parent.width * 0.1 width: parent.width * 0.1
elide: Text.ElideRight elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
} }
} }
} }
} }
} }
} }
} }
} }

View File

@@ -8,19 +8,21 @@ Item {
readonly property MprisPlayer activePlayer: MprisController.activePlayer readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property bool hasActiveMedia: activePlayer !== null readonly property bool hasActiveMedia: activePlayer !== null
readonly property bool isPlaying: hasActiveMedia && activePlayer readonly property bool isPlaying: hasActiveMedia && activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing
&& activePlayer.playbackState === MprisPlaybackState.Playing
width: 20 width: 20
height: Theme.iconSize height: Theme.iconSize
Loader { Loader {
active: isPlaying active: isPlaying
sourceComponent: Component { sourceComponent: Component {
Ref { Ref {
service: CavaService service: CavaService
} }
} }
} }
Timer { Timer {
@@ -30,10 +32,7 @@ Item {
interval: 256 interval: 256
repeat: true repeat: true
onTriggered: { onTriggered: {
CavaService.values = [Math.random() * 40 + 10, Math.random( 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];
) * 60 + 20, Math.random() * 50 + 15, Math.random(
) * 35 + 20, Math.random() * 45 + 15, Math.random(
) * 55 + 25]
} }
} }
@@ -48,15 +47,13 @@ Item {
width: 2 width: 2
height: { height: {
if (root.isPlaying && CavaService.values.length > index) { if (root.isPlaying && CavaService.values.length > index) {
const rawLevel = CavaService.values[index] || 0 const rawLevel = CavaService.values[index] || 0;
const scaledLevel = Math.sqrt( const scaledLevel = Math.sqrt(Math.min(Math.max(rawLevel, 0), 100) / 100) * 100;
Math.min(Math.max(rawLevel, 0), const maxHeight = Theme.iconSize - 2;
100) / 100) * 100 const minHeight = 3;
const maxHeight = Theme.iconSize - 2 return minHeight + (scaledLevel / 100) * (maxHeight - minHeight);
const minHeight = 3
return minHeight + (scaledLevel / 100) * (maxHeight - minHeight)
} }
return 3 return 3;
} }
radius: 1.5 radius: 1.5
color: Theme.primary color: Theme.primary
@@ -68,8 +65,13 @@ Item {
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.standardDecel easing.bezierCurve: Anims.standardDecel
} }
} }
} }
} }
} }
} }

View File

@@ -15,113 +15,156 @@ Rectangle {
property real barHeight: 48 property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30)) readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal toggleBatteryPopup signal toggleBatteryPopup()
width: batteryContent.implicitWidth + horizontalPadding * 2 width: batteryContent.implicitWidth + horizontalPadding * 2
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground)
const baseColor = batteryArea.containsMouse return "transparent";
|| batteryPopupVisible ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, const baseColor = batteryArea.containsMouse || batteryPopupVisible ? Theme.primaryPressed : Theme.secondaryHover;
baseColor.a * Theme.widgetTransparency) return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
visible: true visible: true
Row { Row {
id: batteryContent id: batteryContent
anchors.centerIn: parent anchors.centerIn: parent
spacing: SettingsData.topBarNoBackground ? 1 : 2 spacing: SettingsData.topBarNoBackground ? 1 : 2
DankIcon { DankIcon {
name: { name: {
if (!BatteryService.batteryAvailable) if (!BatteryService.batteryAvailable) {
return "power" return "power";
}
if (BatteryService.isCharging) { if (BatteryService.isCharging) {
if (BatteryService.batteryLevel >= 90) if (BatteryService.batteryLevel >= 90) {
return "battery_charging_full" 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 >= 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";
}
// Check if plugged in but not charging (like at 80% charge limit) // Check if plugged in but not charging (like at 80% charge limit)
if (BatteryService.isPluggedIn) { if (BatteryService.isPluggedIn) {
if (BatteryService.batteryLevel >= 90) if (BatteryService.batteryLevel >= 90) {
return "battery_charging_full" return "battery_charging_full";
if (BatteryService.batteryLevel >= 80) }
return "battery_charging_90"
if (BatteryService.batteryLevel >= 60) if (BatteryService.batteryLevel >= 80) {
return "battery_charging_80" return "battery_charging_90";
if (BatteryService.batteryLevel >= 50) }
return "battery_charging_60"
if (BatteryService.batteryLevel >= 30) if (BatteryService.batteryLevel >= 60) {
return "battery_charging_50" return "battery_charging_80";
if (BatteryService.batteryLevel >= 20) }
return "battery_charging_30"
return "battery_charging_20" 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";
}
// On battery power
if (BatteryService.batteryLevel >= 95) {
return "battery_full";
} }
// On battery power if (BatteryService.batteryLevel >= 85) {
if (BatteryService.batteryLevel >= 95) return "battery_6_bar";
return "battery_full" }
if (BatteryService.batteryLevel >= 85)
return "battery_6_bar" if (BatteryService.batteryLevel >= 70) {
if (BatteryService.batteryLevel >= 70) return "battery_5_bar";
return "battery_5_bar" }
if (BatteryService.batteryLevel >= 55)
return "battery_4_bar" if (BatteryService.batteryLevel >= 55) {
if (BatteryService.batteryLevel >= 40) return "battery_4_bar";
return "battery_3_bar" }
if (BatteryService.batteryLevel >= 25)
return "battery_2_bar" if (BatteryService.batteryLevel >= 40) {
return "battery_1_bar" return "battery_3_bar";
}
if (BatteryService.batteryLevel >= 25) {
return "battery_2_bar";
}
return "battery_1_bar";
} }
size: Theme.iconSize - 6 size: Theme.iconSize - 6
color: { color: {
if (!BatteryService.batteryAvailable) if (!BatteryService.batteryAvailable) {
return Theme.surfaceText return Theme.surfaceText;
}
if (BatteryService.isLowBattery && !BatteryService.isCharging) if (BatteryService.isLowBattery && !BatteryService.isCharging) {
return Theme.error return Theme.error;
}
if (BatteryService.isCharging || BatteryService.isPluggedIn) if (BatteryService.isCharging || BatteryService.isPluggedIn) {
return Theme.primary return Theme.primary;
}
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: BatteryService.batteryLevel + "%" text: `${BatteryService.batteryLevel}%`
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium font.weight: Font.Medium
color: { color: {
if (!BatteryService.batteryAvailable) if (!BatteryService.batteryAvailable) {
return Theme.surfaceText return Theme.surfaceText;
}
if (BatteryService.isLowBattery && !BatteryService.isCharging) if (BatteryService.isLowBattery && !BatteryService.isCharging) {
return Theme.error return Theme.error;
}
if (BatteryService.isCharging) if (BatteryService.isCharging) {
return Theme.primary return Theme.primary;
}
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: BatteryService.batteryAvailable visible: BatteryService.batteryAvailable
} }
} }
MouseArea { MouseArea {
@@ -132,15 +175,13 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) { if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0 const screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition( popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
} }
toggleBatteryPopup() toggleBatteryPopup();
} }
} }
@@ -168,30 +209,33 @@ Rectangle {
text: { text: {
if (!BatteryService.batteryAvailable) { if (!BatteryService.batteryAvailable) {
if (typeof PowerProfiles === "undefined") if (typeof PowerProfiles === "undefined") {
return "Power Management" return "Power Management";
}
switch (PowerProfiles.profile) { switch (PowerProfiles.profile) {
case PowerProfile.PowerSaver: case PowerProfile.PowerSaver:
return "Power Profile: Power Saver" return "Power Profile: Power Saver";
case PowerProfile.Performance: case PowerProfile.Performance:
return "Power Profile: Performance" return "Power Profile: Performance";
default: default:
return "Power Profile: Balanced" return "Power Profile: Balanced";
} }
} }
let status = BatteryService.batteryStatus const status = BatteryService.batteryStatus;
let level = BatteryService.batteryLevel + "%" const level = `${BatteryService.batteryLevel}%`;
let time = BatteryService.formatTimeRemaining() const time = BatteryService.formatTimeRemaining();
if (time !== "Unknown") if (time !== "Unknown") {
return status + " • " + level + " • " + time return `${status} ${level} ${time}`;
else } else {
return status + " • " + level return `${status} ${level}`;
}
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
} }
Behavior on opacity { Behavior on opacity {
@@ -199,7 +243,9 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
Behavior on color { Behavior on color {
@@ -207,5 +253,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }

View File

@@ -15,28 +15,31 @@ DankPopout {
property var triggerScreen: null property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) { function setTriggerPosition(x, y, width, section, screen) {
triggerX = x triggerX = x;
triggerY = y triggerY = y;
triggerWidth = width triggerWidth = width;
triggerSection = section triggerSection = section;
triggerScreen = screen triggerScreen = screen;
} }
function isActiveProfile(profile) { function isActiveProfile(profile) {
if (typeof PowerProfiles === "undefined") if (typeof PowerProfiles === "undefined") {
return false return false;
}
return PowerProfiles.profile === profile return PowerProfiles.profile === profile;
} }
function setProfile(profile) { function setProfile(profile) {
if (typeof PowerProfiles === "undefined") { if (typeof PowerProfiles === "undefined") {
ToastService.showError("power-profiles-daemon not available") ToastService.showError("power-profiles-daemon not available");
return return ;
} }
PowerProfiles.profile = profile PowerProfiles.profile = profile;
if (PowerProfiles.profile !== profile) if (PowerProfiles.profile !== profile) {
ToastService.showError("Failed to set power profile") ToastService.showError("Failed to set power profile");
}
} }
popupWidth: 400 popupWidth: 400
@@ -62,26 +65,29 @@ DankPopout {
antialiasing: true antialiasing: true
smooth: true smooth: true
focus: true focus: true
Component.onCompleted: { Component.onCompleted: {
if (root.shouldBeVisible) if (root.shouldBeVisible) {
forceActiveFocus() forceActiveFocus();
} }
Keys.onPressed: function (event) { }
Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape) { if (event.key === Qt.Key_Escape) {
root.close() root.close();
event.accepted = true event.accepted = true;
} }
} }
Connections { Connections {
function onShouldBeVisibleChanged() { function onShouldBeVisibleChanged() {
if (root.shouldBeVisible) if (root.shouldBeVisible) {
Qt.callLater(function () { Qt.callLater(function() {
batteryContent.forceActiveFocus() batteryContent.forceActiveFocus();
}) });
}
} }
target: root target: root
} }
@@ -116,6 +122,7 @@ DankPopout {
Column { Column {
id: contentColumn id: contentColumn
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
@@ -156,23 +163,21 @@ DankPopout {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
root.close() root.close();
} }
} }
} }
} }
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 80 height: 80
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.4)
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
Theme.getContentBackgroundAlpha() * 0.4)
border.color: BatteryService.isCharging ? Theme.primary : (BatteryService.isLowBattery ? Theme.error : Theme.outlineMedium) border.color: BatteryService.isCharging ? Theme.primary : (BatteryService.isLowBattery ? Theme.error : Theme.outlineMedium)
border.width: BatteryService.isCharging border.width: BatteryService.isCharging || BatteryService.isLowBattery ? 2 : 1
|| BatteryService.isLowBattery ? 2 : 1
visible: BatteryService.batteryAvailable visible: BatteryService.batteryAvailable
Row { Row {
@@ -184,67 +189,99 @@ DankPopout {
DankIcon { DankIcon {
name: { name: {
if (!BatteryService.batteryAvailable) if (!BatteryService.batteryAvailable)
return "power" return "power";
// Check if plugged in but not charging (like at 80% charge limit) // Check if plugged in but not charging (like at 80% charge limit)
if (!BatteryService.isCharging if (!BatteryService.isCharging && BatteryService.isPluggedIn) {
&& BatteryService.isPluggedIn) { if (BatteryService.batteryLevel >= 90) {
if (BatteryService.batteryLevel >= 90) return "battery_charging_full";
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 >= 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.isCharging) {
if (BatteryService.batteryLevel >= 90) if (BatteryService.batteryLevel >= 90) {
return "battery_charging_full" return "battery_charging_full";
if (BatteryService.batteryLevel >= 80) }
return "battery_charging_90"
if (BatteryService.batteryLevel >= 60) if (BatteryService.batteryLevel >= 80) {
return "battery_charging_80" return "battery_charging_90";
if (BatteryService.batteryLevel >= 50) }
return "battery_charging_60"
if (BatteryService.batteryLevel >= 30) if (BatteryService.batteryLevel >= 60) {
return "battery_charging_50" return "battery_charging_80";
if (BatteryService.batteryLevel >= 20) }
return "battery_charging_30"
return "battery_charging_20" 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 { } else {
if (BatteryService.batteryLevel >= 95) if (BatteryService.batteryLevel >= 95) {
return "battery_full" return "battery_full";
if (BatteryService.batteryLevel >= 85) }
return "battery_6_bar"
if (BatteryService.batteryLevel >= 70) if (BatteryService.batteryLevel >= 85) {
return "battery_5_bar" return "battery_6_bar";
if (BatteryService.batteryLevel >= 55) }
return "battery_4_bar"
if (BatteryService.batteryLevel >= 40) if (BatteryService.batteryLevel >= 70) {
return "battery_3_bar" return "battery_5_bar";
if (BatteryService.batteryLevel >= 25) }
return "battery_2_bar"
return "battery_1_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 size: Theme.iconSizeLarge
color: { color: {
if (BatteryService.isLowBattery if (BatteryService.isLowBattery && !BatteryService.isCharging)
&& !BatteryService.isCharging) return Theme.error;
return Theme.error
if (BatteryService.isCharging if (BatteryService.isCharging || BatteryService.isPluggedIn)
|| BatteryService.isPluggedIn) return Theme.primary;
return Theme.primary
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@@ -257,17 +294,18 @@ DankPopout {
spacing: Theme.spacingM spacing: Theme.spacingM
StyledText { StyledText {
text: BatteryService.batteryLevel + "%" text: `${BatteryService.batteryLevel}%`
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
color: { color: {
if (BatteryService.isLowBattery if (BatteryService.isLowBattery && !BatteryService.isCharging) {
&& !BatteryService.isCharging) return Theme.error;
return Theme.error }
if (BatteryService.isCharging) if (BatteryService.isCharging) {
return Theme.primary return Theme.primary;
}
return Theme.surfaceText return Theme.surfaceText;
} }
font.weight: Font.Bold font.weight: Font.Bold
} }
@@ -276,44 +314,47 @@ DankPopout {
text: BatteryService.batteryStatus text: BatteryService.batteryStatus
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: { color: {
if (BatteryService.isLowBattery if (BatteryService.isLowBattery && !BatteryService.isCharging) {
&& !BatteryService.isCharging) return Theme.error;
return Theme.error }
if (BatteryService.isCharging) if (BatteryService.isCharging) {
return Theme.primary return Theme.primary;
}
return Theme.surfaceText return Theme.surfaceText;
} }
font.weight: Font.Medium font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
StyledText { StyledText {
text: { text: {
let time = BatteryService.formatTimeRemaining() const time = BatteryService.formatTimeRemaining();
if (time !== "Unknown") if (time !== "Unknown") {
return BatteryService.isCharging ? "Time until full: " + time : "Time remaining: " + time return BatteryService.isCharging ? `Time until full: ${time}` : `Time remaining: ${time}`;
}
return "" return "";
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium color: Theme.surfaceTextMedium
visible: text.length > 0 visible: text.length > 0
} }
} }
} }
} }
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 80 height: 80
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.4)
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
Theme.getContentBackgroundAlpha() * 0.4)
border.color: Theme.outlineMedium border.color: Theme.outlineMedium
border.width: 1 border.width: 1
visible: !BatteryService.batteryAvailable visible: !BatteryService.batteryAvailable
@@ -345,8 +386,11 @@ DankPopout {
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceTextMedium color: Theme.surfaceTextMedium
} }
} }
} }
} }
Column { Column {
@@ -380,14 +424,15 @@ DankPopout {
text: BatteryService.batteryHealth text: BatteryService.batteryHealth
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: { color: {
if (BatteryService.batteryHealth === "N/A") if (BatteryService.batteryHealth === "N/A") {
return Theme.surfaceText return Theme.surfaceText;
}
var healthNum = parseInt( const healthNum = parseInt(BatteryService.batteryHealth);
BatteryService.batteryHealth) return healthNum < 80 ? Theme.error : Theme.surfaceText;
return healthNum < 80 ? Theme.error : Theme.surfaceText
} }
} }
} }
Column { Column {
@@ -402,14 +447,15 @@ DankPopout {
} }
StyledText { StyledText {
text: BatteryService.batteryCapacity text: BatteryService.batteryCapacity > 0 ? `${BatteryService.batteryCapacity.toFixed(1)} Wh` : "Unknown"
> 0 ? BatteryService.batteryCapacity.toFixed(
1) + " Wh" : "Unknown"
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText color: Theme.surfaceText
} }
} }
} }
} }
Column { Column {
@@ -436,10 +482,8 @@ DankPopout {
height: 50 height: 50
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: profileArea.containsMouse ? Theme.primaryHoverLight : (root.isActiveProfile(modelData) ? Theme.primaryPressed : Theme.surfaceLight) color: profileArea.containsMouse ? Theme.primaryHoverLight : (root.isActiveProfile(modelData) ? Theme.primaryPressed : Theme.surfaceLight)
border.color: root.isActiveProfile( border.color: root.isActiveProfile(modelData) ? Theme.primary : Theme.outlineLight
modelData) ? Theme.primary : Theme.outlineLight border.width: root.isActiveProfile(modelData) ? 2 : 1
border.width: root.isActiveProfile(
modelData) ? 2 : 1
Row { Row {
anchors.left: parent.left anchors.left: parent.left
@@ -448,11 +492,9 @@ DankPopout {
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { DankIcon {
name: Theme.getPowerProfileIcon( name: Theme.getPowerProfileIcon(modelData)
modelData)
size: Theme.iconSize size: Theme.iconSize
color: root.isActiveProfile( color: root.isActiveProfile(modelData) ? Theme.primary : Theme.surfaceText
modelData) ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@@ -461,22 +503,20 @@ DankPopout {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
StyledText { StyledText {
text: Theme.getPowerProfileLabel( text: Theme.getPowerProfileLabel(modelData)
modelData)
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: root.isActiveProfile( color: root.isActiveProfile(modelData) ? Theme.primary : Theme.surfaceText
modelData) ? Theme.primary : Theme.surfaceText font.weight: root.isActiveProfile(modelData) ? Font.Medium : Font.Normal
font.weight: root.isActiveProfile(
modelData) ? Font.Medium : Font.Normal
} }
StyledText { StyledText {
text: Theme.getPowerProfileDescription( text: Theme.getPowerProfileDescription(modelData)
modelData)
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium color: Theme.surfaceTextMedium
} }
} }
} }
MouseArea { MouseArea {
@@ -486,12 +526,16 @@ DankPopout {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
root.setProfile(modelData) root.setProfile(modelData);
} }
} }
} }
} }
} }
} }
Rectangle { Rectangle {
@@ -501,9 +545,7 @@ DankPopout {
color: Theme.errorHover color: Theme.errorHover
border.color: Theme.primarySelected border.color: Theme.primarySelected
border.width: 1 border.width: 1
visible: (typeof PowerProfiles !== "undefined") visible: (typeof PowerProfiles !== "undefined") && PowerProfiles.degradationReason !== PerformanceDegradationReason.None
&& PowerProfiles.degradationReason
!== PerformanceDegradationReason.None
Row { Row {
anchors.left: parent.left anchors.left: parent.left
@@ -530,17 +572,21 @@ DankPopout {
} }
StyledText { StyledText {
text: (typeof PowerProfiles text: (typeof PowerProfiles !== "undefined") ? PerformanceDegradationReason.toString(PowerProfiles.degradationReason) : ""
!== "undefined") ? PerformanceDegradationReason.toString(
PowerProfiles.degradationReason) : ""
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.error.r, Theme.error.g, color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.8)
Theme.error.b, 0.8)
} }
} }
} }
} }
} }
} }
} }
} }

View File

@@ -21,10 +21,12 @@ Rectangle {
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
return "transparent"
}
const baseColor = clockMouseArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover const baseColor = clockMouseArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
baseColor.a * Theme.widgetTransparency)
} }
Component.onCompleted: { Component.onCompleted: {
root.currentDate = systemClock.date root.currentDate = systemClock.date
@@ -39,7 +41,7 @@ Rectangle {
StyledText { StyledText {
text: { text: {
if (SettingsData.use24HourClock) { if (SettingsData.use24HourClock) {
return root.currentDate.toLocaleTimeString(Qt.locale(), Locale.ShortFormat) return root.currentDate.toLocaleTimeString(Qt.locale(), "HH:mm")
} else { } else {
return root.currentDate.toLocaleTimeString(Qt.locale(), "h:mm AP") return root.currentDate.toLocaleTimeString(Qt.locale(), "h:mm AP")
} }
@@ -62,6 +64,7 @@ Rectangle {
if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0) { if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0) {
return root.currentDate.toLocaleDateString(Qt.locale(), SettingsData.clockDateFormat) return root.currentDate.toLocaleDateString(Qt.locale(), SettingsData.clockDateFormat)
} }
return root.currentDate.toLocaleDateString(Qt.locale(), "ddd d") return root.currentDate.toLocaleDateString(Qt.locale(), "ddd d")
} }
font.pixelSize: Theme.fontSizeMedium - 1 font.pixelSize: Theme.fontSizeMedium - 1
@@ -86,13 +89,11 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) { if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0)
var currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen
var screenX = currentScreen.x || 0 const screenX = currentScreen.x || 0
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX
popupTarget.setTriggerPosition( popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen)
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
} }
root.clockClicked() root.clockClicked()
} }

View File

@@ -11,7 +11,6 @@ Rectangle {
property var popupTarget: null property var popupTarget: null
property var parentScreen: null property var parentScreen: null
property var widgetData: null property var widgetData: null
property bool showNetworkIcon: SettingsData.controlCenterShowNetworkIcon property bool showNetworkIcon: SettingsData.controlCenterShowNetworkIcon
property bool showBluetoothIcon: SettingsData.controlCenterShowBluetoothIcon property bool showBluetoothIcon: SettingsData.controlCenterShowBluetoothIcon
property bool showAudioIcon: SettingsData.controlCenterShowAudioIcon property bool showAudioIcon: SettingsData.controlCenterShowAudioIcon
@@ -19,17 +18,18 @@ Rectangle {
property real barHeight: 48 property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30)) readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal clicked signal clicked()
width: controlIndicators.implicitWidth + horizontalPadding * 2 width: controlIndicators.implicitWidth + horizontalPadding * 2
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = controlCenterArea.containsMouse return "transparent";
|| root.isActive ? Theme.primaryPressed : Theme.secondaryHover }
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency) const baseColor = controlCenterArea.containsMouse || root.isActive ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
Row { Row {
@@ -40,21 +40,29 @@ Rectangle {
DankIcon { DankIcon {
id: networkIcon id: networkIcon
name: { name: {
if (NetworkService.wifiToggling) if (NetworkService.wifiToggling) {
return "sync" return "sync";
if (NetworkService.networkStatus === "ethernet") }
return "lan"
return NetworkService.wifiSignalIcon if (NetworkService.networkStatus === "ethernet") {
return "lan";
}
return NetworkService.wifiSignalIcon;
} }
size: Theme.iconSize - 8 size: Theme.iconSize - 8
color: { color: {
if (NetworkService.wifiToggling) return Theme.primary if (NetworkService.wifiToggling) {
return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.outlineButton return Theme.primary;
}
return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.outlineButton;
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: root.showNetworkIcon visible: root.showNetworkIcon
RotationAnimation on rotation { RotationAnimation on rotation {
running: NetworkService.wifiToggling running: NetworkService.wifiToggling
loops: Animation.Infinite loops: Animation.Infinite
@@ -62,10 +70,12 @@ Rectangle {
to: 360 to: 360
duration: 1000 duration: 1000
} }
} }
DankIcon { DankIcon {
id: bluetoothIcon id: bluetoothIcon
name: "bluetooth" name: "bluetooth"
size: Theme.iconSize - 8 size: Theme.iconSize - 8
color: BluetoothService.enabled ? Theme.primary : Theme.outlineButton color: BluetoothService.enabled ? Theme.primary : Theme.outlineButton
@@ -85,15 +95,15 @@ Rectangle {
name: { name: {
if (AudioService.sink && AudioService.sink.audio) { if (AudioService.sink && AudioService.sink.audio) {
if (AudioService.sink.audio.muted if (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0) {
|| AudioService.sink.audio.volume === 0) return "volume_off";
return "volume_off" } else if (AudioService.sink.audio.volume * 100 < 33) {
else if (AudioService.sink.audio.volume * 100 < 33) return "volume_down";
return "volume_down" } else {
else return "volume_up";
return "volume_up" }
} }
return "volume_up" return "volume_up";
} }
size: Theme.iconSize - 8 size: Theme.iconSize - 8
color: Theme.surfaceText color: Theme.surfaceText
@@ -106,25 +116,24 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
onWheel: function (wheelEvent) { onWheel: function(wheelEvent) {
let delta = wheelEvent.angleDelta.y let delta = wheelEvent.angleDelta.y;
let currentVolume = (AudioService.sink let currentVolume = (AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.volume * 100) || 0;
&& AudioService.sink.audio let newVolume;
&& AudioService.sink.audio.volume * 100) if (delta > 0) {
|| 0 newVolume = Math.min(100, currentVolume + 5);
let newVolume } else {
if (delta > 0) newVolume = Math.max(0, currentVolume - 5);
newVolume = Math.min(100, currentVolume + 5)
else
newVolume = Math.max(0, currentVolume - 5)
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = false
AudioService.sink.audio.volume = newVolume / 100
AudioService.volumeChanged()
} }
wheelEvent.accepted = true if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = false;
AudioService.sink.audio.volume = newVolume / 100;
AudioService.volumeChanged();
}
wheelEvent.accepted = true;
} }
} }
} }
DankIcon { DankIcon {
@@ -143,6 +152,7 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: !root.showNetworkIcon && !root.showBluetoothIcon && !root.showAudioIcon visible: !root.showNetworkIcon && !root.showBluetoothIcon && !root.showAudioIcon
} }
} }
MouseArea { MouseArea {
@@ -153,16 +163,13 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) { if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0 const screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition( popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
} }
root.clicked();
root.clicked()
} }
} }
@@ -171,5 +178,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }

View File

@@ -21,16 +21,18 @@ Rectangle {
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = cpuArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover return "transparent";
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, }
baseColor.a * Theme.widgetTransparency)
const baseColor = cpuArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["cpu"]) DgopService.addRef(["cpu"]);
} }
Component.onDestruction: { Component.onDestruction: {
DgopService.removeRef(["cpu"]) DgopService.removeRef(["cpu"]);
} }
MouseArea { MouseArea {
@@ -41,22 +43,23 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) { if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0 const screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition( popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
} }
DgopService.setSortBy("cpu") DgopService.setSortBy("cpu");
if (root.toggleProcessList) if (root.toggleProcessList) {
root.toggleProcessList() root.toggleProcessList();
}
} }
} }
Row { Row {
id: cpuContent id: cpuContent
anchors.centerIn: parent anchors.centerIn: parent
spacing: 3 spacing: 3
@@ -64,30 +67,33 @@ Rectangle {
name: "memory" name: "memory"
size: Theme.iconSize - 8 size: Theme.iconSize - 8
color: { color: {
if (DgopService.cpuUsage > 80) if (DgopService.cpuUsage > 80) {
return Theme.tempDanger return Theme.tempDanger;
}
if (DgopService.cpuUsage > 60) if (DgopService.cpuUsage > 60) {
return Theme.tempWarning return Theme.tempWarning;
}
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: { text: {
if (DgopService.cpuUsage === undefined if (DgopService.cpuUsage === undefined || DgopService.cpuUsage === null || DgopService.cpuUsage === 0) {
|| DgopService.cpuUsage === null return "--%";
|| DgopService.cpuUsage === 0) {
return "--%"
} }
return DgopService.cpuUsage.toFixed(0) + "%"
return DgopService.cpuUsage.toFixed(0) + "%";
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
} }

View File

@@ -21,16 +21,18 @@ Rectangle {
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = cpuTempArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover return "transparent";
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, }
baseColor.a * Theme.widgetTransparency)
const baseColor = cpuTempArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["cpu"]) DgopService.addRef(["cpu"]);
} }
Component.onDestruction: { Component.onDestruction: {
DgopService.removeRef(["cpu"]) DgopService.removeRef(["cpu"]);
} }
MouseArea { MouseArea {
@@ -41,22 +43,23 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) { if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0 const screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition( popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
} }
DgopService.setSortBy("cpu") DgopService.setSortBy("cpu");
if (root.toggleProcessList) if (root.toggleProcessList) {
root.toggleProcessList() root.toggleProcessList();
}
} }
} }
Row { Row {
id: cpuTempContent id: cpuTempContent
anchors.centerIn: parent anchors.centerIn: parent
spacing: 3 spacing: 3
@@ -64,31 +67,33 @@ Rectangle {
name: "memory" name: "memory"
size: Theme.iconSize - 8 size: Theme.iconSize - 8
color: { color: {
if (DgopService.cpuTemperature > 85) if (DgopService.cpuTemperature > 85) {
return Theme.tempDanger return Theme.tempDanger;
}
if (DgopService.cpuTemperature > 69) if (DgopService.cpuTemperature > 69) {
return Theme.tempWarning return Theme.tempWarning;
}
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: { text: {
if (DgopService.cpuTemperature === undefined if (DgopService.cpuTemperature === undefined || DgopService.cpuTemperature === null || DgopService.cpuTemperature < 0) {
|| DgopService.cpuTemperature === null return "--°";
|| DgopService.cpuTemperature < 0) {
return "--°"
} }
return Math.round(DgopService.cpuTemperature) + "°"
return Math.round(DgopService.cpuTemperature) + "°";
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Behavior on color { Behavior on color {
@@ -96,5 +101,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }

View File

@@ -1,6 +1,6 @@
import QtQuick
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import QtQuick
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
@@ -17,19 +17,20 @@ Rectangle {
readonly property int maxCompactWidth: 288 readonly property int maxCompactWidth: 288
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
width: compactMode ? Math.min(baseWidth, width: compactMode ? Math.min(baseWidth, maxCompactWidth) : Math.min(baseWidth, maxNormalWidth)
maxCompactWidth) : Math.min(baseWidth,
maxNormalWidth)
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (!activeWindow || !activeWindow.title) if (!activeWindow || !activeWindow.title) {
return "transparent" return "transparent";
}
if (SettingsData.topBarNoBackground) return "transparent"
const baseColor = mouseArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover if (SettingsData.topBarNoBackground) {
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, return "transparent";
baseColor.a * Theme.widgetTransparency) }
const baseColor = mouseArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
clip: true clip: true
visible: activeWindow && activeWindow.title visible: activeWindow && activeWindow.title
@@ -44,12 +45,12 @@ Rectangle {
id: appText id: appText
text: { text: {
if (!activeWindow || !activeWindow.appId) if (!activeWindow || !activeWindow.appId) {
return "" return "";
}
var desktopEntry = DesktopEntries.heuristicLookup(activeWindow.appId) const desktopEntry = DesktopEntries.heuristicLookup(activeWindow.appId);
return desktopEntry return desktopEntry && desktopEntry.name ? desktopEntry.name : activeWindow.appId;
&& desktopEntry.name ? desktopEntry.name : activeWindow.appId
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium font.weight: Font.Medium
@@ -73,24 +74,22 @@ Rectangle {
id: titleText id: titleText
text: { text: {
var title = activeWindow && activeWindow.title ? activeWindow.title : "" const title = activeWindow && activeWindow.title ? activeWindow.title : "";
var appName = appText.text const appName = appText.text;
if (!title || !appName) {
if (!title || !appName) return title;
return title }
// Remove app name from end of title if it exists there // Remove app name from end of title if it exists there
if (title.endsWith(" - " + appName)) { if (title.endsWith(" - " + appName)) {
return title.substring( return title.substring(0, title.length - (" - " + appName).length);
0, title.length - (" - " + appName).length)
}
if (title.endsWith(appName)) {
return title.substring(
0, title.length - appName.length).replace(
/ - $/, "")
} }
return title if (title.endsWith(appName)) {
return title.substring(0, title.length - appName.length).replace(/ - $/, "");
}
return title;
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium font.weight: Font.Medium
@@ -101,6 +100,7 @@ Rectangle {
width: Math.min(implicitWidth, compactMode ? 280 : 250) width: Math.min(implicitWidth, compactMode ? 280 : 250)
visible: text.length > 0 visible: text.length > 0
} }
} }
MouseArea { MouseArea {
@@ -115,6 +115,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
Behavior on width { Behavior on width {
@@ -122,5 +123,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }

View File

@@ -16,64 +16,97 @@ Rectangle {
property var widgetData: null property var widgetData: null
property real barHeight: 48 property real barHeight: 48
property real widgetHeight: 30 property real widgetHeight: 30
property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0
!== undefined) ? widgetData.selectedGpuIndex : 0 readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
property real displayTemp: {
Connections { if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
target: SettingsData return 0;
function onWidgetDataChanged() {
// Force property re-evaluation by triggering change detection
root.selectedGpuIndex = Qt.binding(() => {
return (root.widgetData
&& root.widgetData.selectedGpuIndex !== undefined) ? root.widgetData.selectedGpuIndex : 0
})
} }
if (selectedGpuIndex >= 0 && selectedGpuIndex < DgopService.availableGpus.length) {
return DgopService.availableGpus[selectedGpuIndex].temperature || 0;
}
return 0;
} }
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30)) function updateWidgetPciId(pciId) {
// Find and update this widget's pciId in the settings
const sections = ["left", "center", "right"];
for (let s = 0; s < sections.length; s++) {
const sectionId = sections[s];
let widgets = [];
if (sectionId === "left") {
widgets = SettingsData.topBarLeftWidgets.slice();
} else if (sectionId === "center") {
widgets = SettingsData.topBarCenterWidgets.slice();
} else if (sectionId === "right") {
widgets = SettingsData.topBarRightWidgets.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.setTopBarLeftWidgets(widgets);
} else if (sectionId === "center") {
SettingsData.setTopBarCenterWidgets(widgets);
} else if (sectionId === "right") {
SettingsData.setTopBarRightWidgets(widgets);
}
return ;
}
}
}
}
width: gpuTempContent.implicitWidth + horizontalPadding * 2 width: gpuTempContent.implicitWidth + horizontalPadding * 2
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = gpuArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover return "transparent";
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, }
baseColor.a * Theme.widgetTransparency)
const baseColor = gpuArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["gpu"]) DgopService.addRef(["gpu"]);
console.log("GpuTemperature widget - pciId:", console.log("GpuTemperature widget - pciId:", widgetData ? widgetData.pciId : "no widgetData", "selectedGpuIndex:", widgetData ? widgetData.selectedGpuIndex : "no widgetData");
widgetData ? widgetData.pciId : "no widgetData",
"selectedGpuIndex:",
widgetData ? widgetData.selectedGpuIndex : "no widgetData")
// Add this widget's PCI ID to the service // Add this widget's PCI ID to the service
if (widgetData && widgetData.pciId) { if (widgetData && widgetData.pciId) {
console.log("Adding GPU PCI ID to service:", widgetData.pciId) console.log("Adding GPU PCI ID to service:", widgetData.pciId);
DgopService.addGpuPciId(widgetData.pciId) DgopService.addGpuPciId(widgetData.pciId);
} else { } else {
console.log("No PCI ID in widget data, starting auto-detection") console.log("No PCI ID in widget data, starting auto-detection");
// No PCI ID saved, auto-detect and save the first GPU // No PCI ID saved, auto-detect and save the first GPU
autoSaveTimer.running = true autoSaveTimer.running = true;
} }
} }
Component.onDestruction: { Component.onDestruction: {
DgopService.removeRef(["gpu"]) DgopService.removeRef(["gpu"]);
// Remove this widget's PCI ID from the service // Remove this widget's PCI ID from the service
if (widgetData && widgetData.pciId) { if (widgetData && widgetData.pciId) {
DgopService.removeGpuPciId(widgetData.pciId) DgopService.removeGpuPciId(widgetData.pciId);
} }
} }
property real displayTemp: { Connections {
if (!DgopService.availableGpus function onWidgetDataChanged() {
|| DgopService.availableGpus.length === 0) // Force property re-evaluation by triggering change detection
return 0 root.selectedGpuIndex = Qt.binding(() => {
if (selectedGpuIndex >= 0 return (root.widgetData && root.widgetData.selectedGpuIndex !== undefined) ? root.widgetData.selectedGpuIndex : 0;
&& selectedGpuIndex < DgopService.availableGpus.length) { });
return DgopService.availableGpus[selectedGpuIndex].temperature || 0
} }
return 0
target: SettingsData
} }
MouseArea { MouseArea {
@@ -84,22 +117,23 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) { if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0 const screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition( popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
} }
DgopService.setSortBy("cpu") DgopService.setSortBy("cpu");
if (root.toggleProcessList) if (root.toggleProcessList) {
root.toggleProcessList() root.toggleProcessList();
}
} }
} }
Row { Row {
id: gpuTempContent id: gpuTempContent
anchors.centerIn: parent anchors.centerIn: parent
spacing: 3 spacing: 3
@@ -107,30 +141,50 @@ Rectangle {
name: "auto_awesome_mosaic" name: "auto_awesome_mosaic"
size: Theme.iconSize - 8 size: Theme.iconSize - 8
color: { color: {
if (root.displayTemp > 80) if (root.displayTemp > 80) {
return Theme.tempDanger return Theme.tempDanger;
}
if (root.displayTemp > 65) if (root.displayTemp > 65) {
return Theme.tempWarning return Theme.tempWarning;
}
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: { text: {
if (root.displayTemp === undefined || root.displayTemp === null if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) {
|| root.displayTemp === 0) { return "--°";
return "--°"
} }
return Math.round(root.displayTemp) + "°"
return Math.round(root.displayTemp) + "°";
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
}
Timer {
id: autoSaveTimer
interval: 100
running: false
onTriggered: {
if (DgopService.availableGpus && DgopService.availableGpus.length > 0) {
const firstGpu = DgopService.availableGpus[0];
if (firstGpu && firstGpu.pciId) {
// Save the first GPU's PCI ID to this widget's settings
updateWidgetPciId(firstGpu.pciId);
DgopService.addGpuPciId(firstGpu.pciId);
}
}
}
} }
Behavior on color { Behavior on color {
@@ -138,58 +192,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
Timer {
id: autoSaveTimer
interval: 100
running: false
onTriggered: {
if (DgopService.availableGpus
&& DgopService.availableGpus.length > 0) {
const firstGpu = DgopService.availableGpus[0]
if (firstGpu && firstGpu.pciId) {
// Save the first GPU's PCI ID to this widget's settings
updateWidgetPciId(firstGpu.pciId)
DgopService.addGpuPciId(firstGpu.pciId)
}
}
}
}
function updateWidgetPciId(pciId) {
// Find and update this widget's pciId in the settings
var sections = ["left", "center", "right"]
for (var s = 0; s < sections.length; s++) {
var sectionId = sections[s]
var widgets = []
if (sectionId === "left")
widgets = SettingsData.topBarLeftWidgets.slice()
else if (sectionId === "center")
widgets = SettingsData.topBarCenterWidgets.slice()
else if (sectionId === "right")
widgets = SettingsData.topBarRightWidgets.slice()
for (var i = 0; i < widgets.length; i++) {
var 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.setTopBarLeftWidgets(widgets)
else if (sectionId === "center")
SettingsData.setTopBarCenterWidgets(widgets)
else if (sectionId === "right")
SettingsData.setTopBarRightWidgets(widgets)
return
}
}
}
}
} }

View File

@@ -18,14 +18,17 @@ Rectangle {
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = mouseArea.containsMouse ? Theme.primaryPressed : (SessionService.idleInhibited ? Theme.primaryHover : Theme.secondaryHover) return "transparent";
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, }
baseColor.a * Theme.widgetTransparency)
const baseColor = mouseArea.containsMouse ? Theme.primaryPressed : (SessionService.idleInhibited ? Theme.primaryHover : Theme.secondaryHover);
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
DankIcon { DankIcon {
id: idleIcon id: idleIcon
anchors.centerIn: parent anchors.centerIn: parent
name: SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle" name: SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
size: Theme.iconSize - 6 size: Theme.iconSize - 6
@@ -38,9 +41,8 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
SessionService.toggleIdleInhibit() SessionService.toggleIdleInhibit();
} }
} }
@@ -49,5 +51,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }

View File

@@ -1,9 +1,9 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import qs.Common import qs.Common
import qs.Modules.ProcessList
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
import qs.Modules.ProcessList
Rectangle { Rectangle {
id: root id: root
@@ -13,12 +13,13 @@ Rectangle {
width: contentRow.implicitWidth + horizontalPadding * 2 width: contentRow.implicitWidth + horizontalPadding * 2
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = mouseArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover return "transparent";
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, }
baseColor.a * Theme.widgetTransparency)
const baseColor = mouseArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
MouseArea { MouseArea {
@@ -27,9 +28,8 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
NiriService.cycleKeyboardLayout() NiriService.cycleKeyboardLayout();
} }
} }
@@ -45,6 +45,7 @@ Rectangle {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Behavior on color { Behavior on color {
@@ -52,5 +53,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }

View File

@@ -14,41 +14,42 @@ Item {
property real barHeight: 48 property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30)) readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal clicked signal clicked()
width: Theme.iconSize + horizontalPadding * 2 width: Theme.iconSize + horizontalPadding * 2
height: widgetHeight height: widgetHeight
MouseArea { MouseArea {
id: launcherArea id: launcherArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
onPressed: { onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) { if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0 const screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition( popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
} }
root.clicked() root.clicked();
} }
} }
Rectangle { Rectangle {
id: launcherContent id: launcherContent
anchors.fill: parent anchors.fill: parent
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = launcherArea.containsMouse ? Theme.primaryPressed : (SessionService.idleInhibited ? Theme.primaryHover : Theme.secondaryHover) return "transparent";
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, }
baseColor.a * Theme.widgetTransparency)
const baseColor = launcherArea.containsMouse ? Theme.primaryPressed : (SessionService.idleInhibited ? Theme.primaryHover : Theme.secondaryHover);
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
SystemLogo { SystemLogo {
@@ -74,6 +75,9 @@ Item {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
} }

View File

@@ -13,21 +13,21 @@ Rectangle {
readonly property int textWidth: { readonly property int textWidth: {
switch (SettingsData.mediaSize) { switch (SettingsData.mediaSize) {
case 0: case 0:
return 0 // No text in small mode return 0; // No text in small mode
case 2: case 2:
return 180 // Large text area return 180; // Large text area
default: default:
return 120 // Medium text area return 120; // Medium text area
} }
} }
readonly property int currentContentWidth: { readonly property int currentContentWidth: {
// Calculate actual content width: // Calculate actual content width:
// AudioViz (20) + spacing + [text + spacing] + controls (prev:20 + spacing + play:24 + spacing + next:20) + padding // AudioViz (20) + spacing + [text + spacing] + controls (prev:20 + spacing + play:24 + spacing + next:20) + padding
const controlsWidth = 20 + Theme.spacingXS + 24 + Theme.spacingXS + 20 // ~72px total const controlsWidth = 20 + Theme.spacingXS + 24 + Theme.spacingXS + 20;
const audioVizWidth = 20 // ~72px total
const contentWidth = audioVizWidth + Theme.spacingXS + controlsWidth const audioVizWidth = 20;
return contentWidth + (textWidth > 0 ? textWidth + Theme.spacingXS : 0) + horizontalPadding * 2 const contentWidth = audioVizWidth + Theme.spacingXS + controlsWidth;
return contentWidth + (textWidth > 0 ? textWidth + Theme.spacingXS : 0) + horizontalPadding * 2;
} }
property string section: "center" property string section: "center"
property var popupTarget: null property var popupTarget: null
@@ -36,15 +36,17 @@ Rectangle {
property real widgetHeight: 30 property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30)) readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal clicked signal clicked()
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = Theme.surfaceTextHover return "transparent";
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, }
baseColor.a * Theme.widgetTransparency)
const baseColor = Theme.surfaceTextHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
states: [ states: [
State { State {
@@ -56,6 +58,7 @@ Rectangle {
opacity: 1 opacity: 1
width: currentContentWidth width: currentContentWidth
} }
}, },
State { State {
name: "hidden" name: "hidden"
@@ -66,6 +69,7 @@ Rectangle {
opacity: 0 opacity: 0
width: 0 width: 0
} }
} }
] ]
transitions: [ transitions: [
@@ -83,7 +87,9 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
}, },
Transition { Transition {
from: "hidden" from: "hidden"
@@ -94,6 +100,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
] ]
@@ -115,6 +122,25 @@ Rectangle {
Rectangle { Rectangle {
id: textContainer id: textContainer
property string displayText: {
if (!activePlayer || !activePlayer.trackTitle) {
return "";
}
let identity = activePlayer.identity || "";
let isWebMedia = identity.toLowerCase().includes("firefox") || identity.toLowerCase().includes("chrome") || identity.toLowerCase().includes("chromium") || identity.toLowerCase().includes("edge") || identity.toLowerCase().includes("safari");
let title = "";
let subtitle = "";
if (isWebMedia && activePlayer.trackTitle) {
title = activePlayer.trackTitle;
subtitle = activePlayer.trackArtist || identity;
} else {
title = activePlayer.trackTitle || "Unknown Track";
subtitle = activePlayer.trackArtist || "";
}
return subtitle.length > 0 ? title + " • " + subtitle : title;
}
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: textWidth width: textWidth
height: 20 height: 20
@@ -122,48 +148,28 @@ Rectangle {
clip: true clip: true
color: "transparent" color: "transparent"
property string displayText: {
if (!activePlayer || !activePlayer.trackTitle)
return ""
let identity = activePlayer.identity || ""
let isWebMedia = identity.toLowerCase().includes("firefox")
|| identity.toLowerCase().includes(
"chrome") || identity.toLowerCase(
).includes("chromium")
|| identity.toLowerCase().includes(
"edge") || identity.toLowerCase().includes("safari")
let title = ""
let subtitle = ""
if (isWebMedia && activePlayer.trackTitle) {
title = activePlayer.trackTitle
subtitle = activePlayer.trackArtist || identity
} else {
title = activePlayer.trackTitle || "Unknown Track"
subtitle = activePlayer.trackArtist || ""
}
return subtitle.length > 0 ? title + " • " + subtitle : title
}
StyledText { StyledText {
id: mediaText id: mediaText
property bool needsScrolling: implicitWidth > textContainer.width
property real scrollOffset: 0
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: textContainer.displayText text: textContainer.displayText
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
font.weight: Font.Medium font.weight: Font.Medium
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
property bool needsScrolling: implicitWidth > textContainer.width
property real scrollOffset: 0
x: needsScrolling ? -scrollOffset : 0 x: needsScrolling ? -scrollOffset : 0
onTextChanged: {
scrollOffset = 0;
scrollAnimation.restart();
}
SequentialAnimation { SequentialAnimation {
id: scrollAnimation id: scrollAnimation
running: mediaText.needsScrolling
&& textContainer.visible running: mediaText.needsScrolling && textContainer.visible
loops: Animation.Infinite loops: Animation.Infinite
PauseAnimation { PauseAnimation {
@@ -175,9 +181,7 @@ Rectangle {
property: "scrollOffset" property: "scrollOffset"
from: 0 from: 0
to: mediaText.implicitWidth - textContainer.width + 5 to: mediaText.implicitWidth - textContainer.width + 5
duration: Math.max( duration: Math.max(1000, (mediaText.implicitWidth - textContainer.width + 5) * 60)
1000,
(mediaText.implicitWidth - textContainer.width + 5) * 60)
easing.type: Easing.Linear easing.type: Easing.Linear
} }
@@ -189,41 +193,33 @@ Rectangle {
target: mediaText target: mediaText
property: "scrollOffset" property: "scrollOffset"
to: 0 to: 0
duration: Math.max( duration: Math.max(1000, (mediaText.implicitWidth - textContainer.width + 5) * 60)
1000,
(mediaText.implicitWidth - textContainer.width + 5) * 60)
easing.type: Easing.Linear easing.type: Easing.Linear
} }
} }
onTextChanged: {
scrollOffset = 0
scrollAnimation.restart()
}
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
enabled: root.playerAvailable && root.opacity > 0 enabled: root.playerAvailable && root.opacity > 0 && root.width > 0 && textContainer.visible
&& root.width > 0 && textContainer.visible
hoverEnabled: enabled hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onPressed: { onPressed: {
if (root.popupTarget if (root.popupTarget && root.popupTarget.setTriggerPosition) {
&& root.popupTarget.setTriggerPosition) { const globalPos = mapToGlobal(0, 0);
var globalPos = mapToGlobal(0, 0) const currentScreen = root.parentScreen || Screen;
var currentScreen = root.parentScreen || Screen const screenX = currentScreen.x || 0;
var screenX = currentScreen.x || 0 const relativeX = globalPos.x - screenX;
var relativeX = globalPos.x - screenX root.popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, root.width, root.section, currentScreen);
root.popupTarget.setTriggerPosition(
relativeX,
barHeight + Theme.spacingXS,
root.width, root.section, currentScreen)
} }
root.clicked() root.clicked();
} }
} }
} }
} }
Row { Row {
@@ -254,10 +250,12 @@ Rectangle {
hoverEnabled: enabled hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: { onClicked: {
if (activePlayer) if (activePlayer) {
activePlayer.previous() activePlayer.previous();
}
} }
} }
} }
Rectangle { Rectangle {
@@ -265,18 +263,15 @@ Rectangle {
height: 24 height: 24
radius: 12 radius: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: activePlayer color: activePlayer && activePlayer.playbackState === 1 ? Theme.primary : Theme.primaryHover
&& activePlayer.playbackState === 1 ? Theme.primary : Theme.primaryHover
visible: root.playerAvailable visible: root.playerAvailable
opacity: activePlayer ? 1 : 0.3 opacity: activePlayer ? 1 : 0.3
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
name: activePlayer name: activePlayer && activePlayer.playbackState === 1 ? "pause" : "play_arrow"
&& activePlayer.playbackState === 1 ? "pause" : "play_arrow"
size: 14 size: 14
color: activePlayer color: activePlayer && activePlayer.playbackState === 1 ? Theme.background : Theme.primary
&& activePlayer.playbackState === 1 ? Theme.background : Theme.primary
} }
MouseArea { MouseArea {
@@ -285,10 +280,12 @@ Rectangle {
hoverEnabled: enabled hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: { onClicked: {
if (activePlayer) if (activePlayer) {
activePlayer.togglePlaying() activePlayer.togglePlaying();
}
} }
} }
} }
Rectangle { Rectangle {
@@ -315,12 +312,16 @@ Rectangle {
hoverEnabled: enabled hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: { onClicked: {
if (activePlayer) if (activePlayer) {
activePlayer.next() activePlayer.next();
}
} }
} }
} }
} }
} }
Behavior on color { Behavior on color {
@@ -328,6 +329,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
Behavior on width { Behavior on width {
@@ -335,5 +337,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }

View File

@@ -1,9 +1,9 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import qs.Common import qs.Common
import qs.Modules.ProcessList
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
import qs.Modules.ProcessList
Rectangle { Rectangle {
id: root id: root
@@ -11,37 +11,36 @@ Rectangle {
property int availableWidth: 400 property int availableWidth: 400
readonly property int baseWidth: contentRow.implicitWidth + Theme.spacingS * 2 readonly property int baseWidth: contentRow.implicitWidth + Theme.spacingS * 2
readonly property int maxNormalWidth: 456 readonly property int maxNormalWidth: 456
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
function formatNetworkSpeed(bytesPerSec) { function formatNetworkSpeed(bytesPerSec) {
if (bytesPerSec < 1024) if (bytesPerSec < 1024) {
return bytesPerSec.toFixed(0) + " B/s" return bytesPerSec.toFixed(0) + " B/s";
else if (bytesPerSec < 1024 * 1024) } else if (bytesPerSec < 1024 * 1024) {
return (bytesPerSec / 1024).toFixed(1) + " KB/s" return (bytesPerSec / 1024).toFixed(1) + " KB/s";
else if (bytesPerSec < 1024 * 1024 * 1024) } else if (bytesPerSec < 1024 * 1024 * 1024) {
return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s" return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s";
else } else {
return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(1) + " GB/s" return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(1) + " GB/s";
}
} }
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
width: contentRow.implicitWidth + horizontalPadding * 2 width: contentRow.implicitWidth + horizontalPadding * 2
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = networkArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover return "transparent";
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, }
baseColor.a * Theme.widgetTransparency)
}
const baseColor = networkArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["network"]) DgopService.addRef(["network"]);
} }
Component.onDestruction: { Component.onDestruction: {
DgopService.removeRef(["network"]) DgopService.removeRef(["network"]);
} }
MouseArea { MouseArea {
@@ -76,13 +75,13 @@ Rectangle {
} }
StyledText { StyledText {
text: DgopService.networkRxRate > 0 ? formatNetworkSpeed( text: DgopService.networkRxRate > 0 ? formatNetworkSpeed(DgopService.networkRxRate) : "0 B/s"
DgopService.networkRxRate) : "0 B/s"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Row { Row {
@@ -96,14 +95,15 @@ Rectangle {
} }
StyledText { StyledText {
text: DgopService.networkTxRate > 0 ? formatNetworkSpeed( text: DgopService.networkTxRate > 0 ? formatNetworkSpeed(DgopService.networkTxRate) : "0 B/s"
DgopService.networkTxRate) : "0 B/s"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
} }
Behavior on color { Behavior on color {
@@ -111,5 +111,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }

View File

@@ -13,21 +13,23 @@ Rectangle {
property real barHeight: 48 property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30)) readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal clicked signal clicked()
width: notepadIcon.width + horizontalPadding * 2 width: notepadIcon.width + horizontalPadding * 2
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = notepadArea.containsMouse return "transparent";
|| root.isActive ? Theme.primaryPressed : Theme.secondaryHover }
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency) const baseColor = notepadArea.containsMouse || root.isActive ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
DankIcon { DankIcon {
id: notepadIcon id: notepadIcon
anchors.centerIn: parent anchors.centerIn: parent
name: "assignment" name: "assignment"
size: Theme.iconSize - 6 size: Theme.iconSize - 6
@@ -54,7 +56,7 @@ Rectangle {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
root.clicked() root.clicked();
} }
} }
@@ -63,5 +65,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
}
}

View File

@@ -14,26 +14,27 @@ Rectangle {
property real barHeight: 48 property real barHeight: 48
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30)) readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal clicked signal clicked()
width: notificationIcon.width + horizontalPadding * 2 width: notificationIcon.width + horizontalPadding * 2
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = notificationArea.containsMouse return "transparent";
|| root.isActive ? Theme.primaryPressed : Theme.secondaryHover }
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency) const baseColor = notificationArea.containsMouse || root.isActive ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
DankIcon { DankIcon {
id: notificationIcon id: notificationIcon
anchors.centerIn: parent anchors.centerIn: parent
name: SessionData.doNotDisturb ? "notifications_off" : "notifications" name: SessionData.doNotDisturb ? "notifications_off" : "notifications"
size: Theme.iconSize - 6 size: Theme.iconSize - 6
color: SessionData.doNotDisturb ? Theme.error : (notificationArea.containsMouse color: SessionData.doNotDisturb ? Theme.error : (notificationArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText)
|| root.isActive ? Theme.primary : Theme.surfaceText)
} }
Rectangle { Rectangle {
@@ -56,15 +57,13 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) { if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0 const screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition( popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
} }
root.clicked() root.clicked();
} }
} }
@@ -73,5 +72,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }

View File

@@ -12,10 +12,8 @@ Rectangle {
property var parentScreen: null property var parentScreen: null
property real widgetHeight: 30 property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS
readonly property bool hasActivePrivacy: PrivacyService.anyPrivacyActive readonly property bool hasActivePrivacy: PrivacyService.anyPrivacyActive
readonly property int activeCount: PrivacyService.microphoneActive + PrivacyService.cameraActive readonly property int activeCount: PrivacyService.microphoneActive + PrivacyService.cameraActive + PrivacyService.screensharingActive
+ PrivacyService.screensharingActive
readonly property real contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0 readonly property real contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
width: hasActivePrivacy ? (contentWidth + horizontalPadding * 2) : 0 width: hasActivePrivacy ? (contentWidth + horizontalPadding * 2) : 0
@@ -24,18 +22,17 @@ Rectangle {
visible: hasActivePrivacy visible: hasActivePrivacy
opacity: hasActivePrivacy ? 1 : 0 opacity: hasActivePrivacy ? 1 : 0
enabled: hasActivePrivacy enabled: hasActivePrivacy
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
return Qt.rgba( return "transparent";
privacyArea.containsMouse ? Theme.errorPressed.r : Theme.errorHover.r, }
privacyArea.containsMouse ? Theme.errorPressed.g : Theme.errorHover.g,
privacyArea.containsMouse ? Theme.errorPressed.b : Theme.errorHover.b, return Qt.rgba(privacyArea.containsMouse ? Theme.errorPressed.r : Theme.errorHover.r, privacyArea.containsMouse ? Theme.errorPressed.g : Theme.errorHover.g, privacyArea.containsMouse ? Theme.errorPressed.b : Theme.errorHover.b, (privacyArea.containsMouse ? Theme.errorPressed.a : Theme.errorHover.a) * Theme.widgetTransparency);
(privacyArea.containsMouse ? Theme.errorPressed.a : Theme.errorHover.a)
* Theme.widgetTransparency)
} }
MouseArea { MouseArea {
// Privacy indicator click handler
id: privacyArea id: privacyArea
anchors.fill: parent anchors.fill: parent
@@ -43,7 +40,6 @@ Rectangle {
enabled: hasActivePrivacy enabled: hasActivePrivacy
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
} }
} }
@@ -65,6 +61,7 @@ Rectangle {
filled: true filled: true
anchors.centerIn: parent anchors.centerIn: parent
} }
} }
Item { Item {
@@ -91,6 +88,7 @@ Rectangle {
anchors.rightMargin: -2 anchors.rightMargin: -2
anchors.topMargin: -1 anchors.topMargin: -1
} }
} }
Item { Item {
@@ -106,15 +104,9 @@ Rectangle {
filled: true filled: true
anchors.centerIn: parent anchors.centerIn: parent
} }
}
}
Behavior on width {
enabled: hasActivePrivacy && visible
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
} }
} }
Rectangle { Rectangle {
@@ -129,26 +121,18 @@ Rectangle {
visible: false visible: false
opacity: privacyArea.containsMouse && hasActivePrivacy ? 1 : 0 opacity: privacyArea.containsMouse && hasActivePrivacy ? 1 : 0
z: 100 z: 100
x: (parent.width - width) / 2 x: (parent.width - width) / 2
y: -height - Theme.spacingXS y: -height - Theme.spacingXS
StyledText { StyledText {
id: tooltipText id: tooltipText
anchors.centerIn: parent anchors.centerIn: parent
text: PrivacyService.getPrivacySummary() text: PrivacyService.getPrivacySummary()
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
} }
Behavior on opacity {
enabled: hasActivePrivacy && root.visible
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Rectangle { Rectangle {
width: 8 width: 8
height: 8 height: 8
@@ -160,5 +144,27 @@ Rectangle {
anchors.top: parent.bottom anchors.top: parent.bottom
anchors.topMargin: -4 anchors.topMargin: -4
} }
Behavior on opacity {
enabled: hasActivePrivacy && root.visible
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
} }
Behavior on width {
enabled: hasActivePrivacy && visible
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
} }

View File

@@ -21,16 +21,18 @@ Rectangle {
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = ramArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover return "transparent";
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, }
baseColor.a * Theme.widgetTransparency)
const baseColor = ramArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["memory"]) DgopService.addRef(["memory"]);
} }
Component.onDestruction: { Component.onDestruction: {
DgopService.removeRef(["memory"]) DgopService.removeRef(["memory"]);
} }
MouseArea { MouseArea {
@@ -41,22 +43,23 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) { if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0 const screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition( popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
} }
DgopService.setSortBy("memory") DgopService.setSortBy("memory");
if (root.toggleProcessList) if (root.toggleProcessList) {
root.toggleProcessList() root.toggleProcessList();
}
} }
} }
Row { Row {
id: ramContent id: ramContent
anchors.centerIn: parent anchors.centerIn: parent
spacing: 3 spacing: 3
@@ -64,30 +67,33 @@ Rectangle {
name: "developer_board" name: "developer_board"
size: Theme.iconSize - 8 size: Theme.iconSize - 8
color: { color: {
if (DgopService.memoryUsage > 90) if (DgopService.memoryUsage > 90) {
return Theme.tempDanger return Theme.tempDanger;
}
if (DgopService.memoryUsage > 75) if (DgopService.memoryUsage > 75) {
return Theme.tempWarning return Theme.tempWarning;
}
return Theme.surfaceText return Theme.surfaceText;
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: { text: {
if (DgopService.memoryUsage === undefined if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) {
|| DgopService.memoryUsage === null return "--%";
|| DgopService.memoryUsage === 0) {
return "--%"
} }
return DgopService.memoryUsage.toFixed(0) + "%"
return DgopService.memoryUsage.toFixed(0) + "%";
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
} }

View File

@@ -19,20 +19,21 @@ Rectangle {
// The visual root for this window // The visual root for this window
property Item windowRoot: (Window.window ? Window.window.contentItem : null) property Item windowRoot: (Window.window ? Window.window.contentItem : null)
readonly property var sortedToplevels: { readonly property var sortedToplevels: {
if (SettingsData.runningAppsCurrentWorkspace){ if (SettingsData.runningAppsCurrentWorkspace) {
return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, parentScreen.name) return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, parentScreen.name);
} }
return CompositorService.sortedToplevels return CompositorService.sortedToplevels;
} }
readonly property int windowCount: sortedToplevels.length readonly property int windowCount: sortedToplevels.length
readonly property int calculatedWidth: { readonly property int calculatedWidth: {
if (windowCount === 0) if (windowCount === 0) {
return 0 return 0;
}
if (SettingsData.runningAppsCompactMode) { if (SettingsData.runningAppsCompactMode) {
return windowCount * 24 + (windowCount - 1) * Theme.spacingXS + horizontalPadding * 2 return windowCount * 24 + (windowCount - 1) * Theme.spacingXS + horizontalPadding * 2;
} else { } else {
return windowCount * (24 + Theme.spacingXS + 120) return windowCount * (24 + Theme.spacingXS + 120)
+ (windowCount - 1) * Theme.spacingXS + horizontalPadding * 2 + (windowCount - 1) * Theme.spacingXS + horizontalPadding * 2;
} }
} }
@@ -42,13 +43,16 @@ Rectangle {
visible: windowCount > 0 visible: windowCount > 0
clip: false clip: false
color: { color: {
if (windowCount === 0) if (windowCount === 0) {
return "transparent" return "transparent";
}
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = Theme.secondaryHover return "transparent";
}
const baseColor = Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency) baseColor.a * Theme.widgetTransparency);
} }
MouseArea { MouseArea {
@@ -60,26 +64,26 @@ Rectangle {
property real touchpadThreshold: 500 property real touchpadThreshold: 500
onWheel: (wheel) => { onWheel: (wheel) => {
const deltaY = wheel.angleDelta.y const deltaY = wheel.angleDelta.y;
const isMouseWheel = Math.abs(deltaY) >= 120 const isMouseWheel = Math.abs(deltaY) >= 120
&& (Math.abs(deltaY) % 120) === 0 && (Math.abs(deltaY) % 120) === 0;
var windows = root.sortedToplevels; const windows = root.sortedToplevels;
if (windows.length < 2) { if (windows.length < 2) {
return; return;
} }
if (isMouseWheel) { if (isMouseWheel) {
// Direct mouse wheel action // Direct mouse wheel action
var currentIndex = -1; let currentIndex = -1;
for (var i = 0; i < windows.length; i++) { for (let i = 0; i < windows.length; i++) {
if (windows[i].activated) { if (windows[i].activated) {
currentIndex = i; currentIndex = i;
break; break;
} }
} }
var nextIndex; let nextIndex;
if (deltaY < 0) { if (deltaY < 0) {
if (currentIndex === -1) { if (currentIndex === -1) {
nextIndex = 0; nextIndex = 0;
@@ -94,24 +98,24 @@ Rectangle {
} }
} }
var nextWindow = windows[nextIndex]; const nextWindow = windows[nextIndex];
if (nextWindow) { if (nextWindow) {
nextWindow.activate(); nextWindow.activate();
} }
} else { } else {
// Touchpad - accumulate small deltas // Touchpad - accumulate small deltas
scrollAccumulator += deltaY scrollAccumulator += deltaY;
if (Math.abs(scrollAccumulator) >= touchpadThreshold) { if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
var currentIndex = -1; let currentIndex = -1;
for (var i = 0; i < windows.length; i++) { for (let i = 0; i < windows.length; i++) {
if (windows[i].activated) { if (windows[i].activated) {
currentIndex = i; currentIndex = i;
break; break;
} }
} }
var nextIndex; let nextIndex;
if (scrollAccumulator < 0) { if (scrollAccumulator < 0) {
if (currentIndex === -1) { if (currentIndex === -1) {
nextIndex = 0; nextIndex = 0;
@@ -126,16 +130,16 @@ Rectangle {
} }
} }
var nextWindow = windows[nextIndex]; const nextWindow = windows[nextIndex];
if (nextWindow) { if (nextWindow) {
nextWindow.activate(); nextWindow.activate();
} }
scrollAccumulator = 0 scrollAccumulator = 0;
} }
} }
wheel.accepted = true wheel.accepted = true;
} }
} }
@@ -158,11 +162,11 @@ Rectangle {
property string windowTitle: modelData.title || "(Unnamed)" property string windowTitle: modelData.title || "(Unnamed)"
property var toplevelObject: modelData property var toplevelObject: modelData
property string tooltipText: { property string tooltipText: {
var appName = "Unknown" let appName = "Unknown";
if (appId) { if (appId) {
var desktopEntry = DesktopEntries.heuristicLookup(appId) const desktopEntry = DesktopEntries.heuristicLookup(appId);
appName = desktopEntry appName = desktopEntry
&& desktopEntry.name ? desktopEntry.name : appId && desktopEntry.name ? desktopEntry.name : appId;
} }
return appName + (windowTitle ? " • " + windowTitle : "") return appName + (windowTitle ? " • " + windowTitle : "")
} }
@@ -174,7 +178,7 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: { color: {
if (isFocused) if (isFocused) {
return mouseArea.containsMouse ? Qt.rgba( return mouseArea.containsMouse ? Qt.rgba(
Theme.primary.r, Theme.primary.r,
Theme.primary.g, Theme.primary.g,
@@ -183,13 +187,14 @@ Rectangle {
Theme.primary.r, Theme.primary.r,
Theme.primary.g, Theme.primary.g,
Theme.primary.b, Theme.primary.b,
0.2) 0.2);
else } else {
return mouseArea.containsMouse ? Qt.rgba( return mouseArea.containsMouse ? Qt.rgba(
Theme.primaryHover.r, Theme.primaryHover.r,
Theme.primaryHover.g, Theme.primaryHover.g,
Theme.primaryHover.b, Theme.primaryHover.b,
0.1) : "transparent" 0.1) : "transparent";
}
} }
Behavior on color { Behavior on color {
@@ -220,14 +225,16 @@ Rectangle {
anchors.centerIn: parent anchors.centerIn: parent
visible: !iconImg.visible visible: !iconImg.visible
text: { text: {
if (!appId) if (!appId) {
return "?" return "?";
}
var desktopEntry = DesktopEntries.heuristicLookup(appId) const desktopEntry = DesktopEntries.heuristicLookup(appId);
if (desktopEntry && desktopEntry.name) if (desktopEntry && desktopEntry.name) {
return desktopEntry.name.charAt(0).toUpperCase() return desktopEntry.name.charAt(0).toUpperCase();
}
return appId.charAt(0).toUpperCase() return appId.charAt(0).toUpperCase();
} }
font.pixelSize: 10 font.pixelSize: 10
color: Theme.surfaceText color: Theme.surfaceText
@@ -260,45 +267,47 @@ Rectangle {
onClicked: (mouse) => { onClicked: (mouse) => {
if (mouse.button === Qt.LeftButton) { if (mouse.button === Qt.LeftButton) {
if (toplevelObject) { if (toplevelObject) {
toplevelObject.activate() toplevelObject.activate();
} }
} else if (mouse.button === Qt.RightButton) { } else if (mouse.button === Qt.RightButton) {
if (tooltipLoader.item) if (tooltipLoader.item) {
tooltipLoader.item.hideTooltip() tooltipLoader.item.hideTooltip();
tooltipLoader.active = false }
tooltipLoader.active = false;
windowContextMenuLoader.active = true windowContextMenuLoader.active = true;
if (windowContextMenuLoader.item) { if (windowContextMenuLoader.item) {
windowContextMenuLoader.item.currentWindow = toplevelObject windowContextMenuLoader.item.currentWindow = toplevelObject;
var globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0) const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0);
var screenX = root.parentScreen ? root.parentScreen.x : 0 const screenX = root.parentScreen ? root.parentScreen.x : 0;
var screenY = root.parentScreen ? root.parentScreen.y : 0 const screenY = root.parentScreen ? root.parentScreen.y : 0;
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX;
var yPos = Theme.barHeight + SettingsData.topBarSpacing - 7 const yPos = Theme.barHeight + SettingsData.topBarSpacing - 7;
windowContextMenuLoader.item.showAt(relativeX, yPos) windowContextMenuLoader.item.showAt(relativeX, yPos);
} }
} }
} }
onEntered: { onEntered: {
root.hoveredItem = delegateItem root.hoveredItem = delegateItem;
var globalPos = delegateItem.mapToGlobal( const globalPos = delegateItem.mapToGlobal(
delegateItem.width / 2, delegateItem.height) delegateItem.width / 2, delegateItem.height);
tooltipLoader.active = true tooltipLoader.active = true;
if (tooltipLoader.item) { if (tooltipLoader.item) {
var tooltipY = Theme.barHeight const tooltipY = Theme.barHeight
+ SettingsData.topBarSpacing + Theme.spacingXS + SettingsData.topBarSpacing + Theme.spacingXS;
tooltipLoader.item.showTooltip( tooltipLoader.item.showTooltip(
delegateItem.tooltipText, globalPos.x, delegateItem.tooltipText, globalPos.x,
tooltipY, root.parentScreen) tooltipY, root.parentScreen);
} }
} }
onExited: { onExited: {
if (root.hoveredItem === delegateItem) { if (root.hoveredItem === delegateItem) {
root.hoveredItem = null root.hoveredItem = null;
if (tooltipLoader.item) if (tooltipLoader.item) {
tooltipLoader.item.hideTooltip() tooltipLoader.item.hideTooltip();
}
tooltipLoader.active = false tooltipLoader.active = false;
} }
} }
} }
@@ -325,16 +334,16 @@ Rectangle {
property point anchorPos: Qt.point(0, 0) property point anchorPos: Qt.point(0, 0)
function showAt(x, y) { function showAt(x, y) {
screen = root.parentScreen screen = root.parentScreen;
anchorPos = Qt.point(x, y) anchorPos = Qt.point(x, y);
isVisible = true isVisible = true;
visible = true visible = true;
} }
function close() { function close() {
isVisible = false isVisible = false;
visible = false visible = false;
windowContextMenuLoader.active = false windowContextMenuLoader.active = false;
} }
implicitWidth: 100 implicitWidth: 100
@@ -355,15 +364,15 @@ Rectangle {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: contextMenuWindow.close() onClicked: contextMenuWindow.close();
} }
Rectangle { Rectangle {
x: { x: {
var left = 10 const left = 10;
var right = contextMenuWindow.width - width - 10 const right = contextMenuWindow.width - width - 10;
var want = contextMenuWindow.anchorPos.x - width / 2 const want = contextMenuWindow.anchorPos.x - width / 2;
return Math.max(left, Math.min(right, want)) return Math.max(left, Math.min(right, want));
} }
y: contextMenuWindow.anchorPos.y y: contextMenuWindow.anchorPos.y
width: 100 width: 100
@@ -394,9 +403,9 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if (contextMenuWindow.currentWindow) { if (contextMenuWindow.currentWindow) {
contextMenuWindow.currentWindow.close() contextMenuWindow.currentWindow.close();
} }
contextMenuWindow.close() contextMenuWindow.close();
} }
} }
} }

View File

@@ -12,28 +12,23 @@ PanelWindow {
property var targetScreen: null property var targetScreen: null
function showTooltip(text, x, y, screen) { function showTooltip(text, x, y, screen) {
tooltipText = text tooltipText = text;
targetScreen = screen targetScreen = screen;
const screenX = screen ? screen.x : 0;
var screenX = screen ? screen.x : 0 targetX = x - screenX;
targetX = x - screenX targetY = y;
targetY = y visible = true;
visible = true
} }
function hideTooltip() { function hideTooltip() {
visible = false visible = false;
} }
screen: targetScreen screen: targetScreen
implicitWidth: Math.min(300, Math.max( implicitWidth: Math.min(300, Math.max(120, textContent.implicitWidth + Theme.spacingM * 2))
120,
textContent.implicitWidth + Theme.spacingM * 2))
implicitHeight: textContent.implicitHeight + Theme.spacingS * 2 implicitHeight: textContent.implicitHeight + Theme.spacingS * 2
color: "transparent" color: "transparent"
visible: false visible: false
WlrLayershell.layer: WlrLayershell.Overlay WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1 WlrLayershell.exclusiveZone: -1
@@ -56,6 +51,7 @@ PanelWindow {
Text { Text {
id: textContent id: textContent
anchors.centerIn: parent anchors.centerIn: parent
text: root.tooltipText text: root.tooltipText
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
@@ -65,5 +61,7 @@ PanelWindow {
elide: Text.ElideRight elide: Text.ElideRight
width: parent.width - Theme.spacingM * 2 width: parent.width - Theme.spacingM * 2
} }
} }
} }

View File

@@ -11,22 +11,22 @@ Rectangle {
property var parentScreen: null property var parentScreen: null
property real widgetHeight: 30 property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS
readonly property int calculatedWidth: SystemTray.items.values.length > 0 ? SystemTray.items.values.length * 24 + horizontalPadding * 2 : 0
readonly property int calculatedWidth: SystemTray.items.values.length
> 0 ? SystemTray.items.values.length
* 24 + horizontalPadding * 2 : 0
width: calculatedWidth width: calculatedWidth
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SystemTray.items.values.length === 0) if (SystemTray.items.values.length === 0) {
return "transparent" return "transparent";
}
if (SettingsData.topBarNoBackground) return "transparent"
const baseColor = Theme.secondaryHover if (SettingsData.topBarNoBackground) {
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, return "transparent";
baseColor.a * Theme.widgetTransparency) }
const baseColor = Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
visible: SystemTray.items.values.length > 0 visible: SystemTray.items.values.length > 0
@@ -42,21 +42,22 @@ Rectangle {
delegate: Item { delegate: Item {
property var trayItem: modelData property var trayItem: modelData
property string iconSource: { property string iconSource: {
let icon = trayItem && trayItem.icon let icon = trayItem && trayItem.icon;
if (typeof icon === 'string' || icon instanceof String) { if (typeof icon === 'string' || icon instanceof String) {
if (icon.includes("?path=")) { if (icon.includes("?path=")) {
const split = icon.split("?path=") const split = icon.split("?path=");
if (split.length !== 2) if (split.length !== 2) {
return icon return icon;
const name = split[0] }
const path = split[1]
const fileName = name.substring( const name = split[0];
name.lastIndexOf("/") + 1) const path = split[1];
return `file://${path}/${fileName}` const fileName = name.substring(name.lastIndexOf("/") + 1);
return `file://${path}/${fileName}`;
} }
return icon return icon;
} }
return "" return "";
} }
width: 24 width: 24
@@ -74,7 +75,9 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
IconImage { IconImage {
@@ -94,37 +97,36 @@ Rectangle {
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: mouse => { onClicked: (mouse) => {
if (!trayItem) if (!trayItem) {
return return;
}
if (mouse.button === Qt.LeftButton if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
&& !trayItem.onlyMenu) { trayItem.activate();
trayItem.activate() return ;
return }
} if (trayItem.hasMenu) {
const globalPos = mapToGlobal(0, 0);
if (trayItem.hasMenu) { const currentScreen = parentScreen || Screen;
var globalPos = mapToGlobal(0, 0) const screenX = currentScreen.x || 0;
var currentScreen = parentScreen const relativeX = globalPos.x - screenX;
|| Screen menuAnchor.menu = trayItem.menu;
var screenX = currentScreen.x || 0 menuAnchor.anchor.window = parentWindow;
var relativeX = globalPos.x - screenX menuAnchor.anchor.rect = Qt.rect(relativeX, Theme.barHeight + Theme.spacingS, parent.width, 1);
menuAnchor.menu = trayItem.menu menuAnchor.open();
menuAnchor.anchor.window = parentWindow }
menuAnchor.anchor.rect = Qt.rect( }
relativeX,
Theme.barHeight + Theme.spacingS,
parent.width, 1)
menuAnchor.open()
}
}
} }
} }
} }
} }
QsMenuAnchor { QsMenuAnchor {
id: menuAnchor id: menuAnchor
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -13,22 +13,25 @@ Rectangle {
property string section: "right" property string section: "right"
property var popupTarget: null property var popupTarget: null
property var parentScreen: null property var parentScreen: null
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal toggleVpnPopup() signal toggleVpnPopup()
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
width: Theme.iconSize + horizontalPadding * 2 width: Theme.iconSize + horizontalPadding * 2
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const base = clickArea.containsMouse || (popupTarget && popupTarget.shouldBeVisible) ? Theme.primaryPressed : Theme.secondaryHover return "transparent";
return Qt.rgba(base.r, base.g, base.b, base.a * Theme.widgetTransparency) }
const base = clickArea.containsMouse || (popupTarget && popupTarget.shouldBeVisible) ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(base.r, base.g, base.b, base.a * Theme.widgetTransparency);
} }
DankIcon { DankIcon {
id: icon id: icon
name: VpnService.isBusy ? "sync" : (VpnService.connected ? "vpn_lock" : "vpn_key_off") name: VpnService.isBusy ? "sync" : (VpnService.connected ? "vpn_lock" : "vpn_key_off")
size: Theme.iconSize - 6 size: Theme.iconSize - 6
color: VpnService.connected ? Theme.primary : Theme.surfaceText color: VpnService.connected ? Theme.primary : Theme.surfaceText
@@ -41,27 +44,30 @@ Rectangle {
to: 360 to: 360
duration: 900 duration: 900
} }
} }
MouseArea { MouseArea {
id: clickArea id: clickArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) { if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0 const screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen) popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
} }
root.toggleVpnPopup() root.toggleVpnPopup();
} }
} }
Rectangle { Rectangle {
id: tooltip id: tooltip
width: Math.max(120, tooltipText.contentWidth + Theme.spacingM * 2) width: Math.max(120, tooltipText.contentWidth + Theme.spacingM * 2)
height: tooltipText.contentHeight + Theme.spacingS * 2 height: tooltipText.contentHeight + Theme.spacingS * 2
radius: Theme.cornerRadius radius: Theme.cornerRadius
@@ -76,19 +82,32 @@ Rectangle {
Text { Text {
id: tooltipText id: tooltipText
anchors.centerIn: parent anchors.centerIn: parent
text: { text: {
if (!VpnService.connected) return "VPN Disconnected" if (!VpnService.connected) {
const names = VpnService.activeNames || [] return "VPN Disconnected";
if (names.length <= 1) return "VPN Connected • " + (names[0] || "") }
return "VPN Connected • " + names[0] + " +" + (names.length - 1)
const names = VpnService.activeNames || [];
if (names.length <= 1) {
return "VPN Connected • " + (names[0] || "");
}
return "VPN Connected • " + names[0] + " +" + (names.length - 1);
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: Theme.shortDuration; easing.type: Theme.standardEasing } NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
} }
} }
} }

View File

@@ -1,13 +1,14 @@
// No external details import; content inlined for consistency
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import Quickshell.Widgets import Quickshell.Widgets
import qs.Widgets
import qs.Common import qs.Common
import qs.Services import qs.Services
// No external details import; content inlined for consistency import qs.Widgets
DankPopout { DankPopout {
id: root id: root
@@ -16,11 +17,11 @@ DankPopout {
property var triggerScreen: null property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) { function setTriggerPosition(x, y, width, section, screen) {
triggerX = x triggerX = x;
triggerY = y triggerY = y;
triggerWidth = width triggerWidth = width;
triggerSection = section triggerSection = section;
triggerScreen = screen triggerScreen = screen;
} }
popupWidth: 360 popupWidth: 360
@@ -37,6 +38,7 @@ DankPopout {
content: Component { content: Component {
Rectangle { Rectangle {
id: content id: content
implicitHeight: contentColumn.height + Theme.spacingL * 2 implicitHeight: contentColumn.height + Theme.spacingL * 2
color: Theme.popupBackground() color: Theme.popupBackground()
radius: Theme.cornerRadius radius: Theme.cornerRadius
@@ -45,11 +47,10 @@ DankPopout {
antialiasing: true antialiasing: true
smooth: true smooth: true
focus: true focus: true
Keys.onPressed: function(event) {
Keys.onPressed: function (event) {
if (event.key === Qt.Key_Escape) { if (event.key === Qt.Key_Escape) {
root.close() root.close();
event.accepted = true event.accepted = true;
} }
} }
@@ -85,6 +86,7 @@ DankPopout {
Column { Column {
id: contentColumn id: contentColumn
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
@@ -94,6 +96,7 @@ DankPopout {
Item { Item {
width: parent.width width: parent.width
height: 32 height: 32
StyledText { StyledText {
text: "VPN Connections" text: "VPN Connections"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -120,17 +123,21 @@ DankPopout {
MouseArea { MouseArea {
id: closeArea id: closeArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: root.close() onPressed: root.close()
} }
} }
} }
// Inlined VPN details // Inlined VPN details
Rectangle { Rectangle {
id: vpnDetail id: vpnDetail
width: parent.width width: parent.width
implicitHeight: detailsColumn.implicitHeight + Theme.spacingM * 2 implicitHeight: detailsColumn.implicitHeight + Theme.spacingM * 2
radius: Theme.cornerRadius radius: Theme.cornerRadius
@@ -141,6 +148,7 @@ DankPopout {
Column { Column {
id: detailsColumn id: detailsColumn
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
spacing: Theme.spacingS spacing: Theme.spacingS
@@ -151,20 +159,32 @@ DankPopout {
StyledText { StyledText {
text: { text: {
if (!VpnService.connected) return "Active: None" if (!VpnService.connected) {
const names = VpnService.activeNames || [] return "Active: None";
if (names.length <= 1) return "Active: " + (names[0] || "VPN") }
return "Active: " + names[0] + " +" + (names.length - 1)
const names = VpnService.activeNames || [];
if (names.length <= 1) {
return "Active: " + (names[0] || "VPN");
}
return "Active: " + names[0] + " +" + (names.length - 1);
} }
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText color: Theme.surfaceText
font.weight: Font.Medium font.weight: Font.Medium
} }
Item { Layout.fillWidth: true; height: 1 } Item {
Layout.fillWidth: true
height: 1
}
// Removed Quick Connect for clarity // Removed Quick Connect for clarity
Item { width: 1; height: 1 } Item {
width: 1
height: 1
}
// Disconnect all (shown only when any active) // Disconnect all (shown only when any active)
Rectangle { Rectangle {
@@ -180,21 +200,40 @@ DankPopout {
Row { Row {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingXS spacing: Theme.spacingXS
DankIcon { name: "link_off"; size: Theme.fontSizeSmall; color: Theme.surfaceText }
StyledText { text: "Disconnect"; font.pixelSize: Theme.fontSizeSmall; color: Theme.surfaceText; font.weight: Font.Medium } DankIcon {
name: "link_off"
size: Theme.fontSizeSmall
color: Theme.surfaceText
}
StyledText {
text: "Disconnect"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
} }
MouseArea { MouseArea {
id: discAllArea id: discAllArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: VpnService.disconnectAllActive() onClicked: VpnService.disconnectAllActive()
} }
} }
} }
Rectangle { height: 1; width: parent.width; color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) } Rectangle {
height: 1
width: parent.width
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
}
DankFlickable { DankFlickable {
width: parent.width width: parent.width
@@ -204,6 +243,7 @@ DankPopout {
Column { Column {
id: listCol id: listCol
width: parent.width width: parent.width
spacing: Theme.spacingXS spacing: Theme.spacingXS
@@ -215,16 +255,38 @@ DankPopout {
Column { Column {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingS spacing: Theme.spacingS
DankIcon { name: "playlist_remove"; size: 36; color: Theme.surfaceVariantText; anchors.horizontalCenter: parent.horizontalCenter }
StyledText { text: "No VPN profiles found"; font.pixelSize: Theme.fontSizeMedium; color: Theme.surfaceVariantText; anchors.horizontalCenter: parent.horizontalCenter } DankIcon {
StyledText { text: "Add a VPN in NetworkManager"; font.pixelSize: Theme.fontSizeSmall; color: Theme.surfaceVariantText; anchors.horizontalCenter: parent.horizontalCenter } name: "playlist_remove"
size: 36
color: Theme.surfaceVariantText
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: "No VPN profiles found"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: "Add a VPN in NetworkManager"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
anchors.horizontalCenter: parent.horizontalCenter
}
} }
} }
Repeater { Repeater {
model: VpnService.profiles model: VpnService.profiles
delegate: Rectangle { delegate: Rectangle {
required property var modelData required property var modelData
width: parent ? parent.width : 300 width: parent ? parent.width : 300
height: 50 height: 50
radius: Theme.cornerRadius radius: Theme.cornerRadius
@@ -249,56 +311,109 @@ DankPopout {
Column { Column {
spacing: 2 spacing: 2
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
StyledText { StyledText {
text: modelData.name text: modelData.name
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: VpnService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText color: VpnService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText
}
StyledText {
text: {
if (modelData.type === "wireguard") {
return "WireGuard";
}
const svc = modelData.serviceType || "";
if (svc.indexOf("openvpn") !== -1) {
return "OpenVPN";
}
if (svc.indexOf("wireguard") !== -1) {
return "WireGuard (plugin)";
}
if (svc.indexOf("openconnect") !== -1) {
return "OpenConnect";
}
if (svc.indexOf("fortissl") !== -1 || svc.indexOf("forti") !== -1) {
return "Fortinet";
}
if (svc.indexOf("strongswan") !== -1) {
return "IPsec (strongSwan)";
}
if (svc.indexOf("libreswan") !== -1) {
return "IPsec (Libreswan)";
}
if (svc.indexOf("l2tp") !== -1) {
return "L2TP/IPsec";
}
if (svc.indexOf("pptp") !== -1) {
return "PPTP";
}
if (svc.indexOf("vpnc") !== -1) {
return "Cisco (vpnc)";
}
if (svc.indexOf("sstp") !== -1) {
return "SSTP";
}
if (svc) {
const parts = svc.split('.');
return parts[parts.length - 1];
}
return "VPN";
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
}
} }
StyledText { Item {
text: { Layout.fillWidth: true
if (modelData.type === "wireguard") return "WireGuard" height: 1
var svc = modelData.serviceType || ""
if (svc.indexOf("openvpn") !== -1) return "OpenVPN"
if (svc.indexOf("wireguard") !== -1) return "WireGuard (plugin)"
if (svc.indexOf("openconnect") !== -1) return "OpenConnect"
if (svc.indexOf("fortissl") !== -1 || svc.indexOf("forti") !== -1) return "Fortinet"
if (svc.indexOf("strongswan") !== -1) return "IPsec (strongSwan)"
if (svc.indexOf("libreswan") !== -1) return "IPsec (Libreswan)"
if (svc.indexOf("l2tp") !== -1) return "L2TP/IPsec"
if (svc.indexOf("pptp") !== -1) return "PPTP"
if (svc.indexOf("vpnc") !== -1) return "Cisco (vpnc)"
if (svc.indexOf("sstp") !== -1) return "SSTP"
if (svc) {
var parts = svc.split('.')
return parts[parts.length-1]
}
return "VPN"
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
} }
}
Item { Layout.fillWidth: true; height: 1 }
} }
MouseArea { MouseArea {
id: rowArea id: rowArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: VpnService.toggle(modelData.uuid) onClicked: VpnService.toggle(modelData.uuid)
} }
} }
}
Item {
height: 1
width: 1
} }
Item { height: 1; width: 1 }
} }
} }
} }
} }
} }
} }
} }
} }

View File

@@ -13,18 +13,19 @@ Rectangle {
property real widgetHeight: 30 property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS
signal clicked signal clicked()
visible: SettingsData.weatherEnabled visible: SettingsData.weatherEnabled
width: visible ? Math.min(100, width: visible ? Math.min(100, weatherRow.implicitWidth + horizontalPadding * 2) : 0
weatherRow.implicitWidth + horizontalPadding * 2) : 0
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground) {
const baseColor = weatherArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover return "transparent";
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, }
baseColor.a * Theme.widgetTransparency)
const baseColor = weatherArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
} }
Ref { Ref {
@@ -46,16 +47,18 @@ Rectangle {
StyledText { StyledText {
text: { text: {
var temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp;
if (temp === undefined || temp === null || temp === 0) { if (temp === undefined || temp === null || temp === 0) {
return "--°" + (SettingsData.useFahrenheit ? "F" : "C") return "--°" + (SettingsData.useFahrenheit ? "F" : "C");
} }
return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C")
return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C");
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
MouseArea { MouseArea {
@@ -66,15 +69,13 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: { onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) { if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0) const globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen const currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0 const screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition( popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
} }
root.clicked() root.clicked();
} }
} }
@@ -83,6 +84,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
Behavior on width { Behavior on width {
@@ -90,5 +92,7 @@ Rectangle {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }

View File

@@ -22,260 +22,190 @@ Rectangle {
} }
property var workspaceList: { property var workspaceList: {
if (CompositorService.isNiri) { if (CompositorService.isNiri) {
var baseList = getNiriWorkspaces() const baseList = getNiriWorkspaces()
return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList
} else if (CompositorService.isHyprland) { }
var workspaces = Hyprland.workspaces ? Hyprland.workspaces.values : [] if (CompositorService.isHyprland) {
const workspaces = Hyprland.workspaces?.values || []
if (workspaces.length === 0) { if (workspaces.length === 0) {
return [{id: 1, name: "1"}] return [{
"id": 1,
"name": "1"
}]
} }
var sorted = workspaces.slice().sort((a, b) => a.id - b.id) const sorted = workspaces.slice().sort((a, b) => a.id - b.id)
return SettingsData.showWorkspacePadding ? padWorkspaces(sorted) : sorted return SettingsData.showWorkspacePadding ? padWorkspaces(sorted) : sorted
} }
return [1] return [1]
} }
function getWorkspaceIcons(ws) { function getWorkspaceIcons(ws) {
if (!SettingsData.showWorkspaceApps) return [] if (!SettingsData.showWorkspaceApps || !ws) {
return []
var chunks = [] }
if (!ws) return chunks
var targetWorkspaceId let targetWorkspaceId
if (CompositorService.isNiri) { if (CompositorService.isNiri) {
// For Niri, we need to find the workspace ID from allWorkspaces const wsNumber = typeof ws === "number" ? ws : -1
var wsNumber = typeof ws === "number" ? ws : -1 if (wsNumber <= 0) {
if (wsNumber > 0) { return []
for (var j = 0; j < NiriService.allWorkspaces.length; j++) {
var workspace = NiriService.allWorkspaces[j]
if (workspace.idx + 1 === wsNumber && workspace.output === root.screenName) {
targetWorkspaceId = workspace.id
break
}
}
} }
if (targetWorkspaceId === undefined) return chunks const workspace = NiriService.allWorkspaces.find(w => w.idx + 1 === wsNumber && w.output === root.screenName)
if (!workspace) {
return []
}
targetWorkspaceId = workspace.id
} else if (CompositorService.isHyprland) { } else if (CompositorService.isHyprland) {
targetWorkspaceId = ws.id !== undefined ? ws.id : ws targetWorkspaceId = ws.id !== undefined ? ws.id : ws
} else { } else {
return chunks return []
} }
var wins = [] const wins = CompositorService.isNiri ? (NiriService.windows || []) : (Hyprland.clients?.values || [])
if (CompositorService.isNiri) {
wins = NiriService.windows || []
} else if (CompositorService.isHyprland) {
wins = Hyprland.clients ? Hyprland.clients.values : []
}
var byApp = {} const byApp = {}
var isActiveWs = false const isActiveWs = CompositorService.isNiri ? NiriService.allWorkspaces.some(ws => ws.id === targetWorkspaceId && ws.is_active) : targetWorkspaceId === root.currentWorkspace
if (CompositorService.isNiri) {
for (var j = 0; j < NiriService.allWorkspaces.length; j++) {
var ws2 = NiriService.allWorkspaces[j]
if (ws2.id === targetWorkspaceId && ws2.is_active) {
isActiveWs = true
break
}
}
} else if (CompositorService.isHyprland) {
isActiveWs = targetWorkspaceId === root.currentWorkspace
}
for (var i = 0; i < wins.length; i++) { wins.forEach((w, i) => {
var w = wins[i] if (!w) {
if (!w) continue return
}
var winWs const winWs = CompositorService.isNiri ? w.workspace_id : (w.workspace?.id ?? w.workspaceId)
if (CompositorService.isNiri) {
winWs = w.workspace_id
} else if (CompositorService.isHyprland) {
winWs = w.workspace && w.workspace.id !== undefined ? w.workspace.id : w.workspaceId
}
if (winWs === undefined || winWs === null) continue
if (winWs !== targetWorkspaceId) continue
var keyBase = (w.app_id || w.appId || w.class || w.windowClass || w.exe || "unknown").toLowerCase() if (winWs === undefined || winWs === null || winWs !== targetWorkspaceId) {
var key = isActiveWs ? keyBase + "_" + i : keyBase return
}
if (!byApp[key]) { const keyBase = (w.app_id || w.appId || w.class || w.windowClass || w.exe || "unknown").toLowerCase()
var icon = Quickshell.iconPath(DesktopEntries.heuristicLookup(Paths.moddedAppId(keyBase))?.icon, true) const key = isActiveWs ? `${keyBase}_${i}` : keyBase
byApp[key] = {
type: "icon",
icon: icon,
active: !!w.is_focused || !!w.activated,
count: 1,
windowId: w.id || w.address,
fallbackText: w.app_id || w.appId || w.class || w.title || ""
}
} else {
byApp[key].count++
if (w.is_focused || w.activated) byApp[key].active = true
}
}
for (var k in byApp) if (!byApp[key]) {
chunks.push(byApp[k]) const icon = Quickshell.iconPath(DesktopEntries.heuristicLookup(Paths.moddedAppId(keyBase))?.icon, true)
byApp[key] = {
"type": "icon",
"icon": icon,
"active": !!(w.is_focused || w.activated),
"count": 1,
"windowId": w.id || w.address,
"fallbackText": w.app_id || w.appId || w.class || w.title || ""
}
} else {
byApp[key].count++
if (w.is_focused || w.activated) {
byApp[key].active = true
}
}
})
return chunks return Object.values(byApp)
} }
function padWorkspaces(list) { function padWorkspaces(list) {
var padded = list.slice() const padded = list.slice()
const placeholder = CompositorService.isHyprland ? {
"id": -1,
"name": ""
} : -1
while (padded.length < 3) { while (padded.length < 3) {
if (CompositorService.isHyprland) { padded.push(placeholder)
padded.push({id: -1, name: ""})
} else {
padded.push(-1)
}
} }
return padded return padded
} }
function getNiriWorkspaces() { function getNiriWorkspaces() {
if (NiriService.allWorkspaces.length === 0) if (NiriService.allWorkspaces.length === 0) {
return [1, 2] return [1, 2]
if (!root.screenName)
return NiriService.getCurrentOutputWorkspaceNumbers()
var displayWorkspaces = []
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
var ws = NiriService.allWorkspaces[i]
if (ws.output === root.screenName)
displayWorkspaces.push(ws.idx + 1)
} }
if (!root.screenName) {
return NiriService.getCurrentOutputWorkspaceNumbers()
}
const displayWorkspaces = NiriService.allWorkspaces.filter(ws => ws.output === root.screenName).map(ws => ws.idx + 1)
return displayWorkspaces.length > 0 ? displayWorkspaces : [1, 2] return displayWorkspaces.length > 0 ? displayWorkspaces : [1, 2]
} }
function getNiriActiveWorkspace() { function getNiriActiveWorkspace() {
if (NiriService.allWorkspaces.length === 0) if (NiriService.allWorkspaces.length === 0) {
return 1 return 1
if (!root.screenName)
return NiriService.getCurrentWorkspaceNumber()
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
var ws = NiriService.allWorkspaces[i]
if (ws.output === root.screenName && ws.is_active)
return ws.idx + 1
} }
return 1
if (!root.screenName) {
return NiriService.getCurrentWorkspaceNumber()
}
const activeWs = NiriService.allWorkspaces.find(ws => ws.output === root.screenName && ws.is_active)
return activeWs ? activeWs.idx + 1 : 1
} }
readonly property real padding: (widgetHeight - workspaceRow.implicitHeight) / 2 readonly property real padding: (widgetHeight - workspaceRow.implicitHeight) / 2
function getRealWorkspaces() {
return root.workspaceList.filter(ws => {
if (CompositorService.isHyprland) {
return ws && ws.id !== -1
}
return ws !== -1
})
}
function switchWorkspace(direction) {
if (CompositorService.isNiri) {
const realWorkspaces = getRealWorkspaces()
if (realWorkspaces.length < 2) {
return
}
const currentIndex = realWorkspaces.findIndex(ws => ws === root.currentWorkspace)
const validIndex = currentIndex === -1 ? 0 : currentIndex
const nextIndex = direction > 0 ? (validIndex + 1) % realWorkspaces.length : (validIndex - 1 + realWorkspaces.length) % realWorkspaces.length
NiriService.switchToWorkspace(realWorkspaces[nextIndex] - 1)
} else if (CompositorService.isHyprland) {
const command = direction > 0 ? "workspace r+1" : "workspace r-1"
Hyprland.dispatch(command)
}
}
width: workspaceRow.implicitWidth + padding * 2 width: workspaceRow.implicitWidth + padding * 2
height: widgetHeight height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: { color: {
if (SettingsData.topBarNoBackground) return "transparent" if (SettingsData.topBarNoBackground)
return "transparent"
const baseColor = Theme.surfaceTextHover const baseColor = Theme.surfaceTextHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
baseColor.a * Theme.widgetTransparency)
} }
visible: CompositorService.isNiri || CompositorService.isHyprland visible: CompositorService.isNiri || CompositorService.isHyprland
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
property real scrollAccumulator: 0 property real scrollAccumulator: 0
property real touchpadThreshold: 500 property real touchpadThreshold: 500
onWheel: (wheel) => {
const deltaY = wheel.angleDelta.y
const isMouseWheel = Math.abs(deltaY) >= 120
&& (Math.abs(deltaY) % 120) === 0
if (isMouseWheel) {
// Direct mouse wheel action
if (CompositorService.isNiri) {
var realWorkspaces = [];
for (var i = 0; i < root.workspaceList.length; i++) {
if (root.workspaceList[i] !== -1) {
realWorkspaces.push(root.workspaceList[i]);
}
}
if (realWorkspaces.length < 2) return; onWheel: wheel => {
const deltaY = wheel.angleDelta.y
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0
const direction = deltaY < 0 ? 1 : -1
var currentIndex = -1; if (isMouseWheel) {
for (var i = 0; i < realWorkspaces.length; i++) { switchWorkspace(direction)
if (realWorkspaces[i] === root.currentWorkspace) { } else {
currentIndex = i; scrollAccumulator += deltaY
break;
}
}
if (currentIndex === -1) currentIndex = 0;
var nextIndex; if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
if (deltaY < 0) { const touchDirection = scrollAccumulator < 0 ? 1 : -1
nextIndex = (currentIndex + 1) % realWorkspaces.length; switchWorkspace(touchDirection)
} else { scrollAccumulator = 0
nextIndex = (currentIndex - 1 + realWorkspaces.length) % realWorkspaces.length; }
} }
NiriService.switchToWorkspace(realWorkspaces[nextIndex] - 1);
} else if (CompositorService.isHyprland) { wheel.accepted = true
if (deltaY < 0) { }
Hyprland.dispatch("workspace r+1");
} else {
Hyprland.dispatch("workspace r-1");
}
}
} else {
// Touchpad - accumulate small deltas
scrollAccumulator += deltaY
if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
if (CompositorService.isNiri) {
var realWorkspaces = [];
for (var i = 0; i < root.workspaceList.length; i++) {
if (root.workspaceList[i] !== -1) {
realWorkspaces.push(root.workspaceList[i]);
}
}
if (realWorkspaces.length < 2) {
scrollAccumulator = 0;
return;
}
var currentIndex = -1;
for (var i = 0; i < realWorkspaces.length; i++) {
if (realWorkspaces[i] === root.currentWorkspace) {
currentIndex = i;
break;
}
}
if (currentIndex === -1) currentIndex = 0;
var nextIndex;
if (scrollAccumulator < 0) {
nextIndex = (currentIndex + 1) % realWorkspaces.length;
} else {
nextIndex = (currentIndex - 1 + realWorkspaces.length) % realWorkspaces.length;
}
NiriService.switchToWorkspace(realWorkspaces[nextIndex] - 1);
} else if (CompositorService.isHyprland) {
if (scrollAccumulator < 0) {
Hyprland.dispatch("workspace r+1");
} else {
Hyprland.dispatch("workspace r-1");
}
}
scrollAccumulator = 0
}
}
wheel.accepted = true
}
} }
Row { Row {
@@ -302,23 +232,16 @@ Rectangle {
} }
property bool isHovered: mouseArea.containsMouse property bool isHovered: mouseArea.containsMouse
property var workspaceData: { property var workspaceData: {
if (isPlaceholder) if (isPlaceholder) {
return null return null
if (CompositorService.isNiri) {
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
var ws = NiriService.allWorkspaces[i]
if (ws.idx + 1 === modelData && ws.output === root.screenName)
return ws
}
} else if (CompositorService.isHyprland) {
return modelData
} }
return null
if (CompositorService.isNiri) {
return NiriService.allWorkspaces.find(ws => ws.idx + 1 === modelData && ws.output === root.screenName) || null
}
return CompositorService.isHyprland ? modelData : null
} }
property var iconData: workspaceData property var iconData: workspaceData?.name ? SettingsData.getWorkspaceNameIcon(workspaceData.name) : null
&& workspaceData.name ? SettingsData.getWorkspaceNameIcon(
workspaceData.name) : null
property bool hasIcon: iconData !== null property bool hasIcon: iconData !== null
property var icons: SettingsData.showWorkspaceApps ? root.getWorkspaceIcons(CompositorService.isHyprland ? modelData : (modelData === -1 ? null : modelData)) : [] property var icons: SettingsData.showWorkspaceApps ? root.getWorkspaceIcons(CompositorService.isHyprland ? modelData : (modelData === -1 ? null : modelData)) : []
@@ -344,14 +267,14 @@ Rectangle {
cursorShape: isPlaceholder ? Qt.ArrowCursor : Qt.PointingHandCursor cursorShape: isPlaceholder ? Qt.ArrowCursor : Qt.PointingHandCursor
enabled: !isPlaceholder enabled: !isPlaceholder
onClicked: { onClicked: {
if (!isPlaceholder) { if (isPlaceholder) {
if (CompositorService.isNiri) { return
NiriService.switchToWorkspace(modelData - 1) }
} else if (CompositorService.isHyprland) {
if (modelData && modelData.id) { if (CompositorService.isNiri) {
Hyprland.dispatch(`workspace ${modelData.id}`) NiriService.switchToWorkspace(modelData - 1)
} } else if (CompositorService.isHyprland && modelData?.id) {
} Hyprland.dispatch(`workspace ${modelData.id}`)
} }
} }
} }
@@ -416,53 +339,36 @@ Rectangle {
DankIcon { DankIcon {
visible: hasIcon && iconData.type === "icon" && (!SettingsData.showWorkspaceApps || icons.length === 0) visible: hasIcon && iconData.type === "icon" && (!SettingsData.showWorkspaceApps || icons.length === 0)
anchors.centerIn: parent anchors.centerIn: parent
name: hasIcon name: (hasIcon && iconData.type === "icon") ? iconData.value : ""
&& iconData.type === "icon" ? iconData.value : ""
size: Theme.fontSizeSmall size: Theme.fontSizeSmall
color: isActive ? Qt.rgba(Theme.surfaceContainer.r, color: isActive ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : Theme.surfaceTextMedium
Theme.surfaceContainer.g,
Theme.surfaceContainer.b,
0.95) : Theme.surfaceTextMedium
weight: isActive && !isPlaceholder ? 500 : 400 weight: isActive && !isPlaceholder ? 500 : 400
} }
StyledText { StyledText {
visible: hasIcon && iconData.type === "text" && (!SettingsData.showWorkspaceApps || icons.length === 0) visible: hasIcon && iconData.type === "text" && (!SettingsData.showWorkspaceApps || icons.length === 0)
anchors.centerIn: parent anchors.centerIn: parent
text: hasIcon text: (hasIcon && iconData.type === "text") ? iconData.value : ""
&& iconData.type === "text" ? iconData.value : "" color: isActive ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : Theme.surfaceTextMedium
color: isActive ? Qt.rgba(Theme.surfaceContainer.r,
Theme.surfaceContainer.g,
Theme.surfaceContainer.b,
0.95) : Theme.surfaceTextMedium
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: isActive font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal
&& !isPlaceholder ? Font.DemiBold : Font.Normal
} }
StyledText { StyledText {
visible: (SettingsData.showWorkspaceIndex && !hasIcon && (!SettingsData.showWorkspaceApps || icons.length === 0)) visible: (SettingsData.showWorkspaceIndex && !hasIcon && (!SettingsData.showWorkspaceApps || icons.length === 0))
anchors.centerIn: parent anchors.centerIn: parent
text: { text: {
if (CompositorService.isHyprland) { const isPlaceholder = CompositorService.isHyprland ? (modelData?.id === -1) : (modelData === -1)
if (modelData && modelData.id === -1) {
return index + 1 if (isPlaceholder) {
}
return modelData && modelData.id ? modelData.id : ""
}
if (modelData === -1) {
return index + 1 return index + 1
} }
return modelData - 1
return CompositorService.isHyprland ? (modelData?.id || "") : (modelData - 1)
} }
color: isActive ? Qt.rgba( color: isActive ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium
Theme.surfaceContainer.r,
Theme.surfaceContainer.g,
Theme.surfaceContainer.b,
0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.weight: isActive font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal
&& !isPlaceholder ? Font.DemiBold : Font.Normal
} }
Behavior on width { Behavior on width {
@@ -481,4 +387,4 @@ Rectangle {
} }
} }
} }
} }

View File

@@ -17,43 +17,38 @@ Singleton {
if (applications.length === 0) if (applications.length === 0)
return [] return []
const queryLower = query.toLowerCase() const queryLower = query.toLowerCase().trim()
const scoredApps = [] const scoredApps = []
for (const app of applications) { for (const app of applications) {
const name = (app.name || "").toLowerCase() const name = (app.name || "").toLowerCase()
const genericName = (app.genericName || "").toLowerCase() const genericName = (app.genericName || "").toLowerCase()
const comment = (app.comment || "").toLowerCase() const comment = (app.comment || "").toLowerCase()
const keywords = app.keywords ? app.keywords.map(k => k.toLowerCase()) : [] const keywords = app.keywords ? app.keywords.map(k => k.toLowerCase()) : []
let score = 0 let score = 0
let matched = false let matched = false
const nameWords = name.trim().split(/\s+/).filter(w => w.length > 0) const nameWords = name.trim().split(/\s+/).filter(w => w.length > 0)
const containsAsWord = nameWords.includes(queryLower) const containsAsWord = nameWords.includes(queryLower)
const startsWithAsWord = nameWords.some(word => word.startsWith(queryLower)) const startsWithAsWord = nameWords.some(word => word.startsWith(queryLower))
if (name === queryLower) { if (name === queryLower) {
score = 10000 score = 10000
matched = true matched = true
} } else if (containsAsWord) {
else if (containsAsWord) {
score = 9500 + (100 - Math.min(name.length, 100)) score = 9500 + (100 - Math.min(name.length, 100))
matched = true matched = true
} } else if (name.startsWith(queryLower)) {
else if (name.startsWith(queryLower)) {
score = 9000 + (100 - Math.min(name.length, 100)) score = 9000 + (100 - Math.min(name.length, 100))
matched = true matched = true
} } else if (startsWithAsWord) {
else if (startsWithAsWord) {
score = 8500 + (100 - Math.min(name.length, 100)) score = 8500 + (100 - Math.min(name.length, 100))
matched = true matched = true
} } else if (name.includes(queryLower)) {
else if (name.includes(queryLower)) {
score = 8000 + (100 - Math.min(name.length, 100)) score = 8000 + (100 - Math.min(name.length, 100))
matched = true matched = true
} } else if (keywords.length > 0) {
else if (keywords.length > 0) {
for (const keyword of keywords) { for (const keyword of keywords) {
if (keyword === queryLower) { if (keyword === queryLower) {
score = 6000 score = 6000
@@ -73,29 +68,30 @@ Singleton {
if (!matched && genericName.includes(queryLower)) { if (!matched && genericName.includes(queryLower)) {
score = 4000 score = 4000
matched = true matched = true
} } else if (!matched && comment.includes(queryLower)) {
else if (!matched && comment.includes(queryLower)) {
score = 3000 score = 3000
matched = true matched = true
} } else if (!matched) {
else if (!matched) {
const nameFinder = new Fzf.Finder([app], { const nameFinder = new Fzf.Finder([app], {
"selector": a => a.name || "", "selector": a => a.name || "",
"casing": "case-insensitive", "casing": "case-insensitive",
"fuzzy": "v2" "fuzzy": "v2"
}) })
const fuzzyResults = nameFinder.find(query) const fuzzyResults = nameFinder.find(query)
if (fuzzyResults.length > 0 && fuzzyResults[0].score > 0) { if (fuzzyResults.length > 0 && fuzzyResults[0].score > 0) {
score = Math.min(fuzzyResults[0].score, 2000) score = Math.min(fuzzyResults[0].score, 2000)
matched = true matched = true
} }
} }
if (matched) { if (matched) {
scoredApps.push({ app, score }) scoredApps.push({
"app": app,
"score": score
})
} }
} }
scoredApps.sort((a, b) => b.score - a.score) scoredApps.sort((a, b) => b.score - a.score)
return scoredApps.slice(0, 50).map(item => item.app) return scoredApps.slice(0, 50).map(item => item.app)
} }

View File

@@ -1,4 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# https://github.com/jesperhh/qmlfmt # Find and format all QML files, then fix pragma ComponentBehavior
find . -name "*.qml" -exec qmlfmt -t 4 -i 4 -b 250 -w {} \; find . -name "*.qml" -exec sh -c '
qmlfmt -t 4 -i 4 -b 250 -w "$1"
sed -i "s/pragma ComponentBehavior$/pragma ComponentBehavior: Bound/g" "$1"
' _ {} \;