This commit is contained in:
Philipp Heckel 2022-01-06 01:05:57 +01:00
parent 63fff52fcf
commit 7961f9f9e2
7 changed files with 144 additions and 89 deletions

View file

@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 6, "version": 6,
"identityHash": "0c64bd96a759eb0d899cd251756d6c00", "identityHash": "6fd36c6995d3ae734f4ba7c8beaf9a95",
"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, `click` TEXT NOT NULL, `attachmentName` TEXT, `attachmentType` TEXT, `attachmentSize` INTEGER, `attachmentExpires` INTEGER, `attachmentPreviewUrl` TEXT, `attachmentUrl` TEXT, `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, `attachmentName` TEXT, `attachmentType` TEXT, `attachmentSize` INTEGER, `attachmentExpires` INTEGER, `attachmentPreviewUrl` TEXT, `attachmentUrl` TEXT, `attachmentContentUri` TEXT, `deleted` INTEGER NOT NULL, PRIMARY KEY(`id`, `subscriptionId`))",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -173,6 +173,12 @@
"affinity": "TEXT", "affinity": "TEXT",
"notNull": false "notNull": false
}, },
{
"fieldPath": "attachmentContentUri",
"columnName": "attachmentContentUri",
"affinity": "TEXT",
"notNull": false
},
{ {
"fieldPath": "deleted", "fieldPath": "deleted",
"columnName": "deleted", "columnName": "deleted",
@ -194,7 +200,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, '0c64bd96a759eb0d899cd251756d6c00')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6fd36c6995d3ae734f4ba7c8beaf9a95')"
] ]
} }
} }

View file

@ -58,6 +58,7 @@ data class Notification(
@ColumnInfo(name = "attachmentExpires") val attachmentExpires: Long?, // Unix timestamp @ColumnInfo(name = "attachmentExpires") val attachmentExpires: Long?, // Unix timestamp
@ColumnInfo(name = "attachmentPreviewUrl") val attachmentPreviewUrl: String?, @ColumnInfo(name = "attachmentPreviewUrl") val attachmentPreviewUrl: String?,
@ColumnInfo(name = "attachmentUrl") val attachmentUrl: String?, @ColumnInfo(name = "attachmentUrl") val attachmentUrl: String?,
@ColumnInfo(name = "attachmentContentUri") val attachmentContentUri: String?,
@ColumnInfo(name = "deleted") val deleted: Boolean, @ColumnInfo(name = "deleted") val deleted: Boolean,
) )
@ -220,6 +221,9 @@ interface NotificationDao {
@Insert(onConflict = OnConflictStrategy.IGNORE) @Insert(onConflict = OnConflictStrategy.IGNORE)
fun add(notification: Notification) fun add(notification: Notification)
@Update(onConflict = OnConflictStrategy.IGNORE)
fun update(notification: Notification)
@Query("SELECT * FROM notification WHERE id = :notificationId") @Query("SELECT * FROM notification WHERE id = :notificationId")
fun get(notificationId: String): Notification? fun get(notificationId: String): Notification?

View file

@ -104,6 +104,11 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri
return true return true
} }
fun updateNotification(notification: Notification) {
notificationDao.update(notification)
}
@Suppress("RedundantSuspendModifier") @Suppress("RedundantSuspendModifier")
@WorkerThread @WorkerThread
suspend fun markAsDeleted(notificationId: String) { suspend fun markAsDeleted(notificationId: String) {
@ -290,6 +295,8 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri
const val SHARED_PREFS_UNIFIED_PUSH_ENABLED = "UnifiedPushEnabled" const val SHARED_PREFS_UNIFIED_PUSH_ENABLED = "UnifiedPushEnabled"
const val SHARED_PREFS_UNIFIED_PUSH_BASE_URL = "UnifiedPushBaseURL" const val SHARED_PREFS_UNIFIED_PUSH_BASE_URL = "UnifiedPushBaseURL"
const val PREVIEWS_CACHE_DIR = "Previews"
private const val TAG = "NtfyRepository" private const val TAG = "NtfyRepository"
private var instance: Repository? = null private var instance: Repository? = null

View file

@ -127,6 +127,7 @@ class ApiService {
attachmentExpires = message.attachment?.expires, attachmentExpires = message.attachment?.expires,
attachmentPreviewUrl = message.attachment?.preview_url, attachmentPreviewUrl = message.attachment?.preview_url,
attachmentUrl = message.attachment?.url, attachmentUrl = message.attachment?.url,
attachmentContentUri = null,
notificationId = Random.nextInt(), notificationId = Random.nextInt(),
deleted = false deleted = false
) )
@ -163,6 +164,7 @@ class ApiService {
attachmentExpires = message.attachment?.expires, attachmentExpires = message.attachment?.expires,
attachmentPreviewUrl = message.attachment?.preview_url, attachmentPreviewUrl = message.attachment?.preview_url,
attachmentUrl = message.attachment?.url, attachmentUrl = message.attachment?.url,
attachmentContentUri = null,
notificationId = 0, notificationId = 0,
deleted = false deleted = false
) )

View file

@ -2,6 +2,7 @@ package io.heckel.ntfy.msg
import android.content.ContentValues import android.content.ContentValues
import android.content.Context import android.content.Context
import android.graphics.BitmapFactory
import android.os.Environment import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.util.Log import android.util.Log
@ -9,15 +10,17 @@ import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.data.Notification
import io.heckel.ntfy.data.Repository
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.data.Subscription
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import java.io.File
import java.io.FileOutputStream
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class AttachmentDownloadWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) { class AttachmentDownloadWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) {
private val client = OkHttpClient.Builder() private val client = OkHttpClient.Builder()
.callTimeout(15, TimeUnit.SECONDS) // Total timeout for entire request .callTimeout(5, TimeUnit.MINUTES) // Total timeout for entire request
.connectTimeout(15, TimeUnit.SECONDS) .connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS) .writeTimeout(15, TimeUnit.SECONDS)
@ -28,16 +31,17 @@ class AttachmentDownloadWorker(private val context: Context, params: WorkerParam
if (context.applicationContext !is Application) return Result.failure() if (context.applicationContext !is Application) return Result.failure()
val notificationId = inputData.getString("id") ?: return Result.failure() val notificationId = inputData.getString("id") ?: return Result.failure()
val app = context.applicationContext as Application val app = context.applicationContext as Application
val notification = app.repository.getNotification(notificationId) ?: return Result.failure() val repository = app.repository
val subscription = app.repository.getSubscription(notification.subscriptionId) ?: return Result.failure() val notification = repository.getNotification(notificationId) ?: return Result.failure()
val subscription = repository.getSubscription(notification.subscriptionId) ?: return Result.failure()
if (notification.attachmentPreviewUrl != null) { if (notification.attachmentPreviewUrl != null) {
downloadPreview(subscription, notification) downloadPreview(repository, subscription, notification)
} }
downloadAttachment(subscription, notification) downloadAttachment(repository, subscription, notification)
return Result.success() return Result.success()
} }
private fun downloadPreview(subscription: Subscription, notification: Notification) { private fun downloadPreview(repository: Repository, subscription: Subscription, notification: Notification) {
val url = notification.attachmentPreviewUrl ?: return val url = notification.attachmentPreviewUrl ?: return
Log.d(TAG, "Downloading preview from $url") Log.d(TAG, "Downloading preview from $url")
@ -49,47 +53,17 @@ class AttachmentDownloadWorker(private val context: Context, params: WorkerParam
if (!response.isSuccessful || response.body == null) { if (!response.isSuccessful || response.body == null) {
throw Exception("Preview download failed: ${response.code}") throw Exception("Preview download failed: ${response.code}")
} }
Log.d(TAG, "Preview download: successful response, proceeding with download") val previewFile = File(applicationContext.cacheDir.absolutePath, "preview-" + notification.id)
/*val dir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) Log.d(TAG, "Downloading preview to cache file: $previewFile")
Log.d(TAG, "dir: $dir") FileOutputStream(previewFile).use { fileOut ->
if (dir == null /*|| !dir.mkdirs()*/) {
throw Exception("Cannot access target storage dir")
}*/
val contentResolver = applicationContext.contentResolver
val contentValues = ContentValues()
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "flower.jpg")
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
val uri = contentResolver.insert(MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL), contentValues)
?: throw Exception("Cannot get content URI")
val out = contentResolver.openOutputStream(uri) ?: throw Exception("Cannot open output stream")
out.use { fileOut ->
response.body!!.byteStream().copyTo(fileOut) response.body!!.byteStream().copyTo(fileOut)
} }
Log.d(TAG, "Preview downloaded; updating notification")
/* notifier.update(subscription, notification)
val file = File(context.cacheDir, "somefile")
context.openFileOutput(file.absolutePath, Context.MODE_PRIVATE).use { fileOut ->
response.body!!.byteStream().copyTo(fileOut)
}
val file = File(dir, "myfile.txt")
Log.d(TAG, "dir: $dir, file: $file")
FileOutputStream(file).use { fileOut ->
response.body!!.byteStream().copyTo(fileOut)
}*/
/*
context.openFileOutput(file.absolutePath, Context.MODE_PRIVATE).use { fileOut ->
response.body!!.byteStream().copyTo(fileOut)
}*/
//val bitmap = BitmapFactory.decodeFile(file.absolutePath)
Log.d(TAG, "now we would display the preview image")
//displayInternal(subscription, notification, bitmap)
} }
} }
private fun downloadAttachment(subscription: Subscription, notification: Notification) { private fun downloadAttachment(repository: Repository, subscription: Subscription, notification: Notification) {
val url = notification.attachmentUrl ?: return val url = notification.attachmentUrl ?: return
Log.d(TAG, "Downloading attachment from $url") Log.d(TAG, "Downloading attachment from $url")
@ -103,6 +77,7 @@ class AttachmentDownloadWorker(private val context: Context, params: WorkerParam
} }
val name = notification.attachmentName ?: "attachment.bin" val name = notification.attachmentName ?: "attachment.bin"
val mimeType = notification.attachmentType ?: "application/octet-stream" val mimeType = notification.attachmentType ?: "application/octet-stream"
val size = notification.attachmentSize ?: 0
val resolver = applicationContext.contentResolver val resolver = applicationContext.contentResolver
val details = ContentValues().apply { val details = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name) put(MediaStore.MediaColumns.DISPLAY_NAME, name)
@ -115,10 +90,26 @@ class AttachmentDownloadWorker(private val context: Context, params: WorkerParam
Log.d(TAG, "Starting download to content URI: $uri") Log.d(TAG, "Starting download to content URI: $uri")
val out = resolver.openOutputStream(uri) ?: throw Exception("Cannot open output stream") val out = resolver.openOutputStream(uri) ?: throw Exception("Cannot open output stream")
out.use { fileOut -> out.use { fileOut ->
response.body!!.byteStream().copyTo(fileOut) val fileIn = response.body!!.byteStream()
var bytesCopied: Long = 0
val buffer = ByteArray(8 * 1024)
var bytes = fileIn.read(buffer)
var lastProgress = 0L
while (bytes >= 0) {
if (System.currentTimeMillis() - lastProgress > 500) {
val progress = if (size > 0) (bytesCopied.toFloat()/size.toFloat()*100).toInt() else NotificationService.PROGRESS_INDETERMINATE
notifier.update(subscription, notification, progress = progress)
lastProgress = System.currentTimeMillis()
}
fileOut.write(buffer, 0, bytes)
bytesCopied += bytes
bytes = fileIn.read(buffer)
}
} }
Log.d(TAG, "Attachment download: successful response, proceeding with download") Log.d(TAG, "Attachment download: successful response, proceeding with download")
notifier.update(subscription, notification) val newNotification = notification.copy(attachmentContentUri = uri.toString())
repository.updateNotification(newNotification)
notifier.update(subscription, newNotification)
} }
} }

View file

@ -7,6 +7,7 @@ import android.app.TaskStackBuilder
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.media.RingtoneManager import android.media.RingtoneManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@ -18,13 +19,17 @@ import androidx.work.WorkManager
import androidx.work.workDataOf import androidx.work.workDataOf
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.data.Notification
import io.heckel.ntfy.data.Repository
import io.heckel.ntfy.data.Subscription import io.heckel.ntfy.data.Subscription
import io.heckel.ntfy.ui.DetailActivity import io.heckel.ntfy.ui.DetailActivity
import io.heckel.ntfy.ui.MainActivity import io.heckel.ntfy.ui.MainActivity
import io.heckel.ntfy.util.formatMessage import io.heckel.ntfy.util.formatMessage
import io.heckel.ntfy.util.formatTitle import io.heckel.ntfy.util.formatTitle
import java.io.File
class NotificationService(val context: Context) { class NotificationService(val context: Context) {
private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
fun display(subscription: Subscription, notification: Notification) { fun display(subscription: Subscription, notification: Notification) {
Log.d(TAG, "Displaying notification $notification") Log.d(TAG, "Displaying notification $notification")
@ -39,9 +44,9 @@ class NotificationService(val context: Context) {
} }
} }
fun update(subscription: Subscription, notification: Notification) { fun update(subscription: Subscription, notification: Notification, progress: Int = PROGRESS_NONE) {
Log.d(TAG, "Updating notification $notification") Log.d(TAG, "Updating notification $notification")
displayInternal(subscription, notification) displayInternal(subscription, notification, update = true, progress = progress)
} }
fun cancel(notification: Notification) { fun cancel(notification: Notification) {
@ -53,45 +58,94 @@ class NotificationService(val context: Context) {
} }
fun createNotificationChannels() { fun createNotificationChannels() {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager (1..5).forEach { priority -> maybeCreateNotificationChannel(priority) }
(1..5).forEach { priority -> maybeCreateNotificationChannel(notificationManager, priority) }
} }
private fun displayInternal(subscription: Subscription, notification: Notification, bitmap: Bitmap? = null) { private fun displayInternal(subscription: Subscription, notification: Notification, update: Boolean = false, progress: Int = PROGRESS_NONE) {
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 channelId = toChannelId(notification.priority) val channelId = toChannelId(notification.priority)
var notificationBuilder = NotificationCompat.Builder(context, channelId) val builder = 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)
.setSound(defaultSoundUri) .setOnlyAlertOnce(true) // Do not vibrate or play sound if already showing (updates!)
.setAutoCancel(true) // Cancel when notification is clicked .setAutoCancel(true) // Cancel when notification is clicked
notificationBuilder = setContentIntent(notificationBuilder, subscription, notification) setStyle(builder, notification, message) // Preview picture or big text style
setContentIntent(builder, subscription, notification)
maybeSetSound(builder, update)
maybeSetProgress(builder, progress)
maybeAddOpenAction(builder, notification)
maybeAddCopyUrlAction(builder, notification)
if (notification.attachmentUrl != null) { maybeCreateNotificationChannel(notification.priority)
val viewIntent = PendingIntent.getActivity(context, 0, Intent(Intent.ACTION_VIEW, Uri.parse(notification.attachmentUrl)), 0) notificationManager.notify(notification.notificationId, builder.build())
val openIntent = PendingIntent.getActivity(context, 0, Intent(Intent.ACTION_VIEW, Uri.parse("content://media/external/file/39")), 0)
notificationBuilder
.addAction(NotificationCompat.Action.Builder(0, "Open", openIntent).build())
.addAction(NotificationCompat.Action.Builder(0, "Copy URL", viewIntent).build())
.addAction(NotificationCompat.Action.Builder(0, "Download", viewIntent).build())
} }
notificationBuilder = if (bitmap != null) {
notificationBuilder private fun maybeSetSound(builder: NotificationCompat.Builder, update: Boolean) {
if (!update) {
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
builder.setSound(defaultSoundUri)
} else {
builder.setSound(null)
}
}
private fun setStyle(builder: NotificationCompat.Builder, notification: Notification, message: String) {
val previewFile = File(context.applicationContext.cacheDir.absolutePath, "preview-" + notification.id)
if (previewFile.exists()) {
try {
val bitmap = BitmapFactory.decodeFile(previewFile.absolutePath)
builder
.setLargeIcon(bitmap) .setLargeIcon(bitmap)
.setStyle(NotificationCompat.BigPictureStyle() .setStyle(NotificationCompat.BigPictureStyle()
.bigPicture(bitmap) .bigPicture(bitmap)
.bigLargeIcon(null)) .bigLargeIcon(null))
} catch (_: Exception) {
builder.setStyle(NotificationCompat.BigTextStyle().bigText(message))
}
} else { } else {
notificationBuilder.setStyle(NotificationCompat.BigTextStyle().bigText(message)) builder.setStyle(NotificationCompat.BigTextStyle().bigText(message))
}
} }
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager private fun setContentIntent(builder: NotificationCompat.Builder, subscription: Subscription, notification: Notification) {
maybeCreateNotificationChannel(notificationManager, notification.priority) if (notification.click == "") {
notificationManager.notify(notification.notificationId, notificationBuilder.build()) builder.setContentIntent(detailActivityIntent(subscription))
} else {
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))
}
}
}
private fun maybeSetProgress(builder: NotificationCompat.Builder, progress: Int) {
if (progress >= 0) {
builder.setProgress(100, progress, false)
} else {
builder.setProgress(0, 0, false) // Remove progress bar
}
}
private fun maybeAddOpenAction(notificationBuilder: NotificationCompat.Builder, notification: Notification) {
if (notification.attachmentContentUri != null) {
val contentUri = Uri.parse(notification.attachmentContentUri)
val openIntent = PendingIntent.getActivity(context, 0, Intent(Intent.ACTION_VIEW, contentUri), 0)
notificationBuilder.addAction(NotificationCompat.Action.Builder(0, "Open", openIntent).build())
}
}
private fun maybeAddCopyUrlAction(builder: NotificationCompat.Builder, notification: Notification) {
if (notification.attachmentUrl != null) {
// XXXXXXXXx
val copyUrlIntent = PendingIntent.getActivity(context, 0, Intent(Intent.ACTION_VIEW, Uri.parse(notification.attachmentUrl)), 0)
builder.addAction(NotificationCompat.Action.Builder(0, "Copy URL", copyUrlIntent).build())
}
} }
private fun scheduleAttachmentDownload(subscription: Subscription, notification: Notification) { private fun scheduleAttachmentDownload(subscription: Subscription, notification: Notification) {
@ -105,19 +159,6 @@ class NotificationService(val context: Context) {
workManager.enqueue(workRequest) workManager.enqueue(workRequest)
} }
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))
}
}
private fun detailActivityIntent(subscription: Subscription): PendingIntent? { private fun detailActivityIntent(subscription: Subscription): PendingIntent? {
val intent = Intent(context, DetailActivity::class.java) val intent = Intent(context, DetailActivity::class.java)
intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id) intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id)
@ -131,7 +172,7 @@ class NotificationService(val context: Context) {
} }
} }
private fun maybeCreateNotificationChannel(notificationManager: NotificationManager, priority: Int) { private fun maybeCreateNotificationChannel(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!
@ -179,6 +220,9 @@ class NotificationService(val context: Context) {
} }
companion object { companion object {
const val PROGRESS_NONE = -1
const val PROGRESS_INDETERMINATE = -2
private const val TAG = "NtfyNotificationService" private const val TAG = "NtfyNotificationService"
private const val CHANNEL_ID_MIN = "ntfy-min" private const val CHANNEL_ID_MIN = "ntfy-min"
private const val CHANNEL_ID_LOW = "ntfy-low" private const val CHANNEL_ID_LOW = "ntfy-low"

View file

@ -96,6 +96,7 @@ class FirebaseService : FirebaseMessagingService() {
attachmentExpires = attachmentExpires, attachmentExpires = attachmentExpires,
attachmentPreviewUrl = attachmentPreviewUrl, attachmentPreviewUrl = attachmentPreviewUrl,
attachmentUrl = attachmentUrl, attachmentUrl = attachmentUrl,
attachmentContentUri = null,
notificationId = Random.nextInt(), notificationId = Random.nextInt(),
deleted = false deleted = false
) )