diff --git a/app/src/main/java/io/heckel/ntfy/msg/NotificationDispatcher.kt b/app/src/main/java/io/heckel/ntfy/msg/NotificationDispatcher.kt index c763b44..e4bedae 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/NotificationDispatcher.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/NotificationDispatcher.kt @@ -7,6 +7,7 @@ import io.heckel.ntfy.db.Subscription import io.heckel.ntfy.util.Log import io.heckel.ntfy.up.Distributor import io.heckel.ntfy.util.decodeBytesMessage +import io.heckel.ntfy.util.displayName import io.heckel.ntfy.util.safeLet /** @@ -19,7 +20,15 @@ class NotificationDispatcher(val context: Context, val repository: Repository) { private val distributor = Distributor(context) fun init() { - notifier.createNotificationChannels() + notifier.createDefaultNotificationChannels() + } + + fun createNotificationChannels(subscription: Subscription) { + notifier.createNotificationChannels("" + subscription.id, "" + subscription.id, displayName(subscription)) + } + + fun deleteNotificationChannels(subscription: Subscription) { + notifier.deleteNotificationChannels("" + subscription.id, "" + subscription.id) } fun dispatch(subscription: Subscription, notification: Notification) { diff --git a/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt b/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt index 068426d..1e464bc 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt @@ -56,14 +56,23 @@ class NotificationService(val context: Context) { } } - fun createNotificationChannels() { - (1..5).forEach { priority -> maybeCreateNotificationChannel(DEFAULT_CHANNEL, priority) } + fun createDefaultNotificationChannels() { + createNotificationChannels(DEFAULT_CHANNEL, DEFAULT_GROUP_ID, context.getString(R.string.channel_notifications_group_default_name)) + } + + fun createNotificationChannels(name: String, groupId: String?, groupName: String?) { + (1..5).forEach { priority -> maybeCreateNotificationChannel(name, priority, groupId, groupName) } + } + + fun deleteNotificationChannels(name: String, groupId: String?) { + (1..5).forEach { priority -> maybeDeleteNotificationChannel(name, priority, groupId) } } private fun displayInternal(subscription: Subscription, notification: Notification, update: Boolean = false) { val title = formatTitle(subscription, notification) - val channelId = toChannelId(DEFAULT_CHANNEL, notification.priority) - val builder = NotificationCompat.Builder(context, channelId) + val channelName = if(subscription.ownNotificationChannels) "" + subscription.id else DEFAULT_CHANNEL + val groupId = if(subscription.ownNotificationChannels) "" + subscription.id else null + val builder = NotificationCompat.Builder(context, toChannelId(channelName, notification.priority)) .setSmallIcon(R.drawable.ic_notification) .setColor(ContextCompat.getColor(context, Colors.notificationIcon(context))) .setContentTitle(title) @@ -79,7 +88,7 @@ class NotificationService(val context: Context) { maybeAddCancelAction(builder, notification) maybeAddUserActions(builder, notification) - maybeCreateNotificationChannel(DEFAULT_CHANNEL, notification.priority) + maybeCreateNotificationChannel(channelName, notification.priority, groupId, displayName(subscription)) notificationManager.notify(notification.notificationId, builder.build()) } @@ -312,7 +321,7 @@ class NotificationService(val context: Context) { } } - private fun maybeCreateNotificationChannel(name: String, priority: Int) { + private fun maybeCreateNotificationChannel(name: String, priority: Int, groupId: String?, groupName: String?=null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Note: To change a notification channel, you must delete the old one and create a new one! @@ -345,13 +354,25 @@ class NotificationService(val context: Context) { } else -> NotificationChannel(toChannelId(name, priority), context.getString(R.string.channel_notifications_default_name), NotificationManager.IMPORTANCE_DEFAULT) } - maybeCreateNotificationChannelGroup(DEFAULT_GROUP_ID, context.getString(R.string.channel_notifications_group_default_name)) - channel.setGroup(DEFAULT_GROUP_ID) + + if(groupId != null && groupName != null) { + maybeCreateNotificationChannelGroup(groupId, groupName) + channel.setGroup(groupId) + } notificationManager.createNotificationChannel(channel) } } + private fun maybeDeleteNotificationChannel(name: String, priority: Int, groupId: String?) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationManager.deleteNotificationChannel(toChannelId(name, priority)) + if(groupId != null) { + notificationManager.deleteNotificationChannelGroup(groupId) + } + } + } + private fun maybeCreateNotificationChannelGroup(id: String, name: String) { notificationManager.createNotificationChannelGroup(NotificationChannelGroup(id, name)) } diff --git a/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt index 91b41d1..f7eb3f1 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt @@ -21,6 +21,7 @@ import io.heckel.ntfy.R import io.heckel.ntfy.db.Repository import io.heckel.ntfy.db.Subscription import io.heckel.ntfy.msg.DownloadAttachmentWorker +import io.heckel.ntfy.msg.NotificationDispatcher import io.heckel.ntfy.service.SubscriberServiceManager import io.heckel.ntfy.util.* import kotlinx.coroutines.* @@ -35,6 +36,7 @@ class DetailSettingsActivity : AppCompatActivity() { private lateinit var repository: Repository private lateinit var serviceManager: SubscriberServiceManager private lateinit var settingsFragment: SettingsFragment + private lateinit var dispatcher: NotificationDispatcher private var subscriptionId: Long = 0 override fun onCreate(savedInstanceState: Bundle?) { @@ -45,6 +47,7 @@ class DetailSettingsActivity : AppCompatActivity() { repository = Repository.getInstance(this) serviceManager = SubscriberServiceManager(this) + dispatcher = NotificationDispatcher(this, repository) subscriptionId = intent.getLongExtra(DetailActivity.EXTRA_SUBSCRIPTION_ID, 0) if (savedInstanceState == null) { @@ -75,6 +78,7 @@ class DetailSettingsActivity : AppCompatActivity() { private lateinit var resolver: ContentResolver private lateinit var repository: Repository private lateinit var serviceManager: SubscriberServiceManager + private lateinit var dispatcher: NotificationDispatcher private lateinit var subscription: Subscription private lateinit var iconSetPref: Preference @@ -87,6 +91,7 @@ class DetailSettingsActivity : AppCompatActivity() { // Dependencies (Fragments need a default constructor) repository = Repository.getInstance(requireActivity()) serviceManager = SubscriberServiceManager(requireActivity()) + dispatcher = NotificationDispatcher(requireActivity(), repository) resolver = requireContext().applicationContext.contentResolver // Create result launcher for custom icon (must be created in onCreatePreferences() directly) @@ -107,6 +112,7 @@ class DetailSettingsActivity : AppCompatActivity() { private fun loadView() { if (subscription.upAppId == null) { loadInstantPref() + loadOwnNotificationChannelsPref() loadMutedUntilPref() loadMinPriorityPref() loadAutoDeletePref() @@ -145,6 +151,34 @@ class DetailSettingsActivity : AppCompatActivity() { } } + private fun loadOwnNotificationChannelsPref() { + val prefId = context?.getString(R.string.detail_settings_notifications_own_notification_channels_key) ?: return + val pref: SwitchPreference? = findPreference(prefId) + pref?.isVisible = true + pref?.isChecked = subscription.ownNotificationChannels + pref?.preferenceDataStore = object : PreferenceDataStore() { + override fun putBoolean(key: String?, value: Boolean) { + save(subscription.copy(ownNotificationChannels = value)) + if(value) { + dispatcher.createNotificationChannels(subscription) + } else { + dispatcher.deleteNotificationChannels(subscription) + } + + } + override fun getBoolean(key: String?, defValue: Boolean): Boolean { + return subscription.ownNotificationChannels + } + } + pref?.summaryProvider = Preference.SummaryProvider { preference -> + if (preference.isChecked) { + getString(R.string.detail_settings_notifications_own_notification_channels_summay_on) + } else { + getString(R.string.detail_settings_notifications_own_notification_channels_summay_off) + } + } + } + private fun loadMutedUntilPref() { val prefId = context?.getString(R.string.detail_settings_notifications_muted_until_key) ?: return val pref: ListPreference? = findPreference(prefId) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ee42d95..d7ce77f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7,7 +7,7 @@ Notifications (default priority) Notifications (high priority) Notifications (max priority) - Standard + Default Subscription Service Listening for incoming notifications Subscribed to instant delivery topics @@ -349,6 +349,9 @@ Instant delivery Notifications are delivered instantly. Requires a foreground service and consumes more battery. Notifications are delivered using Firebase. Delivery may be delayed, but consumes less battery. + Own notification channels + Use own notification channels for this subscription + Use default notification channels Appearance Subscription icon Set an icon to be displayed in notifications diff --git a/app/src/main/res/values/values.xml b/app/src/main/res/values/values.xml index 2ccbda8..8dfe84c 100644 --- a/app/src/main/res/values/values.xml +++ b/app/src/main/res/values/values.xml @@ -34,6 +34,7 @@ SubscriptionNotifications SubscriptionInstant SubscriptionMutedUntil + SubscriptionOwnNotificationChannels SubscriptionMinPriority SubscriptionAutoDelete SubscriptionAppearance diff --git a/app/src/main/res/xml/detail_preferences.xml b/app/src/main/res/xml/detail_preferences.xml index e209f16..382d6e5 100644 --- a/app/src/main/res/xml/detail_preferences.xml +++ b/app/src/main/res/xml/detail_preferences.xml @@ -14,6 +14,10 @@ app:entryValues="@array/settings_notifications_muted_until_values" app:defaultValue="0" app:isPreferenceVisible="false"/> +