From 24d22459726fca09e6ed0659a3137aa981d90b87 Mon Sep 17 00:00:00 2001 From: Jay Date: Wed, 6 Nov 2019 00:26:30 -0800 Subject: [PATCH] Added "Mark as read" and "View chapters" actions to updates notification --- .../data/library/LibraryUpdateService.kt | 8 +- .../data/notification/NotificationReceiver.kt | 105 +++++++++++++++++- .../kanade/tachiyomi/ui/main/MainActivity.kt | 5 + .../tachiyomi/ui/manga/MangaController.kt | 13 ++- app/src/main/res/values/strings.xml | 2 +- build.gradle | 2 +- 6 files changed, 126 insertions(+), 9 deletions(-) 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 b094d39604..0dab6ac0b5 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 @@ -311,7 +311,7 @@ class LibraryUpdateService( } } // Convert to the manga that contains new chapters. - .map { Pair(manga, (it.first.minBy { ch -> ch.chapter_number }!!)) } + .map { Pair(manga, (it.first.maxBy { ch -> ch.source_order }!!)) } } // Add manga with new chapters to the list. .doOnNext { manga -> @@ -470,6 +470,12 @@ class LibraryUpdateService( this@LibraryUpdateService, manga, chapter ) ) + addAction(R.drawable.ic_in_library_24dp, getString(R.string.action_mark_as_read), + NotificationReceiver.markAsReadPendingBroadcast(this@LibraryUpdateService, + manga, chapter, Notifications.GROUP_NEW_CHAPTERS)) + addAction(R.drawable.ic_glasses_black_24dp, getString(R.string.action_view_chapters), + NotificationReceiver.openChapterPendingActivity(this@LibraryUpdateService, + manga, Notifications.GROUP_NEW_CHAPTERS)) setAutoCancel(true) }, manga.id.hashCode())) } 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 d0652895b3..38aaedf86d 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 @@ -2,16 +2,13 @@ package eu.kanade.tachiyomi.data.notification import android.app.Activity import android.app.KeyguardManager -import android.app.Notification import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.ClipData import android.content.Context import android.content.Intent import android.os.Build -import android.os.Bundle import android.os.Handler -import androidx.appcompat.app.AppCompatActivity import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Chapter @@ -19,11 +16,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.DiskUtil import eu.kanade.tachiyomi.util.getUriCompat import eu.kanade.tachiyomi.util.notificationManager import eu.kanade.tachiyomi.util.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 @@ -67,6 +70,14 @@ 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.getStringExtra(EXTRA_GROUP_ID) + ) + val url = intent.getStringExtra(EXTRA_CHAPTER_URL) ?: return + markAsRead(url) + } } } @@ -151,6 +162,27 @@ class NotificationReceiver : BroadcastReceiver() { Handler().post { dismissNotification(context, notificationId) } } + /** + * Method called when user wants to stop a library update + * + * @param context context of application + * @param notificationId id of notification + */ + private fun markAsRead(chapterUrl: String) { + val db: DatabaseHelper = Injekt.get() + val chapter = db.getChapter(chapterUrl).executeAsBlocking() ?: return + chapter.read = true + db.updateChapterProgress(chapter).executeAsBlocking() + val preferences: PreferencesHelper = Injekt.get() + if (preferences.removeAfterMarkedAsRead()) { + val mangaId = chapter.manga_id ?: return + 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" @@ -163,6 +195,9 @@ class NotificationReceiver : BroadcastReceiver() { // Called to cancel library update. private const val ACTION_CANCEL_LIBRARY_UPDATE = "$ID.$NAME.CANCEL_LIBRARY_UPDATE" + // Called to cancel library update. + 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" @@ -187,12 +222,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 * @@ -254,6 +295,25 @@ 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: String? + = null) { + context.notificationManager.cancel(notificationId) + if (groupId != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + val notifications = context.notificationManager.activeNotifications.filter { it + .groupKey.contains(groupId) } + if (notifications.size == 1) { + context.notificationManager.cancel(notifications.first().id) + } + } + } + /** * Returns [PendingIntent] that starts a service which cancels the notification and starts a share activity * @@ -294,7 +354,7 @@ 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 @@ -307,6 +367,43 @@ class NotificationReceiver : BroadcastReceiver() { .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: String): + 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, chapter: + Chapter, groupId: String): + PendingIntent { + val newIntent = Intent(context, NotificationReceiver::class.java).apply { + action = ACTION_MARK_AS_READ + putExtra(EXTRA_CHAPTER_URL, chapter.url) + putExtra(EXTRA_NOTIFICATION_ID, manga.id.hashCode()) + putExtra(EXTRA_GROUP_ID, groupId) + } + return PendingIntent.getBroadcast(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT) + } + /** * Returns [PendingIntent] that starts a service which stops the library update * 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 766cb21075..72f23bebc0 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 @@ -26,6 +26,7 @@ import android.widget.LinearLayout 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.data.preference.PreferencesHelper import eu.kanade.tachiyomi.ui.base.activity.BaseActivity import eu.kanade.tachiyomi.ui.base.controller.* @@ -221,6 +222,10 @@ class MainActivity : BaseActivity() { } private fun handleIntentAction(intent: Intent): Boolean { + val notificationId = intent.getIntExtra("notificationId", -1) + if (notificationId > -1) NotificationReceiver.dismissNotification( + applicationContext, notificationId, intent.getStringExtra("groupId") + ) 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/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index 326c61dfae..25f1583589 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -1,6 +1,9 @@ package eu.kanade.tachiyomi.ui.manga import android.Manifest.permission.WRITE_EXTERNAL_STORAGE +import android.app.NotificationManager +import android.content.Context +import android.content.Intent import android.os.Bundle import com.google.android.material.tabs.TabLayout import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat @@ -19,6 +22,7 @@ import com.jakewharton.rxrelay.PublishRelay import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager @@ -62,8 +66,13 @@ class MangaController : RxController, TabbedController { constructor(mangaId: Long) : this( Injekt.get().getManga(mangaId).executeAsBlocking()) - @Suppress("unused") - constructor(bundle: Bundle) : this(bundle.getLong(MANGA_EXTRA)) + constructor(bundle: Bundle) : this(bundle.getLong(MANGA_EXTRA)) { + val notificationId = bundle.getInt("notificationId", -1) + val context = applicationContext ?: return + if (notificationId > -1) NotificationReceiver.dismissNotification( + context, notificationId, bundle.getString("groupId", "") + ) + } var manga: Manga? = null private set diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d8ab319da5..bbee6bdecc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -62,7 +62,7 @@ Sort down Downloaded Next unread - Start Reading + View chapters Start Stop Pause diff --git a/build.gradle b/build.gradle index 11be8ba6c6..493af30669 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.1' + classpath 'com.android.tools.build:gradle:3.5.2' classpath 'com.github.ben-manes:gradle-versions-plugin:0.22.0' classpath 'com.github.zellius:android-shortcut-gradle-plugin:0.1.2' classpath 'com.google.gms:google-services:4.3.2'