mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
Merge branch 'noctalia-dev:main' into pr/networking-refactor-pt2
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user