Added "Mark as read" and "View chapters" actions to updates notification

This commit is contained in:
Jay 2019-11-06 00:26:30 -08:00
parent 7c52c8306a
commit 24d2245972
6 changed files with 126 additions and 9 deletions

View File

@ -311,7 +311,7 @@ class LibraryUpdateService(
} }
} }
// Convert to the manga that contains new chapters. // 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. // Add manga with new chapters to the list.
.doOnNext { manga -> .doOnNext { manga ->
@ -470,6 +470,12 @@ class LibraryUpdateService(
this@LibraryUpdateService, manga, chapter 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) setAutoCancel(true)
}, manga.id.hashCode())) }, manga.id.hashCode()))
} }

View File

@ -2,16 +2,13 @@ package eu.kanade.tachiyomi.data.notification
import android.app.Activity import android.app.Activity
import android.app.KeyguardManager import android.app.KeyguardManager
import android.app.Notification
import android.app.PendingIntent import android.app.PendingIntent
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.ClipData import android.content.ClipData
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle
import android.os.Handler import android.os.Handler
import androidx.appcompat.app.AppCompatActivity
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
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
@ -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.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadService import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.library.LibraryUpdateService 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.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.util.DiskUtil import eu.kanade.tachiyomi.util.DiskUtil
import eu.kanade.tachiyomi.util.getUriCompat import eu.kanade.tachiyomi.util.getUriCompat
import eu.kanade.tachiyomi.util.notificationManager import eu.kanade.tachiyomi.util.notificationManager
import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.util.toast
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File import java.io.File
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
@ -67,6 +70,14 @@ class NotificationReceiver : BroadcastReceiver() {
openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1), openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1),
intent.getLongExtra(EXTRA_CHAPTER_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) } 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 { companion object {
private const val NAME = "NotificationReceiver" private const val NAME = "NotificationReceiver"
@ -163,6 +195,9 @@ class NotificationReceiver : BroadcastReceiver() {
// Called to cancel library update. // Called to cancel library update.
private const val ACTION_CANCEL_LIBRARY_UPDATE = "$ID.$NAME.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 // Called to open chapter
private const val ACTION_OPEN_CHAPTER = "$ID.$NAME.ACTION_OPEN_CHAPTER" private const val ACTION_OPEN_CHAPTER = "$ID.$NAME.ACTION_OPEN_CHAPTER"
@ -187,12 +222,18 @@ class NotificationReceiver : BroadcastReceiver() {
// Value containing notification id. // Value containing notification id.
private const val EXTRA_NOTIFICATION_ID = "$ID.$NAME.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. // Value containing manga id.
private const val EXTRA_MANGA_ID = "$ID.$NAME.EXTRA_MANGA_ID" private const val EXTRA_MANGA_ID = "$ID.$NAME.EXTRA_MANGA_ID"
// Value containing chapter id. // Value containing chapter id.
private const val EXTRA_CHAPTER_ID = "$ID.$NAME.EXTRA_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 * 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) 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 * 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 context context of application
* @param manga manga of chapter * @param manga manga of chapter
@ -307,6 +367,43 @@ class NotificationReceiver : BroadcastReceiver() {
.FLAG_UPDATE_CURRENT) .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 * Returns [PendingIntent] that starts a service which stops the library update
* *

View File

@ -26,6 +26,7 @@ import android.widget.LinearLayout
import com.bluelinelabs.conductor.* import com.bluelinelabs.conductor.*
import eu.kanade.tachiyomi.Migrations import eu.kanade.tachiyomi.Migrations
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
import eu.kanade.tachiyomi.ui.base.controller.* import eu.kanade.tachiyomi.ui.base.controller.*
@ -221,6 +222,10 @@ class MainActivity : BaseActivity() {
} }
private fun handleIntentAction(intent: Intent): Boolean { 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) { when (intent.action) {
SHORTCUT_LIBRARY -> setSelectedDrawerItem(R.id.nav_drawer_library) SHORTCUT_LIBRARY -> setSelectedDrawerItem(R.id.nav_drawer_library)
SHORTCUT_RECENTLY_UPDATED -> setSelectedDrawerItem(R.id.nav_drawer_recent_updates) SHORTCUT_RECENTLY_UPDATED -> setSelectedDrawerItem(R.id.nav_drawer_recent_updates)

View File

@ -1,6 +1,9 @@
package eu.kanade.tachiyomi.ui.manga package eu.kanade.tachiyomi.ui.manga
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
@ -19,6 +22,7 @@ import com.jakewharton.rxrelay.PublishRelay
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga 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.data.track.TrackManager
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
@ -62,8 +66,13 @@ class MangaController : RxController, TabbedController {
constructor(mangaId: Long) : this( constructor(mangaId: Long) : this(
Injekt.get<DatabaseHelper>().getManga(mangaId).executeAsBlocking()) Injekt.get<DatabaseHelper>().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 var manga: Manga? = null
private set private set

View File

@ -62,7 +62,7 @@
<string name="action_sort_down">Sort down</string> <string name="action_sort_down">Sort down</string>
<string name="action_show_downloaded">Downloaded</string> <string name="action_show_downloaded">Downloaded</string>
<string name="action_next_unread">Next unread</string> <string name="action_next_unread">Next unread</string>
<string name="action_start_reading">Start Reading</string> <string name="action_view_chapters">View chapters</string>
<string name="action_start">Start</string> <string name="action_start">Start</string>
<string name="action_stop">Stop</string> <string name="action_stop">Stop</string>
<string name="action_pause">Pause</string> <string name="action_pause">Pause</string>

View File

@ -7,7 +7,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { 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.ben-manes:gradle-versions-plugin:0.22.0'
classpath 'com.github.zellius:android-shortcut-gradle-plugin:0.1.2' classpath 'com.github.zellius:android-shortcut-gradle-plugin:0.1.2'
classpath 'com.google.gms:google-services:4.3.2' classpath 'com.google.gms:google-services:4.3.2'