1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 13:32:50 -05:00

Merge branch 'master' of github.com:AvengeMedia/DankMaterialShell

This commit is contained in:
purian23
2025-09-25 19:32:42 -04:00
15 changed files with 784 additions and 127 deletions

View File

@@ -0,0 +1,719 @@
import QtQuick
import qs.Common
import qs.Services
import qs.Modules.ControlCenter.Widgets
import qs.Modules.ControlCenter.Components
import "../utils/layout.js" as LayoutUtils
Column {
id: root
property bool editMode: false
property string expandedSection: ""
property int expandedWidgetIndex: -1
property var model: null
property var expandedWidgetData: null
signal expandClicked(var widgetData, int globalIndex)
signal removeWidget(int index)
signal moveWidget(int fromIndex, int toIndex)
signal toggleWidgetSize(int index)
spacing: editMode ? Theme.spacingL : Theme.spacingS
property var currentRowWidgets: []
property real currentRowWidth: 0
property int expandedRowIndex: -1
function calculateRowsAndWidgets() {
return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex)
}
property var layoutResult: {
const dummy = [expandedSection, expandedWidgetIndex, model?.controlCenterWidgets]
return calculateRowsAndWidgets()
}
onLayoutResultChanged: {
expandedRowIndex = layoutResult.expandedRowIndex
}
Repeater {
model: root.layoutResult.rows
Column {
width: root.width
spacing: 0
property int rowIndex: index
property var rowWidgets: modelData
property bool isSliderOnlyRow: {
const widgets = rowWidgets || []
if (widgets.length === 0) return false
return widgets.every(w => w.id === "volumeSlider" || w.id === "brightnessSlider" || w.id === "inputVolumeSlider")
}
topPadding: isSliderOnlyRow ? (root.editMode ? 4 : -12) : 0
bottomPadding: isSliderOnlyRow ? (root.editMode ? 4 : -12) : 0
Flow {
width: parent.width
spacing: Theme.spacingS
Repeater {
model: rowWidgets || []
Item {
property var widgetData: modelData
property int globalWidgetIndex: {
const widgets = SettingsData.controlCenterWidgets || []
for (var i = 0; i < widgets.length; i++) {
if (widgets[i].id === modelData.id) {
if (modelData.id === "diskUsage") {
if (widgets[i].instanceId === modelData.instanceId) {
return i
}
} else {
return i
}
}
}
return -1
}
property int widgetWidth: modelData.width || 50
width: {
const baseWidth = root.width
const spacing = Theme.spacingS
if (widgetWidth <= 25) {
return (baseWidth - spacing * 3) / 4
} else if (widgetWidth <= 50) {
return (baseWidth - spacing) / 2
} else if (widgetWidth <= 75) {
return (baseWidth - spacing * 2) * 0.75
} else {
return baseWidth
}
}
height: 60
Loader {
id: widgetLoader
anchors.fill: parent
property var widgetData: parent.widgetData
property int widgetIndex: parent.globalWidgetIndex
property int globalWidgetIndex: parent.globalWidgetIndex
property int widgetWidth: parent.widgetWidth
sourceComponent: {
const id = modelData.id || ""
if (id === "wifi" || id === "bluetooth" || id === "audioOutput" || id === "audioInput") {
return compoundPillComponent
} else if (id === "volumeSlider") {
return audioSliderComponent
} else if (id === "brightnessSlider") {
return brightnessSliderComponent
} else if (id === "inputVolumeSlider") {
return inputAudioSliderComponent
} else if (id === "battery") {
return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent
} else if (id === "diskUsage") {
return diskUsagePillComponent
} else {
return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent
}
}
}
}
}
}
DetailHost {
width: parent.width
height: active ? (250 + Theme.spacingS) : 0
property bool active: {
if (root.expandedSection === "") return false
if (root.expandedSection.startsWith("diskUsage_") && root.expandedWidgetData) {
const expandedInstanceId = root.expandedWidgetData.instanceId
return rowWidgets.some(w => w.id === "diskUsage" && w.instanceId === expandedInstanceId)
}
return rowIndex === root.expandedRowIndex
}
visible: active
expandedSection: root.expandedSection
expandedWidgetData: root.expandedWidgetData
}
}
}
Component {
id: compoundPillComponent
CompoundPill {
property var widgetData: parent.widgetData || {}
property int widgetIndex: parent.widgetIndex || 0
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
width: parent.width
height: 60
iconName: {
switch (widgetData.id || "") {
case "wifi": {
if (NetworkService.wifiToggling) {
return "sync"
}
if (NetworkService.networkStatus === "ethernet") {
return "settings_ethernet"
}
if (NetworkService.networkStatus === "wifi") {
return NetworkService.wifiSignalIcon
}
if (NetworkService.wifiEnabled) {
return "wifi_off"
}
return "wifi_off"
}
case "bluetooth": {
if (!BluetoothService.available) {
return "bluetooth_disabled"
}
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) {
return "bluetooth_disabled"
}
return "bluetooth"
}
case "audioOutput": {
if (!AudioService.sink) return "volume_off"
let volume = AudioService.sink.audio.volume
let muted = AudioService.sink.audio.muted
if (muted || volume === 0.0) return "volume_off"
if (volume <= 0.33) return "volume_down"
if (volume <= 0.66) return "volume_up"
return "volume_up"
}
case "audioInput": {
if (!AudioService.source) return "mic_off"
let muted = AudioService.source.audio.muted
return muted ? "mic_off" : "mic"
}
default: return widgetDef?.icon || "help"
}
}
primaryText: {
switch (widgetData.id || "") {
case "wifi": {
if (NetworkService.wifiToggling) {
return NetworkService.wifiEnabled ? "Disabling WiFi..." : "Enabling WiFi..."
}
if (NetworkService.networkStatus === "ethernet") {
return "Ethernet"
}
if (NetworkService.networkStatus === "wifi" && NetworkService.currentWifiSSID) {
return NetworkService.currentWifiSSID
}
if (NetworkService.wifiEnabled) {
return "Not connected"
}
return "WiFi off"
}
case "bluetooth": {
if (!BluetoothService.available) {
return "Bluetooth"
}
if (!BluetoothService.adapter) {
return "No adapter"
}
if (!BluetoothService.adapter.enabled) {
return "Disabled"
}
return "Enabled"
}
case "audioOutput": return AudioService.sink?.description || "No output device"
case "audioInput": return AudioService.source?.description || "No input device"
default: return widgetDef?.text || "Unknown"
}
}
secondaryText: {
switch (widgetData.id || "") {
case "wifi": {
if (NetworkService.wifiToggling) {
return "Please wait..."
}
if (NetworkService.networkStatus === "ethernet") {
return "Connected"
}
if (NetworkService.networkStatus === "wifi") {
return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : "Connected"
}
if (NetworkService.wifiEnabled) {
return "Select network"
}
return ""
}
case "bluetooth": {
if (!BluetoothService.available) {
return "No adapters"
}
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) {
return "Off"
}
const primaryDevice = (() => {
if (!BluetoothService.adapter || !BluetoothService.adapter.devices) {
return null
}
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
for (let device of devices) {
if (device && device.connected) {
return device
}
}
return null
})()
if (primaryDevice) {
return primaryDevice.name || primaryDevice.alias || primaryDevice.deviceName || "Connected Device"
}
return "No devices"
}
case "audioOutput": {
if (!AudioService.sink) {
return "Select device"
}
if (AudioService.sink.audio.muted) {
return "Muted"
}
return Math.round(AudioService.sink.audio.volume * 100) + "%"
}
case "audioInput": {
if (!AudioService.source) {
return "Select device"
}
if (AudioService.source.audio.muted) {
return "Muted"
}
return Math.round(AudioService.source.audio.volume * 100) + "%"
}
default: return widgetDef?.description || ""
}
}
isActive: {
switch (widgetData.id || "") {
case "wifi": {
if (NetworkService.wifiToggling) {
return false
}
if (NetworkService.networkStatus === "ethernet") {
return true
}
if (NetworkService.networkStatus === "wifi") {
return true
}
return NetworkService.wifiEnabled
}
case "bluetooth": return !!(BluetoothService.available && BluetoothService.adapter && BluetoothService.adapter.enabled)
case "audioOutput": return !!(AudioService.sink && !AudioService.sink.audio.muted)
case "audioInput": return !!(AudioService.source && !AudioService.source.audio.muted)
default: return false
}
}
enabled: (widgetDef?.enabled ?? true)
onToggled: {
if (root.editMode) return
switch (widgetData.id || "") {
case "wifi": {
if (NetworkService.networkStatus !== "ethernet" && !NetworkService.wifiToggling) {
NetworkService.toggleWifiRadio()
}
break
}
case "bluetooth": {
if (BluetoothService.available && BluetoothService.adapter) {
BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled
}
break
}
case "audioOutput": {
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = !AudioService.sink.audio.muted
}
break
}
case "audioInput": {
if (AudioService.source && AudioService.source.audio) {
AudioService.source.audio.muted = !AudioService.source.audio.muted
}
break
}
}
}
onExpandClicked: {
if (root.editMode) return
root.expandClicked(widgetData, widgetIndex)
}
onWheelEvent: function (wheelEvent) {
const id = widgetData.id || ""
if (id === "audioOutput") {
if (!AudioService.sink || !AudioService.sink.audio) return
let delta = wheelEvent.angleDelta.y
let currentVolume = AudioService.sink.audio.volume * 100
let newVolume
if (delta > 0)
newVolume = Math.min(100, currentVolume + 5)
else
newVolume = Math.max(0, currentVolume - 5)
AudioService.sink.audio.muted = false
AudioService.sink.audio.volume = newVolume / 100
wheelEvent.accepted = true
} else if (id === "audioInput") {
if (!AudioService.source || !AudioService.source.audio) return
let delta = wheelEvent.angleDelta.y
let currentVolume = AudioService.source.audio.volume * 100
let newVolume
if (delta > 0)
newVolume = Math.min(100, currentVolume + 5)
else
newVolume = Math.max(0, currentVolume - 5)
AudioService.source.audio.muted = false
AudioService.source.audio.volume = newVolume / 100
wheelEvent.accepted = true
}
}
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)
}
}
}
Component {
id: audioSliderComponent
Item {
property var widgetData: parent.widgetData || {}
property int widgetIndex: parent.widgetIndex || 0
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
width: parent.width
height: 16
AudioSliderRow {
anchors.centerIn: parent
width: parent.width
height: 14
property color sliderTrackColor: Theme.surfaceContainerHigh
}
EditModeOverlay {
anchors.fill: parent
editMode: root.editMode
widgetData: parent.widgetData
widgetIndex: parent.widgetIndex
showSizeControls: true
isSlider: true
onRemoveWidget: (index) => root.removeWidget(index)
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
}
}
}
Component {
id: brightnessSliderComponent
Item {
property var widgetData: parent.widgetData || {}
property int widgetIndex: parent.widgetIndex || 0
width: parent.width
height: 16
BrightnessSliderRow {
anchors.centerIn: parent
width: parent.width
height: 14
property color sliderTrackColor: Theme.surfaceContainerHigh
}
EditModeOverlay {
anchors.fill: parent
editMode: root.editMode
widgetData: parent.widgetData
widgetIndex: parent.widgetIndex
showSizeControls: true
isSlider: true
onRemoveWidget: (index) => root.removeWidget(index)
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
}
}
}
Component {
id: inputAudioSliderComponent
Item {
property var widgetData: parent.widgetData || {}
property int widgetIndex: parent.widgetIndex || 0
width: parent.width
height: 16
InputAudioSliderRow {
anchors.centerIn: parent
width: parent.width
height: 14
property color sliderTrackColor: Theme.surfaceContainerHigh
}
EditModeOverlay {
anchors.fill: parent
editMode: root.editMode
widgetData: parent.widgetData
widgetIndex: parent.widgetIndex
showSizeControls: true
isSlider: true
onRemoveWidget: (index) => root.removeWidget(index)
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
}
}
}
Component {
id: batteryPillComponent
BatteryPill {
property var widgetData: parent.widgetData || {}
property int widgetIndex: parent.widgetIndex || 0
width: parent.width
height: 60
onExpandClicked: {
if (!root.editMode) {
root.expandClicked(widgetData, widgetIndex)
}
}
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)
}
}
}
Component {
id: smallBatteryComponent
SmallBatteryButton {
property var widgetData: parent.widgetData || {}
property int widgetIndex: parent.widgetIndex || 0
width: parent.width
height: 48
onClicked: {
if (!root.editMode) {
root.expandClicked(widgetData, widgetIndex)
}
}
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)
}
}
}
Component {
id: toggleButtonComponent
ToggleButton {
property var widgetData: parent.widgetData || {}
property int widgetIndex: parent.widgetIndex || 0
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
width: parent.width
height: 60
iconName: {
switch (widgetData.id || "") {
case "nightMode": return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"
case "darkMode": return "contrast"
case "doNotDisturb": return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"
case "idleInhibitor": return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
default: return widgetDef?.icon || "help"
}
}
text: {
switch (widgetData.id || "") {
case "nightMode": return "Night Mode"
case "darkMode": return SessionData.isLightMode ? "Light Mode" : "Dark Mode"
case "doNotDisturb": return "Do Not Disturb"
case "idleInhibitor": return SessionService.idleInhibited ? "Keeping Awake" : "Keep Awake"
default: return widgetDef?.text || "Unknown"
}
}
secondaryText: ""
iconRotation: widgetData.id === "darkMode" && SessionData.isLightMode ? 180 : 0
isActive: {
switch (widgetData.id || "") {
case "nightMode": return DisplayService.nightModeEnabled || false
case "darkMode": return !SessionData.isLightMode
case "doNotDisturb": return SessionData.doNotDisturb || false
case "idleInhibitor": return SessionService.idleInhibited || false
default: return false
}
}
enabled: (widgetDef?.enabled ?? true) && !root.editMode
onClicked: {
switch (widgetData.id || "") {
case "nightMode": {
if (DisplayService.automationAvailable) {
DisplayService.toggleNightMode()
}
break
}
case "darkMode": {
Theme.toggleLightMode()
break
}
case "doNotDisturb": {
SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
break
}
case "idleInhibitor": {
SessionService.toggleIdleInhibit()
break
}
}
}
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)
}
}
}
Component {
id: smallToggleComponent
SmallToggleButton {
property var widgetData: parent.widgetData || {}
property int widgetIndex: parent.widgetIndex || 0
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
width: parent.width
height: 48
iconName: {
switch (widgetData.id || "") {
case "nightMode": return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"
case "darkMode": return "contrast"
case "doNotDisturb": return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"
case "idleInhibitor": return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
default: return widgetDef?.icon || "help"
}
}
iconRotation: widgetData.id === "darkMode" && SessionData.isLightMode ? 180 : 0
isActive: {
switch (widgetData.id || "") {
case "nightMode": return DisplayService.nightModeEnabled || false
case "darkMode": return !SessionData.isLightMode
case "doNotDisturb": return SessionData.doNotDisturb || false
case "idleInhibitor": return SessionService.idleInhibited || false
default: return false
}
}
enabled: (widgetDef?.enabled ?? true) && !root.editMode
onClicked: {
switch (widgetData.id || "") {
case "nightMode": {
if (DisplayService.automationAvailable) {
DisplayService.toggleNightMode()
}
break
}
case "darkMode": {
Theme.toggleLightMode()
break
}
case "doNotDisturb": {
SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
break
}
case "idleInhibitor": {
SessionService.toggleIdleInhibit()
break
}
}
}
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)
}
}
}
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)
}
}
}
}

View File

@@ -57,10 +57,6 @@ Rectangle {
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Behavior on color {
ColorAnimation { duration: Theme.shortDuration }
}
MouseArea {
id: iconArea
anchors.fill: parent
@@ -138,9 +134,9 @@ Rectangle {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: deviceMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHigh
color: deviceMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHighest
border.color: modelData === AudioService.source ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
border.width: modelData === AudioService.source ? 2 : 1
border.width: 0
Row {
anchors.left: parent.left
@@ -198,14 +194,6 @@ Rectangle {
}
}
}
Behavior on color {
ColorAnimation { duration: Theme.shortDuration }
}
Behavior on border.color {
ColorAnimation { duration: Theme.shortDuration }
}
}
}
}

View File

@@ -57,10 +57,6 @@ Rectangle {
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Behavior on color {
ColorAnimation { duration: Theme.shortDuration }
}
MouseArea {
id: iconArea
anchors.fill: parent
@@ -143,9 +139,9 @@ Rectangle {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: deviceMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHigh
color: deviceMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHighest
border.color: modelData === AudioService.sink ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
border.width: modelData === AudioService.sink ? 2 : 1
border.width: 0
Row {
anchors.left: parent.left
@@ -205,14 +201,6 @@ Rectangle {
}
}
}
Behavior on color {
ColorAnimation { duration: Theme.shortDuration }
}
Behavior on border.color {
ColorAnimation { duration: Theme.shortDuration }
}
}
}
}

View File

@@ -206,7 +206,7 @@ Item {
radius: Theme.cornerRadius
color: {
if (modelData.name === currentCodec)
return Theme.surfaceContainerHigh;
return Theme.surfaceContainerHighest;
else if (codecMouseArea.containsMouse)
return Theme.surfaceHover;
else
@@ -272,12 +272,6 @@ Item {
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
}
}
}

View File

@@ -96,13 +96,6 @@ Rectangle {
BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
@@ -159,7 +152,7 @@ Rectangle {
return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12)
if (deviceMouseArea.containsMouse)
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
return Theme.surfaceContainerHigh
return Theme.surfaceContainerHighest
}
border.color: {
if (modelData.state === BluetoothDeviceState.Connecting)
@@ -168,7 +161,7 @@ Rectangle {
return Theme.primary
return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
}
border.width: (modelData.connected || modelData.state === BluetoothDeviceState.Connecting) ? 2 : 1
border.width: 0
Row {
anchors.left: parent.left
@@ -284,14 +277,6 @@ Rectangle {
}
}
}
Behavior on color {
ColorAnimation { duration: Theme.shortDuration }
}
Behavior on border.color {
ColorAnimation { duration: Theme.shortDuration }
}
}
}
@@ -347,7 +332,7 @@ Rectangle {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: availableMouseArea.containsMouse && !isBusy ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHigh
color: availableMouseArea.containsMouse && !isBusy ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHighest
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
border.width: 0
opacity: canConnect ? 1 : 0.6
@@ -427,9 +412,6 @@ Rectangle {
}
}
Behavior on color {
ColorAnimation { duration: Theme.shortDuration }
}
}
}

View File

@@ -6,6 +6,8 @@ import qs.Services
import qs.Widgets
Rectangle {
id: root
property string currentMountPath: "/"
property string instanceId: ""
@@ -76,9 +78,9 @@ Rectangle {
width: parent.width
height: 80
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
color: Theme.surfaceContainerHighest
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
border.width: modelData.mount === currentMountPath ? 2 : 0
Row {
anchors.left: parent.left
@@ -152,16 +154,11 @@ Rectangle {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (modelData.mount !== currentMountPath) {
currentMountPath = modelData.mount
mountPathChanged(modelData.mount)
}
currentMountPath = modelData.mount
mountPathChanged(modelData.mount)
}
}
Behavior on border.color {
ColorAnimation { duration: Theme.shortDuration }
}
}
}
}

View File

@@ -27,20 +27,11 @@ Rectangle {
NetworkService.scanWifi()
}
}
Component.onDestruction: {
NetworkService.removeRef()
}
property var wifiPasswordModalRef: {
wifiPasswordModalLoader.active = true
return wifiPasswordModalLoader.item
}
property var networkInfoModalRef: {
networkInfoModalLoader.active = true
return networkInfoModalLoader.item
}
Row {
id: headerRow
anchors.left: parent.left
@@ -177,12 +168,6 @@ Rectangle {
onClicked: NetworkService.toggleWifiRadio()
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
@@ -242,9 +227,9 @@ Rectangle {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: networkMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHigh
color: networkMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHighest
border.color: modelData.ssid === NetworkService.currentWifiSSID ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
border.width: modelData.ssid === NetworkService.currentWifiSSID ? 2 : 1
border.width: 0
Row {
anchors.left: parent.left
@@ -332,9 +317,7 @@ Rectangle {
onClicked: function(event) {
if (modelData.ssid !== NetworkService.currentWifiSSID) {
if (modelData.secured && !modelData.saved) {
if (wifiPasswordModalRef) {
wifiPasswordModalRef.show(modelData.ssid)
}
wifiPasswordModal.show(modelData.ssid)
} else {
NetworkService.connectToWifi(modelData.ssid)
}
@@ -343,13 +326,6 @@ Rectangle {
}
}
Behavior on color {
ColorAnimation { duration: Theme.shortDuration }
}
Behavior on border.color {
ColorAnimation { duration: Theme.shortDuration }
}
}
}
}
@@ -395,9 +371,7 @@ Rectangle {
NetworkService.disconnectWifi()
} else {
if (networkContextMenu.currentSecured && !networkContextMenu.currentSaved) {
if (wifiPasswordModalRef) {
wifiPasswordModalRef.show(networkContextMenu.currentSSID)
}
wifiPasswordModal.show(networkContextMenu.currentSSID)
} else {
NetworkService.connectToWifi(networkContextMenu.currentSSID)
}
@@ -423,10 +397,8 @@ Rectangle {
}
onTriggered: {
if (networkInfoModalRef) {
let networkData = NetworkService.getNetworkInfo(networkContextMenu.currentSSID)
networkInfoModalRef.showNetworkInfo(networkContextMenu.currentSSID, networkData)
}
let networkData = NetworkService.getNetworkInfo(networkContextMenu.currentSSID)
networkInfoModal.showNetworkInfo(networkContextMenu.currentSSID, networkData)
}
}
@@ -454,22 +426,12 @@ Rectangle {
}
}
LazyLoader {
id: wifiPasswordModalLoader
active: false
WifiPasswordModal {
id: wifiPasswordModal
}
WifiPasswordModal {
id: wifiPasswordModal
}
LazyLoader {
id: networkInfoModalLoader
active: false
NetworkInfoModal {
id: networkInfoModal
}
NetworkInfoModal {
id: networkInfoModal
}

View File

@@ -30,9 +30,6 @@ CompoundPill {
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) {
return "bluetooth_disabled"
}
if (primaryDevice) {
return BluetoothService.getDeviceIcon(primaryDevice)
}
return "bluetooth"
}

View File

@@ -29,7 +29,10 @@ Rectangle {
readonly property color _containerBg: Theme.surfaceContainerHigh
color: _containerBg
color: {
const baseColor = bodyMouse.containsMouse ? Theme.widgetBaseHoverColor : _containerBg
return baseColor
}
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.10)
border.width: 0
antialiasing: true

View File

@@ -31,7 +31,11 @@ Rectangle {
readonly property color _tileIconActive: Theme.primaryContainer
readonly property color _tileIconInactive: Theme.primary
color: isActive ? _tileBgActive : _tileBgInactive
color: {
if (isActive) return _tileBgActive
const baseColor = mouseArea.containsMouse ? Theme.widgetBaseHoverColor : _tileBgInactive
return baseColor
}
border.color: isActive ? _tileRingActive : "transparent"
border.width: isActive ? 1 : 0
antialiasing: true

View File

@@ -32,7 +32,11 @@ Rectangle {
readonly property color _tileIconActive: Theme.primaryContainer
readonly property color _tileIconInactive: Theme.primary
color: isActive ? _tileBgActive : _tileBgInactive
color: {
if (isActive) return _tileBgActive
const baseColor = mouseArea.containsMouse ? Theme.widgetBaseHoverColor : _tileBgInactive
return baseColor
}
border.color: isActive ? _tileRingActive : "transparent"
border.width: isActive ? 1 : 0
antialiasing: true

View File

@@ -27,7 +27,11 @@ Rectangle {
readonly property color _tileRingActive:
Qt.rgba(Theme.primaryText.r, Theme.primaryText.g, Theme.primaryText.b, 0.22)
color: isActive ? _tileBgActive : _tileBgInactive
color: {
if (isActive) return _tileBgActive
const baseColor = mouseArea.containsMouse ? Theme.widgetBaseHoverColor : _tileBgInactive
return baseColor
}
border.color: isActive ? _tileRingActive : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 0
opacity: enabled ? 1.0 : 0.6

View File

@@ -0,0 +1,3 @@
[templates.dank]
input_path = './matugen/templates/dank.json'
output_path = '~/.cache/quickshell/dankshell/dms-colors.json'

View File

@@ -0,0 +1,10 @@
{
"colors": {
"dark": {<* for name, value in colors *>
"{{name}}": "{{value.dark.hex}}"<* if not loop.last *>,<* endif *><* endfor *>
},
"light": {<* for name, value in colors *>
"{{name}}": "{{value.light.hex}}"<* if not loop.last *>,<* endif *><* endfor *>
}
}
}

View File

@@ -74,16 +74,21 @@ build_once() {
cat "$SHELL_DIR/matugen/configs/base.toml" > "$TMP_CFG"
echo "" >> "$TMP_CFG"
# Always include dank config for dms-colors.json
cat "$SHELL_DIR/matugen/configs/dank.toml" >> "$TMP_CFG"
echo "" >> "$TMP_CFG"
if command -v niri >/dev/null 2>&1; then
cat "$SHELL_DIR/matugen/configs/niri.toml" >> "$TMP_CFG"
echo "" >> "$TMP_CFG"
fi
if command -v qt5ct >/dev/null 2>&1; then
cat "$SHELL_DIR/matugen/configs/qt5ct.toml" >> "$TMP_CFG"
echo "" >> "$TMP_CFG"
fi
if command -v qt6ct >/dev/null 2>&1; then
cat "$SHELL_DIR/matugen/configs/qt6ct.toml" >> "$TMP_CFG"
echo "" >> "$TMP_CFG"
@@ -201,9 +206,6 @@ build_once() {
echo "$JSON" | grep -q '"primary"' || { echo "matugen JSON missing primary" >&2; return 2; }
printf "%s" "$JSON" > "$LAST_JSON"
# Write JSON for Theme.qml FileView to watch
printf "%s" "$JSON" > "$STATE_DIR/dms-colors.json"
if [ "$mode" = "light" ]; then
SECTION=$(echo "$JSON" | sed -n 's/.*"light":{\([^}]*\)}.*/\1/p')