Add update notifications for EH/EXH galleries

This commit is contained in:
NerdNumber9 2019-08-08 20:04:31 -04:00
parent 14879c4466
commit ac6dbbcd89
4 changed files with 96 additions and 68 deletions

View File

@ -0,0 +1,75 @@
package eu.kanade.tachiyomi.data.library
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.os.Build
import android.support.v4.app.NotificationCompat
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.chop
import eu.kanade.tachiyomi.util.notification
import eu.kanade.tachiyomi.util.notificationManager
class LibraryUpdateNotifier(private val context: Context) {
/**
* Bitmap of the app for notifications.
*/
val notificationBitmap by lazy {
BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher)
}
/**
* Shows the notification containing the result of the update done by the service.
*
* @param updates a list of manga with new updates.
*/
fun showResultNotification(updates: List<Manga>) {
val newUpdates = updates.map { it.title.chop(45) }.toMutableSet()
// Append new chapters from a previous, existing notification
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val previousNotification = context.notificationManager.activeNotifications
.find { it.id == Notifications.ID_LIBRARY_RESULT }
if (previousNotification != null) {
val oldUpdates = previousNotification.notification.extras
.getString(Notification.EXTRA_BIG_TEXT)
if (!oldUpdates.isNullOrEmpty()) {
newUpdates += oldUpdates.split("\n")
}
}
}
context.notificationManager.notify(Notifications.ID_LIBRARY_RESULT, context.notification(Notifications.CHANNEL_LIBRARY) {
setSmallIcon(R.drawable.ic_book_white_24dp)
setLargeIcon(notificationBitmap)
setContentTitle(context.getString(R.string.notification_new_chapters))
if (newUpdates.size > 1) {
setContentText(context.getString(R.string.notification_new_chapters_text, newUpdates.size))
setStyle(NotificationCompat.BigTextStyle().bigText(newUpdates.joinToString("\n")))
setNumber(newUpdates.size)
} else {
setContentText(newUpdates.first())
}
priority = NotificationCompat.PRIORITY_HIGH
setContentIntent(getNotificationIntent(context))
setAutoCancel(true)
})
}
/**
* Returns an intent to open the main activity.
*/
private fun getNotificationIntent(context: Context): PendingIntent {
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.action = MainActivity.SHORTCUT_RECENTLY_UPDATED
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
}

View File

@ -1,11 +1,8 @@
package eu.kanade.tachiyomi.data.library
import android.app.Notification
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.os.Build
import android.os.IBinder
import android.os.PowerManager
@ -28,7 +25,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.*
import exh.LIBRARY_UPDATE_EXCLUDED_SOURCES
import rx.Observable
@ -73,12 +69,7 @@ class LibraryUpdateService(
NotificationReceiver.cancelLibraryUpdatePendingBroadcast(this)
}
/**
* Bitmap of the app for notifications.
*/
private val notificationBitmap by lazy {
BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
}
private val updateNotifier by lazy { LibraryUpdateNotifier(this) }
/**
* Cached progress notification to avoid creating a lot.
@ -86,7 +77,7 @@ class LibraryUpdateService(
private val progressNotification by lazy { NotificationCompat.Builder(this, Notifications.CHANNEL_LIBRARY)
.setContentTitle(getString(R.string.app_name))
.setSmallIcon(R.drawable.ic_refresh_white_24dp_img)
.setLargeIcon(notificationBitmap)
.setLargeIcon(updateNotifier.notificationBitmap)
.setOngoing(true)
.setOnlyAlertOnce(true)
.addAction(R.drawable.ic_clear_grey_24dp_img, getString(android.R.string.cancel), cancelIntent)
@ -319,7 +310,7 @@ class LibraryUpdateService(
// Notify result of the overall update.
.doOnCompleted {
if (newUpdates.isNotEmpty()) {
showResultNotification(newUpdates)
updateNotifier.showResultNotification(newUpdates)
if (downloadNew && hasDownloads) {
DownloadService.start(this)
}
@ -439,61 +430,10 @@ class LibraryUpdateService(
.build())
}
/**
* Shows the notification containing the result of the update done by the service.
*
* @param updates a list of manga with new updates.
*/
private fun showResultNotification(updates: List<Manga>) {
val newUpdates = updates.map { it.title.chop(45) }.toMutableSet()
// Append new chapters from a previous, existing notification
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val previousNotification = notificationManager.activeNotifications
.find { it.id == Notifications.ID_LIBRARY_RESULT }
if (previousNotification != null) {
val oldUpdates = previousNotification.notification.extras
.getString(Notification.EXTRA_BIG_TEXT)
if (!oldUpdates.isNullOrEmpty()) {
newUpdates += oldUpdates.split("\n")
}
}
}
notificationManager.notify(Notifications.ID_LIBRARY_RESULT, notification(Notifications.CHANNEL_LIBRARY) {
setSmallIcon(R.drawable.ic_book_white_24dp)
setLargeIcon(notificationBitmap)
setContentTitle(getString(R.string.notification_new_chapters))
if (newUpdates.size > 1) {
setContentText(getString(R.string.notification_new_chapters_text, newUpdates.size))
setStyle(NotificationCompat.BigTextStyle().bigText(newUpdates.joinToString("\n")))
setNumber(newUpdates.size)
} else {
setContentText(newUpdates.first())
}
priority = NotificationCompat.PRIORITY_HIGH
setContentIntent(getNotificationIntent())
setAutoCancel(true)
})
}
/**
* Cancels the progress notification.
*/
private fun cancelProgressNotification() {
notificationManager.cancel(Notifications.ID_LIBRARY_PROGRESS)
}
/**
* Returns an intent to open the main activity.
*/
private fun getNotificationIntent(): PendingIntent {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.action = MainActivity.SHORTCUT_RECENTLY_UPDATED
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
}

View File

@ -26,9 +26,9 @@ class EHentaiUpdateHelper(context: Context) {
/**
* @param chapters Cannot be an empty list!
*
* @return Pair<Accepted, Discarded>
* @return Triple<Accepted, Discarded, HasNew>
*/
fun findAcceptedRootAndDiscardOthers(sourceId: Long, chapters: List<Chapter>): Single<Pair<ChapterChain, List<ChapterChain>>> {
fun findAcceptedRootAndDiscardOthers(sourceId: Long, chapters: List<Chapter>): Single<Triple<ChapterChain, List<ChapterChain>, Boolean>> {
// Find other chains
val chainsObservable = Observable.merge(chapters.map { chapter ->
db.getChapters(chapter.url).asRxSingle().toObservable()
@ -62,6 +62,8 @@ class EHentaiUpdateHelper(context: Context) {
val chainsAsChapters = chains.flatMap { it.chapters }
if(toDiscard.isNotEmpty()) {
var new = false
// Copy chain chapters to curChapters
val newChapters = toDiscard
.flatMap { chain ->
@ -98,6 +100,7 @@ class EHentaiUpdateHelper(context: Context) {
existing.bookmark = existing.bookmark || chapter.bookmark
curChapters
} else if (chapter.date_upload > 0) { // Ignore chapters using the old system
new = true
curChapters + ChapterImpl().apply {
manga_id = accepted.manga.id
url = chapter.url
@ -145,8 +148,8 @@ class EHentaiUpdateHelper(context: Context) {
db.setMangaCategories(newCategories, rootsToMutate.map { it.manga })
}
newAccepted to toDiscard
} else accepted to emptyList()
Triple(newAccepted, toDiscard, new)
} else Triple(accepted, emptyList(), false)
}.toSingle()
}
}

View File

@ -15,6 +15,7 @@ import com.kizitonwose.time.hours
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.library.LibraryUpdateNotifier
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.source.SourceManager
@ -49,6 +50,8 @@ class EHentaiUpdateWorker: JobService(), CoroutineScope {
private val updateHelper: EHentaiUpdateHelper by injectLazy()
private val logger = XLog.tag("EHUpdater")
private val updateNotifier by lazy { LibraryUpdateNotifier(this) }
/**
* This method is called if the system has determined that you must stop execution of your job
* even before you've had a chance to call [.jobFinished].
@ -152,6 +155,7 @@ class EHentaiUpdateWorker: JobService(), CoroutineScope {
var failuresThisIteration = 0
var updatedThisIteration = 0
val updatedManga = mutableListOf<Manga>()
val modifiedThisIteration = mutableSetOf<Long>()
try {
@ -205,9 +209,13 @@ class EHentaiUpdateWorker: JobService(), CoroutineScope {
}
// Find accepted root and discard others
val (acceptedRoot, discardedRoots) =
val (acceptedRoot, discardedRoots, hasNew) =
updateHelper.findAcceptedRootAndDiscardOthers(manga.source, chapters).await()
if(hasNew && updatedManga.none { it.id == acceptedRoot.manga.id }) {
updatedManga += acceptedRoot.manga
}
modifiedThisIteration += acceptedRoot.manga.id!!
modifiedThisIteration += discardedRoots.map { it.manga.id!! }
updatedThisIteration++
@ -222,6 +230,8 @@ class EHentaiUpdateWorker: JobService(), CoroutineScope {
)
)
)
updateNotifier.showResultNotification(updatedManga)
}
}