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,
"database": {
"version": 5,
"identityHash": "306578182c2ad0f9803956beda094d28",
"identityHash": "f662a6c15e0b9e510350918228bfa0ea",
"entities": [
{
"tableName": "Subscription",
@ -80,7 +80,7 @@
},
{
"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": [
{
"fieldPath": "id",
@ -131,6 +131,12 @@
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "click",
"columnName": "click",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "deleted",
"columnName": "deleted",
@ -152,7 +158,7 @@
"views": [],
"setupQueries": [
"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 = "priority", defaultValue = "3") val priority: Int, // 1=min, 3=default, 5=max
@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,
)
@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 fun subscriptionDao(): SubscriptionDao
abstract fun notificationDao(): NotificationDao
@ -71,6 +72,7 @@ abstract class Database : RoomDatabase() {
.addMigrations(MIGRATION_2_3)
.addMigrations(MIGRATION_3_4)
.addMigrations(MIGRATION_4_5)
.addMigrations(MIGRATION_5_6)
.fallbackToDestructiveMigration()
.build()
this.instance = instance
@ -115,6 +117,12 @@ abstract class Database : RoomDatabase() {
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,
priority = toPriority(message.priority),
tags = joinTags(message.tags),
click = message.click ?: "",
notificationId = Random.nextInt(),
deleted = false
)
@ -149,6 +150,7 @@ class ApiService {
message = message.message,
priority = toPriority(message.priority),
tags = joinTags(message.tags),
click = message.click ?: "",
notificationId = 0,
deleted = false
)
@ -164,6 +166,7 @@ class ApiService {
val topic: String,
val priority: Int?,
val tags: List<String>?,
val click: String?,
val title: String?,
val message: String
)

View file

@ -7,9 +7,9 @@ import android.app.TaskStackBuilder
import android.content.Context
import android.content.Intent
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import io.heckel.ntfy.R
@ -24,37 +24,38 @@ class NotificationService(val context: Context) {
fun send(subscription: Subscription, 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 message = formatMessage(notification)
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val channelId = toChannelId(notification.priority)
val notificationBuilder = NotificationCompat.Builder(context, channelId)
var notificationBuilder = NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_notification)
.setColor(ContextCompat.getColor(context, R.color.primaryColor))
.setContentTitle(title)
.setContentText(message)
.setStyle(NotificationCompat.BigTextStyle().bigText(message))
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent) // Click target for notification
.setAutoCancel(true) // Cancel when notification is clicked
notificationBuilder = setContentIntent(notificationBuilder, subscription, notification)
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
maybeCreateNotificationChannel(notificationManager, notification.priority)
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) {
if (notification.notificationId != 0) {
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) }
}
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) {
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!

View file

@ -56,6 +56,7 @@ class FirebaseService : FirebaseMessagingService() {
val message = data["message"]
val priority = data["priority"]?.toIntOrNull()
val tags = data["tags"]
val click = data["click"]
val truncated = (data["truncated"] ?: "") == "1"
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}")
@ -83,6 +84,7 @@ class FirebaseService : FirebaseMessagingService() {
notificationId = Random.nextInt(),
priority = toPriority(priority),
tags = tags ?: "",
click = click ?: "",
deleted = false
)
if (repository.addNotification(notification)) {