Add "click" handling

This commit is contained in:
Philipp Heckel 2022-01-04 23:45:24 +01:00
parent 598e3376bb
commit 3a5399162d
5 changed files with 52 additions and 19 deletions

View file

@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 5, "version": 5,
"identityHash": "306578182c2ad0f9803956beda094d28", "identityHash": "f662a6c15e0b9e510350918228bfa0ea",
"entities": [ "entities": [
{ {
"tableName": "Subscription", "tableName": "Subscription",
@ -80,7 +80,7 @@
}, },
{ {
"tableName": "Notification", "tableName": "Notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `deleted` INTEGER NOT NULL, PRIMARY KEY(`id`, `subscriptionId`))", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `deleted` INTEGER NOT NULL, PRIMARY KEY(`id`, `subscriptionId`))",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -131,6 +131,12 @@
"affinity": "TEXT", "affinity": "TEXT",
"notNull": true "notNull": true
}, },
{
"fieldPath": "click",
"columnName": "click",
"affinity": "TEXT",
"notNull": true
},
{ {
"fieldPath": "deleted", "fieldPath": "deleted",
"columnName": "deleted", "columnName": "deleted",
@ -152,7 +158,7 @@
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '306578182c2ad0f9803956beda094d28')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f662a6c15e0b9e510350918228bfa0ea')"
] ]
} }
} }

View file

@ -51,10 +51,11 @@ data class Notification(
@ColumnInfo(name = "notificationId") val notificationId: Int, // Android notification popup ID @ColumnInfo(name = "notificationId") val notificationId: Int, // Android notification popup ID
@ColumnInfo(name = "priority", defaultValue = "3") val priority: Int, // 1=min, 3=default, 5=max @ColumnInfo(name = "priority", defaultValue = "3") val priority: Int, // 1=min, 3=default, 5=max
@ColumnInfo(name = "tags") val tags: String, @ColumnInfo(name = "tags") val tags: String,
@ColumnInfo(name = "click") val click: String, // URL/intent to open on notification click
@ColumnInfo(name = "deleted") val deleted: Boolean, @ColumnInfo(name = "deleted") val deleted: Boolean,
) )
@androidx.room.Database(entities = [Subscription::class, Notification::class], version = 5) @androidx.room.Database(entities = [Subscription::class, Notification::class], version = 6)
abstract class Database : RoomDatabase() { abstract class Database : RoomDatabase() {
abstract fun subscriptionDao(): SubscriptionDao abstract fun subscriptionDao(): SubscriptionDao
abstract fun notificationDao(): NotificationDao abstract fun notificationDao(): NotificationDao
@ -71,6 +72,7 @@ abstract class Database : RoomDatabase() {
.addMigrations(MIGRATION_2_3) .addMigrations(MIGRATION_2_3)
.addMigrations(MIGRATION_3_4) .addMigrations(MIGRATION_3_4)
.addMigrations(MIGRATION_4_5) .addMigrations(MIGRATION_4_5)
.addMigrations(MIGRATION_5_6)
.fallbackToDestructiveMigration() .fallbackToDestructiveMigration()
.build() .build()
this.instance = instance this.instance = instance
@ -115,6 +117,12 @@ abstract class Database : RoomDatabase() {
db.execSQL("CREATE UNIQUE INDEX index_Subscription_upConnectorToken ON Subscription (upConnectorToken)") db.execSQL("CREATE UNIQUE INDEX index_Subscription_upConnectorToken ON Subscription (upConnectorToken)")
} }
} }
private val MIGRATION_5_6 = object : Migration(5, 6) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Notification ADD COLUMN click TEXT NOT NULL DEFAULT('')")
}
}
} }
} }

View file

@ -120,6 +120,7 @@ class ApiService {
message = message.message, message = message.message,
priority = toPriority(message.priority), priority = toPriority(message.priority),
tags = joinTags(message.tags), tags = joinTags(message.tags),
click = message.click ?: "",
notificationId = Random.nextInt(), notificationId = Random.nextInt(),
deleted = false deleted = false
) )
@ -149,6 +150,7 @@ class ApiService {
message = message.message, message = message.message,
priority = toPriority(message.priority), priority = toPriority(message.priority),
tags = joinTags(message.tags), tags = joinTags(message.tags),
click = message.click ?: "",
notificationId = 0, notificationId = 0,
deleted = false deleted = false
) )
@ -164,6 +166,7 @@ class ApiService {
val topic: String, val topic: String,
val priority: Int?, val priority: Int?,
val tags: List<String>?, val tags: List<String>?,
val click: String?,
val title: String?, val title: String?,
val message: String val message: String
) )

View file

@ -7,9 +7,9 @@ import android.app.TaskStackBuilder
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.media.RingtoneManager import android.media.RingtoneManager
import android.net.Uri
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import io.heckel.ntfy.R import io.heckel.ntfy.R
@ -24,37 +24,38 @@ class NotificationService(val context: Context) {
fun send(subscription: Subscription, notification: Notification) { fun send(subscription: Subscription, notification: Notification) {
Log.d(TAG, "Displaying notification $notification") Log.d(TAG, "Displaying notification $notification")
// Create an Intent for the activity you want to start
val intent = Intent(context, DetailActivity::class.java)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, subscription.instant)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
val pendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(intent) // Add the intent, which inflates the back stack
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT) // Get the PendingIntent containing the entire back stack
}
val title = formatTitle(subscription, notification) val title = formatTitle(subscription, notification)
val message = formatMessage(notification) val message = formatMessage(notification)
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val channelId = toChannelId(notification.priority) val channelId = toChannelId(notification.priority)
val notificationBuilder = NotificationCompat.Builder(context, channelId) var notificationBuilder = NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_notification) .setSmallIcon(R.drawable.ic_notification)
.setColor(ContextCompat.getColor(context, R.color.primaryColor)) .setColor(ContextCompat.getColor(context, R.color.primaryColor))
.setContentTitle(title) .setContentTitle(title)
.setContentText(message) .setContentText(message)
.setStyle(NotificationCompat.BigTextStyle().bigText(message)) .setStyle(NotificationCompat.BigTextStyle().bigText(message))
.setSound(defaultSoundUri) .setSound(defaultSoundUri)
.setContentIntent(pendingIntent) // Click target for notification
.setAutoCancel(true) // Cancel when notification is clicked .setAutoCancel(true) // Cancel when notification is clicked
notificationBuilder = setContentIntent(notificationBuilder, subscription, notification)
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
maybeCreateNotificationChannel(notificationManager, notification.priority) maybeCreateNotificationChannel(notificationManager, notification.priority)
notificationManager.notify(notification.notificationId, notificationBuilder.build()) notificationManager.notify(notification.notificationId, notificationBuilder.build())
} }
private fun setContentIntent(builder: NotificationCompat.Builder, subscription: Subscription, notification: Notification): NotificationCompat.Builder? {
if (notification.click == "") {
return builder.setContentIntent(detailActivityIntent(subscription))
}
return try {
val uri = Uri.parse(notification.click)
val viewIntent = PendingIntent.getActivity(context, 0, Intent(Intent.ACTION_VIEW, uri), 0)
builder.setContentIntent(viewIntent)
} catch (e: Exception) {
builder.setContentIntent(detailActivityIntent(subscription))
}
}
fun cancel(notification: Notification) { fun cancel(notification: Notification) {
if (notification.notificationId != 0) { if (notification.notificationId != 0) {
Log.d(TAG, "Cancelling notification ${notification.id}: ${notification.message}") Log.d(TAG, "Cancelling notification ${notification.id}: ${notification.message}")
@ -68,6 +69,19 @@ class NotificationService(val context: Context) {
(1..5).forEach { priority -> maybeCreateNotificationChannel(notificationManager, priority) } (1..5).forEach { priority -> maybeCreateNotificationChannel(notificationManager, priority) }
} }
private fun detailActivityIntent(subscription: Subscription): PendingIntent? {
val intent = Intent(context, DetailActivity::class.java)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, subscription.instant)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil)
return TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(intent) // Add the intent, which inflates the back stack
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT) // Get the PendingIntent containing the entire back stack
}
}
private fun maybeCreateNotificationChannel(notificationManager: NotificationManager, priority: Int) { private fun maybeCreateNotificationChannel(notificationManager: NotificationManager, priority: Int) {
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!

View file

@ -56,6 +56,7 @@ class FirebaseService : FirebaseMessagingService() {
val message = data["message"] val message = data["message"]
val priority = data["priority"]?.toIntOrNull() val priority = data["priority"]?.toIntOrNull()
val tags = data["tags"] val tags = data["tags"]
val click = data["click"]
val truncated = (data["truncated"] ?: "") == "1" val truncated = (data["truncated"] ?: "") == "1"
if (id == null || topic == null || message == null || timestamp == null) { if (id == null || topic == null || message == null || timestamp == null) {
Log.d(TAG, "Discarding unexpected message: from=${remoteMessage.from}, fcmprio=${remoteMessage.priority}, fcmprio_orig=${remoteMessage.originalPriority}, data=${data}") Log.d(TAG, "Discarding unexpected message: from=${remoteMessage.from}, fcmprio=${remoteMessage.priority}, fcmprio_orig=${remoteMessage.originalPriority}, data=${data}")
@ -83,6 +84,7 @@ class FirebaseService : FirebaseMessagingService() {
notificationId = Random.nextInt(), notificationId = Random.nextInt(),
priority = toPriority(priority), priority = toPriority(priority),
tags = tags ?: "", tags = tags ?: "",
click = click ?: "",
deleted = false deleted = false
) )
if (repository.addNotification(notification)) { if (repository.addNotification(notification)) {