Add update notifications for EH/EXH galleries
This commit is contained in:
parent
14879c4466
commit
ac6dbbcd89
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.data.library
|
package eu.kanade.tachiyomi.data.library
|
||||||
|
|
||||||
import android.app.Notification
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.os.PowerManager
|
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.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
|
||||||
import eu.kanade.tachiyomi.util.*
|
import eu.kanade.tachiyomi.util.*
|
||||||
import exh.LIBRARY_UPDATE_EXCLUDED_SOURCES
|
import exh.LIBRARY_UPDATE_EXCLUDED_SOURCES
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
@ -73,12 +69,7 @@ class LibraryUpdateService(
|
|||||||
NotificationReceiver.cancelLibraryUpdatePendingBroadcast(this)
|
NotificationReceiver.cancelLibraryUpdatePendingBroadcast(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private val updateNotifier by lazy { LibraryUpdateNotifier(this) }
|
||||||
* Bitmap of the app for notifications.
|
|
||||||
*/
|
|
||||||
private val notificationBitmap by lazy {
|
|
||||||
BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cached progress notification to avoid creating a lot.
|
* 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)
|
private val progressNotification by lazy { NotificationCompat.Builder(this, Notifications.CHANNEL_LIBRARY)
|
||||||
.setContentTitle(getString(R.string.app_name))
|
.setContentTitle(getString(R.string.app_name))
|
||||||
.setSmallIcon(R.drawable.ic_refresh_white_24dp_img)
|
.setSmallIcon(R.drawable.ic_refresh_white_24dp_img)
|
||||||
.setLargeIcon(notificationBitmap)
|
.setLargeIcon(updateNotifier.notificationBitmap)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setOnlyAlertOnce(true)
|
.setOnlyAlertOnce(true)
|
||||||
.addAction(R.drawable.ic_clear_grey_24dp_img, getString(android.R.string.cancel), cancelIntent)
|
.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.
|
// Notify result of the overall update.
|
||||||
.doOnCompleted {
|
.doOnCompleted {
|
||||||
if (newUpdates.isNotEmpty()) {
|
if (newUpdates.isNotEmpty()) {
|
||||||
showResultNotification(newUpdates)
|
updateNotifier.showResultNotification(newUpdates)
|
||||||
if (downloadNew && hasDownloads) {
|
if (downloadNew && hasDownloads) {
|
||||||
DownloadService.start(this)
|
DownloadService.start(this)
|
||||||
}
|
}
|
||||||
@ -439,61 +430,10 @@ class LibraryUpdateService(
|
|||||||
.build())
|
.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.
|
* Cancels the progress notification.
|
||||||
*/
|
*/
|
||||||
private fun cancelProgressNotification() {
|
private fun cancelProgressNotification() {
|
||||||
notificationManager.cancel(Notifications.ID_LIBRARY_PROGRESS)
|
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,9 @@ class EHentaiUpdateHelper(context: Context) {
|
|||||||
/**
|
/**
|
||||||
* @param chapters Cannot be an empty list!
|
* @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
|
// Find other chains
|
||||||
val chainsObservable = Observable.merge(chapters.map { chapter ->
|
val chainsObservable = Observable.merge(chapters.map { chapter ->
|
||||||
db.getChapters(chapter.url).asRxSingle().toObservable()
|
db.getChapters(chapter.url).asRxSingle().toObservable()
|
||||||
@ -62,6 +62,8 @@ class EHentaiUpdateHelper(context: Context) {
|
|||||||
val chainsAsChapters = chains.flatMap { it.chapters }
|
val chainsAsChapters = chains.flatMap { it.chapters }
|
||||||
|
|
||||||
if(toDiscard.isNotEmpty()) {
|
if(toDiscard.isNotEmpty()) {
|
||||||
|
var new = false
|
||||||
|
|
||||||
// Copy chain chapters to curChapters
|
// Copy chain chapters to curChapters
|
||||||
val newChapters = toDiscard
|
val newChapters = toDiscard
|
||||||
.flatMap { chain ->
|
.flatMap { chain ->
|
||||||
@ -98,6 +100,7 @@ class EHentaiUpdateHelper(context: Context) {
|
|||||||
existing.bookmark = existing.bookmark || chapter.bookmark
|
existing.bookmark = existing.bookmark || chapter.bookmark
|
||||||
curChapters
|
curChapters
|
||||||
} else if (chapter.date_upload > 0) { // Ignore chapters using the old system
|
} else if (chapter.date_upload > 0) { // Ignore chapters using the old system
|
||||||
|
new = true
|
||||||
curChapters + ChapterImpl().apply {
|
curChapters + ChapterImpl().apply {
|
||||||
manga_id = accepted.manga.id
|
manga_id = accepted.manga.id
|
||||||
url = chapter.url
|
url = chapter.url
|
||||||
@ -145,8 +148,8 @@ class EHentaiUpdateHelper(context: Context) {
|
|||||||
db.setMangaCategories(newCategories, rootsToMutate.map { it.manga })
|
db.setMangaCategories(newCategories, rootsToMutate.map { it.manga })
|
||||||
}
|
}
|
||||||
|
|
||||||
newAccepted to toDiscard
|
Triple(newAccepted, toDiscard, new)
|
||||||
} else accepted to emptyList()
|
} else Triple(accepted, emptyList(), false)
|
||||||
}.toSingle()
|
}.toSingle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import com.kizitonwose.time.hours
|
|||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
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.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
@ -49,6 +50,8 @@ class EHentaiUpdateWorker: JobService(), CoroutineScope {
|
|||||||
private val updateHelper: EHentaiUpdateHelper by injectLazy()
|
private val updateHelper: EHentaiUpdateHelper by injectLazy()
|
||||||
private val logger = XLog.tag("EHUpdater")
|
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
|
* 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].
|
* even before you've had a chance to call [.jobFinished].
|
||||||
@ -152,6 +155,7 @@ class EHentaiUpdateWorker: JobService(), CoroutineScope {
|
|||||||
|
|
||||||
var failuresThisIteration = 0
|
var failuresThisIteration = 0
|
||||||
var updatedThisIteration = 0
|
var updatedThisIteration = 0
|
||||||
|
val updatedManga = mutableListOf<Manga>()
|
||||||
val modifiedThisIteration = mutableSetOf<Long>()
|
val modifiedThisIteration = mutableSetOf<Long>()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -205,9 +209,13 @@ class EHentaiUpdateWorker: JobService(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find accepted root and discard others
|
// Find accepted root and discard others
|
||||||
val (acceptedRoot, discardedRoots) =
|
val (acceptedRoot, discardedRoots, hasNew) =
|
||||||
updateHelper.findAcceptedRootAndDiscardOthers(manga.source, chapters).await()
|
updateHelper.findAcceptedRootAndDiscardOthers(manga.source, chapters).await()
|
||||||
|
|
||||||
|
if(hasNew && updatedManga.none { it.id == acceptedRoot.manga.id }) {
|
||||||
|
updatedManga += acceptedRoot.manga
|
||||||
|
}
|
||||||
|
|
||||||
modifiedThisIteration += acceptedRoot.manga.id!!
|
modifiedThisIteration += acceptedRoot.manga.id!!
|
||||||
modifiedThisIteration += discardedRoots.map { it.manga.id!! }
|
modifiedThisIteration += discardedRoots.map { it.manga.id!! }
|
||||||
updatedThisIteration++
|
updatedThisIteration++
|
||||||
@ -222,6 +230,8 @@ class EHentaiUpdateWorker: JobService(), CoroutineScope {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
updateNotifier.showResultNotification(updatedManga)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user