mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Group notifcations for Library updates (#2582)
This commit is contained in:
		| @@ -52,6 +52,14 @@ interface ChapterQueries : DbProvider { | ||||
|                     .build()) | ||||
|             .prepare() | ||||
|  | ||||
|     fun getChapter(url: String, mangaId: Long) = db.get() | ||||
|         .`object`(Chapter::class.java) | ||||
|         .withQuery(Query.builder() | ||||
|             .table(ChapterTable.TABLE) | ||||
|             .where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?") | ||||
|             .whereArgs(url, mangaId) | ||||
|             .build()) | ||||
|         .prepare() | ||||
|  | ||||
|     fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare() | ||||
|  | ||||
|   | ||||
| @@ -30,27 +30,11 @@ internal class DownloadNotifier(private val context: Context) { | ||||
|      */ | ||||
|     private var isDownloading = false | ||||
|  | ||||
|     /** | ||||
|      * The size of queue on start download. | ||||
|      */ | ||||
|     var initialQueueSize = 0 | ||||
|         set(value) { | ||||
|             if (value != 0) { | ||||
|                 isSingleChapter = (value == 1) | ||||
|             } | ||||
|             field = value | ||||
|         } | ||||
|  | ||||
|     /** | ||||
|      * Updated when error is thrown | ||||
|      */ | ||||
|     var errorThrown = false | ||||
|  | ||||
|     /** | ||||
|      * Updated when only single page is downloaded | ||||
|      */ | ||||
|     var isSingleChapter = false | ||||
|  | ||||
|     /** | ||||
|      * Updated when paused | ||||
|      */ | ||||
| @@ -144,39 +128,6 @@ internal class DownloadNotifier(private val context: Context) { | ||||
|  | ||||
|         // Reset initial values | ||||
|         isDownloading = false | ||||
|         initialQueueSize = 0 | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called when chapter is downloaded. | ||||
|      * | ||||
|      * @param download download object containing download information. | ||||
|      */ | ||||
|     fun onDownloadCompleted(download: Download, queue: DownloadQueue) { | ||||
|         // Check if last download | ||||
|         if (!queue.isEmpty()) { | ||||
|             return | ||||
|         } | ||||
|         // Create notification. | ||||
|         with(notificationBuilder) { | ||||
|             val title = download.manga.title.chop(15) | ||||
|             val quotedTitle = Pattern.quote(title) | ||||
|             val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "") | ||||
|             setContentTitle("$title - $chapter".chop(30)) | ||||
|             setContentText(context.getString(R.string.update_check_notification_download_complete)) | ||||
|             setSmallIcon(android.R.drawable.stat_sys_download_done) | ||||
|             setAutoCancel(true) | ||||
|             clearActions() | ||||
|             setContentIntent(NotificationReceiver.openChapterPendingBroadcast(context, download.manga, download.chapter)) | ||||
|             setProgress(0, 0, false) | ||||
|         } | ||||
|  | ||||
|         // Show notification. | ||||
|         notificationBuilder.show() | ||||
|  | ||||
|         // Reset initial values | ||||
|         isDownloading = false | ||||
|         initialQueueSize = 0 | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -126,8 +126,6 @@ class Downloader( | ||||
|             if (notifier.paused) { | ||||
|                 notifier.paused = false | ||||
|                 notifier.onDownloadPaused() | ||||
|             } else if (notifier.isSingleChapter && !notifier.errorThrown) { | ||||
|                 notifier.isSingleChapter = false | ||||
|             } else { | ||||
|                 notifier.dismiss() | ||||
|             } | ||||
| @@ -229,9 +227,6 @@ class Downloader( | ||||
|         if (chaptersToQueue.isNotEmpty()) { | ||||
|             queue.addAll(chaptersToQueue) | ||||
|  | ||||
|             // Initialize queue size. | ||||
|             notifier.initialQueueSize = queue.size | ||||
|  | ||||
|             if (isRunning) { | ||||
|                 // Send the list of downloads to the downloader. | ||||
|                 downloadsRelay.call(chaptersToQueue) | ||||
| @@ -428,9 +423,6 @@ class Downloader( | ||||
|             queue.remove(download) | ||||
|         } | ||||
|         if (areAllDownloadsFinished()) { | ||||
|             if (notifier.isSingleChapter && !notifier.errorThrown) { | ||||
|                 notifier.onDownloadCompleted(download, queue) | ||||
|             } | ||||
|             DownloadService.stop(context) | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -10,6 +10,10 @@ import android.os.Build | ||||
| import android.os.IBinder | ||||
| import android.os.PowerManager | ||||
| import androidx.core.app.NotificationCompat | ||||
| import androidx.core.app.NotificationCompat.GROUP_ALERT_SUMMARY | ||||
| import androidx.core.app.NotificationManagerCompat | ||||
| import androidx.core.content.ContextCompat | ||||
| import com.bumptech.glide.Glide | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| @@ -202,9 +206,9 @@ class LibraryUpdateService( | ||||
|      * @return the start value of the command. | ||||
|      */ | ||||
|     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { | ||||
|         if (intent == null) return Service.START_NOT_STICKY | ||||
|         if (intent == null) return START_NOT_STICKY | ||||
|         val target = intent.getSerializableExtra(KEY_TARGET) as? Target | ||||
|                 ?: return Service.START_NOT_STICKY | ||||
|                 ?: return START_NOT_STICKY | ||||
|  | ||||
|         // Unsubscribe from any previous subscription if needed. | ||||
|         subscription?.unsubscribe() | ||||
| @@ -276,7 +280,7 @@ class LibraryUpdateService( | ||||
|         // Initialize the variables holding the progress of the updates. | ||||
|         val count = AtomicInteger(0) | ||||
|         // List containing new updates | ||||
|         val newUpdates = ArrayList<Manga>() | ||||
|         val newUpdates = ArrayList<Pair<LibraryManga, Array<Chapter>>>() | ||||
|         // list containing failed updates | ||||
|         val failedUpdates = ArrayList<Manga>() | ||||
|         // List containing categories that get included in downloads. | ||||
| @@ -309,7 +313,8 @@ class LibraryUpdateService( | ||||
|                                 } | ||||
|                             } | ||||
|                             // Convert to the manga that contains new chapters. | ||||
|                             .map { manga } | ||||
|                             .map { Pair(manga, (it.first.sortedByDescending { ch -> ch | ||||
|                                 .source_order }.toTypedArray())) } | ||||
|                 } | ||||
|                 // Add manga with new chapters to the list. | ||||
|                 .doOnNext { manga -> | ||||
| @@ -331,6 +336,7 @@ class LibraryUpdateService( | ||||
|  | ||||
|                     cancelProgressNotification() | ||||
|                 } | ||||
|                 .map { manga -> manga.first } | ||||
|     } | ||||
|  | ||||
|     fun downloadChapters(manga: Manga, chapters: List<Chapter>) { | ||||
| @@ -444,39 +450,76 @@ class LibraryUpdateService( | ||||
|      * | ||||
|      * @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") | ||||
|     private fun showResultNotification(updates: List<Pair<Manga, Array<Chapter>>>) { | ||||
|         val notifications = ArrayList<Pair<Notification, Int>>() | ||||
|         updates.forEach { | ||||
|             val manga = it.first | ||||
|             val chapters = it.second | ||||
|             val chapterNames = chapters.map { chapter -> chapter.name }.toSet() | ||||
|             notifications.add(Pair(notification(Notifications.CHANNEL_NEW_CHAPTERS) { | ||||
|                 setSmallIcon(R.drawable.ic_tachi) | ||||
|                 try { | ||||
|                     val icon = Glide.with(this@LibraryUpdateService) | ||||
|                         .asBitmap().load(manga).dontTransform().centerCrop().circleCrop() | ||||
|                         .override(256, 256).submit().get() | ||||
|                     setLargeIcon(icon) | ||||
|                 } | ||||
|             } | ||||
|                 catch (e: Exception) { } | ||||
|                 setGroupAlertBehavior(GROUP_ALERT_SUMMARY) | ||||
|                 setContentTitle(manga.title) | ||||
|                 val chaptersNames = if (chapterNames.size > 5) { | ||||
|                     "${chapterNames.take(4).joinToString(", ")}, " + | ||||
|                         resources.getQuantityString(R.plurals.notification_and_n_more, | ||||
|                             (chapterNames.size - 4), (chapterNames.size - 4)) | ||||
|                 } else chapterNames.joinToString(", ") | ||||
|                 setContentText(chaptersNames) | ||||
|                 setStyle(NotificationCompat.BigTextStyle().bigText(chaptersNames)) | ||||
|                 priority = NotificationCompat.PRIORITY_HIGH | ||||
|                 setGroup(Notifications.GROUP_NEW_CHAPTERS) | ||||
|                 setContentIntent( | ||||
|                     NotificationReceiver.openChapterPendingActivity( | ||||
|                         this@LibraryUpdateService, manga, chapters.first() | ||||
|                     ) | ||||
|                 ) | ||||
|                 addAction(R.drawable.ic_glasses_black_24dp, getString(R.string.action_mark_as_read), | ||||
|                     NotificationReceiver.markAsReadPendingBroadcast(this@LibraryUpdateService, | ||||
|                         manga, chapters, Notifications.ID_NEW_CHAPTERS)) | ||||
|                 addAction(R.drawable.ic_book_white_24dp, getString(R.string.action_view_chapters), | ||||
|                     NotificationReceiver.openChapterPendingActivity(this@LibraryUpdateService, | ||||
|                         manga, Notifications.ID_NEW_CHAPTERS)) | ||||
|                 setAutoCancel(true) | ||||
|             }, manga.id.hashCode())) | ||||
|         } | ||||
|  | ||||
|         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()) | ||||
|         NotificationManagerCompat.from(this).apply { | ||||
|  | ||||
|             notify(Notifications.ID_NEW_CHAPTERS, notification(Notifications.CHANNEL_NEW_CHAPTERS) { | ||||
|                 setSmallIcon(R.drawable.ic_tachi) | ||||
|                 setLargeIcon(notificationBitmap) | ||||
|                 setContentTitle(getString(R.string.notification_new_chapters)) | ||||
|                 if (updates.size > 1) { | ||||
|                     setContentText(resources.getQuantityString(R.plurals | ||||
|                         .notification_new_chapters_text, | ||||
|                         updates.size, updates.size)) | ||||
|                     setStyle(NotificationCompat.BigTextStyle().bigText(updates.joinToString("\n") { | ||||
|                         it.first.title.chop(45) | ||||
|                     })) | ||||
|                 } | ||||
|                 else { | ||||
|                     setContentText(updates.first().first.title.chop(45)) | ||||
|                 } | ||||
|                 priority = NotificationCompat.PRIORITY_HIGH | ||||
|                 setGroup(Notifications.GROUP_NEW_CHAPTERS) | ||||
|                 setGroupAlertBehavior(GROUP_ALERT_SUMMARY) | ||||
|                 setGroupSummary(true) | ||||
|                 setContentIntent(getNotificationIntent()) | ||||
|                 setAutoCancel(true) | ||||
|             }) | ||||
|  | ||||
|             notifications.forEach { | ||||
|                 notify(it.second, it.first) | ||||
|             } | ||||
|             priority = NotificationCompat.PRIORITY_HIGH | ||||
|             setContentIntent(getNotificationIntent()) | ||||
|             setAutoCancel(true) | ||||
|         }) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import android.app.PendingIntent | ||||
| import android.content.BroadcastReceiver | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.os.Build | ||||
| import android.os.Handler | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| @@ -12,11 +13,17 @@ import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.download.DownloadManager | ||||
| import eu.kanade.tachiyomi.data.download.DownloadService | ||||
| import eu.kanade.tachiyomi.data.library.LibraryUpdateService | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.source.SourceManager | ||||
| import eu.kanade.tachiyomi.ui.main.MainActivity | ||||
| import eu.kanade.tachiyomi.ui.manga.MangaController | ||||
| import eu.kanade.tachiyomi.ui.reader.ReaderActivity | ||||
| import eu.kanade.tachiyomi.util.storage.DiskUtil | ||||
| import eu.kanade.tachiyomi.util.storage.getUriCompat | ||||
| import eu.kanade.tachiyomi.util.system.notificationManager | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| import uy.kohesive.injekt.injectLazy | ||||
| import java.io.File | ||||
| import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID | ||||
| @@ -60,6 +67,15 @@ class NotificationReceiver : BroadcastReceiver() { | ||||
|                 openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1), | ||||
|                         intent.getLongExtra(EXTRA_CHAPTER_ID, -1)) | ||||
|             } | ||||
|             ACTION_MARK_AS_READ -> { | ||||
|                 val notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1) | ||||
|                 if (notificationId > -1) dismissNotification( | ||||
|                     context, notificationId, intent.getIntExtra(EXTRA_GROUP_ID, 0) | ||||
|                 ) | ||||
|                 val urls = intent.getStringArrayExtra(EXTRA_CHAPTER_URL) ?: return | ||||
|                 val mangaId = intent.getLongExtra(EXTRA_MANGA_ID, -1) | ||||
|                 markAsRead(urls, mangaId) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -104,7 +120,6 @@ class NotificationReceiver : BroadcastReceiver() { | ||||
|         val db = DatabaseHelper(context) | ||||
|         val manga = db.getManga(mangaId).executeAsBlocking() | ||||
|         val chapter = db.getChapter(chapterId).executeAsBlocking() | ||||
|  | ||||
|         if (manga != null && chapter != null) { | ||||
|             val intent = ReaderActivity.newIntent(context, manga, chapter).apply { | ||||
|                 flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP | ||||
| @@ -143,6 +158,28 @@ class NotificationReceiver : BroadcastReceiver() { | ||||
|         Handler().post { dismissNotification(context, notificationId) } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method called when user wants to mark as read | ||||
|      * | ||||
|      * @param context context of application | ||||
|      * @param notificationId id of notification | ||||
|      */ | ||||
|     private fun markAsRead(chapterUrls: Array<String>, mangaId: Long) { | ||||
|         val db: DatabaseHelper = Injekt.get() | ||||
|         chapterUrls.forEach { | ||||
|             val chapter = db.getChapter(it, mangaId).executeAsBlocking() ?: return | ||||
|             chapter.read = true | ||||
|             db.updateChapterProgress(chapter).executeAsBlocking() | ||||
|             val preferences: PreferencesHelper = Injekt.get() | ||||
|             if (preferences.removeAfterMarkedAsRead()) { | ||||
|                 val manga = db.getManga(mangaId).executeAsBlocking() ?: return | ||||
|                 val sourceManager: SourceManager = Injekt.get() | ||||
|                 val source = sourceManager.get(manga.source) ?: return | ||||
|                 downloadManager.deleteChapters(listOf(chapter), manga, source) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         private const val NAME = "NotificationReceiver" | ||||
|  | ||||
| @@ -155,6 +192,9 @@ class NotificationReceiver : BroadcastReceiver() { | ||||
|         // Called to cancel library update. | ||||
|         private const val ACTION_CANCEL_LIBRARY_UPDATE = "$ID.$NAME.CANCEL_LIBRARY_UPDATE" | ||||
|  | ||||
|         // Called to mark as read | ||||
|         private const val ACTION_MARK_AS_READ = "$ID.$NAME.MARK_AS_READ" | ||||
|  | ||||
|         // Called to open chapter | ||||
|         private const val ACTION_OPEN_CHAPTER = "$ID.$NAME.ACTION_OPEN_CHAPTER" | ||||
|  | ||||
| @@ -179,12 +219,18 @@ class NotificationReceiver : BroadcastReceiver() { | ||||
|         // Value containing notification id. | ||||
|         private const val EXTRA_NOTIFICATION_ID = "$ID.$NAME.NOTIFICATION_ID" | ||||
|  | ||||
|         // Value containing group id. | ||||
|         private const val EXTRA_GROUP_ID = "$ID.$NAME.EXTRA_GROUP_ID" | ||||
|  | ||||
|         // Value containing manga id. | ||||
|         private const val EXTRA_MANGA_ID = "$ID.$NAME.EXTRA_MANGA_ID" | ||||
|  | ||||
|         // Value containing chapter id. | ||||
|         private const val EXTRA_CHAPTER_ID = "$ID.$NAME.EXTRA_CHAPTER_ID" | ||||
|  | ||||
|         // Value containing chapter url. | ||||
|         private const val EXTRA_CHAPTER_URL = "$ID.$NAME.EXTRA_CHAPTER_URL" | ||||
|  | ||||
|         /** | ||||
|          * Returns a [PendingIntent] that resumes the download of a chapter | ||||
|          * | ||||
| @@ -246,6 +292,32 @@ class NotificationReceiver : BroadcastReceiver() { | ||||
|             return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Returns [PendingIntent] that starts a service which dismissed the notification | ||||
|          * | ||||
|          * @param context context of application | ||||
|          * @param notificationId id of notification | ||||
|          * @return [PendingIntent] | ||||
|          */ | ||||
|         internal fun dismissNotification(context: Context, notificationId: Int, groupId: Int? = | ||||
|             null) { | ||||
|             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { | ||||
|                 val groupKey = context.notificationManager.activeNotifications.find { | ||||
|                     it.id == notificationId | ||||
|                 }?.groupKey | ||||
|                 if (groupId != null && groupId != 0 && groupKey != null && groupKey.isNotEmpty()) { | ||||
|                     val notifications = context.notificationManager.activeNotifications.filter { | ||||
|                         it.groupKey == groupKey | ||||
|                     } | ||||
|                     if (notifications.size == 2) { | ||||
|                         context.notificationManager.cancel(groupId) | ||||
|                         return | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             context.notificationManager.cancel(notificationId) | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Returns [PendingIntent] that starts a service which cancels the notification and starts a share activity | ||||
|          * | ||||
| @@ -281,19 +353,55 @@ class NotificationReceiver : BroadcastReceiver() { | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Returns [PendingIntent] that start a reader activity containing chapter. | ||||
|          * Returns [PendingIntent] that starts a reader activity containing chapter. | ||||
|          * | ||||
|          * @param context context of application | ||||
|          * @param manga manga of chapter | ||||
|          * @param chapter chapter that needs to be opened | ||||
|          */ | ||||
|         internal fun openChapterPendingBroadcast(context: Context, manga: Manga, chapter: Chapter): PendingIntent { | ||||
|             val intent = Intent(context, NotificationReceiver::class.java).apply { | ||||
|                 action = ACTION_OPEN_CHAPTER | ||||
|         internal fun openChapterPendingActivity(context: Context, manga: Manga, chapter: | ||||
|         Chapter): PendingIntent { | ||||
|             val newIntent = ReaderActivity.newIntent(context, manga, chapter) | ||||
|             return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent | ||||
|                 .FLAG_UPDATE_CURRENT) | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Returns [PendingIntent] that opens the manga info controller. | ||||
|          * | ||||
|          * @param context context of application | ||||
|          * @param manga manga of chapter | ||||
|          */ | ||||
|         internal fun openChapterPendingActivity(context: Context, manga: Manga, groupId: Int): | ||||
|             PendingIntent { | ||||
|             val newIntent = | ||||
|                 Intent(context, MainActivity::class.java).setAction(MainActivity.SHORTCUT_MANGA) | ||||
|                     .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) | ||||
|                     .putExtra(MangaController.MANGA_EXTRA, manga.id) | ||||
|                     .putExtra("notificationId", manga.id.hashCode()) | ||||
|                     .putExtra("groupId", groupId) | ||||
|             return PendingIntent.getActivity( | ||||
|                 context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Returns [PendingIntent] that marks a chapter as read and deletes it if preferred | ||||
|          * | ||||
|          * @param context context of application | ||||
|          * @param manga manga of chapter | ||||
|          */ | ||||
|         internal fun markAsReadPendingBroadcast(context: Context, manga: Manga, chapters: | ||||
|             Array<Chapter>, groupId: Int): | ||||
|             PendingIntent { | ||||
|             val newIntent = Intent(context, NotificationReceiver::class.java).apply { | ||||
|                 action = ACTION_MARK_AS_READ | ||||
|                 putExtra(EXTRA_CHAPTER_URL, chapters.map { it.url }.toTypedArray()) | ||||
|                 putExtra(EXTRA_MANGA_ID, manga.id) | ||||
|                 putExtra(EXTRA_CHAPTER_ID, chapter.id) | ||||
|                 putExtra(EXTRA_NOTIFICATION_ID, manga.id.hashCode()) | ||||
|                 putExtra(EXTRA_GROUP_ID, groupId) | ||||
|             } | ||||
|             return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) | ||||
|             return PendingIntent.getBroadcast(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT) | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|   | ||||
| @@ -23,15 +23,21 @@ object Notifications { | ||||
|      * Notification channel and ids used by the library updater. | ||||
|      */ | ||||
|     const val CHANNEL_LIBRARY = "library_channel" | ||||
|     const val ID_LIBRARY_PROGRESS = 101 | ||||
|     const val ID_LIBRARY_RESULT = 102 | ||||
|     const val ID_LIBRARY_PROGRESS = -101 | ||||
|  | ||||
|     /** | ||||
|      * Notification channel and ids used by the downloader. | ||||
|      */ | ||||
|     const val CHANNEL_DOWNLOADER = "downloader_channel" | ||||
|     const val ID_DOWNLOAD_CHAPTER = 201 | ||||
|     const val ID_DOWNLOAD_CHAPTER_ERROR = 202 | ||||
|     const val ID_DOWNLOAD_CHAPTER = -201 | ||||
|     const val ID_DOWNLOAD_CHAPTER_ERROR = -202 | ||||
|  | ||||
|     /** | ||||
|      * Notification channel and ids used by the library updater. | ||||
|      */ | ||||
|     const val CHANNEL_NEW_CHAPTERS = "new_chapters_channel" | ||||
|     const val ID_NEW_CHAPTERS = -301 | ||||
|     const val GROUP_NEW_CHAPTERS = "eu.kanade.tachiyomi.NEW_CHAPTERS" | ||||
|  | ||||
|     /** | ||||
|      * Creates the notification channels introduced in Android Oreo. | ||||
| @@ -45,9 +51,15 @@ object Notifications { | ||||
|                 NotificationChannel(CHANNEL_COMMON, context.getString(R.string.channel_common), | ||||
|                         NotificationManager.IMPORTANCE_LOW), | ||||
|                 NotificationChannel(CHANNEL_LIBRARY, context.getString(R.string.channel_library), | ||||
|                         NotificationManager.IMPORTANCE_LOW), | ||||
|                         NotificationManager.IMPORTANCE_LOW).apply { | ||||
|                     setShowBadge(false) | ||||
|                 }, | ||||
|                 NotificationChannel(CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader), | ||||
|                         NotificationManager.IMPORTANCE_LOW) | ||||
|                         NotificationManager.IMPORTANCE_LOW).apply { | ||||
|                     setShowBadge(false) | ||||
|                 }, | ||||
|                 NotificationChannel(CHANNEL_NEW_CHAPTERS, context.getString(R.string.channel_new_chapters), | ||||
|                         NotificationManager.IMPORTANCE_DEFAULT) | ||||
|         ) | ||||
|         context.notificationManager.createNotificationChannels(channels) | ||||
|     } | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import androidx.drawerlayout.widget.DrawerLayout | ||||
| import com.bluelinelabs.conductor.* | ||||
| import eu.kanade.tachiyomi.Migrations | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.notification.NotificationReceiver | ||||
| import eu.kanade.tachiyomi.ui.base.activity.BaseActivity | ||||
| import eu.kanade.tachiyomi.ui.base.controller.* | ||||
| import eu.kanade.tachiyomi.ui.catalogue.CatalogueController | ||||
| @@ -136,6 +137,10 @@ class MainActivity : BaseActivity() { | ||||
|     } | ||||
|  | ||||
|     private fun handleIntentAction(intent: Intent): Boolean { | ||||
|         val notificationId = intent.getIntExtra("notificationId", -1) | ||||
|         if (notificationId > -1) NotificationReceiver.dismissNotification( | ||||
|             applicationContext, notificationId, intent.getIntExtra("groupId", 0) | ||||
|         ) | ||||
|         when (intent.action) { | ||||
|             SHORTCUT_LIBRARY -> setSelectedDrawerItem(R.id.nav_drawer_library) | ||||
|             SHORTCUT_RECENTLY_UPDATED -> setSelectedDrawerItem(R.id.nav_drawer_recent_updates) | ||||
|   | ||||
| @@ -19,6 +19,8 @@ import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Chapter | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.notification.NotificationReceiver | ||||
| import eu.kanade.tachiyomi.data.notification.Notifications | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.preference.getOrDefault | ||||
| import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity | ||||
| @@ -104,10 +106,14 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() { | ||||
|         const val VERTICAL = 3 | ||||
|         const val WEBTOON = 4 | ||||
|  | ||||
|         fun newIntent(context: Context, manga: Manga, chapter: Chapter): Intent { | ||||
|         fun newIntent(context: Context, manga: Manga, chapter: Chapter): | ||||
|             Intent { | ||||
|             val intent = Intent(context, ReaderActivity::class.java) | ||||
|             intent.putExtra("manga", manga.id) | ||||
|             intent.putExtra("chapter", chapter.id) | ||||
|             // chapters just added from library updates don't have an id yet | ||||
|             intent.putExtra("chapterUrl", chapter.url) | ||||
|             intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) | ||||
|             return intent | ||||
|         } | ||||
|     } | ||||
| @@ -126,13 +132,14 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() { | ||||
|         if (presenter.needsInit()) { | ||||
|             val manga = intent.extras!!.getLong("manga", -1) | ||||
|             val chapter = intent.extras!!.getLong("chapter", -1) | ||||
|  | ||||
|             if (manga == -1L || chapter == -1L) { | ||||
|             val chapterUrl = intent.extras!!.getString("chapterUrl", "") | ||||
|             if (manga == -1L || chapterUrl == "" && chapter == -1L) { | ||||
|                 finish() | ||||
|                 return | ||||
|             } | ||||
|  | ||||
|             presenter.init(manga, chapter) | ||||
|             NotificationReceiver.dismissNotification(this, manga.hashCode(), Notifications.ID_NEW_CHAPTERS) | ||||
|             if (chapter > -1) presenter.init(manga, chapter) | ||||
|             else presenter.init(manga, chapterUrl) | ||||
|         } | ||||
|  | ||||
|         if (savedState != null) { | ||||
|   | ||||
| @@ -185,6 +185,19 @@ class ReaderPresenter( | ||||
|                 }, ReaderActivity::setInitialChapterError) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Initializes this presenter with the given [mangaId] and [chapterUrl]. This method will | ||||
|      * fetch the manga from the database and initialize the initial chapter. | ||||
|      */ | ||||
|     fun init(mangaId: Long, chapterUrl: String) { | ||||
|         if (!needsInit()) return | ||||
|         val context = Injekt.get<Application>() | ||||
|         val db = DatabaseHelper(context) | ||||
|         val chapterId = db.getChapter(chapterUrl, mangaId).executeAsBlocking()?.id | ||||
|         if (chapterId != null) | ||||
|             init(mangaId, chapterId) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Initializes this presenter with the given [manga] and [initialChapterId]. This method will | ||||
|      * set the chapter loader, view subscriptions and trigger an initial load. | ||||
|   | ||||
| @@ -13,12 +13,14 @@ import eu.davidea.flexibleadapter.items.IFlexible | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.download.model.Download | ||||
| import eu.kanade.tachiyomi.data.library.LibraryUpdateService | ||||
| import eu.kanade.tachiyomi.data.notification.Notifications | ||||
| import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController | ||||
| import eu.kanade.tachiyomi.ui.base.controller.NucleusController | ||||
| import eu.kanade.tachiyomi.ui.base.controller.popControllerWithTag | ||||
| import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction | ||||
| import eu.kanade.tachiyomi.ui.manga.MangaController | ||||
| import eu.kanade.tachiyomi.ui.reader.ReaderActivity | ||||
| import eu.kanade.tachiyomi.util.system.notificationManager | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| import kotlinx.android.synthetic.main.recent_chapters_controller.empty_view | ||||
| import kotlinx.android.synthetic.main.recent_chapters_controller.recycler | ||||
| @@ -68,7 +70,7 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(), | ||||
|      */ | ||||
|     override fun onViewCreated(view: View) { | ||||
|         super.onViewCreated(view) | ||||
|  | ||||
|         view.context.notificationManager.cancel(Notifications.ID_NEW_CHAPTERS) | ||||
|         // Init RecyclerView and adapter | ||||
|         val layoutManager = LinearLayoutManager(view.context) | ||||
|         recycler.layoutManager = layoutManager | ||||
|   | ||||
		Reference in New Issue
	
	Block a user