mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
Add disk usage component for TopBar and ControlCenter
This commit is contained in:
@@ -171,7 +171,8 @@ Singleton {
|
||||
"enabled": true,
|
||||
"size": 20,
|
||||
"selectedGpuIndex": 0,
|
||||
"pciId": ""
|
||||
"pciId": "",
|
||||
"mountPath": "/"
|
||||
}
|
||||
leftWidgetsModel.append(dummyItem)
|
||||
centerWidgetsModel.append(dummyItem)
|
||||
@@ -741,6 +742,7 @@ Singleton {
|
||||
var size = typeof order[i] === "string" ? undefined : order[i].size
|
||||
var selectedGpuIndex = typeof order[i] === "string" ? undefined : order[i].selectedGpuIndex
|
||||
var pciId = typeof order[i] === "string" ? undefined : order[i].pciId
|
||||
var mountPath = typeof order[i] === "string" ? undefined : order[i].mountPath
|
||||
var item = {
|
||||
"widgetId": widgetId,
|
||||
"enabled": enabled
|
||||
@@ -751,6 +753,8 @@ Singleton {
|
||||
item.selectedGpuIndex = selectedGpuIndex
|
||||
if (pciId !== undefined)
|
||||
item.pciId = pciId
|
||||
if (mountPath !== undefined)
|
||||
item.mountPath = mountPath
|
||||
|
||||
listModel.append(item)
|
||||
}
|
||||
|
||||
@@ -6,12 +6,14 @@ Item {
|
||||
id: root
|
||||
|
||||
property string expandedSection: ""
|
||||
property var expandedWidgetData: null
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
height: 250
|
||||
y: Theme.spacingS
|
||||
active: parent.height > 0
|
||||
property string sectionKey: root.expandedSection
|
||||
sourceComponent: {
|
||||
switch (root.expandedSection) {
|
||||
case "network":
|
||||
@@ -20,9 +22,17 @@ Item {
|
||||
case "audioOutput": return audioOutputDetailComponent
|
||||
case "audioInput": return audioInputDetailComponent
|
||||
case "battery": return batteryDetailComponent
|
||||
default: return null
|
||||
default:
|
||||
if (root.expandedSection.startsWith("diskUsage_")) {
|
||||
return diskUsageDetailComponent
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
onSectionKeyChanged: {
|
||||
active = false
|
||||
active = true
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
@@ -49,4 +59,28 @@ Item {
|
||||
id: batteryDetailComponent
|
||||
BatteryDetail {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: diskUsageDetailComponent
|
||||
DiskUsageDetail {
|
||||
currentMountPath: root.expandedWidgetData?.mountPath || "/"
|
||||
instanceId: root.expandedWidgetData?.instanceId || ""
|
||||
|
||||
|
||||
onMountPathChanged: (newMountPath) => {
|
||||
if (root.expandedWidgetData && root.expandedWidgetData.id === "diskUsage") {
|
||||
const widgets = SettingsData.controlCenterWidgets || []
|
||||
const newWidgets = widgets.map(w => {
|
||||
if (w.id === "diskUsage" && w.instanceId === root.expandedWidgetData.instanceId) {
|
||||
const updatedWidget = Object.assign({}, w)
|
||||
updatedWidget.mountPath = newMountPath
|
||||
return updatedWidget
|
||||
}
|
||||
return w
|
||||
})
|
||||
SettingsData.setControlCenterWidgets(newWidgets)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ Column {
|
||||
property string expandedSection: ""
|
||||
property int expandedWidgetIndex: -1
|
||||
property var model: null
|
||||
property var expandedWidgetData: null
|
||||
|
||||
signal expandClicked(var widgetData, int globalIndex)
|
||||
signal removeWidget(int index)
|
||||
@@ -28,12 +29,17 @@ Column {
|
||||
return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex)
|
||||
}
|
||||
|
||||
property var layoutResult: {
|
||||
const dummy = [expandedSection, expandedWidgetIndex, model?.controlCenterWidgets]
|
||||
return calculateRowsAndWidgets()
|
||||
}
|
||||
|
||||
onLayoutResultChanged: {
|
||||
expandedRowIndex = layoutResult.expandedRowIndex
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
const result = root.calculateRowsAndWidgets()
|
||||
root.expandedRowIndex = result.expandedRowIndex
|
||||
return result.rows
|
||||
}
|
||||
model: root.layoutResult.rows
|
||||
|
||||
Column {
|
||||
width: root.width
|
||||
@@ -102,6 +108,8 @@ Column {
|
||||
return inputAudioSliderComponent
|
||||
} else if (id === "battery") {
|
||||
return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent
|
||||
} else if (id === "diskUsage") {
|
||||
return diskUsagePillComponent
|
||||
} else {
|
||||
return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent
|
||||
}
|
||||
@@ -115,9 +123,19 @@ Column {
|
||||
DetailHost {
|
||||
width: parent.width
|
||||
height: active ? (250 + Theme.spacingS) : 0
|
||||
property bool active: root.expandedSection !== "" && rowIndex === root.expandedRowIndex
|
||||
property bool active: {
|
||||
if (root.expandedSection === "") return false
|
||||
|
||||
if (root.expandedSection.startsWith("diskUsage_") && root.expandedWidgetData) {
|
||||
const expandedInstanceId = root.expandedWidgetData.instanceId
|
||||
return rowWidgets.some(w => w.id === "diskUsage" && w.instanceId === expandedInstanceId)
|
||||
}
|
||||
|
||||
return rowIndex === root.expandedRowIndex
|
||||
}
|
||||
visible: active
|
||||
expandedSection: root.expandedSection
|
||||
expandedWidgetData: root.expandedWidgetData
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -676,4 +694,35 @@ Column {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: diskUsagePillComponent
|
||||
DiskUsagePill {
|
||||
property var widgetData: parent.widgetData || {}
|
||||
property int widgetIndex: parent.widgetIndex || 0
|
||||
width: parent.width
|
||||
height: 60
|
||||
|
||||
mountPath: widgetData.mountPath || "/"
|
||||
instanceId: widgetData.instanceId || ""
|
||||
|
||||
onExpandClicked: {
|
||||
if (!root.editMode) {
|
||||
root.expandClicked(widgetData, widgetIndex)
|
||||
}
|
||||
}
|
||||
|
||||
EditModeOverlay {
|
||||
anchors.fill: parent
|
||||
editMode: root.editMode
|
||||
widgetData: parent.widgetData
|
||||
widgetIndex: parent.widgetIndex
|
||||
showSizeControls: true
|
||||
isSlider: false
|
||||
onRemoveWidget: (index) => root.removeWidget(index)
|
||||
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
|
||||
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,10 +26,29 @@ DankPopout {
|
||||
property var triggerScreen: null
|
||||
property bool editMode: false
|
||||
property int expandedWidgetIndex: -1
|
||||
property var expandedWidgetData: null
|
||||
|
||||
signal powerActionRequested(string action, string title, string message)
|
||||
signal lockRequested
|
||||
|
||||
function collapseAll() {
|
||||
expandedSection = ""
|
||||
expandedWidgetIndex = -1
|
||||
expandedWidgetData = null
|
||||
}
|
||||
|
||||
onEditModeChanged: {
|
||||
if (editMode) {
|
||||
collapseAll()
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
collapseAll()
|
||||
}
|
||||
}
|
||||
|
||||
readonly property color _containerBg: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.60)
|
||||
|
||||
function setTriggerPosition(x, y, width, section, screen) {
|
||||
@@ -132,10 +151,16 @@ DankPopout {
|
||||
editMode: root.editMode
|
||||
expandedSection: root.expandedSection
|
||||
expandedWidgetIndex: root.expandedWidgetIndex
|
||||
expandedWidgetData: root.expandedWidgetData
|
||||
model: widgetModel
|
||||
onExpandClicked: (widgetData, globalIndex) => {
|
||||
root.expandedWidgetIndex = globalIndex
|
||||
root.toggleSection(widgetData.id)
|
||||
root.expandedWidgetData = widgetData
|
||||
if (widgetData.id === "diskUsage") {
|
||||
root.toggleSection("diskUsage_" + (widgetData.instanceId || "default"))
|
||||
} else {
|
||||
root.toggleSection(widgetData.id)
|
||||
}
|
||||
}
|
||||
onRemoveWidget: (index) => widgetModel.removeWidget(index)
|
||||
onMoveWidget: (fromIndex, toIndex) => widgetModel.moveWidget(fromIndex, toIndex)
|
||||
@@ -147,7 +172,7 @@ DankPopout {
|
||||
visible: editMode
|
||||
availableWidgets: {
|
||||
const existingIds = (SettingsData.controlCenterWidgets || []).map(w => w.id)
|
||||
return widgetModel.baseWidgetDefinitions.filter(w => !existingIds.includes(w.id))
|
||||
return widgetModel.baseWidgetDefinitions.filter(w => w.allowMultiple || !existingIds.includes(w.id))
|
||||
}
|
||||
onAddWidget: (widgetId) => widgetModel.addWidget(widgetId)
|
||||
onResetToDefault: () => widgetModel.resetToDefault()
|
||||
|
||||
169
Modules/ControlCenter/Details/DiskUsageDetail.qml
Normal file
169
Modules/ControlCenter/Details/DiskUsageDetail.qml
Normal file
@@ -0,0 +1,169 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
property string currentMountPath: "/"
|
||||
property string instanceId: ""
|
||||
|
||||
signal mountPathChanged(string newMountPath)
|
||||
|
||||
implicitHeight: diskContent.height + Theme.spacingM
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.6)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
|
||||
Component.onCompleted: {
|
||||
DgopService.addRef(["diskmounts"])
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
DgopService.removeRef(["diskmounts"])
|
||||
}
|
||||
|
||||
DankFlickable {
|
||||
id: diskContent
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: Theme.spacingM
|
||||
anchors.topMargin: Theme.spacingM
|
||||
contentHeight: diskColumn.height
|
||||
clip: true
|
||||
|
||||
Column {
|
||||
id: diskColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 100
|
||||
visible: !DgopService.dgopAvailable || !DgopService.diskMounts || DgopService.diskMounts.length === 0
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
name: DgopService.dgopAvailable ? "storage" : "error"
|
||||
size: 32
|
||||
color: DgopService.dgopAvailable ? Theme.primary : Theme.error
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: DgopService.dgopAvailable ? "No disk data available" : "dgop not available"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: DgopService.diskMounts || []
|
||||
delegate: Rectangle {
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
width: parent.width
|
||||
height: 80
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, index % 2 === 0 ? 0.3 : 0.2)
|
||||
border.color: modelData.mount === currentMountPath ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
border.width: modelData.mount === currentMountPath ? 2 : 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
|
||||
DankIcon {
|
||||
name: "storage"
|
||||
size: Theme.iconSize
|
||||
color: {
|
||||
const percentStr = modelData.percent?.replace("%", "") || "0"
|
||||
const percent = parseFloat(percentStr) || 0
|
||||
if (percent > 90) return Theme.error
|
||||
if (percent > 75) return Theme.warning
|
||||
return modelData.mount === currentMountPath ? Theme.primary : Theme.surfaceText
|
||||
}
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
const percentStr = modelData.percent?.replace("%", "") || "0"
|
||||
const percent = parseFloat(percentStr) || 0
|
||||
return percent.toFixed(0) + "%"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.parent.width - parent.parent.anchors.leftMargin - parent.spacing - 50 - Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: modelData.mount === "/" ? "Root Filesystem" : modelData.mount
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: modelData.mount === currentMountPath ? Font.Medium : Font.Normal
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.mount
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
visible: modelData.mount !== "/"
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: `${modelData.used || "?"} / ${modelData.size || "?"}`
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (modelData.mount !== currentMountPath) {
|
||||
currentMountPath = modelData.mount
|
||||
mountPathChanged(modelData.mount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,6 +106,16 @@ QtObject {
|
||||
"icon": "battery_std",
|
||||
"type": "action",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"id": "diskUsage",
|
||||
"text": "Disk Usage",
|
||||
"description": "Filesystem usage monitoring",
|
||||
"icon": "storage",
|
||||
"type": "action",
|
||||
"enabled": DgopService.dgopAvailable,
|
||||
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined,
|
||||
"allowMultiple": true
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
78
Modules/ControlCenter/Widgets/DiskUsagePill.qml
Normal file
78
Modules/ControlCenter/Widgets/DiskUsagePill.qml
Normal file
@@ -0,0 +1,78 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.ControlCenter.Widgets
|
||||
|
||||
CompoundPill {
|
||||
id: root
|
||||
|
||||
property string mountPath: "/"
|
||||
property string instanceId: ""
|
||||
|
||||
iconName: "storage"
|
||||
|
||||
property var selectedMount: {
|
||||
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const targetMount = DgopService.diskMounts.find(mount => mount.mount === mountPath)
|
||||
return targetMount || DgopService.diskMounts.find(mount => mount.mount === "/") || DgopService.diskMounts[0]
|
||||
}
|
||||
|
||||
property real usagePercent: {
|
||||
if (!selectedMount || !selectedMount.percent) {
|
||||
return 0
|
||||
}
|
||||
const percentStr = selectedMount.percent.replace("%", "")
|
||||
return parseFloat(percentStr) || 0
|
||||
}
|
||||
|
||||
isActive: DgopService.dgopAvailable && selectedMount !== null
|
||||
|
||||
primaryText: {
|
||||
if (!DgopService.dgopAvailable) {
|
||||
return "Disk Usage"
|
||||
}
|
||||
if (!selectedMount) {
|
||||
return "No disk data"
|
||||
}
|
||||
return `Disk Usage • ${selectedMount.mount}`
|
||||
}
|
||||
|
||||
secondaryText: {
|
||||
if (!DgopService.dgopAvailable) {
|
||||
return "dgop not available"
|
||||
}
|
||||
if (!selectedMount) {
|
||||
return "No disk data available"
|
||||
}
|
||||
return `${selectedMount.used} / ${selectedMount.size} (${usagePercent.toFixed(0)}%)`
|
||||
}
|
||||
|
||||
iconColor: {
|
||||
if (!DgopService.dgopAvailable || !selectedMount) {
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||
}
|
||||
if (usagePercent > 90) {
|
||||
return Theme.error
|
||||
}
|
||||
if (usagePercent > 75) {
|
||||
return Theme.warning
|
||||
}
|
||||
return Theme.surfaceText
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
DgopService.addRef(["diskmounts"])
|
||||
}
|
||||
Component.onDestruction: {
|
||||
DgopService.removeRef(["diskmounts"])
|
||||
}
|
||||
|
||||
onToggled: {
|
||||
expandClicked()
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ function calculateRowsAndWidgets(controlCenterColumn, expandedSection, expandedW
|
||||
currentWidth += (currentRow.length > 1 ? spacing : 0) + itemWidth
|
||||
}
|
||||
|
||||
if (widget.id === expandedSection && expandedWidgetIndex === i) {
|
||||
if (expandedWidgetIndex === i) {
|
||||
expandedRow = rows.length
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@ function addWidget(widgetId) {
|
||||
"enabled": true,
|
||||
"width": 50
|
||||
}
|
||||
|
||||
if (widgetId === "diskUsage") {
|
||||
widget.instanceId = generateUniqueId()
|
||||
widget.mountPath = "/"
|
||||
}
|
||||
|
||||
widgets.push(widget)
|
||||
SettingsData.setControlCenterWidgets(widgets)
|
||||
}
|
||||
|
||||
function generateUniqueId() {
|
||||
return Date.now().toString(36) + Math.random().toString(36).substr(2)
|
||||
}
|
||||
|
||||
function removeWidget(index) {
|
||||
var widgets = SettingsData.controlCenterWidgets.slice()
|
||||
if (index >= 0 && index < widgets.length) {
|
||||
|
||||
@@ -67,6 +67,13 @@ Item {
|
||||
"id": "memUsage",
|
||||
"text": "Memory Usage",
|
||||
"description": "Memory usage indicator",
|
||||
"icon": "developer_board",
|
||||
"enabled": DgopService.dgopAvailable,
|
||||
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined
|
||||
}, {
|
||||
"id": "diskUsage",
|
||||
"text": "Disk Usage",
|
||||
"description": "Percentage",
|
||||
"icon": "storage",
|
||||
"enabled": DgopService.dgopAvailable,
|
||||
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined
|
||||
@@ -223,6 +230,9 @@ Item {
|
||||
widgetObj.showBluetoothIcon = true
|
||||
widgetObj.showAudioIcon = true
|
||||
}
|
||||
if (widgetId === "diskUsage") {
|
||||
widgetObj.mountPath = "/"
|
||||
}
|
||||
|
||||
var widgets = []
|
||||
if (targetSection === "left") {
|
||||
@@ -412,6 +422,52 @@ Item {
|
||||
SettingsData.setTopBarRightWidgets(widgets)
|
||||
}
|
||||
|
||||
function handleDiskMountSelectionChanged(sectionId, widgetIndex, mountPath) {
|
||||
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()
|
||||
|
||||
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
||||
var widget = widgets[widgetIndex]
|
||||
if (typeof widget === "string") {
|
||||
widgets[widgetIndex] = {
|
||||
"id": widget,
|
||||
"enabled": true,
|
||||
"mountPath": mountPath
|
||||
}
|
||||
} else {
|
||||
var newWidget = {
|
||||
"id": widget.id,
|
||||
"enabled": widget.enabled,
|
||||
"mountPath": mountPath
|
||||
}
|
||||
if (widget.size !== undefined)
|
||||
newWidget.size = widget.size
|
||||
if (widget.selectedGpuIndex !== undefined)
|
||||
newWidget.selectedGpuIndex = widget.selectedGpuIndex
|
||||
if (widget.pciId !== undefined)
|
||||
newWidget.pciId = widget.pciId
|
||||
if (widget.id === "controlCenterButton") {
|
||||
newWidget.showNetworkIcon = widget.showNetworkIcon !== undefined ? widget.showNetworkIcon : true
|
||||
newWidget.showBluetoothIcon = widget.showBluetoothIcon !== undefined ? widget.showBluetoothIcon : true
|
||||
newWidget.showAudioIcon = widget.showAudioIcon !== undefined ? widget.showAudioIcon : true
|
||||
}
|
||||
widgets[widgetIndex] = newWidget
|
||||
}
|
||||
}
|
||||
|
||||
if (sectionId === "left")
|
||||
SettingsData.setTopBarLeftWidgets(widgets)
|
||||
else if (sectionId === "center")
|
||||
SettingsData.setTopBarCenterWidgets(widgets)
|
||||
else if (sectionId === "right")
|
||||
SettingsData.setTopBarRightWidgets(widgets)
|
||||
}
|
||||
|
||||
function handleControlCenterSettingChanged(sectionId, widgetIndex, settingName, value) {
|
||||
// Control Center settings are global, not per-widget instance
|
||||
if (settingName === "showNetworkIcon") {
|
||||
@@ -441,6 +497,8 @@ Item {
|
||||
=== "string" ? undefined : widget.selectedGpuIndex
|
||||
var widgetPciId = typeof widget
|
||||
=== "string" ? undefined : widget.pciId
|
||||
var widgetMountPath = typeof widget
|
||||
=== "string" ? undefined : widget.mountPath
|
||||
var widgetShowNetworkIcon = typeof widget === "string" ? undefined : widget.showNetworkIcon
|
||||
var widgetShowBluetoothIcon = typeof widget === "string" ? undefined : widget.showBluetoothIcon
|
||||
var widgetShowAudioIcon = typeof widget === "string" ? undefined : widget.showAudioIcon
|
||||
@@ -456,6 +514,8 @@ Item {
|
||||
item.selectedGpuIndex = widgetSelectedGpuIndex
|
||||
if (widgetPciId !== undefined)
|
||||
item.pciId = widgetPciId
|
||||
if (widgetMountPath !== undefined)
|
||||
item.mountPath = widgetMountPath
|
||||
if (widgetShowNetworkIcon !== undefined)
|
||||
item.showNetworkIcon = widgetShowNetworkIcon
|
||||
if (widgetShowBluetoothIcon !== undefined)
|
||||
@@ -1045,6 +1105,10 @@ Item {
|
||||
sectionId, widgetIndex,
|
||||
selectedIndex)
|
||||
}
|
||||
onDiskMountSelectionChanged: (sectionId, widgetIndex, mountPath) => {
|
||||
topBarTab.handleDiskMountSelectionChanged(
|
||||
sectionId, widgetIndex, mountPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1115,6 +1179,10 @@ Item {
|
||||
sectionId, widgetIndex,
|
||||
selectedIndex)
|
||||
}
|
||||
onDiskMountSelectionChanged: (sectionId, widgetIndex, mountPath) => {
|
||||
topBarTab.handleDiskMountSelectionChanged(
|
||||
sectionId, widgetIndex, mountPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1185,6 +1253,10 @@ Item {
|
||||
sectionId, widgetIndex,
|
||||
selectedIndex)
|
||||
}
|
||||
onDiskMountSelectionChanged: (sectionId, widgetIndex, mountPath) => {
|
||||
topBarTab.handleDiskMountSelectionChanged(
|
||||
sectionId, widgetIndex, mountPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ Column {
|
||||
signal spacerSizeChanged(string sectionId, int widgetIndex, int newSize)
|
||||
signal compactModeChanged(string widgetId, var value)
|
||||
signal gpuSelectionChanged(string sectionId, int widgetIndex, int selectedIndex)
|
||||
signal diskMountSelectionChanged(string sectionId, int widgetIndex, string mountPath)
|
||||
signal controlCenterSettingChanged(string sectionId, int widgetIndex, string settingName, bool value)
|
||||
|
||||
width: parent.width
|
||||
@@ -187,6 +188,38 @@ Column {
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 120
|
||||
height: 32
|
||||
visible: modelData.id === "diskUsage"
|
||||
DankDropdown {
|
||||
id: diskMountDropdown
|
||||
anchors.fill: parent
|
||||
currentValue: {
|
||||
const mountPath = modelData.mountPath || "/"
|
||||
if (mountPath === "/") {
|
||||
return "root (/)"
|
||||
}
|
||||
return mountPath
|
||||
}
|
||||
options: {
|
||||
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
|
||||
return ["root (/)"]
|
||||
}
|
||||
return DgopService.diskMounts.map(mount => {
|
||||
if (mount.mount === "/") {
|
||||
return "root (/)"
|
||||
}
|
||||
return mount.mount
|
||||
})
|
||||
}
|
||||
onValueChanged: value => {
|
||||
const newPath = value === "root (/)" ? "/" : value
|
||||
root.diskMountSelectionChanged(root.sectionId, index, newPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 32
|
||||
height: 32
|
||||
|
||||
171
Modules/TopBar/DiskUsage.qml
Normal file
171
Modules/TopBar/DiskUsage.qml
Normal file
@@ -0,0 +1,171 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property var widgetData: null
|
||||
property real widgetHeight: 30
|
||||
property string mountPath: (widgetData && widgetData.mountPath !== undefined) ? widgetData.mountPath : "/"
|
||||
readonly property real horizontalPadding: SettingsData.topBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
||||
|
||||
property var selectedMount: {
|
||||
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Force re-evaluation when mountPath changes
|
||||
const currentMountPath = root.mountPath || "/"
|
||||
|
||||
// First try to find exact match
|
||||
for (let i = 0; i < DgopService.diskMounts.length; i++) {
|
||||
if (DgopService.diskMounts[i].mount === currentMountPath) {
|
||||
return DgopService.diskMounts[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to root
|
||||
for (let i = 0; i < DgopService.diskMounts.length; i++) {
|
||||
if (DgopService.diskMounts[i].mount === "/") {
|
||||
return DgopService.diskMounts[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Last resort - first mount
|
||||
return DgopService.diskMounts[0] || null
|
||||
}
|
||||
|
||||
property real diskUsagePercent: {
|
||||
if (!selectedMount || !selectedMount.percent) {
|
||||
return 0
|
||||
}
|
||||
const percentStr = selectedMount.percent.replace("%", "")
|
||||
return parseFloat(percentStr) || 0
|
||||
}
|
||||
|
||||
width: diskContent.implicitWidth + horizontalPadding * 2
|
||||
height: widgetHeight
|
||||
radius: SettingsData.topBarNoBackground ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (SettingsData.topBarNoBackground) {
|
||||
return "transparent"
|
||||
}
|
||||
|
||||
const baseColor = Theme.widgetBaseBackgroundColor
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
|
||||
}
|
||||
Component.onCompleted: {
|
||||
DgopService.addRef(["diskmounts"])
|
||||
}
|
||||
Component.onDestruction: {
|
||||
DgopService.removeRef(["diskmounts"])
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onWidgetDataChanged() {
|
||||
// Force property re-evaluation by triggering change detection
|
||||
root.mountPath = Qt.binding(() => {
|
||||
return (root.widgetData && root.widgetData.mountPath !== undefined) ? root.widgetData.mountPath : "/"
|
||||
})
|
||||
|
||||
root.selectedMount = Qt.binding(() => {
|
||||
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const currentMountPath = root.mountPath || "/"
|
||||
|
||||
// First try to find exact match
|
||||
for (let i = 0; i < DgopService.diskMounts.length; i++) {
|
||||
if (DgopService.diskMounts[i].mount === currentMountPath) {
|
||||
return DgopService.diskMounts[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to root
|
||||
for (let i = 0; i < DgopService.diskMounts.length; i++) {
|
||||
if (DgopService.diskMounts[i].mount === "/") {
|
||||
return DgopService.diskMounts[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Last resort - first mount
|
||||
return DgopService.diskMounts[0] || null
|
||||
})
|
||||
}
|
||||
|
||||
target: SettingsData
|
||||
}
|
||||
|
||||
|
||||
Row {
|
||||
id: diskContent
|
||||
|
||||
anchors.centerIn: parent
|
||||
spacing: 3
|
||||
|
||||
DankIcon {
|
||||
name: "storage"
|
||||
size: Theme.iconSize - 8
|
||||
color: {
|
||||
if (root.diskUsagePercent > 90) {
|
||||
return Theme.tempDanger
|
||||
}
|
||||
if (root.diskUsagePercent > 75) {
|
||||
return Theme.tempWarning
|
||||
}
|
||||
return Theme.surfaceText
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!root.selectedMount) {
|
||||
return "--"
|
||||
}
|
||||
return root.selectedMount.mount
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideNone
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) {
|
||||
return "--%"
|
||||
}
|
||||
return root.diskUsagePercent.toFixed(0) + "%"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideNone
|
||||
|
||||
StyledTextMetrics {
|
||||
id: diskBaseline
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
text: "100%"
|
||||
}
|
||||
|
||||
width: Math.max(diskBaseline.width, paintedWidth)
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: 120
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,6 +483,7 @@ PanelWindow {
|
||||
"clipboard": clipboardComponent,
|
||||
"cpuUsage": cpuUsageComponent,
|
||||
"memUsage": memUsageComponent,
|
||||
"diskUsage": diskUsageComponent,
|
||||
"cpuTemp": cpuTempComponent,
|
||||
"gpuTemp": gpuTempComponent,
|
||||
"notificationButton": notificationButtonComponent,
|
||||
@@ -1003,6 +1004,15 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: diskUsageComponent
|
||||
|
||||
DiskUsage {
|
||||
widgetHeight: root.widgetHeight
|
||||
widgetData: parent.widgetData
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: cpuTempComponent
|
||||
|
||||
|
||||
@@ -335,7 +335,6 @@ Rectangle {
|
||||
onClicked: {
|
||||
root.currentValue = modelData
|
||||
root.valueChanged(modelData)
|
||||
dropdownMenu.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user