diff --git a/privacy-indicator/Main.qml b/privacy-indicator/Main.qml index e88d62f7..0c645643 100644 --- a/privacy-indicator/Main.qml +++ b/privacy-indicator/Main.qml @@ -31,6 +31,7 @@ Item { property bool enableToast: cfg.enableToast ?? defaults.enableToast ?? true property string activeColorKey: cfg.activeColor ?? defaults.activeColor ?? "primary" property string micFilterRegex: cfg.micFilterRegex ?? defaults.micFilterRegex ?? "" + property string camFilterRegex: cfg.camFilterRegex ?? defaults.camFilterRegex ?? "" PwObjectTracker { objects: Pipewire.ready ? Pipewire.nodes.values : [] @@ -44,8 +45,25 @@ Item { onStreamFinished: { var appsString = this.text.trim(); var apps = appsString.length > 0 ? appsString.split(',') : []; - root.camApps = apps; - root.camActive = apps.length > 0; + + var filterRegex = null; + if (root.camFilterRegex && root.camFilterRegex.length > 0) { + try { + filterRegex = new RegExp(root.camFilterRegex); + } catch (e) { + Logger.w("PrivacyIndicator: Invalid camFilterRegex:", root.camFilterRegex); + } + } + + var appNames = []; + for (var i = 0; i < apps.length; i++) { + appName = apps[i]; + if (filterRegex && appName && filterRegex.test(appName)) continue; + if (appName && appNames.indexOf(appName) === -1) appNames.push(appName); + } + + root.camApps = appNames; + root.camActive = appNames.length > 0; } } } @@ -265,7 +283,7 @@ Item { property bool oldMicActive: false onMicActiveChanged: { if (enableToast && micActive && !oldMicActive) { - ToastService.showNotice(pluginApi?.tr("toast.mic-on") || "Microphone is active", "", "microphone"); + ToastService.showNotice(pluginApi?.tr("toast.mic-on"), "", "microphone"); } oldMicActive = micActive } @@ -273,7 +291,7 @@ Item { property bool oldCamActive: false onCamActiveChanged: { if (enableToast && camActive && !oldCamActive) { - ToastService.showNotice(pluginApi?.tr("toast.cam-on") || "Camera is active", "", "camera"); + ToastService.showNotice(pluginApi?.tr("toast.cam-on"), "", "camera"); } oldCamActive = camActive } @@ -285,7 +303,7 @@ Item { property bool oldScrActive: false onScrActiveChanged: { if (enableToast && scrActive && !oldScrActive) { - ToastService.showNotice(pluginApi?.tr("toast.screen-on") || "Screen sharing is active", "", "screen-share"); + ToastService.showNotice(pluginApi?.tr("toast.screen-on"), "", "screen-share"); } oldScrActive = scrActive } diff --git a/privacy-indicator/Panel.qml b/privacy-indicator/Panel.qml index 4b16bc75..241a9168 100644 --- a/privacy-indicator/Panel.qml +++ b/privacy-indicator/Panel.qml @@ -16,6 +16,7 @@ Item { property real contentPreferredHeight: 450 * Style.uiScaleRatio readonly property var mainInstance: pluginApi?.mainInstance + readonly property var allowAttach: true Rectangle { id: panelContainer @@ -46,7 +47,7 @@ Item { NText { Layout.fillWidth: true - text: pluginApi?.tr("history.title") || "Access History" + text: pluginApi?.tr("history.title") font.weight: Style.fontWeightBold pointSize: Style.fontSizeL color: Color.mOnSurface @@ -154,7 +155,7 @@ Item { NText { Layout.alignment: Qt.AlignHCenter visible: (!mainInstance || mainInstance.accessHistory.length === 0) - text: pluginApi?.tr("history.empty") || "No recent access" + text: pluginApi?.tr("history.empty") color: Qt.alpha(Color.mOnSurface, 0.5) pointSize: Style.fontSizeM Layout.topMargin: Style.marginL diff --git a/privacy-indicator/Settings.qml b/privacy-indicator/Settings.qml index c978015d..84d77e7d 100644 --- a/privacy-indicator/Settings.qml +++ b/privacy-indicator/Settings.qml @@ -18,6 +18,7 @@ ColumnLayout { property string activeColor: cfg.activeColor ?? defaults.activeColor ?? "primary" property string inactiveColor: cfg.inactiveColor ?? defaults.inactiveColor ?? "none" property string micFilterRegex: cfg.micFilterRegex ?? defaults.micFilterRegex + property string camFilterRegex: cfg.camFilterRegex ?? defaults.camFilterRegex spacing: Style.marginL @@ -102,12 +103,21 @@ ColumnLayout { NTextInput { Layout.fillWidth: true - label: pluginApi?.tr("settings.micFilterRegex.label") || "Microphone filter regex" - description: pluginApi?.tr("settings.micFilterRegex.desc") || "Regex pattern to filter out microphone applications" + label: pluginApi?.tr("settings.micFilterRegex.label") + description: pluginApi?.tr("settings.micFilterRegex.desc") placeholderText: "effect_input.rnnoise|easyeffects" text: root.micFilterRegex onTextChanged: root.micFilterRegex = text } + + NTextInput { + Layout.fillWidth: true + label: pluginApi?.tr("settings.camFilterRegex.label") + description: pluginApi?.tr("settings.camFilterRegex.desc") + placeholderText: "droidcam" + text: root.camFilterRegex + onTextChanged: root.camFilterRegex = text + } } function saveSettings() { diff --git a/privacy-indicator/i18n/en.json b/privacy-indicator/i18n/en.json index 4c327884..fa654188 100644 --- a/privacy-indicator/i18n/en.json +++ b/privacy-indicator/i18n/en.json @@ -30,6 +30,10 @@ "micFilterRegex": { "desc": "Regex pattern to filter out microphone applications. Matching apps are completely excluded from detection.", "label": "Microphone filter regex" + }, + "camFilterRegex": { + "desc": "Regex pattern to filter out camera applications. Matching apps are completely excluded from detection.", + "label": "Camera filter regex" } }, "tooltip": { @@ -51,4 +55,4 @@ "stopped": "Stopped" } } -} \ No newline at end of file +} diff --git a/privacy-indicator/manifest.json b/privacy-indicator/manifest.json index 2a21ea88..079a2e99 100644 --- a/privacy-indicator/manifest.json +++ b/privacy-indicator/manifest.json @@ -30,7 +30,8 @@ "iconSpacing": 4, "activeColor": "primary", "inactiveColor": "none", - "micFilterRegex": "" + "micFilterRegex": "", + "camFilterRegex": "" } } }