1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-27 06:52:50 -05:00

qmlfmt with 4 space

This commit is contained in:
bbedward
2025-08-20 00:05:14 -04:00
parent 6e0977c719
commit b688bbfe83
154 changed files with 28809 additions and 27639 deletions

View File

@@ -4,71 +4,72 @@ import qs.Common
import qs.Services
Item {
id: root
id: root
readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property bool hasActiveMedia: activePlayer !== null
readonly property bool isPlaying: hasActiveMedia && activePlayer
&& activePlayer.playbackState === MprisPlaybackState.Playing
readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property bool hasActiveMedia: activePlayer !== null
readonly property bool isPlaying: hasActiveMedia && activePlayer
&& activePlayer.playbackState === MprisPlaybackState.Playing
width: 20
height: Theme.iconSize
width: 20
height: Theme.iconSize
Loader {
active: isPlaying
sourceComponent: Component {
Ref {
service: CavaService
}
}
}
Timer {
id: fallbackTimer
running: !CavaService.cavaAvailable && isPlaying
interval: 256
repeat: true
onTriggered: {
CavaService.values = [Math.random() * 40 + 10, Math.random(
) * 60 + 20, Math.random() * 50 + 15, Math.random(
) * 35 + 20, Math.random() * 45 + 15, Math.random(
) * 55 + 25]
}
}
Row {
anchors.centerIn: parent
spacing: 1.5
Repeater {
model: 6
Rectangle {
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)
}
return 3
Loader {
active: isPlaying
sourceComponent: Component {
Ref {
service: CavaService
}
}
}
Timer {
id: fallbackTimer
running: !CavaService.cavaAvailable && isPlaying
interval: 256
repeat: true
onTriggered: {
CavaService.values = [Math.random() * 40 + 10, Math.random(
) * 60 + 20, Math.random() * 50 + 15, Math.random(
) * 35 + 20, Math.random() * 45 + 15, Math.random(
) * 55 + 25]
}
}
Row {
anchors.centerIn: parent
spacing: 1.5
Repeater {
model: 6
Rectangle {
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)
}
return 3
}
radius: 1.5
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
Behavior on height {
NumberAnimation {
duration: Anims.durShort
easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.standardDecel
}
}
}
}
radius: 1.5
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
Behavior on height {
NumberAnimation {
duration: Anims.durShort
easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.standardDecel
}
}
}
}
}
}

View File

@@ -5,202 +5,202 @@ import qs.Services
import qs.Widgets
Rectangle {
id: battery
id: battery
property bool batteryPopupVisible: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property bool batteryPopupVisible: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
signal toggleBatteryPopup
signal toggleBatteryPopup
width: BatteryService.batteryAvailable ? 70 : 40
height: 30
radius: Theme.cornerRadius
color: {
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 {
anchors.centerIn: parent
spacing: 2
DankIcon {
name: {
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"
}
// 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"
}
// 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"
}
size: Theme.iconSize - 6
color: {
if (!BatteryService.batteryAvailable)
return Theme.surfaceText
if (BatteryService.isLowBattery && !BatteryService.isCharging)
return Theme.error
if (BatteryService.isCharging || BatteryService.isPluggedIn)
return Theme.primary
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: BatteryService.batteryLevel + "%"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: {
if (!BatteryService.batteryAvailable)
return Theme.surfaceText
if (BatteryService.isLowBattery && !BatteryService.isCharging)
return Theme.error
if (BatteryService.isCharging)
return Theme.primary
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
visible: BatteryService.batteryAvailable
}
}
MouseArea {
id: batteryArea
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,
Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
toggleBatteryPopup()
}
}
Rectangle {
id: batteryTooltip
width: Math.max(120, tooltipText.contentWidth + Theme.spacingM * 2)
height: tooltipText.contentHeight + Theme.spacingS * 2
width: BatteryService.batteryAvailable ? 70 : 40
height: 30
radius: Theme.cornerRadius
color: Theme.surfaceContainer
border.color: Theme.surfaceVariantAlpha
border.width: 1
visible: batteryArea.containsMouse && !batteryPopupVisible
anchors.bottom: parent.top
anchors.bottomMargin: Theme.spacingS
anchors.horizontalCenter: parent.horizontalCenter
opacity: batteryArea.containsMouse ? 1 : 0
color: {
const baseColor = batteryArea.containsMouse
|| batteryPopupVisible ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
visible: true
Column {
anchors.centerIn: parent
spacing: 2
Row {
anchors.centerIn: parent
spacing: 2
StyledText {
id: tooltipText
DankIcon {
name: {
if (!BatteryService.batteryAvailable)
return "power"
text: {
if (!BatteryService.batteryAvailable) {
if (typeof PowerProfiles === "undefined")
return "Power Management"
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"
}
switch (PowerProfiles.profile) {
case PowerProfile.PowerSaver:
return "Power Profile: Power Saver"
case PowerProfile.Performance:
return "Power Profile: Performance"
default:
return "Power Profile: Balanced"
// 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"
}
// 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"
}
}
let status = BatteryService.batteryStatus
let level = BatteryService.batteryLevel + "%"
let time = BatteryService.formatTimeRemaining()
if (time !== "Unknown")
return status + " • " + level + " • " + time
else
return status + " • " + level
size: Theme.iconSize - 6
color: {
if (!BatteryService.batteryAvailable)
return Theme.surfaceText
if (BatteryService.isLowBattery && !BatteryService.isCharging)
return Theme.error
if (BatteryService.isCharging || BatteryService.isPluggedIn)
return Theme.primary
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: BatteryService.batteryLevel + "%"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: {
if (!BatteryService.batteryAvailable)
return Theme.surfaceText
if (BatteryService.isLowBattery && !BatteryService.isCharging)
return Theme.error
if (BatteryService.isCharging)
return Theme.primary
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
visible: BatteryService.batteryAvailable
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
horizontalAlignment: Text.AlignHCenter
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
MouseArea {
id: batteryArea
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
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, Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
toggleBatteryPopup()
}
}
Rectangle {
id: batteryTooltip
width: Math.max(120, tooltipText.contentWidth + Theme.spacingM * 2)
height: tooltipText.contentHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainer
border.color: Theme.surfaceVariantAlpha
border.width: 1
visible: batteryArea.containsMouse && !batteryPopupVisible
anchors.bottom: parent.top
anchors.bottomMargin: Theme.spacingS
anchors.horizontalCenter: parent.horizontalCenter
opacity: batteryArea.containsMouse ? 1 : 0
Column {
anchors.centerIn: parent
spacing: 2
StyledText {
id: tooltipText
text: {
if (!BatteryService.batteryAvailable) {
if (typeof PowerProfiles === "undefined")
return "Power Management"
switch (PowerProfiles.profile) {
case PowerProfile.PowerSaver:
return "Power Profile: Power Saver"
case PowerProfile.Performance:
return "Power Profile: Performance"
default:
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
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
horizontalAlignment: Text.AlignHCenter
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,17 +12,18 @@ Rectangle {
property var popupTarget: null
property var parentScreen: null
signal clockClicked()
signal clockClicked
width: clockRow.implicitWidth + Theme.spacingS * 2
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = clockMouseArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
const baseColor = clockMouseArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
Component.onCompleted: {
root.currentDate = systemClock.date;
root.currentDate = systemClock.date
}
Row {
@@ -32,7 +33,10 @@ Rectangle {
spacing: Theme.spacingS
StyledText {
text: SettingsData.use24HourClock ? Qt.formatTime(root.currentDate, "H:mm") : Qt.formatTime(root.currentDate, "h:mm AP")
text: SettingsData.use24HourClock ? Qt.formatTime(
root.currentDate,
"H:mm") : Qt.formatTime(
root.currentDate, "h:mm AP")
font.pixelSize: Theme.fontSizeMedium - 1
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
@@ -53,7 +57,6 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.clockCompactMode
}
}
SystemClock {
@@ -71,13 +74,15 @@ 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, Theme.barHeight + Theme.spacingXS, width, section, currentScreen);
var globalPos = mapToGlobal(0, 0)
var currentScreen = parentScreen || Screen
var screenX = currentScreen.x || 0
var relativeX = globalPos.x - screenX
popupTarget.setTriggerPosition(
relativeX, Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
root.clockClicked();
root.clockClicked()
}
}
@@ -86,7 +91,5 @@ Rectangle {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

@@ -4,134 +4,139 @@ import qs.Services
import qs.Widgets
Rectangle {
id: root
id: root
property bool isActive: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property bool isActive: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
signal clicked
signal clicked
width: Math.max(80, controlIndicators.implicitWidth + Theme.spacingS * 2)
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = controlCenterArea.containsMouse
|| root.isActive ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
Row {
id: controlIndicators
anchors.centerIn: parent
spacing: Theme.spacingXS
DankIcon {
name: {
if (NetworkService.networkStatus === "ethernet")
return "lan"
return NetworkService.wifiSignalIcon
}
size: Theme.iconSize - 8
color: NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.outlineButton
anchors.verticalCenter: parent.verticalCenter
visible: true
width: Math.max(80, controlIndicators.implicitWidth + Theme.spacingS * 2)
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = controlCenterArea.containsMouse
|| root.isActive ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
DankIcon {
name: "bluetooth"
size: Theme.iconSize - 8
color: BluetoothService.enabled ? Theme.primary : Theme.outlineButton
anchors.verticalCenter: parent.verticalCenter
visible: BluetoothService.available && BluetoothService.enabled
}
Row {
id: controlIndicators
Rectangle {
width: audioIcon.implicitWidth + 4
height: audioIcon.implicitHeight + 4
color: "transparent"
anchors.verticalCenter: parent.verticalCenter
DankIcon {
id: audioIcon
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"
}
return "volume_up"
}
size: Theme.iconSize - 8
color: audioWheelArea.containsMouse || controlCenterArea.containsMouse
|| root.isActive ? Theme.primary : Theme.surfaceText
anchors.centerIn: parent
}
spacing: Theme.spacingXS
MouseArea {
id: audioWheelArea
DankIcon {
name: {
if (NetworkService.networkStatus === "ethernet")
return "lan"
return NetworkService.wifiSignalIcon
}
size: Theme.iconSize - 8
color: NetworkService.networkStatus
!== "disconnected" ? Theme.primary : Theme.outlineButton
anchors.verticalCenter: parent.verticalCenter
visible: true
}
DankIcon {
name: "bluetooth"
size: Theme.iconSize - 8
color: BluetoothService.enabled ? Theme.primary : Theme.outlineButton
anchors.verticalCenter: parent.verticalCenter
visible: BluetoothService.available && BluetoothService.enabled
}
Rectangle {
width: audioIcon.implicitWidth + 4
height: audioIcon.implicitHeight + 4
color: "transparent"
anchors.verticalCenter: parent.verticalCenter
DankIcon {
id: audioIcon
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"
}
return "volume_up"
}
size: Theme.iconSize - 8
color: audioWheelArea.containsMouse
|| controlCenterArea.containsMouse
|| root.isActive ? Theme.primary : Theme.surfaceText
anchors.centerIn: parent
}
MouseArea {
id: audioWheelArea
anchors.fill: parent
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)
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = false
AudioService.sink.audio.volume = newVolume / 100
}
wheelEvent.accepted = true
}
}
}
DankIcon {
name: "mic"
size: Theme.iconSize - 8
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
visible: false // TODO: Add mic detection
}
}
MouseArea {
id: controlCenterArea
anchors.fill: parent
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)
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = false
AudioService.sink.audio.volume = newVolume / 100
}
wheelEvent.accepted = 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, Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
root.clicked()
}
}
}
DankIcon {
name: "mic"
size: Theme.iconSize - 8
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
visible: false // TODO: Add mic detection
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
MouseArea {
id: controlCenterArea
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,
Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
root.clicked()
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

@@ -5,84 +5,84 @@ import qs.Services
import qs.Widgets
Rectangle {
id: root
id: root
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
width: 55
height: 30
radius: Theme.cornerRadius
color: {
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"])
}
Component.onDestruction: {
DgopService.removeRef(["cpu"])
}
MouseArea {
id: cpuArea
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,
Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
DgopService.setSortBy("cpu")
if (root.toggleProcessList)
root.toggleProcessList()
width: 55
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = cpuArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
}
Row {
anchors.centerIn: parent
spacing: 3
DankIcon {
name: "memory"
size: Theme.iconSize - 8
color: {
if (DgopService.cpuUsage > 80)
return Theme.tempDanger
if (DgopService.cpuUsage > 60)
return Theme.tempWarning
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
Component.onCompleted: {
DgopService.addRef(["cpu"])
}
Component.onDestruction: {
DgopService.removeRef(["cpu"])
}
StyledText {
text: {
if (DgopService.cpuUsage === undefined
|| DgopService.cpuUsage === null
|| DgopService.cpuUsage === 0) {
return "--%"
MouseArea {
id: cpuArea
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, Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
DgopService.setSortBy("cpu")
if (root.toggleProcessList)
root.toggleProcessList()
}
}
Row {
anchors.centerIn: parent
spacing: 3
DankIcon {
name: "memory"
size: Theme.iconSize - 8
color: {
if (DgopService.cpuUsage > 80)
return Theme.tempDanger
if (DgopService.cpuUsage > 60)
return Theme.tempWarning
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
if (DgopService.cpuUsage === undefined
|| DgopService.cpuUsage === null
|| DgopService.cpuUsage === 0) {
return "--%"
}
return DgopService.cpuUsage.toFixed(0) + "%"
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
return DgopService.cpuUsage.toFixed(0) + "%"
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
}

View File

@@ -5,91 +5,91 @@ import qs.Services
import qs.Widgets
Rectangle {
id: root
id: root
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
width: 55
height: 30
radius: Theme.cornerRadius
color: {
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"])
}
Component.onDestruction: {
DgopService.removeRef(["cpu"])
}
MouseArea {
id: cpuTempArea
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,
Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
DgopService.setSortBy("cpu")
if (root.toggleProcessList)
root.toggleProcessList()
width: 55
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = cpuTempArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
}
Row {
anchors.centerIn: parent
spacing: 3
DankIcon {
name: "memory"
size: Theme.iconSize - 8
color: {
if (DgopService.cpuTemperature > 85)
return Theme.tempDanger
if (DgopService.cpuTemperature > 69)
return Theme.tempWarning
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
Component.onCompleted: {
DgopService.addRef(["cpu"])
}
Component.onDestruction: {
DgopService.removeRef(["cpu"])
}
StyledText {
text: {
if (DgopService.cpuTemperature === undefined
|| DgopService.cpuTemperature === null
|| DgopService.cpuTemperature < 0) {
return "--°"
MouseArea {
id: cpuTempArea
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, Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
DgopService.setSortBy("cpu")
if (root.toggleProcessList)
root.toggleProcessList()
}
return Math.round(DgopService.cpuTemperature) + "°"
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
Row {
anchors.centerIn: parent
spacing: 3
DankIcon {
name: "memory"
size: Theme.iconSize - 8
color: {
if (DgopService.cpuTemperature > 85)
return Theme.tempDanger
if (DgopService.cpuTemperature > 69)
return Theme.tempWarning
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
if (DgopService.cpuTemperature === undefined
|| DgopService.cpuTemperature === null
|| DgopService.cpuTemperature < 0) {
return "--°"
}
return Math.round(DgopService.cpuTemperature) + "°"
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -13,15 +13,18 @@ Rectangle {
readonly property int maxNormalWidth: 456
readonly property int maxCompactWidth: 288
width: compactMode ? Math.min(baseWidth, maxCompactWidth) : Math.min(baseWidth, maxNormalWidth)
width: compactMode ? Math.min(baseWidth,
maxCompactWidth) : Math.min(baseWidth,
maxNormalWidth)
height: 30
radius: Theme.cornerRadius
color: {
if (!NiriService.focusedWindowTitle)
return "transparent";
return "transparent"
const baseColor = mouseArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
const baseColor = mouseArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
clip: true
visible: NiriService.niriAvailable && NiriService.focusedWindowTitle
@@ -37,16 +40,17 @@ Rectangle {
text: {
if (!NiriService.focusedWindowId)
return "";
return ""
var window = NiriService.windows.find((w) => {
return w.id == NiriService.focusedWindowId;
});
var window = NiriService.windows.find(w => {
return w.id == NiriService.focusedWindowId
})
if (!window || !window.app_id)
return "";
return ""
var desktopEntry = DesktopEntries.byId(window.app_id);
return desktopEntry && desktopEntry.name ? desktopEntry.name : window.app_id;
var desktopEntry = DesktopEntries.byId(window.app_id)
return desktopEntry
&& desktopEntry.name ? desktopEntry.name : window.app_id
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
@@ -70,20 +74,24 @@ Rectangle {
id: titleText
text: {
var title = NiriService.focusedWindowTitle || "";
var appName = appText.text;
if (!title || !appName) return title;
var title = NiriService.focusedWindowTitle || ""
var 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);
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).replace(
/ - $/, "")
}
return title;
return title
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
@@ -94,7 +102,6 @@ Rectangle {
width: Math.min(implicitWidth, compactMode ? 280 : 250)
visible: text.length > 0
}
}
MouseArea {
@@ -109,7 +116,6 @@ Rectangle {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on width {
@@ -117,7 +123,5 @@ Rectangle {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

@@ -5,182 +5,185 @@ import qs.Services
import qs.Widgets
Rectangle {
id: root
id: root
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property var widgetData: null
property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex
!== undefined) ? widgetData.selectedGpuIndex : 0
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property var widgetData: null
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
})
}
}
width: 55
height: 30
radius: Theme.cornerRadius
color: {
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")
// 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)
} else {
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
}
}
Component.onDestruction: {
DgopService.removeRef(["gpu"])
// Remove this widget's PCI ID from the service
if (widgetData && 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
}
MouseArea {
id: gpuArea
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,
Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
DgopService.setSortBy("cpu")
if (root.toggleProcessList)
root.toggleProcessList()
}
}
Row {
anchors.centerIn: parent
spacing: 3
DankIcon {
name: "auto_awesome_mosaic"
size: Theme.iconSize - 8
color: {
if (root.displayTemp > 80)
return Theme.tempDanger
if (root.displayTemp > 65)
return Theme.tempWarning
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
if (root.displayTemp === undefined || root.displayTemp === null
|| root.displayTemp === 0) {
return "--°"
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
})
}
return Math.round(root.displayTemp) + "°"
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
width: 55
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = gpuArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
}
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)
Component.onCompleted: {
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)
} else {
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
}
}
}
}
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
Component.onDestruction: {
DgopService.removeRef(["gpu"])
// Remove this widget's PCI ID from the service
if (widgetData && 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
}
MouseArea {
id: gpuArea
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, Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
DgopService.setSortBy("cpu")
if (root.toggleProcessList)
root.toggleProcessList()
}
}
Row {
anchors.centerIn: parent
spacing: 3
DankIcon {
name: "auto_awesome_mosaic"
size: Theme.iconSize - 8
color: {
if (root.displayTemp > 80)
return Theme.tempDanger
if (root.displayTemp > 65)
return Theme.tempWarning
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
if (root.displayTemp === undefined || root.displayTemp === null
|| root.displayTemp === 0) {
return "--°"
}
return Math.round(root.displayTemp) + "°"
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Behavior on color {
ColorAnimation {
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

@@ -7,46 +7,43 @@ import qs.Widgets
Rectangle {
id: root
property string section: "right"
property var popupTarget: null
property var parentScreen: null
width: 40
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = mouseArea.containsMouse
? Theme.primaryPressed
: (IdleInhibitorService.idleInhibited ? Theme.primaryHover : Theme.secondaryHover)
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
const baseColor = mouseArea.containsMouse ? Theme.primaryPressed : (IdleInhibitorService.idleInhibited ? Theme.primaryHover : Theme.secondaryHover)
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
DankIcon {
anchors.centerIn: parent
name: IdleInhibitorService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
size: Theme.iconSize - 6
color: Theme.surfaceText
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
IdleInhibitorService.toggleIdleInhibit()
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -4,63 +4,62 @@ import qs.Services
import qs.Widgets
Item {
id: root
id: root
property bool isActive: false
property string section: "left"
property var popupTarget: null
property var parentScreen: null
property bool isActive: false
property string section: "left"
property var popupTarget: null
property var parentScreen: null
signal clicked
signal clicked
width: 40
height: 30
width: 40
height: 30
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,
Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
root.clicked()
}
}
MouseArea {
id: launcherArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceTextHover.r, Theme.surfaceTextHover.g, Theme.surfaceTextHover.b,
Theme.surfaceTextHover.a * Theme.widgetTransparency)
SystemLogo {
visible: SettingsData.useOSLogo
anchors.centerIn: parent
width: Theme.iconSize - 3
height: Theme.iconSize - 3
colorOverride: SettingsData.osLogoColorOverride
brightnessOverride: SettingsData.osLogoBrightness
contrastOverride: SettingsData.osLogoContrast
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, Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
root.clicked()
}
}
DankIcon {
visible: !SettingsData.useOSLogo
anchors.centerIn: parent
name: "apps"
size: Theme.iconSize - 6
color: Theme.surfaceText
}
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceTextHover.r, Theme.surfaceTextHover.g,
Theme.surfaceTextHover.b,
Theme.surfaceTextHover.a * Theme.widgetTransparency)
}
}
SystemLogo {
visible: SettingsData.useOSLogo
anchors.centerIn: parent
width: Theme.iconSize - 3
height: Theme.iconSize - 3
colorOverride: SettingsData.osLogoColorOverride
brightnessOverride: SettingsData.osLogoBrightness
contrastOverride: SettingsData.osLogoContrast
}
DankIcon {
visible: !SettingsData.useOSLogo
anchors.centerIn: parent
name: "apps"
size: Theme.iconSize - 6
color: Theme.surfaceText
}
}
}

View File

@@ -5,312 +5,328 @@ import qs.Services
import qs.Widgets
Rectangle {
id: root
id: root
readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property bool playerAvailable: activePlayer !== null
property bool compactMode: false
readonly property int textWidth: {
switch(SettingsData.mediaSize) {
case 0: return 0 // No text in small mode
case 2: return 180 // Large text area
default: return 120 // Medium text area
readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property bool playerAvailable: activePlayer !== null
property bool compactMode: false
readonly property int textWidth: {
switch (SettingsData.mediaSize) {
case 0:
return 0 // No text in small mode
case 2:
return 180 // Large text area
default:
return 120 // Medium text area
}
}
}
readonly property int currentContentWidth: {
// AudioViz (20) + spacing + text + spacing + controls (~90) + padding
const baseWidth = 20 + Theme.spacingXS + 90 + Theme.spacingS * 2
return baseWidth + textWidth + (textWidth > 0 ? Theme.spacingXS : 0)
}
property string section: "center"
property var popupTarget: null
property var parentScreen: null
signal clicked
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = Theme.surfaceTextHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
states: [
State {
name: "shown"
when: playerAvailable
PropertyChanges {
target: root
opacity: 1
width: currentContentWidth
}
},
State {
name: "hidden"
when: !playerAvailable
PropertyChanges {
target: root
opacity: 0
width: 0
}
readonly property int currentContentWidth: {
// AudioViz (20) + spacing + text + spacing + controls (~90) + padding
const baseWidth = 20 + Theme.spacingXS + 90 + Theme.spacingS * 2
return baseWidth + textWidth + (textWidth > 0 ? Theme.spacingXS : 0)
}
]
transitions: [
Transition {
from: "shown"
to: "hidden"
property string section: "center"
property var popupTarget: null
property var parentScreen: null
SequentialAnimation {
PauseAnimation {
duration: 500
signal clicked
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = Theme.surfaceTextHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
states: [
State {
name: "shown"
when: playerAvailable
PropertyChanges {
target: root
opacity: 1
width: currentContentWidth
}
},
State {
name: "hidden"
when: !playerAvailable
PropertyChanges {
target: root
opacity: 0
width: 0
}
}
]
transitions: [
Transition {
from: "shown"
to: "hidden"
SequentialAnimation {
PauseAnimation {
duration: 500
}
NumberAnimation {
properties: "opacity,width"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
},
Transition {
from: "hidden"
to: "shown"
NumberAnimation {
properties: "opacity,width"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
]
Row {
id: mediaRow
anchors.centerIn: parent
spacing: Theme.spacingXS
Row {
id: mediaInfo
spacing: Theme.spacingXS
AudioVisualization {
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
id: textContainer
anchors.verticalCenter: parent.verticalCenter
width: textWidth
height: 20
visible: SettingsData.mediaSize > 0
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
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
SequentialAnimation {
id: scrollAnimation
running: mediaText.needsScrolling
&& textContainer.visible
loops: Animation.Infinite
PauseAnimation {
duration: 2000
}
NumberAnimation {
target: mediaText
property: "scrollOffset"
from: 0
to: mediaText.implicitWidth - textContainer.width + 5
duration: Math.max(
1000,
(mediaText.implicitWidth - textContainer.width + 5) * 60)
easing.type: Easing.Linear
}
PauseAnimation {
duration: 2000
}
NumberAnimation {
target: mediaText
property: "scrollOffset"
to: 0
duration: Math.max(
1000,
(mediaText.implicitWidth - textContainer.width + 5) * 60)
easing.type: Easing.Linear
}
}
onTextChanged: {
scrollOffset = 0
scrollAnimation.restart()
}
}
MouseArea {
anchors.fill: parent
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,
Theme.barHeight + Theme.spacingXS,
root.width, root.section, currentScreen)
}
root.clicked()
}
}
}
}
Row {
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
Rectangle {
width: 20
height: 20
radius: 10
anchors.verticalCenter: parent.verticalCenter
color: prevArea.containsMouse ? Theme.primaryHover : "transparent"
visible: root.playerAvailable
opacity: (activePlayer && activePlayer.canGoPrevious) ? 1 : 0.3
DankIcon {
anchors.centerIn: parent
name: "skip_previous"
size: 12
color: Theme.surfaceText
}
MouseArea {
id: prevArea
anchors.fill: parent
enabled: root.playerAvailable && root.width > 0
hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (activePlayer)
activePlayer.previous()
}
}
}
Rectangle {
width: 24
height: 24
radius: 12
anchors.verticalCenter: parent.verticalCenter
color: activePlayer
&& activePlayer.playbackState === 1 ? Theme.primary : Theme.primaryHover
visible: root.playerAvailable
opacity: activePlayer ? 1 : 0.3
DankIcon {
anchors.centerIn: parent
name: activePlayer
&& activePlayer.playbackState === 1 ? "pause" : "play_arrow"
size: 14
color: activePlayer
&& activePlayer.playbackState === 1 ? Theme.background : Theme.primary
}
MouseArea {
anchors.fill: parent
enabled: root.playerAvailable && root.width > 0
hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (activePlayer)
activePlayer.togglePlaying()
}
}
}
Rectangle {
width: 20
height: 20
radius: 10
anchors.verticalCenter: parent.verticalCenter
color: nextArea.containsMouse ? Theme.primaryHover : "transparent"
visible: playerAvailable
opacity: (activePlayer && activePlayer.canGoNext) ? 1 : 0.3
DankIcon {
anchors.centerIn: parent
name: "skip_next"
size: 12
color: Theme.surfaceText
}
MouseArea {
id: nextArea
anchors.fill: parent
enabled: root.playerAvailable && root.width > 0
hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (activePlayer)
activePlayer.next()
}
}
}
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on width {
NumberAnimation {
properties: "opacity,width"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
},
Transition {
from: "hidden"
to: "shown"
NumberAnimation {
properties: "opacity,width"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
]
Row {
id: mediaRow
anchors.centerIn: parent
spacing: Theme.spacingXS
Row {
id: mediaInfo
spacing: Theme.spacingXS
AudioVisualization {
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
id: textContainer
anchors.verticalCenter: parent.verticalCenter
width: textWidth
height: 20
visible: SettingsData.mediaSize > 0
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
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
SequentialAnimation {
id: scrollAnimation
running: mediaText.needsScrolling && textContainer.visible
loops: Animation.Infinite
PauseAnimation { duration: 2000 }
NumberAnimation {
target: mediaText
property: "scrollOffset"
from: 0
to: mediaText.implicitWidth - textContainer.width + 5
duration: Math.max(1000, (mediaText.implicitWidth - textContainer.width + 5) * 60)
easing.type: Easing.Linear
}
PauseAnimation { duration: 2000 }
NumberAnimation {
target: mediaText
property: "scrollOffset"
to: 0
duration: Math.max(1000, (mediaText.implicitWidth - textContainer.width + 5) * 60)
easing.type: Easing.Linear
}
}
onTextChanged: {
scrollOffset = 0
scrollAnimation.restart()
}
}
MouseArea {
anchors.fill: parent
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, Theme.barHeight + Theme.spacingXS, root.width,
root.section, currentScreen)
}
root.clicked()
}
}
}
}
Row {
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
Rectangle {
width: 20
height: 20
radius: 10
anchors.verticalCenter: parent.verticalCenter
color: prevArea.containsMouse ? Theme.primaryHover : "transparent"
visible: root.playerAvailable
opacity: (activePlayer && activePlayer.canGoPrevious) ? 1 : 0.3
DankIcon {
anchors.centerIn: parent
name: "skip_previous"
size: 12
color: Theme.surfaceText
}
MouseArea {
id: prevArea
anchors.fill: parent
enabled: root.playerAvailable && root.width > 0
hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (activePlayer)
activePlayer.previous()
}
}
}
Rectangle {
width: 24
height: 24
radius: 12
anchors.verticalCenter: parent.verticalCenter
color: activePlayer
&& activePlayer.playbackState === 1 ? Theme.primary : Theme.primaryHover
visible: root.playerAvailable
opacity: activePlayer ? 1 : 0.3
DankIcon {
anchors.centerIn: parent
name: activePlayer
&& activePlayer.playbackState === 1 ? "pause" : "play_arrow"
size: 14
color: activePlayer
&& activePlayer.playbackState === 1 ? Theme.background : Theme.primary
}
MouseArea {
anchors.fill: parent
enabled: root.playerAvailable && root.width > 0
hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (activePlayer)
activePlayer.togglePlaying()
}
}
}
Rectangle {
width: 20
height: 20
radius: 10
anchors.verticalCenter: parent.verticalCenter
color: nextArea.containsMouse ? Theme.primaryHover : "transparent"
visible: playerAvailable
opacity: (activePlayer && activePlayer.canGoNext) ? 1 : 0.3
DankIcon {
anchors.centerIn: parent
name: "skip_next"
size: 12
color: Theme.surfaceText
}
MouseArea {
id: nextArea
anchors.fill: parent
enabled: root.playerAvailable && root.width > 0
hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (activePlayer)
activePlayer.next()
}
}
}
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on width {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

@@ -3,70 +3,70 @@ import qs.Common
import qs.Widgets
Rectangle {
id: root
id: root
property bool hasUnread: false
property bool isActive: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property bool hasUnread: false
property bool isActive: false
property string section: "right"
property var popupTarget: null
property var parentScreen: null
signal clicked
signal clicked
width: 40
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = notificationArea.containsMouse
|| root.isActive ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
DankIcon {
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)
}
Rectangle {
width: 8
height: 8
radius: 4
color: Theme.error
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: 6
anchors.topMargin: 6
visible: root.hasUnread
}
MouseArea {
id: notificationArea
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,
Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
root.clicked()
width: 40
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = notificationArea.containsMouse
|| root.isActive ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
DankIcon {
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)
}
Rectangle {
width: 8
height: 8
radius: 4
color: Theme.error
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: 6
anchors.topMargin: 6
visible: root.hasUnread
}
MouseArea {
id: notificationArea
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, Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
root.clicked()
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -5,155 +5,154 @@ import qs.Services
import qs.Widgets
Rectangle {
id: root
id: root
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property string section: "right"
property var popupTarget: null
property var parentScreen: null
readonly property bool hasActivePrivacy: PrivacyService.anyPrivacyActive
readonly property int activeCount: PrivacyService.microphoneActive + PrivacyService.cameraActive
+ PrivacyService.screensharingActive
readonly property bool hasActivePrivacy: PrivacyService.anyPrivacyActive
readonly property int activeCount: PrivacyService.microphoneActive + PrivacyService.cameraActive
+ PrivacyService.screensharingActive
width: hasActivePrivacy ? (activeCount > 1 ? 80 : 60) : 0
height: hasActivePrivacy ? 30 : 0
radius: Theme.cornerRadius
visible: hasActivePrivacy
opacity: hasActivePrivacy ? 1 : 0
enabled: hasActivePrivacy
color: 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 {
id: privacyArea
anchors.fill: parent
hoverEnabled: hasActivePrivacy
enabled: hasActivePrivacy
cursorShape: Qt.PointingHandCursor
onClicked: {
}
}
Row {
anchors.centerIn: parent
spacing: Theme.spacingXS
visible: hasActivePrivacy
Item {
width: 18
height: 18
visible: PrivacyService.microphoneActive
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: "mic"
size: Theme.iconSizeSmall
color: Theme.error
filled: true
anchors.centerIn: parent
}
}
Item {
width: 18
height: 18
visible: PrivacyService.cameraActive
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: "camera_video"
size: Theme.iconSizeSmall
color: Theme.surfaceText
filled: true
anchors.centerIn: parent
}
Rectangle {
width: 6
height: 6
radius: 3
color: Theme.error
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: -2
anchors.topMargin: -1
}
}
Item {
width: 18
height: 18
visible: PrivacyService.screensharingActive
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: "screen_share"
size: Theme.iconSizeSmall
color: Theme.warning
filled: true
anchors.centerIn: parent
}
}
}
Behavior on width {
enabled: hasActivePrivacy && visible
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Rectangle {
id: tooltip
width: tooltipText.contentWidth + Theme.spacingM * 2
height: tooltipText.contentHeight + Theme.spacingS * 2
width: hasActivePrivacy ? (activeCount > 1 ? 80 : 60) : 0
height: hasActivePrivacy ? 30 : 0
radius: Theme.cornerRadius
color: Theme.popupBackground()
border.color: Theme.outlineMedium
border.width: 1
visible: false
opacity: privacyArea.containsMouse && hasActivePrivacy ? 1 : 0
z: 100
visible: hasActivePrivacy
opacity: hasActivePrivacy ? 1 : 0
enabled: hasActivePrivacy
x: (parent.width - width) / 2
y: -height - Theme.spacingXS
color: 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)
StyledText {
id: tooltipText
anchors.centerIn: parent
text: PrivacyService.getPrivacySummary()
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
MouseArea {
id: privacyArea
anchors.fill: parent
hoverEnabled: hasActivePrivacy
enabled: hasActivePrivacy
cursorShape: Qt.PointingHandCursor
onClicked: {
}
}
Behavior on opacity {
enabled: hasActivePrivacy && root.visible
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
Row {
anchors.centerIn: parent
spacing: Theme.spacingXS
visible: hasActivePrivacy
Item {
width: 18
height: 18
visible: PrivacyService.microphoneActive
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: "mic"
size: Theme.iconSizeSmall
color: Theme.error
filled: true
anchors.centerIn: parent
}
}
Item {
width: 18
height: 18
visible: PrivacyService.cameraActive
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: "camera_video"
size: Theme.iconSizeSmall
color: Theme.surfaceText
filled: true
anchors.centerIn: parent
}
Rectangle {
width: 6
height: 6
radius: 3
color: Theme.error
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: -2
anchors.topMargin: -1
}
}
Item {
width: 18
height: 18
visible: PrivacyService.screensharingActive
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: "screen_share"
size: Theme.iconSizeSmall
color: Theme.warning
filled: true
anchors.centerIn: parent
}
}
}
Behavior on width {
enabled: hasActivePrivacy && visible
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Rectangle {
width: 8
height: 8
color: parent.color
border.color: parent.border.color
border.width: parent.border.width
rotation: 45
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.bottom
anchors.topMargin: -4
id: tooltip
width: tooltipText.contentWidth + Theme.spacingM * 2
height: tooltipText.contentHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: Theme.popupBackground()
border.color: Theme.outlineMedium
border.width: 1
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
color: parent.color
border.color: parent.border.color
border.width: parent.border.width
rotation: 45
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.bottom
anchors.topMargin: -4
}
}
}
}

View File

@@ -5,84 +5,84 @@ import qs.Services
import qs.Widgets
Rectangle {
id: root
id: root
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
width: 55
height: 30
radius: Theme.cornerRadius
color: {
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"])
}
Component.onDestruction: {
DgopService.removeRef(["memory"])
}
MouseArea {
id: ramArea
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,
Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
DgopService.setSortBy("memory")
if (root.toggleProcessList)
root.toggleProcessList()
width: 55
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = ramArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
}
Row {
anchors.centerIn: parent
spacing: 3
DankIcon {
name: "developer_board"
size: Theme.iconSize - 8
color: {
if (DgopService.memoryUsage > 90)
return Theme.tempDanger
if (DgopService.memoryUsage > 75)
return Theme.tempWarning
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
Component.onCompleted: {
DgopService.addRef(["memory"])
}
Component.onDestruction: {
DgopService.removeRef(["memory"])
}
StyledText {
text: {
if (DgopService.memoryUsage === undefined
|| DgopService.memoryUsage === null
|| DgopService.memoryUsage === 0) {
return "--%"
MouseArea {
id: ramArea
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, Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
DgopService.setSortBy("memory")
if (root.toggleProcessList)
root.toggleProcessList()
}
}
Row {
anchors.centerIn: parent
spacing: 3
DankIcon {
name: "developer_board"
size: Theme.iconSize - 8
color: {
if (DgopService.memoryUsage > 90)
return Theme.tempDanger
if (DgopService.memoryUsage > 75)
return Theme.tempWarning
return Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
if (DgopService.memoryUsage === undefined
|| DgopService.memoryUsage === null
|| DgopService.memoryUsage === 0) {
return "--%"
}
return DgopService.memoryUsage.toFixed(0) + "%"
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
return DgopService.memoryUsage.toFixed(0) + "%"
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
}

View File

@@ -17,11 +17,13 @@ Rectangle {
property Item windowRoot: (Window.window ? Window.window.contentItem : null)
readonly property int windowCount: NiriService.windows.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 + Theme.spacingS * 2;
return windowCount * 24 + (windowCount - 1) * Theme.spacingXS + Theme.spacingS * 2
} else {
return windowCount * (24 + Theme.spacingXS + 120) + (windowCount - 1) * Theme.spacingXS + Theme.spacingS * 2;
return windowCount * (24 + Theme.spacingXS + 120)
+ (windowCount - 1) * Theme.spacingXS + Theme.spacingS * 2
}
}
@@ -32,10 +34,11 @@ Rectangle {
clip: false
color: {
if (windowCount === 0)
return "transparent";
return "transparent"
const baseColor = Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
const baseColor = Theme.secondaryHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
Row {
@@ -52,17 +55,19 @@ Rectangle {
delegate: Item {
id: delegateItem
property bool isFocused: String(modelData.id) === String(NiriService.focusedWindowId)
property bool isFocused: String(modelData.id) === String(
NiriService.focusedWindowId)
property string appId: modelData.app_id || ""
property string windowTitle: modelData.title || "(Unnamed)"
property int windowId: modelData.id
property string tooltipText: {
var appName = "Unknown";
var appName = "Unknown"
if (appId) {
var desktopEntry = DesktopEntries.byId(appId);
appName = desktopEntry && desktopEntry.name ? desktopEntry.name : appId;
var desktopEntry = DesktopEntries.byId(appId)
appName = desktopEntry
&& desktopEntry.name ? desktopEntry.name : appId
}
return appName + (windowTitle ? " • " + windowTitle : "");
return appName + (windowTitle ? " • " + windowTitle : "")
}
width: SettingsData.runningAppsCompactMode ? 24 : (24 + Theme.spacingXS + 120)
@@ -73,9 +78,21 @@ Rectangle {
radius: Theme.cornerRadius
color: {
if (isFocused)
return mouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2);
return mouseArea.containsMouse ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.3) : Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.2)
else
return mouseArea.containsMouse ? Qt.rgba(Theme.primaryHover.r, Theme.primaryHover.g, Theme.primaryHover.b, 0.1) : "transparent";
return mouseArea.containsMouse ? Qt.rgba(
Theme.primaryHover.r,
Theme.primaryHover.g,
Theme.primaryHover.b,
0.1) : "transparent"
}
Behavior on color {
@@ -83,9 +100,7 @@ Rectangle {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
// App icon
@@ -99,14 +114,17 @@ Rectangle {
height: 18
source: {
if (!appId)
return "";
return ""
var desktopEntry = DesktopEntries.byId(appId);
var desktopEntry = DesktopEntries.byId(appId)
if (desktopEntry && desktopEntry.icon) {
var iconPath = Quickshell.iconPath(desktopEntry.icon, SettingsData.iconTheme === "System Default" ? "" : SettingsData.iconTheme);
return iconPath;
var iconPath = Quickshell.iconPath(
desktopEntry.icon,
SettingsData.iconTheme
=== "System Default" ? "" : SettingsData.iconTheme)
return iconPath
}
return "";
return ""
}
smooth: true
mipmap: true
@@ -122,13 +140,13 @@ Rectangle {
visible: !iconImg.visible
text: {
if (!appId)
return "?";
return "?"
var desktopEntry = DesktopEntries.byId(appId);
var desktopEntry = DesktopEntries.byId(appId)
if (desktopEntry && desktopEntry.name)
return desktopEntry.name.charAt(0).toUpperCase();
return desktopEntry.name.charAt(0).toUpperCase()
return appId.charAt(0).toUpperCase();
return appId.charAt(0).toUpperCase()
}
font.pixelSize: 10
color: Theme.surfaceText
@@ -158,32 +176,33 @@ Rectangle {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
NiriService.focusWindow(windowId);
NiriService.focusWindow(windowId)
}
onEntered: {
root.hoveredItem = delegateItem;
var globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height);
tooltipLoader.active = true;
root.hoveredItem = delegateItem
var globalPos = delegateItem.mapToGlobal(
delegateItem.width / 2, delegateItem.height)
tooltipLoader.active = true
if (tooltipLoader.item) {
var tooltipY = Theme.barHeight + SettingsData.topBarSpacing + Theme.spacingXS;
tooltipLoader.item.showTooltip(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen);
var tooltipY = Theme.barHeight
+ SettingsData.topBarSpacing + Theme.spacingXS
tooltipLoader.item.showTooltip(
delegateItem.tooltipText, globalPos.x,
tooltipY, root.parentScreen)
}
}
onExited: {
if (root.hoveredItem === delegateItem) {
root.hoveredItem = null;
root.hoveredItem = null
if (tooltipLoader.item)
tooltipLoader.item.hideTooltip();
tooltipLoader.item.hideTooltip()
tooltipLoader.active = false;
tooltipLoader.active = false
}
}
}
}
}
}
Loader {
@@ -191,9 +210,6 @@ Rectangle {
active: false
sourceComponent: RunningAppsTooltip {
}
sourceComponent: RunningAppsTooltip {}
}
}

View File

@@ -5,53 +5,55 @@ import qs.Common
PanelWindow {
id: root
property string tooltipText: ""
property real targetX: 0
property real targetY: 0
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
}
function hideTooltip() {
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
anchors {
top: true
left: true
}
margins {
left: Math.round(targetX - implicitWidth / 2)
top: Math.round(targetY)
}
Rectangle {
anchors.fill: parent
color: Theme.surfaceContainer
radius: Theme.cornerRadius
border.width: 1
border.color: Theme.outlineMedium
Text {
id: textContent
anchors.centerIn: parent
@@ -64,4 +66,4 @@ PanelWindow {
width: parent.width - Theme.spacingM * 2
}
}
}
}

View File

@@ -92,29 +92,30 @@ Rectangle {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: mouse => {
if (!trayItem)
return
if (!trayItem)
return
if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
trayItem.activate()
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()
}
}
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()
}
}
}
}
}

View File

@@ -31,90 +31,103 @@ PanelWindow {
let fonts = Qt.fontFamilies()
if (fonts.indexOf("Material Symbols Rounded") === -1)
ToastService.showError(
"Please install Material Symbols Rounded and Restart your Shell. See README.md for instructions")
"Please install Material Symbols Rounded and Restart your Shell. See README.md for instructions")
SettingsData.forceTopBarLayoutRefresh.connect(function () {
Qt.callLater(() => {
leftSection.visible = false
centerSection.visible = false
rightSection.visible = false
Qt.callLater(() => {
leftSection.visible = true
centerSection.visible = true
rightSection.visible = true
})
})
leftSection.visible = false
centerSection.visible = false
rightSection.visible = false
Qt.callLater(() => {
leftSection.visible = true
centerSection.visible = true
rightSection.visible = true
})
})
})
// Configure GPU temperature monitoring based on widget configuration
updateGpuTempConfig()
// Force widget initialization after brief delay to ensure services are loaded
Qt.callLater(() => {
Qt.callLater(() => {
forceWidgetRefresh()
})
})
Qt.callLater(() => {
forceWidgetRefresh()
})
})
}
function forceWidgetRefresh() {
// Force reload of all widget sections to handle race condition on desktop hardware
if (leftSection) leftSection.visible = false
if (centerSection) centerSection.visible = false
if (rightSection) rightSection.visible = false
if (leftSection)
leftSection.visible = false
if (centerSection)
centerSection.visible = false
if (rightSection)
rightSection.visible = false
Qt.callLater(() => {
if (leftSection) leftSection.visible = true
if (centerSection) centerSection.visible = true
if (rightSection) rightSection.visible = true
})
if (leftSection)
leftSection.visible = true
if (centerSection)
centerSection.visible = true
if (rightSection)
rightSection.visible = true
})
}
function updateGpuTempConfig() {
const allWidgets = [...(SettingsData.topBarLeftWidgets || []),
...(SettingsData.topBarCenterWidgets || []),
...(SettingsData.topBarRightWidgets || [])]
const allWidgets = [...(SettingsData.topBarLeftWidgets
|| []), ...(SettingsData.topBarCenterWidgets
|| []), ...(SettingsData.topBarRightWidgets
|| [])]
const hasGpuTempWidget = allWidgets.some(widget => {
const widgetId = typeof widget === "string" ? widget : widget.id
const widgetEnabled = typeof widget === "string" ? true : (widget.enabled !== false)
return widgetId === "gpuTemp" && widgetEnabled
})
DgopService.gpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled || SessionData.nonNvidiaGpuTempEnabled
DgopService.nvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled
DgopService.nonNvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nonNvidiaGpuTempEnabled
const widgetId = typeof widget
=== "string" ? widget : widget.id
const widgetEnabled = typeof widget === "string" ? true : (widget.enabled !== false)
return widgetId === "gpuTemp"
&& widgetEnabled
})
DgopService.gpuTempEnabled = hasGpuTempWidget
|| SessionData.nvidiaGpuTempEnabled
|| SessionData.nonNvidiaGpuTempEnabled
DgopService.nvidiaGpuTempEnabled = hasGpuTempWidget
|| SessionData.nvidiaGpuTempEnabled
DgopService.nonNvidiaGpuTempEnabled = hasGpuTempWidget
|| SessionData.nonNvidiaGpuTempEnabled
}
Connections {
function onTopBarTransparencyChanged() {
root.backgroundTransparency = SettingsData.topBarTransparency
}
function onTopBarLeftWidgetsChanged() {
root.updateGpuTempConfig()
}
function onTopBarCenterWidgetsChanged() {
root.updateGpuTempConfig()
}
function onTopBarRightWidgetsChanged() {
root.updateGpuTempConfig()
}
target: SettingsData
}
Connections {
function onNvidiaGpuTempEnabledChanged() {
root.updateGpuTempConfig()
}
function onNonNvidiaGpuTempEnabledChanged() {
root.updateGpuTempConfig()
}
target: SessionData
}
@@ -189,8 +202,10 @@ PanelWindow {
Rectangle {
anchors.fill: parent
radius: SettingsData.topBarSquareCorners ? 0 : Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
Theme.surfaceContainer.b, root.backgroundTransparency)
color: Qt.rgba(Theme.surfaceContainer.r,
Theme.surfaceContainer.g,
Theme.surfaceContainer.b,
root.backgroundTransparency)
layer.enabled: true
Rectangle {
@@ -203,7 +218,8 @@ PanelWindow {
Rectangle {
anchors.fill: parent
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g,
color: Qt.rgba(Theme.surfaceTint.r,
Theme.surfaceTint.g,
Theme.surfaceTint.b, 0.04)
radius: parent.radius
@@ -242,8 +258,7 @@ PanelWindow {
readonly property int launcherButtonWidth: 40
readonly property int workspaceSwitcherWidth: 120 // Approximate
readonly property int focusedAppMaxWidth: 456 // Fixed width since we don't have focusedApp reference
readonly property int estimatedLeftSectionWidth: launcherButtonWidth + workspaceSwitcherWidth
+ focusedAppMaxWidth + (Theme.spacingXS * 2)
readonly property int estimatedLeftSectionWidth: launcherButtonWidth + workspaceSwitcherWidth + focusedAppMaxWidth + (Theme.spacingXS * 2)
readonly property int rightSectionWidth: rightSection.width
readonly property int clockWidth: 120 // Approximate clock width
readonly property int mediaMaxWidth: 280 // Normal max width
@@ -254,19 +269,17 @@ PanelWindow {
readonly property int clockLeftEdge: (availableWidth - clockWidth) / 2
readonly property int clockRightEdge: clockLeftEdge + clockWidth
readonly property int leftSectionRightEdge: estimatedLeftSectionWidth
readonly property int mediaLeftEdge: clockLeftEdge - mediaMaxWidth - Theme.spacingS
readonly property int mediaLeftEdge: clockLeftEdge - mediaMaxWidth
- Theme.spacingS
readonly property int rightSectionLeftEdge: availableWidth - rightSectionWidth
readonly property int leftToClockGap: Math.max(
0,
clockLeftEdge - leftSectionRightEdge)
readonly property int leftToMediaGap: mediaMaxWidth > 0 ? Math.max(
0,
mediaLeftEdge - leftSectionRightEdge) : leftToClockGap
0,
clockLeftEdge - leftSectionRightEdge)
readonly property int leftToMediaGap: mediaMaxWidth > 0 ? Math.max(0, mediaLeftEdge - leftSectionRightEdge) : leftToClockGap
readonly property int mediaToClockGap: mediaMaxWidth > 0 ? Theme.spacingS : 0
readonly property int clockToRightGap: validLayout ? Math.max(
0,
rightSectionLeftEdge
- clockRightEdge) : 1000
0,
rightSectionLeftEdge - clockRightEdge) : 1000
readonly property bool spacingTight: validLayout
&& (leftToMediaGap < 150
|| clockToRightGap < 100)
@@ -396,9 +409,12 @@ PanelWindow {
property int spacerSize: model.size || 20
anchors.verticalCenter: parent ? parent.verticalCenter : undefined
active: topBarContent.getWidgetVisible(model.widgetId)
sourceComponent: topBarContent.getWidgetComponent(model.widgetId)
opacity: topBarContent.getWidgetEnabled(model.enabled) ? 1 : 0
active: topBarContent.getWidgetVisible(
model.widgetId)
sourceComponent: topBarContent.getWidgetComponent(
model.widgetId)
opacity: topBarContent.getWidgetEnabled(
model.enabled) ? 1 : 0
asynchronous: false
}
}
@@ -443,7 +459,8 @@ PanelWindow {
let parentCenterX = width / 2
if (totalWidgets % 2 === 1) {
let middleIndex = Math.floor(totalWidgets / 2)
let currentX = parentCenterX - (centerWidgets[middleIndex].width / 2)
let currentX = parentCenterX
- (centerWidgets[middleIndex].width / 2)
centerWidgets[middleIndex].x = currentX
centerWidgets[middleIndex].anchors.horizontalCenter = undefined
currentX = centerWidgets[middleIndex].x
@@ -452,7 +469,8 @@ PanelWindow {
centerWidgets[i].x = currentX
centerWidgets[i].anchors.horizontalCenter = undefined
}
currentX = centerWidgets[middleIndex].x + centerWidgets[middleIndex].width
currentX = centerWidgets[middleIndex].x
+ centerWidgets[middleIndex].width
for (var i = middleIndex + 1; i < totalWidgets; i++) {
currentX += spacing
centerWidgets[i].x = currentX
@@ -465,7 +483,7 @@ PanelWindow {
let gapCenter = parentCenterX
let halfSpacing = spacing / 2
centerWidgets[leftMiddleIndex].x = gapCenter - halfSpacing
- centerWidgets[leftMiddleIndex].width
- centerWidgets[leftMiddleIndex].width
centerWidgets[leftMiddleIndex].anchors.horizontalCenter = undefined
centerWidgets[rightMiddleIndex].x = gapCenter + halfSpacing
centerWidgets[rightMiddleIndex].anchors.horizontalCenter = undefined
@@ -475,7 +493,8 @@ PanelWindow {
centerWidgets[i].x = currentX
centerWidgets[i].anchors.horizontalCenter = undefined
}
currentX = centerWidgets[rightMiddleIndex].x + centerWidgets[rightMiddleIndex].width
currentX = centerWidgets[rightMiddleIndex].x
+ centerWidgets[rightMiddleIndex].width
for (var i = rightMiddleIndex + 1; i < totalWidgets; i++) {
currentX += spacing
centerWidgets[i].x = currentX
@@ -490,8 +509,8 @@ PanelWindow {
anchors.centerIn: parent
Component.onCompleted: {
Qt.callLater(() => {
Qt.callLater(updateLayout)
})
Qt.callLater(updateLayout)
})
}
onWidthChanged: {
@@ -517,18 +536,23 @@ PanelWindow {
property int spacerSize: model.size || 20
anchors.verticalCenter: parent ? parent.verticalCenter : undefined
active: topBarContent.getWidgetVisible(model.widgetId)
sourceComponent: topBarContent.getWidgetComponent(model.widgetId)
opacity: topBarContent.getWidgetEnabled(model.enabled) ? 1 : 0
active: topBarContent.getWidgetVisible(
model.widgetId)
sourceComponent: topBarContent.getWidgetComponent(
model.widgetId)
opacity: topBarContent.getWidgetEnabled(
model.enabled) ? 1 : 0
asynchronous: false
onLoaded: {
if (item) {
item.onWidthChanged.connect(centerSection.updateLayout)
item.onWidthChanged.connect(
centerSection.updateLayout)
if (model.widgetId === "spacer")
item.spacerSize = Qt.binding(() => {
return model.size || 20
})
return model.size
|| 20
})
Qt.callLater(centerSection.updateLayout)
}
}
@@ -564,15 +588,17 @@ PanelWindow {
property int spacerSize: model.size || 20
anchors.verticalCenter: parent ? parent.verticalCenter : undefined
active: topBarContent.getWidgetVisible(model.widgetId)
sourceComponent: topBarContent.getWidgetComponent(model.widgetId)
opacity: topBarContent.getWidgetEnabled(model.enabled) ? 1 : 0
active: topBarContent.getWidgetVisible(
model.widgetId)
sourceComponent: topBarContent.getWidgetComponent(
model.widgetId)
opacity: topBarContent.getWidgetEnabled(
model.enabled) ? 1 : 0
asynchronous: false
}
}
}
Component {
id: clipboardComponent
@@ -582,8 +608,10 @@ PanelWindow {
radius: Theme.cornerRadius
color: {
const baseColor = clipboardArea.containsMouse ? Theme.primaryHover : Theme.secondaryHover
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)
}
DankIcon {
@@ -695,7 +723,8 @@ PanelWindow {
onClockClicked: {
centcomPopoutLoader.active = true
if (centcomPopoutLoader.item) {
centcomPopoutLoader.item.calendarVisible = !centcomPopoutLoader.item.calendarVisible
centcomPopoutLoader.item.calendarVisible
= !centcomPopoutLoader.item.calendarVisible
}
}
}
@@ -705,7 +734,8 @@ PanelWindow {
id: mediaComponent
Media {
compactMode: topBarContent.spacingTight || topBarContent.overlapping
compactMode: topBarContent.spacingTight
|| topBarContent.overlapping
section: {
if (parent && parent.parent === leftSection)
return "left"
@@ -723,7 +753,8 @@ PanelWindow {
onClicked: {
centcomPopoutLoader.active = true
if (centcomPopoutLoader.item) {
centcomPopoutLoader.item.calendarVisible = !centcomPopoutLoader.item.calendarVisible
centcomPopoutLoader.item.calendarVisible
= !centcomPopoutLoader.item.calendarVisible
}
}
}
@@ -750,7 +781,8 @@ PanelWindow {
onClicked: {
centcomPopoutLoader.active = true
if (centcomPopoutLoader.item) {
centcomPopoutLoader.item.calendarVisible = !centcomPopoutLoader.item.calendarVisible
centcomPopoutLoader.item.calendarVisible
= !centcomPopoutLoader.item.calendarVisible
}
}
}
@@ -801,10 +833,10 @@ PanelWindow {
}
parentScreen: root.screen
toggleProcessList: () => {
processListPopoutLoader.active = true
if (processListPopoutLoader.item)
return processListPopoutLoader.item.toggle()
}
processListPopoutLoader.active = true
if (processListPopoutLoader.item)
return processListPopoutLoader.item.toggle()
}
}
}
@@ -827,10 +859,10 @@ PanelWindow {
}
parentScreen: root.screen
toggleProcessList: () => {
processListPopoutLoader.active = true
if (processListPopoutLoader.item)
return processListPopoutLoader.item.toggle()
}
processListPopoutLoader.active = true
if (processListPopoutLoader.item)
return processListPopoutLoader.item.toggle()
}
}
}
@@ -853,10 +885,10 @@ PanelWindow {
}
parentScreen: root.screen
toggleProcessList: () => {
processListPopoutLoader.active = true
if (processListPopoutLoader.item)
return processListPopoutLoader.item.toggle()
}
processListPopoutLoader.active = true
if (processListPopoutLoader.item)
return processListPopoutLoader.item.toggle()
}
}
}
@@ -880,10 +912,10 @@ PanelWindow {
parentScreen: root.screen
widgetData: parent.widgetData
toggleProcessList: () => {
processListPopoutLoader.active = true
if (processListPopoutLoader.item)
return processListPopoutLoader.item.toggle()
}
processListPopoutLoader.active = true
if (processListPopoutLoader.item)
return processListPopoutLoader.item.toggle()
}
}
}
@@ -1004,7 +1036,8 @@ PanelWindow {
Rectangle {
anchors.fill: parent
color: "transparent"
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
border.color: Qt.rgba(Theme.outline.r,
Theme.outline.g,
Theme.outline.b, 0.1)
border.width: 1
radius: 2

View File

@@ -4,87 +4,87 @@ import qs.Services
import qs.Widgets
Rectangle {
id: root
id: root
property string section: "center"
property var popupTarget: null
property var parentScreen: null
property string section: "center"
property var popupTarget: null
property var parentScreen: null
signal clicked
signal clicked
visible: SettingsData.weatherEnabled
width: visible ? Math.min(100,
weatherRow.implicitWidth + Theme.spacingS * 2) : 0
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = weatherArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
Ref {
service: WeatherService
}
Row {
id: weatherRow
anchors.centerIn: parent
spacing: Theme.spacingXS
DankIcon {
name: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
size: Theme.iconSize - 4
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
visible: SettingsData.weatherEnabled
width: visible ? Math.min(100,
weatherRow.implicitWidth + Theme.spacingS * 2) : 0
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = weatherArea.containsMouse ? Theme.primaryHover : Theme.surfaceTextHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
StyledText {
text: {
var temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp
if (temp === undefined || temp === null || temp === 0) {
return "--°" + (SettingsData.useFahrenheit ? "F" : "C")
Ref {
service: WeatherService
}
Row {
id: weatherRow
anchors.centerIn: parent
spacing: Theme.spacingXS
DankIcon {
name: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
size: Theme.iconSize - 4
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C")
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: weatherArea
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,
Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
root.clicked()
StyledText {
text: {
var temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp
if (temp === undefined || temp === null || temp === 0) {
return "--°" + (SettingsData.useFahrenheit ? "F" : "C")
}
return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C")
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
MouseArea {
id: weatherArea
Behavior on width {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
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, Theme.barHeight + Theme.spacingXS,
width, section, currentScreen)
}
root.clicked()
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on width {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -6,203 +6,209 @@ import qs.Services
import qs.Widgets
Rectangle {
id: root
id: root
property string screenName: ""
property int currentWorkspace: getDisplayActiveWorkspace()
property var workspaceList: {
var baseList = getDisplayWorkspaces()
return SettingsData.showWorkspacePadding ? padWorkspaces(
baseList) : baseList
}
function padWorkspaces(list) {
var padded = list.slice()
while (padded.length < 3)
padded.push(-1) // Use -1 as a placeholder
return padded
}
function getDisplayWorkspaces() {
if (!NiriService.niriAvailable || 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)
}
return displayWorkspaces.length > 0 ? displayWorkspaces : [1, 2]
}
function getDisplayActiveWorkspace() {
if (!NiriService.niriAvailable || 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
}
width: SettingsData.showWorkspacePadding ? Math.max(
120,
workspaceRow.implicitWidth + Theme.spacingL
* 2) : workspaceRow.implicitWidth
+ Theme.spacingL * 2
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = Theme.surfaceTextHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
visible: NiriService.niriAvailable
Connections {
function onAllWorkspacesChanged() {
root.workspaceList
= SettingsData.showWorkspacePadding ? root.padWorkspaces(
root.getDisplayWorkspaces(
)) : root.getDisplayWorkspaces()
root.currentWorkspace = root.getDisplayActiveWorkspace()
property string screenName: ""
property int currentWorkspace: getDisplayActiveWorkspace()
property var workspaceList: {
var baseList = getDisplayWorkspaces()
return SettingsData.showWorkspacePadding ? padWorkspaces(
baseList) : baseList
}
function onFocusedWorkspaceIndexChanged() {
root.currentWorkspace = root.getDisplayActiveWorkspace()
function padWorkspaces(list) {
var padded = list.slice()
while (padded.length < 3)
padded.push(-1) // Use -1 as a placeholder
return padded
}
function onNiriAvailableChanged() {
if (NiriService.niriAvailable) {
root.workspaceList
= SettingsData.showWorkspacePadding ? root.padWorkspaces(
root.getDisplayWorkspaces(
)) : root.getDisplayWorkspaces()
root.currentWorkspace = root.getDisplayActiveWorkspace()
}
}
function getDisplayWorkspaces() {
if (!NiriService.niriAvailable
|| NiriService.allWorkspaces.length === 0)
return [1, 2]
target: NiriService
}
if (!root.screenName)
return NiriService.getCurrentOutputWorkspaceNumbers()
Connections {
function onShowWorkspacePaddingChanged() {
var baseList = root.getDisplayWorkspaces()
root.workspaceList = SettingsData.showWorkspacePadding ? root.padWorkspaces(
baseList) : baseList
}
target: SettingsData
}
Row {
id: workspaceRow
anchors.centerIn: parent
spacing: Theme.spacingS
Repeater {
model: root.workspaceList
Rectangle {
property bool isActive: modelData === root.currentWorkspace
property bool isPlaceholder: modelData === -1
property bool isHovered: mouseArea.containsMouse
property int sequentialNumber: index + 1
property var workspaceData: {
if (isPlaceholder || !NiriService.niriAvailable) return null
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
var displayWorkspaces = []
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
var ws = NiriService.allWorkspaces[i]
if (ws.idx + 1 === modelData) return ws
}
return null
if (ws.output === root.screenName)
displayWorkspaces.push(ws.idx + 1)
}
return displayWorkspaces.length > 0 ? displayWorkspaces : [1, 2]
}
function getDisplayActiveWorkspace() {
if (!NiriService.niriAvailable
|| 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
}
width: SettingsData.showWorkspacePadding ? Math.max(
120,
workspaceRow.implicitWidth + Theme.spacingL
* 2) : workspaceRow.implicitWidth
+ Theme.spacingL * 2
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = Theme.surfaceTextHover
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b,
baseColor.a * Theme.widgetTransparency)
}
visible: NiriService.niriAvailable
Connections {
function onAllWorkspacesChanged() {
root.workspaceList
= SettingsData.showWorkspacePadding ? root.padWorkspaces(
root.getDisplayWorkspaces(
)) : root.getDisplayWorkspaces()
root.currentWorkspace = root.getDisplayActiveWorkspace()
}
function onFocusedWorkspaceIndexChanged() {
root.currentWorkspace = root.getDisplayActiveWorkspace()
}
function onNiriAvailableChanged() {
if (NiriService.niriAvailable) {
root.workspaceList = SettingsData.showWorkspacePadding ? root.padWorkspaces(root.getDisplayWorkspaces()) : root.getDisplayWorkspaces()
root.currentWorkspace = root.getDisplayActiveWorkspace()
}
}
target: NiriService
}
Connections {
function onShowWorkspacePaddingChanged() {
var baseList = root.getDisplayWorkspaces()
root.workspaceList = SettingsData.showWorkspacePadding ? root.padWorkspaces(
baseList) : baseList
}
target: SettingsData
}
Row {
id: workspaceRow
anchors.centerIn: parent
spacing: Theme.spacingS
Repeater {
model: root.workspaceList
Rectangle {
property bool isActive: modelData === root.currentWorkspace
property bool isPlaceholder: modelData === -1
property bool isHovered: mouseArea.containsMouse
property int sequentialNumber: index + 1
property var workspaceData: {
if (isPlaceholder || !NiriService.niriAvailable)
return null
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
var ws = NiriService.allWorkspaces[i]
if (ws.idx + 1 === modelData)
return ws
}
return null
}
property var iconData: workspaceData
&& workspaceData.name ? SettingsData.getWorkspaceNameIcon(
workspaceData.name) : null
property bool hasIcon: iconData !== null
width: isActive ? Theme.spacingXL + Theme.spacingM : Theme.spacingL
+ Theme.spacingXS
height: Theme.spacingL
radius: height / 2
color: isActive ? Theme.primary : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.outlineButton : Theme.surfaceTextAlpha
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: !isPlaceholder
cursorShape: isPlaceholder ? Qt.ArrowCursor : Qt.PointingHandCursor
enabled: !isPlaceholder
onClicked: {
if (!isPlaceholder)
NiriService.switchToWorkspace(modelData - 1)
}
}
// Icon display (priority over numbers)
DankIcon {
visible: hasIcon && iconData.type === "icon"
anchors.centerIn: parent
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
weight: isActive && !isPlaceholder ? 500 : 400
}
// Custom text display (priority over numbers)
StyledText {
visible: hasIcon && iconData.type === "text"
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
font.pixelSize: Theme.fontSizeSmall
font.weight: isActive
&& !isPlaceholder ? Font.DemiBold : Font.Normal
}
// Number display (secondary priority, only when no icon)
StyledText {
visible: SettingsData.showWorkspaceIndex && !hasIcon
anchors.centerIn: parent
text: isPlaceholder ? sequentialNumber : sequentialNumber
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
}
Behavior on width {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on color {
ColorAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
property var iconData: workspaceData && workspaceData.name ? SettingsData.getWorkspaceNameIcon(workspaceData.name) : null
property bool hasIcon: iconData !== null
width: isActive ? Theme.spacingXL + Theme.spacingM : Theme.spacingL + Theme.spacingXS
height: Theme.spacingL
radius: height / 2
color: isActive ? Theme.primary : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.outlineButton : Theme.surfaceTextAlpha
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: !isPlaceholder
cursorShape: isPlaceholder ? Qt.ArrowCursor : Qt.PointingHandCursor
enabled: !isPlaceholder
onClicked: {
if (!isPlaceholder)
NiriService.switchToWorkspace(modelData - 1)
}
}
// Icon display (priority over numbers)
DankIcon {
visible: hasIcon && iconData.type === "icon"
anchors.centerIn: parent
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
weight: isActive && !isPlaceholder ? 500 : 400
}
// Custom text display (priority over numbers)
StyledText {
visible: hasIcon && iconData.type === "text"
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
font.pixelSize: Theme.fontSizeSmall
font.weight: isActive && !isPlaceholder ? Font.DemiBold : Font.Normal
}
// Number display (secondary priority, only when no icon)
StyledText {
visible: SettingsData.showWorkspaceIndex && !hasIcon
anchors.centerIn: parent
text: isPlaceholder ? sequentialNumber : sequentialNumber
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
}
Behavior on width {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on color {
ColorAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
}