1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

feat: Allow more pinned services in Control Center/Settings

This commit is contained in:
purian23
2026-01-15 21:51:17 -05:00
committed by bbedward
parent 27965862d6
commit b0611d6104
5 changed files with 215 additions and 74 deletions

View File

@@ -122,6 +122,21 @@ Rectangle {
contentHeight: audioColumn.height
clip: true
property int maxPinnedInputs: 3
function normalizePinList(value) {
if (Array.isArray(value))
return value.filter(v => v)
if (typeof value === "string" && value.length > 0)
return [value]
return []
}
function getPinnedInputs() {
const pins = SettingsData.audioInputDevicePins || {}
return normalizePinList(pins["preferredInput"])
}
Column {
id: audioColumn
width: parent.width
@@ -133,16 +148,20 @@ Rectangle {
const nodes = Pipewire.nodes.values.filter(node => {
return node.audio && !node.isSink && !node.isStream;
});
const pins = SettingsData.audioInputDevicePins || {};
const pinnedName = pins["preferredInput"];
const pinnedList = audioContent.getPinnedInputs();
let sorted = [...nodes];
sorted.sort((a, b) => {
// Pinned device first
if (a.name === pinnedName && b.name !== pinnedName)
return -1;
if (b.name === pinnedName && a.name !== pinnedName)
return 1;
const aPinnedIndex = pinnedList.indexOf(a.name)
const bPinnedIndex = pinnedList.indexOf(b.name)
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
if (aPinnedIndex === -1)
return 1
if (bPinnedIndex === -1)
return -1
return aPinnedIndex - bPinnedIndex
}
// Then active device
if (a === AudioService.source && b !== AudioService.source)
return -1;
@@ -224,7 +243,7 @@ Rectangle {
height: 28
radius: height / 2
color: {
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
}
@@ -237,7 +256,7 @@ Rectangle {
name: "push_pin"
size: 16
color: {
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -245,12 +264,12 @@ Rectangle {
StyledText {
text: {
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin");
}
font.pixelSize: Theme.fontSizeSmall
color: {
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -261,16 +280,24 @@ Rectangle {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {}));
const isCurrentlyPinned = pins["preferredInput"] === modelData.name;
const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {}))
let pinnedList = audioContent.normalizePinList(pins["preferredInput"])
const pinIndex = pinnedList.indexOf(modelData.name)
if (isCurrentlyPinned) {
delete pins["preferredInput"];
if (pinIndex !== -1) {
pinnedList.splice(pinIndex, 1)
} else {
pins["preferredInput"] = modelData.name;
pinnedList.unshift(modelData.name)
if (pinnedList.length > audioContent.maxPinnedInputs)
pinnedList = pinnedList.slice(0, audioContent.maxPinnedInputs)
}
SettingsData.set("audioInputDevicePins", pins);
if (pinnedList.length > 0)
pins["preferredInput"] = pinnedList
else
delete pins["preferredInput"]
SettingsData.set("audioInputDevicePins", pins)
}
}
}

View File

@@ -132,6 +132,21 @@ Rectangle {
contentHeight: audioColumn.height
clip: true
property int maxPinnedOutputs: 3
function normalizePinList(value) {
if (Array.isArray(value))
return value.filter(v => v)
if (typeof value === "string" && value.length > 0)
return [value]
return []
}
function getPinnedOutputs() {
const pins = SettingsData.audioOutputDevicePins || {}
return normalizePinList(pins["preferredOutput"])
}
Column {
id: audioColumn
width: parent.width
@@ -143,16 +158,20 @@ Rectangle {
const nodes = Pipewire.nodes.values.filter(node => {
return node.audio && node.isSink && !node.isStream;
});
const pins = SettingsData.audioOutputDevicePins || {};
const pinnedName = pins["preferredOutput"];
const pinnedList = audioContent.getPinnedOutputs();
let sorted = [...nodes];
sorted.sort((a, b) => {
// Pinned device first
if (a.name === pinnedName && b.name !== pinnedName)
return -1;
if (b.name === pinnedName && a.name !== pinnedName)
return 1;
const aPinnedIndex = pinnedList.indexOf(a.name)
const bPinnedIndex = pinnedList.indexOf(b.name)
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
if (aPinnedIndex === -1)
return 1
if (bPinnedIndex === -1)
return -1
return aPinnedIndex - bPinnedIndex
}
// Then active device
if (a === AudioService.sink && b !== AudioService.sink)
return -1;
@@ -236,7 +255,7 @@ Rectangle {
height: 28
radius: height / 2
color: {
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
}
@@ -249,7 +268,7 @@ Rectangle {
name: "push_pin"
size: 16
color: {
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -257,12 +276,12 @@ Rectangle {
StyledText {
text: {
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin");
}
font.pixelSize: Theme.fontSizeSmall
color: {
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -273,16 +292,24 @@ Rectangle {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
const pins = JSON.parse(JSON.stringify(SettingsData.audioOutputDevicePins || {}));
const isCurrentlyPinned = pins["preferredOutput"] === modelData.name;
const pins = JSON.parse(JSON.stringify(SettingsData.audioOutputDevicePins || {}))
let pinnedList = audioContent.normalizePinList(pins["preferredOutput"])
const pinIndex = pinnedList.indexOf(modelData.name)
if (isCurrentlyPinned) {
delete pins["preferredOutput"];
if (pinIndex !== -1) {
pinnedList.splice(pinIndex, 1)
} else {
pins["preferredOutput"] = modelData.name;
pinnedList.unshift(modelData.name)
if (pinnedList.length > audioContent.maxPinnedOutputs)
pinnedList = pinnedList.slice(0, audioContent.maxPinnedOutputs)
}
SettingsData.set("audioOutputDevicePins", pins);
if (pinnedList.length > 0)
pins["preferredOutput"] = pinnedList
else
delete pins["preferredOutput"]
SettingsData.set("audioOutputDevicePins", pins)
}
}
}

View File

@@ -150,6 +150,21 @@ Rectangle {
contentHeight: bluetoothColumn.height
clip: true
property int maxPinnedDevices: 3
function normalizePinList(value) {
if (Array.isArray(value))
return value.filter(v => v)
if (typeof value === "string" && value.length > 0)
return [value]
return []
}
function getPinnedDevices() {
const pins = SettingsData.bluetoothDevicePins || {}
return normalizePinList(pins["preferredDevice"])
}
Column {
id: bluetoothColumn
width: parent.width
@@ -162,14 +177,18 @@ Rectangle {
if (!BluetoothService.adapter || !BluetoothService.adapter.devices)
return []
const pins = SettingsData.bluetoothDevicePins || {}
const pinnedAddr = pins["preferredDevice"]
const pinnedList = bluetoothContent.getPinnedDevices()
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
devices.sort((a, b) => {
// Pinned device first
if (a.address === pinnedAddr && b.address !== pinnedAddr) return -1
if (b.address === pinnedAddr && a.address !== pinnedAddr) return 1
const aPinnedIndex = pinnedList.indexOf(a.address)
const bPinnedIndex = pinnedList.indexOf(b.address)
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
if (aPinnedIndex === -1) return 1
if (bPinnedIndex === -1) return -1
return aPinnedIndex - bPinnedIndex
}
// Then connected devices
if (a.connected && !b.connected) return -1
if (!a.connected && b.connected) return 1
@@ -302,7 +321,7 @@ Rectangle {
height: 28
radius: height / 2
color: {
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05)
}
@@ -315,7 +334,7 @@ Rectangle {
name: "push_pin"
size: 16
color: {
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
@@ -323,12 +342,12 @@ Rectangle {
StyledText {
text: {
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin")
}
font.pixelSize: Theme.fontSizeSmall
color: {
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
@@ -340,14 +359,22 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onClicked: {
const pins = JSON.parse(JSON.stringify(SettingsData.bluetoothDevicePins || {}))
const isCurrentlyPinned = pins["preferredDevice"] === modelData.address
let pinnedList = bluetoothContent.normalizePinList(pins["preferredDevice"])
const pinIndex = pinnedList.indexOf(modelData.address)
if (isCurrentlyPinned) {
delete pins["preferredDevice"]
if (pinIndex !== -1) {
pinnedList.splice(pinIndex, 1)
} else {
pins["preferredDevice"] = modelData.address
pinnedList.unshift(modelData.address)
if (pinnedList.length > bluetoothContent.maxPinnedDevices)
pinnedList = pinnedList.slice(0, bluetoothContent.maxPinnedDevices)
}
if (pinnedList.length > 0)
pins["preferredDevice"] = pinnedList
else
delete pins["preferredDevice"]
SettingsData.set("bluetoothDevicePins", pins)
}
}

View File

@@ -463,20 +463,39 @@ Rectangle {
contentHeight: wifiColumn.height
clip: true
property int maxPinnedNetworks: 3
function normalizePinList(value) {
if (Array.isArray(value))
return value.filter(v => v)
if (typeof value === "string" && value.length > 0)
return [value]
return []
}
function getPinnedNetworks() {
const pins = SettingsData.wifiNetworkPins || {}
return normalizePinList(pins["preferredWifi"])
}
property var frozenNetworks: []
property bool menuOpen: false
property var sortedNetworks: {
const ssid = NetworkService.currentWifiSSID;
const networks = NetworkService.wifiNetworks;
const pins = SettingsData.wifiNetworkPins || {};
const pinnedSSID = pins["preferredWifi"];
const pinnedList = getPinnedNetworks()
let sorted = [...networks];
sorted.sort((a, b) => {
if (a.ssid === pinnedSSID && b.ssid !== pinnedSSID)
return -1;
if (b.ssid === pinnedSSID && a.ssid !== pinnedSSID)
return 1;
const aPinnedIndex = pinnedList.indexOf(a.ssid)
const bPinnedIndex = pinnedList.indexOf(b.ssid)
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
if (aPinnedIndex === -1)
return 1
if (bPinnedIndex === -1)
return -1
return aPinnedIndex - bPinnedIndex
}
if (a.ssid === ssid)
return -1;
if (b.ssid === ssid)
@@ -625,7 +644,7 @@ Rectangle {
height: 28
radius: height / 2
color: {
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
return isThisNetworkPinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
}
@@ -638,7 +657,7 @@ Rectangle {
name: "push_pin"
size: 16
color: {
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
return isThisNetworkPinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -646,12 +665,12 @@ Rectangle {
StyledText {
text: {
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
return isThisNetworkPinned ? I18n.tr("Pinned") : I18n.tr("Pin");
}
font.pixelSize: Theme.fontSizeSmall
color: {
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
return isThisNetworkPinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -662,16 +681,24 @@ Rectangle {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}));
const isCurrentlyPinned = pins["preferredWifi"] === modelData.ssid;
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}))
let pinnedList = wifiContent.normalizePinList(pins["preferredWifi"])
const pinIndex = pinnedList.indexOf(modelData.ssid)
if (isCurrentlyPinned) {
delete pins["preferredWifi"];
if (pinIndex !== -1) {
pinnedList.splice(pinIndex, 1)
} else {
pins["preferredWifi"] = modelData.ssid;
pinnedList.unshift(modelData.ssid)
if (pinnedList.length > wifiContent.maxPinnedNetworks)
pinnedList = pinnedList.slice(0, wifiContent.maxPinnedNetworks)
}
SettingsData.set("wifiNetworkPins", pins);
if (pinnedList.length > 0)
pins["preferredWifi"] = pinnedList
else
delete pins["preferredWifi"]
SettingsData.set("wifiNetworkPins", pins)
}
}
}

View File

@@ -15,6 +15,7 @@ Item {
property string expandedVpnUuid: ""
property string expandedWifiSsid: ""
property string expandedEthDevice: ""
property int maxPinnedWifiNetworks: 3
Component.onCompleted: {
NetworkService.addRef();
@@ -30,6 +31,40 @@ Item {
vpnFileBrowserLoader.item.open();
}
function normalizePinList(value) {
if (Array.isArray(value))
return value.filter(v => v)
if (typeof value === "string" && value.length > 0)
return [value]
return []
}
function getPinnedWifiNetworks() {
const pins = SettingsData.wifiNetworkPins || {}
return normalizePinList(pins["preferredWifi"])
}
function toggleWifiPin(ssid) {
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}))
let pinnedList = normalizePinList(pins["preferredWifi"])
const pinIndex = pinnedList.indexOf(ssid)
if (pinIndex !== -1) {
pinnedList.splice(pinIndex, 1)
} else {
pinnedList.unshift(ssid)
if (pinnedList.length > maxPinnedWifiNetworks)
pinnedList = pinnedList.slice(0, maxPinnedWifiNetworks)
}
if (pinnedList.length > 0)
pins["preferredWifi"] = pinnedList
else
delete pins["preferredWifi"]
SettingsData.set("wifiNetworkPins", pins)
}
LazyLoader {
id: vpnFileBrowserLoader
active: false
@@ -1025,15 +1060,19 @@ Item {
model: {
const ssid = NetworkService.currentWifiSSID;
const networks = NetworkService.wifiNetworks || [];
const pins = SettingsData.wifiNetworkPins || {};
const pinnedSSID = pins["preferredWifi"];
const pinnedList = networkTab.getPinnedWifiNetworks();
let sorted = [...networks];
sorted.sort((a, b) => {
if (a.ssid === pinnedSSID && b.ssid !== pinnedSSID)
return -1;
if (b.ssid === pinnedSSID && a.ssid !== pinnedSSID)
return 1;
const aPinnedIndex = pinnedList.indexOf(a.ssid)
const bPinnedIndex = pinnedList.indexOf(b.ssid)
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
if (aPinnedIndex === -1)
return 1
if (bPinnedIndex === -1)
return -1
return aPinnedIndex - bPinnedIndex
}
if (a.ssid === ssid)
return -1;
if (b.ssid === ssid)
@@ -1049,7 +1088,7 @@ Item {
required property int index
readonly property bool isConnected: modelData.ssid === NetworkService.currentWifiSSID
readonly property bool isPinned: (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid
readonly property bool isPinned: networkTab.getPinnedWifiNetworks().includes(modelData.ssid)
readonly property bool isExpanded: networkTab.expandedWifiSsid === modelData.ssid
width: parent.width
@@ -1224,13 +1263,7 @@ Item {
buttonSize: 28
iconColor: isPinned ? Theme.primary : Theme.surfaceVariantText
onClicked: {
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}));
if (isPinned) {
delete pins["preferredWifi"];
} else {
pins["preferredWifi"] = modelData.ssid;
}
SettingsData.set("wifiNetworkPins", pins);
networkTab.toggleWifiPin(modelData.ssid)
}
}