diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 689f0d7..abbd8a2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -18,8 +18,8 @@ android { applicationId = "co.adityarajput.notifilter" minSdk = 29 targetSdk = 36 - versionCode = 15 - versionName = "4.0.0" + versionCode = 16 + versionName = "4.1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/co/adityarajput/notifilter/data/models/App.kt b/app/src/main/java/co/adityarajput/notifilter/data/models/App.kt index f086668..5ba99e6 100644 --- a/app/src/main/java/co/adityarajput/notifilter/data/models/App.kt +++ b/app/src/main/java/co/adityarajput/notifilter/data/models/App.kt @@ -4,3 +4,6 @@ import kotlinx.serialization.Serializable @Serializable data class App(val name: String, val packageName: String) + +val None = App("", "") +val Any = App("Any app", ".*") diff --git a/app/src/main/java/co/adityarajput/notifilter/services/NotificationListener.kt b/app/src/main/java/co/adityarajput/notifilter/services/NotificationListener.kt index 1a89e21..c81a9b4 100644 --- a/app/src/main/java/co/adityarajput/notifilter/services/NotificationListener.kt +++ b/app/src/main/java/co/adityarajput/notifilter/services/NotificationListener.kt @@ -16,6 +16,7 @@ import co.adityarajput.notifilter.Constants import co.adityarajput.notifilter.R import co.adityarajput.notifilter.data.AppContainer import co.adityarajput.notifilter.data.models.Action +import co.adityarajput.notifilter.data.models.Any import co.adityarajput.notifilter.data.models.Filter import co.adityarajput.notifilter.data.models.Notification import co.adityarajput.notifilter.utils.Logger @@ -115,7 +116,7 @@ class NotificationListener : NotificationListenerService() { Logger.d("NotificationListener.onNotificationPosted", "Received $notification") val filter = filters.filter { - notification.origin == it.app.packageName + (notification.origin == it.app.packageName || it.app == Any) && it.enabled && it.schedule.includesNow() && it.matchesTextOf(notification) @@ -230,7 +231,11 @@ class NotificationListener : NotificationListenerService() { } serviceScope.launch { - repository.registerHit(filter, notification.copy(origin = filter.app.name)) + repository.registerHit( + filter, + if (filter.app == Any) notification + else notification.copy(origin = filter.app.name), + ) notifications = repository.notifications().first() Logger.d( "NotificationListener.onNotificationPosted", diff --git a/app/src/main/java/co/adityarajput/notifilter/viewmodels/UpsertFilterViewModel.kt b/app/src/main/java/co/adityarajput/notifilter/viewmodels/UpsertFilterViewModel.kt index 37c1191..624ea48 100644 --- a/app/src/main/java/co/adityarajput/notifilter/viewmodels/UpsertFilterViewModel.kt +++ b/app/src/main/java/co/adityarajput/notifilter/viewmodels/UpsertFilterViewModel.kt @@ -31,7 +31,7 @@ class UpsertFilterViewModel( data class Values( val filterId: Int = 0, val notification: Notification? = null, - val app: App = App("", ""), + val app: App = None, val regexTarget: RegexTarget = RegexTarget.OR, val queryPattern: String = "", val secondaryQueryPattern: String = "", @@ -87,7 +87,7 @@ class UpsertFilterViewModel( init { viewModelScope.launch { - while (state.page.isFirstPage()) { + while (true) { activeNotifications = NotificationListener.instance ?.activeNotifications ?.filter { it.notification.flags and FLAG_GROUP_SUMMARY == 0 } @@ -109,7 +109,7 @@ class UpsertFilterViewModel( when (page) { FormPage.ZAPPER -> return null - FormPage.PACKAGE -> if (values.app.packageName.isBlank()) return FormError.BLANK_FIELDS + FormPage.PACKAGE -> if (values.app == None) return FormError.BLANK_FIELDS FormPage.PATTERN -> { if (values.queryPattern.isBlank()) return FormError.BLANK_FIELDS diff --git a/app/src/main/java/co/adityarajput/notifilter/views/screens/FiltersScreen.kt b/app/src/main/java/co/adityarajput/notifilter/views/screens/FiltersScreen.kt index eebd380..d113fc2 100644 --- a/app/src/main/java/co/adityarajput/notifilter/views/screens/FiltersScreen.kt +++ b/app/src/main/java/co/adityarajput/notifilter/views/screens/FiltersScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.lifecycle.viewmodel.compose.viewModel import co.adityarajput.notifilter.R +import co.adityarajput.notifilter.data.models.Any import co.adityarajput.notifilter.data.models.RegexTarget import co.adityarajput.notifilter.utils.getFirst import co.adityarajput.notifilter.utils.getToggleString @@ -98,7 +99,8 @@ fun FiltersScreen( } }, it.action.verb(), - it.app.name.getFirst(30), + if (it.app == Any) stringResource(R.string.any_app) + else it.app.name.getFirst(30), if (!it.enabled) stringResource(R.string.filter_disabled) else if (!it.historyEnabled) stringResource(R.string.history_disabled) else pluralStringResource(R.plurals.hit, it.hits, it.hits), diff --git a/app/src/main/java/co/adityarajput/notifilter/views/screens/UpsertFilterScreen.kt b/app/src/main/java/co/adityarajput/notifilter/views/screens/UpsertFilterScreen.kt index 44c3149..f8e73c9 100644 --- a/app/src/main/java/co/adityarajput/notifilter/views/screens/UpsertFilterScreen.kt +++ b/app/src/main/java/co/adityarajput/notifilter/views/screens/UpsertFilterScreen.kt @@ -35,9 +35,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.lifecycle.viewmodel.compose.viewModel import co.adityarajput.notifilter.R -import co.adityarajput.notifilter.data.models.Action -import co.adityarajput.notifilter.data.models.App -import co.adityarajput.notifilter.data.models.RegexTarget +import co.adityarajput.notifilter.data.models.* import co.adityarajput.notifilter.utils.filterFirst import co.adityarajput.notifilter.utils.getFirst import co.adityarajput.notifilter.utils.hasAccessibilityServicePermission @@ -219,8 +217,14 @@ private fun ZapperPage(viewModel: UpsertFilterViewModel) { @OptIn(ExperimentalMaterial3Api::class) @Composable private fun PackagePage(viewModel: UpsertFilterViewModel) { - var searchString by remember { mutableStateOf("") } + var searchString by remember { + mutableStateOf( + if (viewModel.state.values.app == Any) "" + else viewModel.state.values.app.name, + ) + } var visibleItemsCount by remember { mutableIntStateOf(10) } + var showAdvancedOptions by remember { mutableStateOf(viewModel.state.values.app == Any) } var showSystemPackages by remember { mutableStateOf(false) } val (apps, searchFinished) = (if (showSystemPackages) viewModel.allPackages else viewModel.visibleApps) @@ -244,26 +248,72 @@ private fun PackagePage(viewModel: UpsertFilterViewModel) { ), singleLine = true, ) - Row( - Modifier - .padding(vertical = dimensionResource(R.dimen.padding_medium)) - .toggleable(showSystemPackages) { showSystemPackages = it }, - Arrangement.spacedBy(dimensionResource(R.dimen.padding_small)), - Alignment.CenterVertically, + Column( + Modifier.padding(dimensionResource(R.dimen.padding_medium)), + Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium)), ) { - Checkbox(showSystemPackages, null) - Column { + Row( + Modifier.toggleable(showAdvancedOptions) { showAdvancedOptions = it }, + Arrangement.spacedBy(dimensionResource(R.dimen.padding_small)), + Alignment.CenterVertically, + ) { + Checkbox(showAdvancedOptions, null) Text( - stringResource(R.string.show_system_packages), + stringResource(R.string.advanced_options), style = MaterialTheme.typography.labelLarge, fontWeight = FontWeight.Normal, ) - Text( - stringResource(R.string.system_packages_warning), - Modifier.padding(top = dimensionResource(R.dimen.padding_small)), - style = MaterialTheme.typography.labelMedium, - fontWeight = FontWeight.Normal, - ) + } + if (showAdvancedOptions) { + Row( + Modifier + .padding(horizontal = dimensionResource(R.dimen.padding_small)) + .toggleable(viewModel.state.values.app == Any) { + viewModel.updateForm( + FormPage.PACKAGE, + viewModel.state.values.copy(app = if (it) Any else None), + ) + }, + Arrangement.spacedBy(dimensionResource(R.dimen.padding_small)), + Alignment.CenterVertically, + ) { + Checkbox(viewModel.state.values.app == Any, null) + Column { + Text( + stringResource(R.string.target_all_apps), + style = MaterialTheme.typography.labelLarge, + fontWeight = FontWeight.Normal, + ) + Text( + stringResource(R.string.all_apps_warning), + Modifier.padding(top = dimensionResource(R.dimen.padding_small)), + style = MaterialTheme.typography.labelMedium, + fontWeight = FontWeight.Normal, + ) + } + } + Row( + Modifier + .padding(horizontal = dimensionResource(R.dimen.padding_small)) + .toggleable(showSystemPackages) { showSystemPackages = it }, + Arrangement.spacedBy(dimensionResource(R.dimen.padding_small)), + Alignment.CenterVertically, + ) { + Checkbox(showSystemPackages, null) + Column { + Text( + stringResource(R.string.show_system_packages), + style = MaterialTheme.typography.labelLarge, + fontWeight = FontWeight.Normal, + ) + Text( + stringResource(R.string.system_packages_warning), + Modifier.padding(top = dimensionResource(R.dimen.padding_small)), + style = MaterialTheme.typography.labelMedium, + fontWeight = FontWeight.Normal, + ) + } + } } } FlowRow( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 906ce07..b30a5ee 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,7 @@ NotiFilter NotiFilter - 4.0.0 + 4.1.0 No filters added.\nTap + to get started. "on weekdays " @@ -13,6 +13,7 @@ tap \"%1$s\" batch every %1$s delay notifications + Any app history disabled filter disabled @@ -38,6 +39,9 @@ Waiting for active notifications… Choose a notification to target Choose an app to target + Advanced options + Target all apps? + Targeting all apps is rarely necessary. This may cause unexpected issues. Show system packages? Notifications from system packages may contain critical information. Package name diff --git a/metadata/en-US/changelogs/16.txt b/metadata/en-US/changelogs/16.txt new file mode 100644 index 0000000..5f0a5b6 --- /dev/null +++ b/metadata/en-US/changelogs/16.txt @@ -0,0 +1,3 @@ +• fix: Handle TAP_NOTIFICATION on Android 14 & 15 +• feat: Let filters target all apps +• fix: Improve UI of "create/edit filter" screen