add detail setting preference to toggle and send notifications to custom channel

This commit is contained in:
Markus Doits 2022-12-01 11:13:20 +01:00
parent 711f1eaf06
commit 9149bc3c8d
No known key found for this signature in database
GPG key ID: 4D406BBC615201D1
6 changed files with 82 additions and 10 deletions

View file

@ -7,6 +7,7 @@ import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.util.Log import io.heckel.ntfy.util.Log
import io.heckel.ntfy.up.Distributor import io.heckel.ntfy.up.Distributor
import io.heckel.ntfy.util.decodeBytesMessage import io.heckel.ntfy.util.decodeBytesMessage
import io.heckel.ntfy.util.displayName
import io.heckel.ntfy.util.safeLet import io.heckel.ntfy.util.safeLet
/** /**
@ -19,7 +20,15 @@ class NotificationDispatcher(val context: Context, val repository: Repository) {
private val distributor = Distributor(context) private val distributor = Distributor(context)
fun init() { 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) { fun dispatch(subscription: Subscription, notification: Notification) {

View file

@ -56,14 +56,23 @@ class NotificationService(val context: Context) {
} }
} }
fun createNotificationChannels() { fun createDefaultNotificationChannels() {
(1..5).forEach { priority -> maybeCreateNotificationChannel(DEFAULT_CHANNEL, priority) } 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) { private fun displayInternal(subscription: Subscription, notification: Notification, update: Boolean = false) {
val title = formatTitle(subscription, notification) val title = formatTitle(subscription, notification)
val channelId = toChannelId(DEFAULT_CHANNEL, notification.priority) val channelName = if(subscription.ownNotificationChannels) "" + subscription.id else DEFAULT_CHANNEL
val builder = NotificationCompat.Builder(context, channelId) val groupId = if(subscription.ownNotificationChannels) "" + subscription.id else null
val builder = NotificationCompat.Builder(context, toChannelId(channelName, notification.priority))
.setSmallIcon(R.drawable.ic_notification) .setSmallIcon(R.drawable.ic_notification)
.setColor(ContextCompat.getColor(context, Colors.notificationIcon(context))) .setColor(ContextCompat.getColor(context, Colors.notificationIcon(context)))
.setContentTitle(title) .setContentTitle(title)
@ -79,7 +88,7 @@ class NotificationService(val context: Context) {
maybeAddCancelAction(builder, notification) maybeAddCancelAction(builder, notification)
maybeAddUserActions(builder, notification) maybeAddUserActions(builder, notification)
maybeCreateNotificationChannel(DEFAULT_CHANNEL, notification.priority) maybeCreateNotificationChannel(channelName, notification.priority, groupId, displayName(subscription))
notificationManager.notify(notification.notificationId, builder.build()) 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) { 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! // 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) 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) 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) { private fun maybeCreateNotificationChannelGroup(id: String, name: String) {
notificationManager.createNotificationChannelGroup(NotificationChannelGroup(id, name)) notificationManager.createNotificationChannelGroup(NotificationChannelGroup(id, name))
} }

View file

@ -21,6 +21,7 @@ import io.heckel.ntfy.R
import io.heckel.ntfy.db.Repository import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.Subscription import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.msg.DownloadAttachmentWorker import io.heckel.ntfy.msg.DownloadAttachmentWorker
import io.heckel.ntfy.msg.NotificationDispatcher
import io.heckel.ntfy.service.SubscriberServiceManager import io.heckel.ntfy.service.SubscriberServiceManager
import io.heckel.ntfy.util.* import io.heckel.ntfy.util.*
import kotlinx.coroutines.* import kotlinx.coroutines.*
@ -35,6 +36,7 @@ class DetailSettingsActivity : AppCompatActivity() {
private lateinit var repository: Repository private lateinit var repository: Repository
private lateinit var serviceManager: SubscriberServiceManager private lateinit var serviceManager: SubscriberServiceManager
private lateinit var settingsFragment: SettingsFragment private lateinit var settingsFragment: SettingsFragment
private lateinit var dispatcher: NotificationDispatcher
private var subscriptionId: Long = 0 private var subscriptionId: Long = 0
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -45,6 +47,7 @@ class DetailSettingsActivity : AppCompatActivity() {
repository = Repository.getInstance(this) repository = Repository.getInstance(this)
serviceManager = SubscriberServiceManager(this) serviceManager = SubscriberServiceManager(this)
dispatcher = NotificationDispatcher(this, repository)
subscriptionId = intent.getLongExtra(DetailActivity.EXTRA_SUBSCRIPTION_ID, 0) subscriptionId = intent.getLongExtra(DetailActivity.EXTRA_SUBSCRIPTION_ID, 0)
if (savedInstanceState == null) { if (savedInstanceState == null) {
@ -75,6 +78,7 @@ class DetailSettingsActivity : AppCompatActivity() {
private lateinit var resolver: ContentResolver private lateinit var resolver: ContentResolver
private lateinit var repository: Repository private lateinit var repository: Repository
private lateinit var serviceManager: SubscriberServiceManager private lateinit var serviceManager: SubscriberServiceManager
private lateinit var dispatcher: NotificationDispatcher
private lateinit var subscription: Subscription private lateinit var subscription: Subscription
private lateinit var iconSetPref: Preference private lateinit var iconSetPref: Preference
@ -87,6 +91,7 @@ class DetailSettingsActivity : AppCompatActivity() {
// Dependencies (Fragments need a default constructor) // Dependencies (Fragments need a default constructor)
repository = Repository.getInstance(requireActivity()) repository = Repository.getInstance(requireActivity())
serviceManager = SubscriberServiceManager(requireActivity()) serviceManager = SubscriberServiceManager(requireActivity())
dispatcher = NotificationDispatcher(requireActivity(), repository)
resolver = requireContext().applicationContext.contentResolver resolver = requireContext().applicationContext.contentResolver
// Create result launcher for custom icon (must be created in onCreatePreferences() directly) // Create result launcher for custom icon (must be created in onCreatePreferences() directly)
@ -107,6 +112,7 @@ class DetailSettingsActivity : AppCompatActivity() {
private fun loadView() { private fun loadView() {
if (subscription.upAppId == null) { if (subscription.upAppId == null) {
loadInstantPref() loadInstantPref()
loadOwnNotificationChannelsPref()
loadMutedUntilPref() loadMutedUntilPref()
loadMinPriorityPref() loadMinPriorityPref()
loadAutoDeletePref() 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<SwitchPreference> { 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() { private fun loadMutedUntilPref() {
val prefId = context?.getString(R.string.detail_settings_notifications_muted_until_key) ?: return val prefId = context?.getString(R.string.detail_settings_notifications_muted_until_key) ?: return
val pref: ListPreference? = findPreference(prefId) val pref: ListPreference? = findPreference(prefId)

View file

@ -7,7 +7,7 @@
<string name="channel_notifications_default_name">Notifications (default priority)</string> <string name="channel_notifications_default_name">Notifications (default priority)</string>
<string name="channel_notifications_high_name">Notifications (high priority)</string> <string name="channel_notifications_high_name">Notifications (high priority)</string>
<string name="channel_notifications_max_name">Notifications (max priority)</string> <string name="channel_notifications_max_name">Notifications (max priority)</string>
<string name="channel_notifications_group_default_name">Standard</string> <string name="channel_notifications_group_default_name">Default</string>
<string name="channel_subscriber_service_name">Subscription Service</string> <string name="channel_subscriber_service_name">Subscription Service</string>
<string name="channel_subscriber_notification_title">Listening for incoming notifications</string> <string name="channel_subscriber_notification_title">Listening for incoming notifications</string>
<string name="channel_subscriber_notification_instant_text">Subscribed to instant delivery topics</string> <string name="channel_subscriber_notification_instant_text">Subscribed to instant delivery topics</string>
@ -349,6 +349,9 @@
<string name="detail_settings_notifications_instant_title">Instant delivery</string> <string name="detail_settings_notifications_instant_title">Instant delivery</string>
<string name="detail_settings_notifications_instant_summary_on">Notifications are delivered instantly. Requires a foreground service and consumes more battery.</string> <string name="detail_settings_notifications_instant_summary_on">Notifications are delivered instantly. Requires a foreground service and consumes more battery.</string>
<string name="detail_settings_notifications_instant_summary_off">Notifications are delivered using Firebase. Delivery may be delayed, but consumes less battery.</string> <string name="detail_settings_notifications_instant_summary_off">Notifications are delivered using Firebase. Delivery may be delayed, but consumes less battery.</string>
<string name="detail_settings_notifications_own_notification_channels_title">Own notification channels</string>
<string name="detail_settings_notifications_own_notification_channels_summay_on">Use own notification channels for this subscription</string>
<string name="detail_settings_notifications_own_notification_channels_summay_off">Use default notification channels</string>
<string name="detail_settings_appearance_header">Appearance</string> <string name="detail_settings_appearance_header">Appearance</string>
<string name="detail_settings_appearance_icon_set_title">Subscription icon</string> <string name="detail_settings_appearance_icon_set_title">Subscription icon</string>
<string name="detail_settings_appearance_icon_set_summary">Set an icon to be displayed in notifications</string> <string name="detail_settings_appearance_icon_set_summary">Set an icon to be displayed in notifications</string>

View file

@ -34,6 +34,7 @@
<string name="detail_settings_notifications_header_key" translatable="false">SubscriptionNotifications</string> <string name="detail_settings_notifications_header_key" translatable="false">SubscriptionNotifications</string>
<string name="detail_settings_notifications_instant_key" translatable="false">SubscriptionInstant</string> <string name="detail_settings_notifications_instant_key" translatable="false">SubscriptionInstant</string>
<string name="detail_settings_notifications_muted_until_key" translatable="false">SubscriptionMutedUntil</string> <string name="detail_settings_notifications_muted_until_key" translatable="false">SubscriptionMutedUntil</string>
<string name="detail_settings_notifications_own_notification_channels_key" translatable="false">SubscriptionOwnNotificationChannels</string>
<string name="detail_settings_notifications_min_priority_key" translatable="false">SubscriptionMinPriority</string> <string name="detail_settings_notifications_min_priority_key" translatable="false">SubscriptionMinPriority</string>
<string name="detail_settings_notifications_auto_delete_key" translatable="false">SubscriptionAutoDelete</string> <string name="detail_settings_notifications_auto_delete_key" translatable="false">SubscriptionAutoDelete</string>
<string name="detail_settings_appearance_header_key" translatable="false">SubscriptionAppearance</string> <string name="detail_settings_appearance_header_key" translatable="false">SubscriptionAppearance</string>

View file

@ -14,6 +14,10 @@
app:entryValues="@array/settings_notifications_muted_until_values" app:entryValues="@array/settings_notifications_muted_until_values"
app:defaultValue="0" app:defaultValue="0"
app:isPreferenceVisible="false"/> app:isPreferenceVisible="false"/>
<SwitchPreference
app:key="@string/detail_settings_notifications_own_notification_channels_key"
app:title="@string/detail_settings_notifications_own_notification_channels_title"
app:isPreferenceVisible="false"/>
<ListPreference <ListPreference
app:key="@string/detail_settings_notifications_min_priority_key" app:key="@string/detail_settings_notifications_min_priority_key"
app:title="@string/settings_notifications_min_priority_title" app:title="@string/settings_notifications_min_priority_title"