WIP
This commit is contained in:
parent
63fff52fcf
commit
7961f9f9e2
7 changed files with 144 additions and 89 deletions
|
@ -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')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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?
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue