From 7f115f2e83833d8e77956bf11fe3edd1f45d7f08 Mon Sep 17 00:00:00 2001 From: Jays2Kings Date: Mon, 17 Feb 2020 07:56:23 -0800 Subject: [PATCH] Group notifcations for Library updates (#2582) --- .../data/database/queries/ChapterQueries.kt | 8 ++ .../data/download/DownloadNotifier.kt | 49 ------- .../tachiyomi/data/download/Downloader.kt | 8 -- .../data/library/LibraryUpdateService.kt | 109 +++++++++++----- .../data/notification/NotificationReceiver.kt | 122 +++++++++++++++++- .../data/notification/Notifications.kt | 24 +++- .../kanade/tachiyomi/ui/main/MainActivity.kt | 5 + .../tachiyomi/ui/reader/ReaderActivity.kt | 17 ++- .../tachiyomi/ui/reader/ReaderPresenter.kt | 13 ++ .../RecentChaptersController.kt | 4 +- app/src/main/res/drawable/ic_tachi.xml | 19 +++ app/src/main/res/values/strings.xml | 13 +- 12 files changed, 280 insertions(+), 111 deletions(-) create mode 100644 app/src/main/res/drawable/ic_tachi.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt index c633e1d81..5d765d13b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt @@ -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() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt index 83badcefd..c0a632941 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt @@ -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 } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index e444ae4cf..e5e3bcfb8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -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) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt index ec3354c26..889f94fc4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt @@ -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() + val newUpdates = ArrayList>>() // list containing failed updates val failedUpdates = ArrayList() // 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) { @@ -444,39 +450,76 @@ class LibraryUpdateService( * * @param updates a list of manga with new updates. */ - private fun showResultNotification(updates: List) { - 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>>) { + val notifications = ArrayList>() + 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) - }) + } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index bca35b4a7..825310b50 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -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, 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, 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) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt index 1b3da06e8..b59b40dbf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt @@ -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) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 6961ff770..60b30cc2c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 2171a4395..f83aff55a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -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() { 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() { 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) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index 323813851..f9298ab60 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -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() + 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. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersController.kt index 5206e7ec9..eaaf86583 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersController.kt @@ -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(), */ 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 diff --git a/app/src/main/res/drawable/ic_tachi.xml b/app/src/main/res/drawable/ic_tachi.xml new file mode 100644 index 000000000..4ae06cc2f --- /dev/null +++ b/app/src/main/res/drawable/ic_tachi.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7a56ccb57..8deb6168e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -61,6 +61,7 @@ Sort down Downloaded Next unread + View chapters Start Stop Pause @@ -484,7 +485,14 @@ Update progress: %1$d/%2$d New chapters found - For %1$d titles + + For %d title + For %d titles + + + and %1$d more chapter. + and %1$d more chapters. + Failed to update cover Please add the manga to your library before doing this Sync canceled @@ -537,7 +545,8 @@ Common - Library + Updating Library Downloader + New Chapters