diff --git a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt index 63519c749..507ae9618 100644 --- a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt +++ b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt @@ -628,6 +628,7 @@ class SettingsRepository( const val KEY_ISLAND_NOTIF_KEEP_PROGRESS = "island_notif_keep_progress" const val KEY_ISLAND_NOTIF_QUEUE = "island_notif_queue" const val KEY_ISLAND_NOTIF_SKIP_SILENT = "island_notif_skip_silent" + const val KEY_ISLAND_NOTIF_FOLLOW_DND = "island_notif_follow_dnd" const val KEY_ISLAND_NOTIF_FILTER_APPS = "island_notif_filter_apps" const val KEY_ISLAND_NOTIF_FILTER_APPS_LIST = "island_notif_filter_apps_list" const val KEY_ISLAND_SHOW_NOTIFICATIONS = "island_show_notifications" @@ -4165,6 +4166,9 @@ class SettingsRepository( fun isIslandNotifSkipSilentEnabled(): Boolean = getBoolean(KEY_ISLAND_NOTIF_SKIP_SILENT, true) fun setIslandNotifSkipSilentEnabled(enabled: Boolean) = putBoolean(KEY_ISLAND_NOTIF_SKIP_SILENT, enabled) + fun isIslandNotifFollowDndEnabled(): Boolean = getBoolean(KEY_ISLAND_NOTIF_FOLLOW_DND, true) + fun setIslandNotifFollowDndEnabled(enabled: Boolean) = putBoolean(KEY_ISLAND_NOTIF_FOLLOW_DND, enabled) + fun isIslandNotifFilterAppsEnabled(): Boolean = getBoolean(KEY_ISLAND_NOTIF_FILTER_APPS, false) fun setIslandNotifFilterAppsEnabled(enabled: Boolean) = putBoolean(KEY_ISLAND_NOTIF_FILTER_APPS, enabled) diff --git a/app/src/main/java/com/sameerasw/essentials/domain/model/ActiveNotificationAlert.kt b/app/src/main/java/com/sameerasw/essentials/domain/model/ActiveNotificationAlert.kt index 655ed8184..78250276c 100644 --- a/app/src/main/java/com/sameerasw/essentials/domain/model/ActiveNotificationAlert.kt +++ b/app/src/main/java/com/sameerasw/essentials/domain/model/ActiveNotificationAlert.kt @@ -27,5 +27,6 @@ data class ActiveNotificationAlert( val actions: List = emptyList(), val chatIcon: Bitmap? = null, val isSilent: Boolean = false, + val blockedByDnd: Boolean = false, ) diff --git a/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt b/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt index 32dfcaf44..61443cc45 100644 --- a/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt +++ b/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt @@ -978,6 +978,11 @@ object FeatureRegistry { R.string.island_notif_skip_silent_desc, "island_notif_skip_silent", ), + SearchSetting( + R.string.island_notif_follow_dnd_title, + R.string.island_notif_follow_dnd_desc, + "island_notif_follow_dnd", + ), SearchSetting( R.string.island_notif_keep_progress_title, R.string.island_notif_keep_progress_desc, diff --git a/app/src/main/java/com/sameerasw/essentials/island/plugins/notifications/NotificationsPlugin.kt b/app/src/main/java/com/sameerasw/essentials/island/plugins/notifications/NotificationsPlugin.kt index 153468a0a..3b055b03c 100644 --- a/app/src/main/java/com/sameerasw/essentials/island/plugins/notifications/NotificationsPlugin.kt +++ b/app/src/main/java/com/sameerasw/essentials/island/plugins/notifications/NotificationsPlugin.kt @@ -42,6 +42,7 @@ class NotificationsPlugin : BaseIslandPlugin() { SettingsRepository.KEY_ISLAND_SHOW_GLOW, SettingsRepository.KEY_ISLAND_NOTIF_QUEUE, SettingsRepository.KEY_ISLAND_NOTIF_SKIP_SILENT, + SettingsRepository.KEY_ISLAND_NOTIF_FOLLOW_DND, SettingsRepository.KEY_ISLAND_NOTIF_FILTER_APPS, SettingsRepository.KEY_ISLAND_NOTIF_FILTER_APPS_LIST, SettingsRepository.KEY_ISLAND_NOTIF_TAP_TO_OPEN, @@ -162,6 +163,7 @@ class NotificationsPlugin : BaseIslandPlugin() { private fun passesFilters(alert: ActiveNotificationAlert): Boolean { if (alert.isSilent && settings.isIslandNotifSkipSilentEnabled()) return false + if (alert.blockedByDnd && settings.isIslandNotifFollowDndEnabled()) return false if (!settings.isIslandNotifFilterAppsEnabled()) return true return settings.loadIslandNotifFilterApps().any { it.isEnabled && it.packageName == alert.packageName } } diff --git a/app/src/main/java/com/sameerasw/essentials/services/NotificationListener.kt b/app/src/main/java/com/sameerasw/essentials/services/NotificationListener.kt index 053d330fd..02528f2b1 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/NotificationListener.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/NotificationListener.kt @@ -266,6 +266,20 @@ class NotificationListener : NotificationListenerService() { return false } + // Do Not Disturb holds this notification back or suppresses its peek; apps and conversations allowed through still pass. + fun isBlockedByDnd( + sbn: StatusBarNotification, + rankingMap: RankingMap? = null, + ): Boolean { + val map = rankingMap ?: currentRanking ?: return false + val ranking = Ranking() + if (!map.getRanking(sbn.key, ranking)) return false + val peekSuppressed = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && + ranking.suppressedVisualEffects and NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK != 0 + return !ranking.matchesInterruptionFilter() || peekSuppressed + } + private fun populateActiveUnreadNotifications() { unreadNotifications.clear() try { @@ -1013,7 +1027,10 @@ class NotificationListener : NotificationListenerService() { } if (!isRepost && isHeadsUpNotification(sbn, rankingMap, allowSilent = true)) { - val alert = extractNotificationAlert(sbn)?.copy(isSilent = isSilentNotification(sbn, rankingMap)) + val alert = extractNotificationAlert(sbn)?.copy( + isSilent = isSilentNotification(sbn, rankingMap), + blockedByDnd = isBlockedByDnd(sbn, rankingMap), + ) if (alert != null) { notifyAlertPosted(alert) } diff --git a/app/src/main/java/com/sameerasw/essentials/ui/features/display/IslandSubSettingsUI.kt b/app/src/main/java/com/sameerasw/essentials/ui/features/display/IslandSubSettingsUI.kt index c9088c5fe..575fe3f79 100644 --- a/app/src/main/java/com/sameerasw/essentials/ui/features/display/IslandSubSettingsUI.kt +++ b/app/src/main/java/com/sameerasw/essentials/ui/features/display/IslandSubSettingsUI.kt @@ -935,6 +935,18 @@ fun IslandNotificationSettingsUI( modifier = Modifier.highlight(highlightSetting == "island_notif_skip_silent"), ) + IconToggleItem( + iconRes = R.drawable.rounded_do_not_disturb_on_24, + title = stringResource(R.string.island_notif_follow_dnd_title), + description = stringResource(R.string.island_notif_follow_dnd_desc), + isChecked = viewModel.isIslandNotifFollowDnd.value, + onCheckedChange = { checked -> + HapticUtil.performVirtualKeyHaptic(view) + viewModel.setIslandNotifFollowDnd(checked) + }, + modifier = Modifier.highlight(highlightSetting == "island_notif_follow_dnd"), + ) + IconToggleItem( iconRes = R.drawable.rounded_downloading_24, title = stringResource(R.string.island_notif_keep_progress_title), diff --git a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt index a7733beea..99f679edd 100644 --- a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt +++ b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt @@ -264,6 +264,7 @@ class MainViewModel : ViewModel() { val isIslandNotifKeepProgress = mutableStateOf(true) val isIslandNotifQueue = mutableStateOf(true) val isIslandNotifSkipSilent = mutableStateOf(true) + val isIslandNotifFollowDnd = mutableStateOf(true) val isIslandNotifFilterApps = mutableStateOf(false) val isIslandShowNotifications = mutableStateOf(true) val isIslandNotifTapToOpen = mutableStateOf(false) @@ -924,6 +925,9 @@ class MainViewModel : ViewModel() { SettingsRepository.KEY_ISLAND_NOTIF_SKIP_SILENT -> isIslandNotifSkipSilent.value = settingsRepository.isIslandNotifSkipSilentEnabled() + SettingsRepository.KEY_ISLAND_NOTIF_FOLLOW_DND -> + isIslandNotifFollowDnd.value = settingsRepository.isIslandNotifFollowDndEnabled() + SettingsRepository.KEY_ISLAND_NOTIF_FILTER_APPS -> isIslandNotifFilterApps.value = settingsRepository.isIslandNotifFilterAppsEnabled() @@ -2433,6 +2437,7 @@ class MainViewModel : ViewModel() { isIslandNotifKeepProgress.value = settingsRepository.isIslandNotifKeepProgressEnabled() isIslandNotifQueue.value = settingsRepository.isIslandNotifQueueEnabled() isIslandNotifSkipSilent.value = settingsRepository.isIslandNotifSkipSilentEnabled() + isIslandNotifFollowDnd.value = settingsRepository.isIslandNotifFollowDndEnabled() isIslandNotifFilterApps.value = settingsRepository.isIslandNotifFilterAppsEnabled() isIslandShowNotifications.value = settingsRepository.isIslandShowNotificationsEnabled() isIslandNotifTapToOpen.value = settingsRepository.isIslandNotifTapToOpenEnabled() @@ -5735,6 +5740,11 @@ class MainViewModel : ViewModel() { settingsRepository.setIslandNotifSkipSilentEnabled(enabled) } + fun setIslandNotifFollowDnd(enabled: Boolean) { + isIslandNotifFollowDnd.value = enabled + settingsRepository.setIslandNotifFollowDndEnabled(enabled) + } + fun setIslandNotifFilterApps(enabled: Boolean) { isIslandNotifFilterApps.value = enabled settingsRepository.setIslandNotifFilterAppsEnabled(enabled) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eb85a1a44..720b7399d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3221,6 +3221,8 @@ Lock screen Only show notifications from the apps you pick Ignore notifications that arrive without sound + Follow Do Not Disturb + Hide notifications that Do Not Disturb silences Show downloads and other ongoing progress Keep several notifications instead of replacing the current one Tap an expanded notification to open its app