Allow alert rules to be removed

This commit is contained in:
ajp_anton
2026-08-18 01:54:22 +00:00
parent 7f61f11cbf
commit ba09bed24f
5 changed files with 31 additions and 5 deletions
@@ -25,6 +25,7 @@ object AlertRuleDialog {
existing: AlertRule?, existing: AlertRule?,
apps: List<InstalledApp>? = null, apps: List<InstalledApp>? = null,
onSave: (String?, AlertRuleDefinition) -> Unit, onSave: (String?, AlertRuleDefinition) -> Unit,
onDelete: (() -> Unit)? = null,
) { ) {
val form = LinearLayout(context).apply { orientation = LinearLayout.VERTICAL; setPadding(dp(context, 24), 0, dp(context, 24), 0) } val form = LinearLayout(context).apply { orientation = LinearLayout.VERTICAL; setPadding(dp(context, 24), 0, dp(context, 24), 0) }
val app = apps?.let { val app = apps?.let {
@@ -45,7 +46,8 @@ object AlertRuleDialog {
val dnd = SwitchMaterial(context).apply { text = "Allow during DND when supported"; isChecked = existing?.allowDuringDnd == true } val dnd = SwitchMaterial(context).apply { text = "Allow during DND when supported"; isChecked = existing?.allowDuringDnd == true }
listOf(profile, post, update, pattern, regex, protected, dnd).forEach(form::addView) listOf(profile, post, update, pattern, regex, protected, dnd).forEach(form::addView)
val dialog = MaterialAlertDialogBuilder(context).setTitle(if (existing == null) "Add rule" else "Edit rule") val dialog = MaterialAlertDialogBuilder(context).setTitle(if (existing == null) "Add rule" else "Edit rule")
.setView(form).setNegativeButton("Cancel", null).setPositiveButton("Save", null).show() .setView(form).setNegativeButton("Cancel", null).setPositiveButton("Save", null)
.apply { if (onDelete != null) setNeutralButton("Delete", null) }.show()
dialog.getButton(android.content.DialogInterface.BUTTON_POSITIVE).setOnClickListener { dialog.getButton(android.content.DialogInterface.BUTTON_POSITIVE).setOnClickListener {
val sources = buildSet { val sources = buildSet {
if (post.isChecked) add(AlertSource.NOTIFICATION_POST) if (post.isChecked) add(AlertSource.NOTIFICATION_POST)
@@ -74,6 +76,13 @@ object AlertRuleDialog {
onSave(app?.selectedItem?.let { it as InstalledApp }?.packageName, definition) onSave(app?.selectedItem?.let { it as InstalledApp }?.packageName, definition)
dialog.dismiss() dialog.dismiss()
} }
if (onDelete != null) dialog.getButton(android.content.DialogInterface.BUTTON_NEUTRAL).setOnClickListener {
MaterialAlertDialogBuilder(context).setTitle("Delete rule?")
.setMessage("This cannot be undone.")
.setNegativeButton("Cancel", null)
.setPositiveButton("Delete") { _, _ -> onDelete(); dialog.dismiss() }
.show()
}
} }
private fun dp(context: Context, value: Int) = (value * context.resources.displayMetrics.density).toInt() private fun dp(context: Context, value: Int) = (value * context.resources.displayMetrics.density).toInt()
@@ -57,10 +57,13 @@ class AppRulesFragment : Fragment(R.layout.fragment_app_rules) {
android.widget.Toast.makeText(requireContext(), "Create a profile first", android.widget.Toast.LENGTH_LONG).show() android.widget.Toast.makeText(requireContext(), "Create a profile first", android.widget.Toast.LENGTH_LONG).show()
return return
} }
AlertRuleDialog.show(requireContext(), configuration, existing) { _, definition -> AlertRuleDialog.show(requireContext(), configuration, existing,
onSave = { _, definition ->
store.save(if (existing == null) AlertRuleEditor.addForApps(configuration, listOf(packageName), definition) else AlertRuleEditor.updateForApp(configuration, existing.id, definition)) store.save(if (existing == null) AlertRuleEditor.addForApps(configuration, listOf(packageName), definition) else AlertRuleEditor.updateForApp(configuration, existing.id, definition))
refresh() refresh()
} },
onDelete = existing?.let { rule -> { store.save(AlertRuleEditor.remove(store.load(), setOf(rule.id))); refresh() } },
)
} }
private fun saveOrder() { private fun saveOrder() {
@@ -42,7 +42,9 @@ class RulesFragment : Fragment(R.layout.fragment_rules) {
return return
} }
val existing = ruleIds?.let { ids -> configuration.rules.first { it.id in ids } } 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) { packageName, definition -> AlertRuleDialog.show(
requireContext(), configuration, existing, if (existing == null) InstalledApps.all(requireContext()) else null,
onSave = { packageName, definition ->
val updated = if (ruleIds == null) { val updated = if (ruleIds == null) {
AlertRuleEditor.addForApps(configuration, listOfNotNull(packageName), definition) AlertRuleEditor.addForApps(configuration, listOfNotNull(packageName), definition)
} else { } else {
@@ -50,7 +52,9 @@ class RulesFragment : Fragment(R.layout.fragment_rules) {
} }
store.save(updated) store.save(updated)
refresh() refresh()
} },
onDelete = ruleIds?.let { ids -> { store.save(AlertRuleEditor.remove(store.load(), ids)); refresh() } },
)
} }
private fun AlertSource.shortName() = if (this == AlertSource.NOTIFICATION_POST) "Appearing" else "Edits" private fun AlertSource.shortName() = if (this == AlertSource.NOTIFICATION_POST) "Appearing" else "Edits"
@@ -88,6 +88,9 @@ object AlertRuleEditor {
}) })
} }
fun remove(configuration: AlertConfiguration, ruleIds: Set<String>): AlertConfiguration =
configuration.copy(rules = configuration.rules.filterNot { it.id in ruleIds })
private fun AlertRule.definition() = AlertRuleDefinition( private fun AlertRule.definition() = AlertRuleDefinition(
sources, matcher, outcome, profileId, playToCompletion, allowDuringDnd, enabled, name, sources, matcher, outcome, profileId, playToCompletion, allowDuringDnd, enabled, name,
) )
@@ -66,6 +66,13 @@ class AlertRuleEditorTest {
assertEquals(0, edited.rules.first { it.id == "other" }.order) assertEquals(0, edited.rules.first { it.id == "other" }.order)
} }
@Test
fun removesExactlyTheRequestedRules() {
val edited = AlertRuleEditor.remove(configuration(rule("one", "chat.app", 0), rule("two", "mail.app", 0)), setOf("one"))
assertEquals(listOf("two"), edited.rules.map { it.id })
}
private fun rule(id: String, packageName: String, order: Int) = AlertRule( private fun rule(id: String, packageName: String, order: Int) = AlertRule(
id, packageName, order, definition.sources, definition.matcher, definition.outcome, definition.profileId, id, packageName, order, definition.sources, definition.matcher, definition.outcome, definition.profileId,
) )