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 .
# Code formatting and linting
./qmlformat-all.sh # Format all QML files using project script
qmlformat -i **/*.qml # Format all QML files in place
qmlfmt -t 4 -i 4 -b 250 -w /path/to/file.qml # Format a QML file (requires qmlfmt, do not use qmlformat)
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
- Prefer property bindings over imperative code
- **CRITICAL**: NEVER add comments unless absolutely essential for complex logic understanding. Code should be self-documenting through clear naming and structure. Comments are a code smell indicating unclear implementation.
- Use guard statements, example `if (abc) { something() return;} somethingElse();`
- Don't use crazy ternary stuff, but use it for simple if else only. `propertyVal: a ? b : c`
2. **Naming Conventions**:
- **Services**: Use `Singleton` type with `id: root`
@@ -228,9 +229,7 @@ shell.qml # Main entry point (minimal orchestration)
- **Properties**: camelCase for properties, PascalCase for types
3. **Null-Safe Operations**:
- **Do NOT use** `?.` operator (not supported by qmlformat)
- **Use** `object && object.property` instead of `object?.property`
- **Example**: `activePlayer && activePlayer.trackTitle` instead of `activePlayer?.trackTitle`
- **Use** `object?.property`
4. **Component Structure**:
```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 ComponentBehavior: Bound
import QtCore
@@ -98,13 +99,9 @@ Singleton {
property var screenPreferences: ({})
readonly property string defaultFontFamily: "Inter Variable"
readonly property string defaultMonoFontFamily: "Fira Code"
readonly property string _homeUrl: StandardPaths.writableLocation(
StandardPaths.HomeLocation)
readonly property string _configUrl: StandardPaths.writableLocation(
StandardPaths.ConfigLocation)
readonly property string _configDir: _configUrl.startsWith(
"file://") ? _configUrl.substring(
7) : _configUrl
readonly property string _homeUrl: StandardPaths.writableLocation(StandardPaths.HomeLocation)
readonly property string _configUrl: StandardPaths.writableLocation(StandardPaths.ConfigLocation)
readonly property string _configDir: _configUrl.startsWith("file://") ? _configUrl.substring(7) : _configUrl
signal forceTopBarLayoutRefresh
signal widgetDataChanged
@@ -166,42 +163,20 @@ Singleton {
currentThemeName = settings.currentThemeName !== undefined ? settings.currentThemeName : "blue"
}
customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : ""
topBarTransparency = settings.topBarTransparency
!== undefined ? (settings.topBarTransparency
> 1 ? settings.topBarTransparency
/ 100 : settings.topBarTransparency) : 0.75
topBarWidgetTransparency = settings.topBarWidgetTransparency
!== undefined ? (settings.topBarWidgetTransparency
> 1 ? settings.topBarWidgetTransparency
/ 100 : settings.topBarWidgetTransparency) : 0.85
popupTransparency = settings.popupTransparency
!== undefined ? (settings.popupTransparency
> 1 ? settings.popupTransparency
/ 100 : settings.popupTransparency) : 0.92
dockTransparency = settings.dockTransparency
!== undefined ? (settings.dockTransparency
> 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
topBarTransparency = settings.topBarTransparency !== undefined ? (settings.topBarTransparency > 1 ? settings.topBarTransparency / 100 : settings.topBarTransparency) : 0.75
topBarWidgetTransparency = settings.topBarWidgetTransparency !== undefined ? (settings.topBarWidgetTransparency > 1 ? settings.topBarWidgetTransparency / 100 : settings.topBarWidgetTransparency) : 0.85
popupTransparency = settings.popupTransparency !== undefined ? (settings.popupTransparency > 1 ? settings.popupTransparency / 100 : settings.popupTransparency) : 0.92
dockTransparency = settings.dockTransparency !== undefined ? (settings.dockTransparency > 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
showMusic = settings.showMusic !== undefined ? settings.showMusic : true
showClipboard = settings.showClipboard !== undefined ? settings.showClipboard : true
@@ -209,68 +184,42 @@ Singleton {
showMemUsage = settings.showMemUsage !== undefined ? settings.showMemUsage : true
showCpuTemp = settings.showCpuTemp !== undefined ? settings.showCpuTemp : true
showGpuTemp = settings.showGpuTemp !== undefined ? settings.showGpuTemp : true
selectedGpuIndex = settings.selectedGpuIndex
!== undefined ? settings.selectedGpuIndex : 0
enabledGpuPciIds = settings.enabledGpuPciIds
!== undefined ? settings.enabledGpuPciIds : []
showSystemTray = settings.showSystemTray
!== undefined ? settings.showSystemTray : true
selectedGpuIndex = settings.selectedGpuIndex !== undefined ? settings.selectedGpuIndex : 0
enabledGpuPciIds = settings.enabledGpuPciIds !== undefined ? settings.enabledGpuPciIds : []
showSystemTray = settings.showSystemTray !== undefined ? settings.showSystemTray : true
showClock = settings.showClock !== undefined ? settings.showClock : true
showNotificationButton = settings.showNotificationButton
!== undefined ? settings.showNotificationButton : true
showNotificationButton = settings.showNotificationButton !== undefined ? settings.showNotificationButton : true
showBattery = settings.showBattery !== undefined ? settings.showBattery : true
showControlCenterButton = settings.showControlCenterButton
!== undefined ? settings.showControlCenterButton : true
controlCenterShowNetworkIcon = settings.controlCenterShowNetworkIcon
!== undefined ? settings.controlCenterShowNetworkIcon : true
controlCenterShowBluetoothIcon = settings.controlCenterShowBluetoothIcon
!== undefined ? settings.controlCenterShowBluetoothIcon : true
controlCenterShowAudioIcon = settings.controlCenterShowAudioIcon
!== undefined ? settings.controlCenterShowAudioIcon : true
showWorkspaceIndex = settings.showWorkspaceIndex
!== undefined ? settings.showWorkspaceIndex : false
showWorkspacePadding = settings.showWorkspacePadding
!== undefined ? settings.showWorkspacePadding : false
showWorkspaceApps = settings.showWorkspaceApps
!== undefined ? settings.showWorkspaceApps : false
maxWorkspaceIcons = settings.maxWorkspaceIcons
!== 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 : ""
showControlCenterButton = settings.showControlCenterButton !== undefined ? settings.showControlCenterButton : true
controlCenterShowNetworkIcon = settings.controlCenterShowNetworkIcon !== undefined ? settings.controlCenterShowNetworkIcon : true
controlCenterShowBluetoothIcon = settings.controlCenterShowBluetoothIcon !== undefined ? settings.controlCenterShowBluetoothIcon : true
controlCenterShowAudioIcon = settings.controlCenterShowAudioIcon !== undefined ? settings.controlCenterShowAudioIcon : true
showWorkspaceIndex = settings.showWorkspaceIndex !== undefined ? settings.showWorkspaceIndex : false
showWorkspacePadding = settings.showWorkspacePadding !== undefined ? settings.showWorkspacePadding : false
showWorkspaceApps = settings.showWorkspaceApps !== undefined ? settings.showWorkspaceApps : false
maxWorkspaceIcons = settings.maxWorkspaceIcons !== 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)
if (settings.topBarWidgetOrder) {
topBarLeftWidgets = settings.topBarWidgetOrder.filter(w => {
return ["launcherButton", "workspaceSwitcher", "focusedWindow"].includes(w)
})
topBarCenterWidgets = settings.topBarWidgetOrder.filter(
w => {
return ["clock", "music", "weather"].includes(
w)
topBarCenterWidgets = settings.topBarWidgetOrder.filter(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 {
var leftWidgets = settings.topBarLeftWidgets
!== undefined ? settings.topBarLeftWidgets : ["launcherButton", "workspaceSwitcher", "focusedWindow"]
var centerWidgets = settings.topBarCenterWidgets
!== undefined ? settings.topBarCenterWidgets : ["music", "clock", "weather"]
var rightWidgets = settings.topBarRightWidgets
!== undefined ? settings.topBarRightWidgets : ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
var leftWidgets = settings.topBarLeftWidgets !== undefined ? settings.topBarLeftWidgets : ["launcherButton", "workspaceSwitcher", "focusedWindow"]
var centerWidgets = settings.topBarCenterWidgets !== undefined ? settings.topBarCenterWidgets : ["music", "clock", "weather"]
var rightWidgets = settings.topBarRightWidgets !== undefined ? settings.topBarRightWidgets : ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
topBarLeftWidgets = leftWidgets
topBarCenterWidgets = centerWidgets
topBarRightWidgets = rightWidgets
@@ -278,54 +227,35 @@ Singleton {
updateListModel(centerWidgetsModel, centerWidgets)
updateListModel(rightWidgetsModel, rightWidgets)
}
appLauncherViewMode = settings.appLauncherViewMode
!== undefined ? settings.appLauncherViewMode : "list"
spotlightModalViewMode = settings.spotlightModalViewMode
!== undefined ? settings.spotlightModalViewMode : "list"
networkPreference = settings.networkPreference
!== undefined ? settings.networkPreference : "auto"
appLauncherViewMode = settings.appLauncherViewMode !== undefined ? settings.appLauncherViewMode : "list"
spotlightModalViewMode = settings.spotlightModalViewMode !== undefined ? settings.spotlightModalViewMode : "list"
networkPreference = settings.networkPreference !== undefined ? settings.networkPreference : "auto"
iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default"
useOSLogo = settings.useOSLogo !== undefined ? settings.useOSLogo : false
osLogoColorOverride = settings.osLogoColorOverride
!== undefined ? settings.osLogoColorOverride : ""
osLogoBrightness = settings.osLogoBrightness
!== undefined ? settings.osLogoBrightness : 0.5
osLogoColorOverride = settings.osLogoColorOverride !== undefined ? settings.osLogoColorOverride : ""
osLogoBrightness = settings.osLogoBrightness !== undefined ? settings.osLogoBrightness : 0.5
osLogoContrast = settings.osLogoContrast !== undefined ? settings.osLogoContrast : 1
wallpaperDynamicTheming = settings.wallpaperDynamicTheming
!== undefined ? settings.wallpaperDynamicTheming : true
fontFamily = settings.fontFamily
!== undefined ? settings.fontFamily : defaultFontFamily
monoFontFamily = settings.monoFontFamily
!== undefined ? settings.monoFontFamily : defaultMonoFontFamily
wallpaperDynamicTheming = settings.wallpaperDynamicTheming !== undefined ? settings.wallpaperDynamicTheming : true
fontFamily = settings.fontFamily !== undefined ? settings.fontFamily : defaultFontFamily
monoFontFamily = settings.monoFontFamily !== undefined ? settings.monoFontFamily : defaultMonoFontFamily
fontWeight = settings.fontWeight !== undefined ? settings.fontWeight : Font.Normal
gtkThemingEnabled = settings.gtkThemingEnabled
!== undefined ? settings.gtkThemingEnabled : false
qtThemingEnabled = settings.qtThemingEnabled
!== undefined ? settings.qtThemingEnabled : false
gtkThemingEnabled = settings.gtkThemingEnabled !== undefined ? settings.gtkThemingEnabled : false
qtThemingEnabled = settings.qtThemingEnabled !== undefined ? settings.qtThemingEnabled : false
showDock = settings.showDock !== undefined ? settings.showDock : false
dockAutoHide = settings.dockAutoHide !== undefined ? settings.dockAutoHide : false
cornerRadius = settings.cornerRadius !== undefined ? settings.cornerRadius : 12
notificationOverlayEnabled = settings.notificationOverlayEnabled
!== undefined ? settings.notificationOverlayEnabled : false
topBarAutoHide = settings.topBarAutoHide
!== undefined ? settings.topBarAutoHide : false
topBarVisible = settings.topBarVisible
!== undefined ? settings.topBarVisible : true
notificationTimeoutLow = settings.notificationTimeoutLow
!== undefined ? settings.notificationTimeoutLow : 5000
notificationTimeoutNormal = settings.notificationTimeoutNormal
!== undefined ? settings.notificationTimeoutNormal : 5000
notificationTimeoutCritical = settings.notificationTimeoutCritical
!== undefined ? settings.notificationTimeoutCritical : 0
notificationOverlayEnabled = settings.notificationOverlayEnabled !== undefined ? settings.notificationOverlayEnabled : false
topBarAutoHide = settings.topBarAutoHide !== undefined ? settings.topBarAutoHide : false
topBarVisible = settings.topBarVisible !== undefined ? settings.topBarVisible : true
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
topBarBottomGap = settings.topBarBottomGap !== undefined ? settings.topBarBottomGap : 0
topBarInnerPadding = settings.topBarInnerPadding !== undefined ? settings.topBarInnerPadding : 8
topBarSquareCorners = settings.topBarSquareCorners
!== undefined ? settings.topBarSquareCorners : false
topBarNoBackground = settings.topBarNoBackground
!== undefined ? settings.topBarNoBackground : false
screenPreferences = settings.screenPreferences
!== undefined ? settings.screenPreferences : ({})
topBarSquareCorners = settings.topBarSquareCorners !== undefined ? settings.topBarSquareCorners : false
topBarNoBackground = settings.topBarNoBackground !== undefined ? settings.topBarNoBackground : false
screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({})
applyStoredTheme()
detectAvailableIconThemes()
detectQtTools()
@@ -706,8 +636,7 @@ Singleton {
var widgetId = typeof order[i] === "string" ? order[i] : order[i].id
var enabled = typeof order[i] === "string" ? true : order[i].enabled
var size = typeof order[i] === "string" ? undefined : order[i].size
var selectedGpuIndex = typeof order[i]
=== "string" ? undefined : order[i].selectedGpuIndex
var selectedGpuIndex = typeof order[i] === "string" ? undefined : order[i].selectedGpuIndex
var pciId = typeof order[i] === "string" ? undefined : order[i].pciId
var item = {
"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"
+ " 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(
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"
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"
Quickshell.execDetached(["sh", "-lc", script])
}
@@ -1018,17 +946,14 @@ Singleton {
onTriggered: {
var availableFonts = Qt.fontFamilies()
var missingFonts = []
if (fontFamily === defaultFontFamily && !availableFonts.includes(
defaultFontFamily))
if (fontFamily === defaultFontFamily && !availableFonts.includes(defaultFontFamily))
missingFonts.push(defaultFontFamily)
if (monoFontFamily === defaultMonoFontFamily
&& !availableFonts.includes(defaultMonoFontFamily))
if (monoFontFamily === defaultMonoFontFamily && !availableFonts.includes(defaultMonoFontFamily))
missingFonts.push(defaultMonoFontFamily)
if (missingFonts.length > 0) {
var message = "Missing fonts: " + missingFonts.join(
", ") + ". Using system defaults."
var message = "Missing fonts: " + missingFonts.join(", ") + ". Using system defaults."
ToastService.showWarning(message)
}
}
@@ -1039,8 +964,7 @@ Singleton {
FileView {
id: settingsFile
path: StandardPaths.writableLocation(
StandardPaths.ConfigLocation) + "/DankMaterialShell/settings.json"
path: StandardPaths.writableLocation(StandardPaths.ConfigLocation) + "/DankMaterialShell/settings.json"
blockLoading: true
blockWrites: true
watchChanges: true
@@ -1085,8 +1009,7 @@ Singleton {
var themes = text.trim().split('\n')
for (var i = 0; i < themes.length; i++) {
var theme = themes[i].trim()
if (theme && theme !== "" && theme !== "default"
&& theme !== "hicolor" && theme !== "locolor")
if (theme && theme !== "" && theme !== "default" && theme !== "hicolor" && theme !== "locolor")
detectedThemes.push(theme)
}
}
@@ -1122,7 +1045,8 @@ Singleton {
Process {
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
onExited: exitCode => {
if (exitCode === 0) {
@@ -1157,5 +1081,4 @@ Singleton {
target: "bar"
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,7 +11,6 @@ DankOSD {
autoHideInterval: 3000
enableMouseInteraction: true
Connections {
target: AudioService
@@ -20,10 +19,11 @@ DankOSD {
}
function onSinkChanged() {
if (root.shouldBeVisible)
if (root.shouldBeVisible) {
root.show()
}
}
}
content: Item {
anchors.fill: parent
@@ -80,11 +80,12 @@ DankOSD {
unit: "%"
Component.onCompleted: {
if (AudioService.sink && AudioService.sink.audio)
if (AudioService.sink && AudioService.sink.audio) {
value = Math.round(AudioService.sink.audio.volume * 100)
}
}
onSliderValueChanged: function(newValue) {
onSliderValueChanged: newValue => {
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.volume = newValue / 100
resetHideTimer()
@@ -99,19 +100,21 @@ DankOSD {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
function onVolumeChanged() {
if (volumeSlider && !volumeSlider.pressed)
if (volumeSlider && !volumeSlider.pressed) {
volumeSlider.value = Math.round(AudioService.sink.audio.volume * 100)
}
}
}
}
}
}
onOsdShown: {
if (AudioService.sink && AudioService.sink.audio && contentLoader.item) {
let slider = contentLoader.item.children[0].children[1]
if (slider)
const slider = contentLoader.item.children[0].children[1]
if (slider) {
slider.value = Math.round(AudioService.sink.audio.volume * 100)
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,64 +16,97 @@ Rectangle {
property var widgetData: null
property real barHeight: 48
property real widgetHeight: 30
property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex
!== undefined) ? widgetData.selectedGpuIndex : 0
Connections {
target: SettingsData
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
})
}
}
property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
property real displayTemp: {
if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
return 0;
}
if (selectedGpuIndex >= 0 && selectedGpuIndex < DgopService.availableGpus.length) {
return DgopService.availableGpus[selectedGpuIndex].temperature || 0;
}
return 0;
}
function updateWidgetPciId(pciId) {
// 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
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.topBarNoBackground) return "transparent"
const baseColor = gpuArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
if (SettingsData.topBarNoBackground) {
return "transparent";
}
const baseColor = gpuArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
Component.onCompleted: {
DgopService.addRef(["gpu"])
console.log("GpuTemperature widget - pciId:",
widgetData ? widgetData.pciId : "no widgetData",
"selectedGpuIndex:",
widgetData ? widgetData.selectedGpuIndex : "no widgetData")
DgopService.addRef(["gpu"]);
console.log("GpuTemperature widget - pciId:", widgetData ? widgetData.pciId : "no widgetData", "selectedGpuIndex:", widgetData ? widgetData.selectedGpuIndex : "no widgetData");
// Add this widget's PCI ID to the service
if (widgetData && widgetData.pciId) {
console.log("Adding GPU PCI ID to service:", widgetData.pciId)
DgopService.addGpuPciId(widgetData.pciId)
console.log("Adding GPU PCI ID to service:", widgetData.pciId);
DgopService.addGpuPciId(widgetData.pciId);
} 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
autoSaveTimer.running = true
autoSaveTimer.running = true;
}
}
Component.onDestruction: {
DgopService.removeRef(["gpu"])
DgopService.removeRef(["gpu"]);
// Remove this widget's PCI ID from the service
if (widgetData && widgetData.pciId) {
DgopService.removeGpuPciId(widgetData.pciId)
}
DgopService.removeGpuPciId(widgetData.pciId);
}
property real displayTemp: {
if (!DgopService.availableGpus
|| DgopService.availableGpus.length === 0)
return 0
if (selectedGpuIndex >= 0
&& selectedGpuIndex < DgopService.availableGpus.length) {
return DgopService.availableGpus[selectedGpuIndex].temperature || 0
}
return 0
Connections {
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;
});
}
target: SettingsData
}
MouseArea {
@@ -84,22 +117,23 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0)
var currentScreen = parentScreen || Screen
var screenX = currentScreen.x || 0
var relativeX = globalPos.x - screenX
popupTarget.setTriggerPosition(
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
}
DgopService.setSortBy("cpu")
if (root.toggleProcessList)
root.toggleProcessList()
DgopService.setSortBy("cpu");
if (root.toggleProcessList) {
root.toggleProcessList();
}
}
}
Row {
id: gpuTempContent
anchors.centerIn: parent
spacing: 3
@@ -107,30 +141,50 @@ Rectangle {
name: "auto_awesome_mosaic"
size: Theme.iconSize - 8
color: {
if (root.displayTemp > 80)
return Theme.tempDanger
if (root.displayTemp > 80) {
return Theme.tempDanger;
}
if (root.displayTemp > 65)
return Theme.tempWarning
if (root.displayTemp > 65) {
return Theme.tempWarning;
}
return Theme.surfaceText
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
if (root.displayTemp === undefined || root.displayTemp === null
|| root.displayTemp === 0) {
return "--°"
if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) {
return "--°";
}
return Math.round(root.displayTemp) + "°"
return Math.round(root.displayTemp) + "°";
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
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 {
@@ -138,58 +192,7 @@ Rectangle {
duration: Theme.shortDuration
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
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.topBarNoBackground) return "transparent"
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)
if (SettingsData.topBarNoBackground) {
return "transparent";
}
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 {
id: idleIcon
anchors.centerIn: parent
name: SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
size: Theme.iconSize - 6
@@ -38,9 +41,8 @@ Rectangle {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
SessionService.toggleIdleInhibit()
SessionService.toggleIdleInhibit();
}
}
@@ -49,5 +51,7 @@ Rectangle {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -12,10 +12,8 @@ Rectangle {
property var parentScreen: null
property real widgetHeight: 30
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS
readonly property bool hasActivePrivacy: PrivacyService.anyPrivacyActive
readonly property int activeCount: PrivacyService.microphoneActive + PrivacyService.cameraActive
+ PrivacyService.screensharingActive
readonly property int activeCount: PrivacyService.microphoneActive + PrivacyService.cameraActive + PrivacyService.screensharingActive
readonly property real contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
width: hasActivePrivacy ? (contentWidth + horizontalPadding * 2) : 0
@@ -24,18 +22,17 @@ Rectangle {
visible: hasActivePrivacy
opacity: hasActivePrivacy ? 1 : 0
enabled: hasActivePrivacy
color: {
if (SettingsData.topBarNoBackground) return "transparent"
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)
if (SettingsData.topBarNoBackground) {
return "transparent";
}
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);
}
MouseArea {
// Privacy indicator click handler
id: privacyArea
anchors.fill: parent
@@ -43,7 +40,6 @@ Rectangle {
enabled: hasActivePrivacy
cursorShape: Qt.PointingHandCursor
onClicked: {
}
}
@@ -65,6 +61,7 @@ Rectangle {
filled: true
anchors.centerIn: parent
}
}
Item {
@@ -91,6 +88,7 @@ Rectangle {
anchors.rightMargin: -2
anchors.topMargin: -1
}
}
Item {
@@ -106,15 +104,9 @@ Rectangle {
filled: true
anchors.centerIn: parent
}
}
}
Behavior on width {
enabled: hasActivePrivacy && visible
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Rectangle {
@@ -129,26 +121,18 @@ Rectangle {
visible: false
opacity: privacyArea.containsMouse && hasActivePrivacy ? 1 : 0
z: 100
x: (parent.width - width) / 2
y: -height - Theme.spacingXS
StyledText {
id: tooltipText
anchors.centerIn: parent
text: PrivacyService.getPrivacySummary()
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
}
Behavior on opacity {
enabled: hasActivePrivacy && root.visible
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Rectangle {
width: 8
height: 8
@@ -160,5 +144,27 @@ Rectangle {
anchors.top: parent.bottom
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
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.topBarNoBackground) return "transparent"
const baseColor = ramArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
if (SettingsData.topBarNoBackground) {
return "transparent";
}
const baseColor = ramArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
Component.onCompleted: {
DgopService.addRef(["memory"])
DgopService.addRef(["memory"]);
}
Component.onDestruction: {
DgopService.removeRef(["memory"])
DgopService.removeRef(["memory"]);
}
MouseArea {
@@ -41,22 +43,23 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0)
var currentScreen = parentScreen || Screen
var screenX = currentScreen.x || 0
var relativeX = globalPos.x - screenX
popupTarget.setTriggerPosition(
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
}
DgopService.setSortBy("memory")
if (root.toggleProcessList)
root.toggleProcessList()
DgopService.setSortBy("memory");
if (root.toggleProcessList) {
root.toggleProcessList();
}
}
}
Row {
id: ramContent
anchors.centerIn: parent
spacing: 3
@@ -64,30 +67,33 @@ Rectangle {
name: "developer_board"
size: Theme.iconSize - 8
color: {
if (DgopService.memoryUsage > 90)
return Theme.tempDanger
if (DgopService.memoryUsage > 90) {
return Theme.tempDanger;
}
if (DgopService.memoryUsage > 75)
return Theme.tempWarning
if (DgopService.memoryUsage > 75) {
return Theme.tempWarning;
}
return Theme.surfaceText
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
if (DgopService.memoryUsage === undefined
|| DgopService.memoryUsage === null
|| DgopService.memoryUsage === 0) {
return "--%"
if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) {
return "--%";
}
return DgopService.memoryUsage.toFixed(0) + "%"
return DgopService.memoryUsage.toFixed(0) + "%";
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
}

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -13,22 +13,25 @@ Rectangle {
property string section: "right"
property var popupTarget: null
property var parentScreen: null
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
signal toggleVpnPopup()
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
width: Theme.iconSize + horizontalPadding * 2
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.topBarNoBackground) return "transparent"
const base = clickArea.containsMouse || (popupTarget && popupTarget.shouldBeVisible) ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(base.r, base.g, base.b, base.a * Theme.widgetTransparency)
if (SettingsData.topBarNoBackground) {
return "transparent";
}
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 {
id: icon
name: VpnService.isBusy ? "sync" : (VpnService.connected ? "vpn_lock" : "vpn_key_off")
size: Theme.iconSize - 6
color: VpnService.connected ? Theme.primary : Theme.surfaceText
@@ -41,27 +44,30 @@ Rectangle {
to: 360
duration: 900
}
}
MouseArea {
id: clickArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0)
var currentScreen = parentScreen || Screen
var screenX = currentScreen.x || 0
var relativeX = globalPos.x - screenX
popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
}
root.toggleVpnPopup()
root.toggleVpnPopup();
}
}
Rectangle {
id: tooltip
width: Math.max(120, tooltipText.contentWidth + Theme.spacingM * 2)
height: tooltipText.contentHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
@@ -76,19 +82,32 @@ Rectangle {
Text {
id: tooltipText
anchors.centerIn: parent
text: {
if (!VpnService.connected) return "VPN Disconnected"
const names = VpnService.activeNames || []
if (names.length <= 1) return "VPN Connected • " + (names[0] || "")
return "VPN Connected • " + names[0] + " +" + (names.length - 1)
if (!VpnService.connected) {
return "VPN Disconnected";
}
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
color: Theme.surfaceText
}
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.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import Quickshell.Widgets
import qs.Widgets
import qs.Common
import qs.Services
// No external details import; content inlined for consistency
import qs.Widgets
DankPopout {
id: root
@@ -16,11 +17,11 @@ DankPopout {
property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x
triggerY = y
triggerWidth = width
triggerSection = section
triggerScreen = screen
triggerX = x;
triggerY = y;
triggerWidth = width;
triggerSection = section;
triggerScreen = screen;
}
popupWidth: 360
@@ -37,6 +38,7 @@ DankPopout {
content: Component {
Rectangle {
id: content
implicitHeight: contentColumn.height + Theme.spacingL * 2
color: Theme.popupBackground()
radius: Theme.cornerRadius
@@ -45,11 +47,10 @@ DankPopout {
antialiasing: true
smooth: true
focus: true
Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape) {
root.close()
event.accepted = true
root.close();
event.accepted = true;
}
}
@@ -85,6 +86,7 @@ DankPopout {
Column {
id: contentColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
@@ -94,6 +96,7 @@ DankPopout {
Item {
width: parent.width
height: 32
StyledText {
text: "VPN Connections"
font.pixelSize: Theme.fontSizeLarge
@@ -120,17 +123,21 @@ DankPopout {
MouseArea {
id: closeArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: root.close()
}
}
}
// Inlined VPN details
Rectangle {
id: vpnDetail
width: parent.width
implicitHeight: detailsColumn.implicitHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
@@ -141,6 +148,7 @@ DankPopout {
Column {
id: detailsColumn
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingS
@@ -151,20 +159,32 @@ DankPopout {
StyledText {
text: {
if (!VpnService.connected) return "Active: None"
const names = VpnService.activeNames || []
if (names.length <= 1) return "Active: " + (names[0] || "VPN")
return "Active: " + names[0] + " +" + (names.length - 1)
if (!VpnService.connected) {
return "Active: None";
}
const names = VpnService.activeNames || [];
if (names.length <= 1) {
return "Active: " + (names[0] || "VPN");
}
return "Active: " + names[0] + " +" + (names.length - 1);
}
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
Item { Layout.fillWidth: true; height: 1 }
Item {
Layout.fillWidth: true
height: 1
}
// Removed Quick Connect for clarity
Item { width: 1; height: 1 }
Item {
width: 1
height: 1
}
// Disconnect all (shown only when any active)
Rectangle {
@@ -180,21 +200,40 @@ DankPopout {
Row {
anchors.centerIn: parent
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 {
id: discAllArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
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 {
width: parent.width
@@ -204,6 +243,7 @@ DankPopout {
Column {
id: listCol
width: parent.width
spacing: Theme.spacingXS
@@ -215,16 +255,38 @@ DankPopout {
Column {
anchors.centerIn: parent
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 }
StyledText { text: "Add a VPN in NetworkManager"; font.pixelSize: Theme.fontSizeSmall; color: Theme.surfaceVariantText; anchors.horizontalCenter: parent.horizontalCenter }
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
}
StyledText {
text: "Add a VPN in NetworkManager"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
Repeater {
model: VpnService.profiles
delegate: Rectangle {
required property var modelData
width: parent ? parent.width : 300
height: 50
radius: Theme.cornerRadius
@@ -258,47 +320,100 @@ DankPopout {
StyledText {
text: {
if (modelData.type === "wireguard") return "WireGuard"
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]
if (modelData.type === "wireguard") {
return "WireGuard";
}
return "VPN"
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
}
}
Item { Layout.fillWidth: true; height: 1 }
Item {
Layout.fillWidth: true
height: 1
}
}
MouseArea {
id: rowArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
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
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 2 : Theme.spacingS
signal clicked
signal clicked()
visible: SettingsData.weatherEnabled
width: visible ? Math.min(100,
weatherRow.implicitWidth + horizontalPadding * 2) : 0
width: visible ? Math.min(100, weatherRow.implicitWidth + horizontalPadding * 2) : 0
height: widgetHeight
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (SettingsData.topBarNoBackground) return "transparent"
const baseColor = weatherArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
if (SettingsData.topBarNoBackground) {
return "transparent";
}
const baseColor = weatherArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
Ref {
@@ -46,16 +47,18 @@ Rectangle {
StyledText {
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) {
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
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
@@ -66,15 +69,13 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onPressed: {
if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0)
var currentScreen = parentScreen || Screen
var screenX = currentScreen.x || 0
var relativeX = globalPos.x - screenX
popupTarget.setTriggerPosition(
relativeX, barHeight + Theme.spacingXS,
width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const screenX = currentScreen.x || 0;
const relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, barHeight + Theme.spacingXS, width, section, currentScreen);
}
root.clicked()
root.clicked();
}
}
@@ -83,6 +84,7 @@ Rectangle {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on width {
@@ -90,5 +92,7 @@ Rectangle {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

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

View File

@@ -17,7 +17,7 @@ Singleton {
if (applications.length === 0)
return []
const queryLower = query.toLowerCase()
const queryLower = query.toLowerCase().trim()
const scoredApps = []
for (const app of applications) {
@@ -36,24 +36,19 @@ Singleton {
if (name === queryLower) {
score = 10000
matched = true
}
else if (containsAsWord) {
} else if (containsAsWord) {
score = 9500 + (100 - Math.min(name.length, 100))
matched = true
}
else if (name.startsWith(queryLower)) {
} else if (name.startsWith(queryLower)) {
score = 9000 + (100 - Math.min(name.length, 100))
matched = true
}
else if (startsWithAsWord) {
} else if (startsWithAsWord) {
score = 8500 + (100 - Math.min(name.length, 100))
matched = true
}
else if (name.includes(queryLower)) {
} else if (name.includes(queryLower)) {
score = 8000 + (100 - Math.min(name.length, 100))
matched = true
}
else if (keywords.length > 0) {
} else if (keywords.length > 0) {
for (const keyword of keywords) {
if (keyword === queryLower) {
score = 6000
@@ -73,12 +68,10 @@ Singleton {
if (!matched && genericName.includes(queryLower)) {
score = 4000
matched = true
}
else if (!matched && comment.includes(queryLower)) {
} else if (!matched && comment.includes(queryLower)) {
score = 3000
matched = true
}
else if (!matched) {
} else if (!matched) {
const nameFinder = new Fzf.Finder([app], {
"selector": a => a.name || "",
"casing": "case-insensitive",
@@ -92,7 +85,10 @@ Singleton {
}
if (matched) {
scoredApps.push({ app, score })
scoredApps.push({
"app": app,
"score": score
})
}
}

View File

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