mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Add update notifications for EH/EXH galleries
This commit is contained in:
		@@ -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
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user