Merge branch 'noctalia-dev:main' into pr/networking-refactor-pt2

This commit is contained in:
Turann_
2026-03-13 00:38:43 +03:00
committed by GitHub
5 changed files with 117 additions and 12 deletions
+8 -1
View File
@@ -629,6 +629,9 @@ SmartPanel {
onMoved: function (value) {
if (appBox.nodeAudio && appBox.modelData && appBox.modelData.ready === true) {
appBox.nodeAudio.volume = value;
var key = AudioService.getAppKey(appBox.modelData);
if (key)
AudioService.setAppStreamVolume(key, value);
}
}
}
@@ -653,7 +656,11 @@ SmartPanel {
enabled: !!(appBox.nodeAudio && appBox.modelData && appBox.modelData.ready === true)
onClicked: {
if (appBox.nodeAudio && appBox.modelData && appBox.modelData.ready === true) {
appBox.nodeAudio.muted = !appBox.appMuted;
var newMuted = !appBox.appMuted;
appBox.nodeAudio.muted = newMuted;
var key = AudioService.getAppKey(appBox.modelData);
if (key)
AudioService.setAppStreamMuted(key, newMuted);
}
}
}
@@ -662,15 +662,14 @@ Item {
spacing: Style.marginXS
visible: Settings.data.network.bluetoothAutoConnect
NIcon {
icon: BluetoothService.getDeviceAutoConnect(modelData.address) ? "repeat" : "repeat-off"
icon: BluetoothService.getDeviceAutoConnect(modelData) ? "repeat" : "repeat-off"
pointSize: Style.fontSizeXS
color: BluetoothService.getDeviceAutoConnect(modelData.address) ? Color.mPrimary : Color.mOnSurface
}
NCheckbox {
label: I18n.tr("common.auto-connect")
labelSize: Style.fontSizeXS
baseSize: Style.baseWidgetSize * 0.5
checked: BluetoothService.getDeviceAutoConnect(modelData.address)
checked: BluetoothService.getDeviceAutoConnect(modelData)
onToggled: checked => BluetoothService.setDeviceAutoConnect(modelData, checked)
}
}
+98
View File
@@ -289,6 +289,104 @@ Singleton {
objects: [...root.sinks, ...root.sources]
}
// Per-app volume persistence (survives stream recreation on track change/seek)
property var appVolumeOverrides: ({})
property var _knownAppStreamIds: ({})
property bool _isApplyingAppOverride: false
PwObjectTracker {
objects: root.appStreams
}
function getAppKey(node): string {
if (!node || !node.properties)
return "";
var props = node.properties;
var binary = props["application.process.binary"] || "";
if (binary) {
var parts = binary.split("/");
return parts[parts.length - 1].toLowerCase();
}
var appName = props["application.name"] || "";
if (appName)
return appName.toLowerCase();
var appId = props["application.id"] || "";
if (appId)
return appId.toLowerCase();
return "";
}
function setAppStreamVolume(appKey: string, volume: real): void {
if (!appKey)
return;
var o = appVolumeOverrides;
if (!o[appKey])
o[appKey] = {};
o[appKey].volume = volume;
appVolumeOverrides = o;
}
function setAppStreamMuted(appKey: string, muted: bool): void {
if (!appKey)
return;
var o = appVolumeOverrides;
if (!o[appKey])
o[appKey] = {};
o[appKey].muted = muted;
appVolumeOverrides = o;
}
function getAppVolumeOverride(appKey: string) {
return appKey ? (appVolumeOverrides[appKey] || null) : null;
}
function _applyAppOverrides(): void {
var streams = root.appStreams;
if (!streams)
return;
var currentIds = {};
_isApplyingAppOverride = true;
for (var i = 0; i < streams.length; i++) {
var s = streams[i];
if (!s)
continue;
currentIds[s.id] = true;
var key = getAppKey(s);
var ov = key ? appVolumeOverrides[key] : null;
if (!ov || !s.audio)
continue;
if (ov.volume !== undefined && Math.abs(s.audio.volume - ov.volume) > root.epsilon) {
s.audio.volume = ov.volume;
}
if (ov.muted !== undefined && s.audio.muted !== ov.muted) {
s.audio.muted = ov.muted;
}
}
_knownAppStreamIds = currentIds;
_isApplyingAppOverride = false;
}
Connections {
target: root
function onAppStreamsChanged() {
_appOverrideTimer.restart();
}
}
Timer {
id: _appOverrideTimer
interval: 50
onTriggered: root._applyAppOverrides()
}
Timer {
id: _appOverrideEnforcer
interval: 1000
running: Object.keys(root.appVolumeOverrides).length > 0 && root.appStreams.length > 0
repeat: true
onTriggered: root._applyAppOverrides()
}
Component.onCompleted: {
wpctlAvailabilityProcess.running = true;
}
+4 -3
View File
@@ -83,10 +83,11 @@ Singleton {
}
}
function getDeviceAutoConnect(mac) {
if (!mac || !cacheAdapter.autoConnectSettings) {
function getDeviceAutoConnect(device) {
if (!device || !device.address || !cacheAdapter.autoConnectSettings) {
return false;
}
const mac = device.address;
const settings = cacheAdapter.autoConnectSettings[mac];
return settings ? !!settings.autoConnect : false;
}
@@ -679,7 +680,7 @@ Singleton {
return;
}
_autoConnectQueue = adapter.devices.values.filter(dev => dev && dev.paired && !dev.connected && !dev.blocked && getDeviceAutoConnect(dev.address) === true);
_autoConnectQueue = adapter.devices.values.filter(dev => dev && dev.paired && !dev.connected && !dev.blocked && getDeviceAutoConnect(dev) === true);
if (root._autoConnectQueue.length > 0) {
autoConnectStepTimer.restart();
+5 -5
View File
@@ -41,8 +41,8 @@ RowLayout {
id: box
Layout.margins: Style.borderS
implicitWidth: Math.round(root.baseSize)
implicitHeight: Math.round(root.baseSize)
implicitWidth: Style.toOdd(root.baseSize)
implicitHeight: Style.toOdd(root.baseSize)
radius: Style.iRadiusXS * (root.baseSize / root.defaultSize)
color: root.checked ? root.activeColor : Color.mSurface
border.color: Color.mOutline
@@ -62,11 +62,11 @@ RowLayout {
NIcon {
visible: root.checked
anchors.centerIn: parent
anchors.horizontalCenterOffset: -1
x: Style.pixelAlignCenter(parent.width, width)
y: Style.pixelAlignCenter(parent.height, height)
icon: "check"
color: root.activeOnColor
pointSize: Math.max(Style.fontSizeXS, root.baseSize * 0.5)
pointSize: Style.toOdd(root.baseSize * 0.5)
}
MouseArea {