From 7fac006ad3069bc5516e7a12b4ffaa82abfa1832 Mon Sep 17 00:00:00 2001 From: ajp_anton Date: Tue, 18 Aug 2026 01:55:32 +0000 Subject: [PATCH] Allow alert rules to cover multiple apps --- .../notificationsmaster/AlertRuleDialog.kt | 25 ++++++++++++++----- .../notificationsmaster/RulesFragment.kt | 4 +-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/se/ajpanton/notificationsmaster/AlertRuleDialog.kt b/app/src/main/java/se/ajpanton/notificationsmaster/AlertRuleDialog.kt index 198497a..f4c0e11 100644 --- a/app/src/main/java/se/ajpanton/notificationsmaster/AlertRuleDialog.kt +++ b/app/src/main/java/se/ajpanton/notificationsmaster/AlertRuleDialog.kt @@ -3,6 +3,7 @@ package se.ajpanton.notificationsmaster import android.content.Context import android.view.View import android.widget.ArrayAdapter +import android.widget.Button import android.widget.CheckBox import android.widget.EditText import android.widget.LinearLayout @@ -24,14 +25,25 @@ object AlertRuleDialog { configuration: AlertConfiguration, existing: AlertRule?, apps: List? = null, - onSave: (String?, AlertRuleDefinition) -> Unit, + onSave: (List?, AlertRuleDefinition) -> Unit, onDelete: (() -> Unit)? = null, ) { val form = LinearLayout(context).apply { orientation = LinearLayout.VERTICAL; setPadding(dp(context, 24), 0, dp(context, 24), 0) } - val app = apps?.let { - Spinner(context).apply { - adapter = ArrayAdapter(context, android.R.layout.simple_spinner_dropdown_item, it) - existing?.let { rule -> setSelection(apps.indexOfFirst { choice -> choice.packageName == rule.packageName }.coerceAtLeast(0)) } + val selectedApps = linkedSetOf() + val app = apps?.let { choices -> + Button(context).apply { + text = "Choose apps" + setOnClickListener { + MaterialAlertDialogBuilder(context).setTitle("Apps this rule applies to") + .setMultiChoiceItems(choices.map { choice -> choice.toString() }.toTypedArray(), choices.map { choice -> choice.packageName in selectedApps }.toBooleanArray()) { _, which, checked -> + if (checked) selectedApps += choices[which].packageName else selectedApps -= choices[which].packageName + text = when (selectedApps.size) { + 0 -> "Choose apps" + 1 -> choices.first { choice -> choice.packageName in selectedApps }.name + else -> choices.first { choice -> choice.packageName in selectedApps }.name + "…" + } + }.setPositiveButton("Done", null).show() + } }.also(form::addView) } val profile = Spinner(context).apply { @@ -54,6 +66,7 @@ object AlertRuleDialog { if (update.isChecked) add(AlertSource.NOTIFICATION_UPDATE) } if (sources.isEmpty()) { post.error = "Choose an event"; return@setOnClickListener } + if (apps != null && selectedApps.isEmpty()) { app?.error = "Choose at least one app"; return@setOnClickListener } val value = pattern.text.toString().trim() val matcher = runCatching { AlertTextMatcher( @@ -73,7 +86,7 @@ object AlertRuleDialog { protected.isChecked, dnd.isChecked, ) - onSave(app?.selectedItem?.let { it as InstalledApp }?.packageName, definition) + onSave(apps?.let { selectedApps.toList() }, definition) dialog.dismiss() } if (onDelete != null) dialog.getButton(android.content.DialogInterface.BUTTON_NEUTRAL).setOnClickListener { diff --git a/app/src/main/java/se/ajpanton/notificationsmaster/RulesFragment.kt b/app/src/main/java/se/ajpanton/notificationsmaster/RulesFragment.kt index e450cec..3b0f10a 100644 --- a/app/src/main/java/se/ajpanton/notificationsmaster/RulesFragment.kt +++ b/app/src/main/java/se/ajpanton/notificationsmaster/RulesFragment.kt @@ -44,9 +44,9 @@ class RulesFragment : Fragment(R.layout.fragment_rules) { val existing = ruleIds?.let { ids -> configuration.rules.first { it.id in ids } } AlertRuleDialog.show( requireContext(), configuration, existing, if (existing == null) InstalledApps.all(requireContext()) else null, - onSave = { packageName, definition -> + onSave = { packageNames, definition -> val updated = if (ruleIds == null) { - AlertRuleEditor.addForApps(configuration, listOfNotNull(packageName), definition) + AlertRuleEditor.addForApps(configuration, packageNames.orEmpty(), definition) } else { AlertRuleEditor.updateConsolidated(configuration, ruleIds, definition) }