Dantotsu/app/src/main/java/ani/dantotsu/notifications/subscription/SubscriptionNotificationTask.kt

222 lines
No EOL
9.3 KiB
Kotlin

package ani.dantotsu.notifications.subscription
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import ani.dantotsu.App
import ani.dantotsu.FileUrl
import ani.dantotsu.R
import ani.dantotsu.connections.anilist.UrlMedia
import ani.dantotsu.hasNotificationPermission
import ani.dantotsu.notifications.Task
import ani.dantotsu.parsers.AnimeSources
import ani.dantotsu.parsers.Episode
import ani.dantotsu.parsers.MangaChapter
import ani.dantotsu.parsers.MangaSources
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.util.Logger
import eu.kanade.tachiyomi.data.notification.Notifications.CHANNEL_SUBSCRIPTION_CHECK
import eu.kanade.tachiyomi.data.notification.Notifications.CHANNEL_SUBSCRIPTION_CHECK_PROGRESS
import eu.kanade.tachiyomi.data.notification.Notifications.ID_SUBSCRIPTION_CHECK_PROGRESS
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class SubscriptionNotificationTask : Task {
private var currentlyPerforming = false
@SuppressLint("MissingPermission")
override suspend fun execute(context: Context): Boolean {
if (!currentlyPerforming) {
try {
withContext(Dispatchers.IO) {
PrefManager.init(context)
currentlyPerforming = true
App.context = context
Logger.log("SubscriptionNotificationTask: execute")
var timeout = 15_000L
do {
delay(1000)
timeout -= 1000
} while (timeout > 0 && !AnimeSources.isInitialized && !MangaSources.isInitialized)
Logger.log("SubscriptionNotificationTask: timeout: $timeout")
if (timeout <= 0) {
currentlyPerforming = false
return@withContext
}
val subscriptions = SubscriptionHelper.getSubscriptions()
var i = 0
val index = subscriptions.map { i++; it.key to i }.toMap()
val notificationManager = NotificationManagerCompat.from(context)
val progressEnabled: Boolean =
PrefManager.getVal(PrefName.SubscriptionCheckingNotifications)
val progressNotification = if (progressEnabled) getProgressNotification(
context,
subscriptions.size
) else null
if (progressNotification != null && hasNotificationPermission(context)) {
notificationManager.notify(
ID_SUBSCRIPTION_CHECK_PROGRESS,
progressNotification.build()
)
//Seems like if the parent coroutine scope gets cancelled, the notification stays
//So adding this as a safeguard? dk if this will be useful
CoroutineScope(Dispatchers.Main).launch {
delay(5 * subscriptions.size * 1000L)
notificationManager.cancel(ID_SUBSCRIPTION_CHECK_PROGRESS)
}
}
fun progress(progress: Int, parser: String, media: String) {
if (progressNotification != null && hasNotificationPermission(context))
notificationManager.notify(
ID_SUBSCRIPTION_CHECK_PROGRESS,
progressNotification
.setProgress(subscriptions.size, progress, false)
.setContentText("$media on $parser")
.build()
)
}
subscriptions.toList().map {
val media = it.second
val text = if (media.isAnime) {
val parser =
SubscriptionHelper.getAnimeParser(media.id)
progress(index[it.first]!!, parser.name, media.name)
val ep: Episode? =
SubscriptionHelper.getEpisode(
parser,
media.id
)
if (ep != null) context.getString(R.string.episode) + "${ep.number}${
if (ep.title != null) " : ${ep.title}" else ""
}${
if (ep.isFiller) " [Filler]" else ""
} " + context.getString(R.string.just_released) to ep.thumbnail
else null
} else {
val parser =
SubscriptionHelper.getMangaParser(media.id)
progress(index[it.first]!!, parser.name, media.name)
val ep: MangaChapter? =
SubscriptionHelper.getChapter(
parser,
media.id
)
if (ep != null) ep.number + " " + context.getString(R.string.just_released) to null
else null
} ?: return@map
val notification = createNotification(
context.applicationContext,
media,
text.first,
text.second
)
if (hasNotificationPermission(context)) {
NotificationManagerCompat.from(context)
.notify(
CHANNEL_SUBSCRIPTION_CHECK,
System.currentTimeMillis().toInt(),
notification
)
}
}
if (progressNotification != null) notificationManager.cancel(
ID_SUBSCRIPTION_CHECK_PROGRESS
)
currentlyPerforming = false
}
return true
} catch (e: Exception) {
Logger.log("SubscriptionNotificationTask: ${e.message}")
Logger.log(e)
return false
}
} else {
return false
}
}
@SuppressLint("MissingPermission")
private fun createNotification(
context: Context,
media: SubscriptionHelper.Companion.SubscribeMedia,
text: String,
thumbnail: FileUrl?
): android.app.Notification {
val pendingIntent = getIntent(context, media.id)
val icon =
if (media.isAnime) R.drawable.ic_round_movie_filter_24 else R.drawable.ic_round_menu_book_24
val builder = NotificationCompat.Builder(context, CHANNEL_SUBSCRIPTION_CHECK)
.setSmallIcon(icon)
.setContentTitle(media.name)
.setContentText(text)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
if (thumbnail != null) {
val bitmap = getBitmapFromUrl(thumbnail.url)
if (bitmap != null) {
builder.setLargeIcon(bitmap)
}
}
return builder.build()
}
private fun getProgressNotification(
context: Context,
size: Int
): NotificationCompat.Builder {
return NotificationCompat.Builder(context, CHANNEL_SUBSCRIPTION_CHECK_PROGRESS)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(context.getString(R.string.checking_subscriptions_title))
.setProgress(size, 0, false)
.setOngoing(true)
.setAutoCancel(false)
}
private fun getBitmapFromUrl(url: String): Bitmap? {
return try {
val inputStream = java.net.URL(url).openStream()
BitmapFactory.decodeStream(inputStream)
} catch (e: Exception) {
null
}
}
private fun getIntent(context: Context, mediaId: Int): PendingIntent {
val notifyIntent = Intent(context, UrlMedia::class.java)
.putExtra("media", mediaId)
.setAction(mediaId.toString())
.apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
return PendingIntent.getActivity(
context, mediaId, notifyIntent,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_ONE_SHOT
} else {
PendingIntent.FLAG_ONE_SHOT
}
)
}
}