mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
Tracking from everywhere (#1173)
* Add tracking everywhere * Add update chapters progress from tracker * Change tracking everywhere to track when marked as read * Mutualize updateTrack method * Mutualize updateTrack method with reader and notification * Revert "Add paused tracking" This reverts commit 9eb37533 * Revert change for library tracking * Revert "Add update chapters progress from tracker" This reverts commit 193a4a8a * rework of updateTrackChapterMarkedAsRead * mutualization after rework * remove oldChapter * reorder updateTrackChapterMarkedAsRead parameters
This commit is contained in:
parent
c1e4effeb5
commit
0d693a910c
13 changed files with 132 additions and 55 deletions
|
@ -10,13 +10,15 @@ import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
|
|
||||||
interface TrackQueries : DbProvider {
|
interface TrackQueries : DbProvider {
|
||||||
|
|
||||||
fun getTracks(manga: Manga) = db.get()
|
fun getTracks(manga: Manga) = getTracks(manga.id)
|
||||||
|
|
||||||
|
fun getTracks(mangaId: Long?) = db.get()
|
||||||
.listOfObjects(Track::class.java)
|
.listOfObjects(Track::class.java)
|
||||||
.withQuery(
|
.withQuery(
|
||||||
Query.builder()
|
Query.builder()
|
||||||
.table(TrackTable.TABLE)
|
.table(TrackTable.TABLE)
|
||||||
.where("${TrackTable.COL_MANGA_ID} = ?")
|
.where("${TrackTable.COL_MANGA_ID} = ?")
|
||||||
.whereArgs(manga.id)
|
.whereArgs(mangaId)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
|
@ -23,6 +23,7 @@ import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.ui.setting.AboutController
|
import eu.kanade.tachiyomi.ui.setting.AboutController
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.updateTrackChapterMarkedAsRead
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||||
|
@ -192,18 +193,21 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||||
*/
|
*/
|
||||||
private fun markAsRead(chapterUrls: Array<String>, mangaId: Long) {
|
private fun markAsRead(chapterUrls: Array<String>, mangaId: Long) {
|
||||||
val db: DatabaseHelper = Injekt.get()
|
val db: DatabaseHelper = Injekt.get()
|
||||||
chapterUrls.forEach {
|
val preferences: PreferencesHelper = Injekt.get()
|
||||||
|
val chapters = chapterUrls.map {
|
||||||
val chapter = db.getChapter(it, mangaId).executeAsBlocking() ?: return
|
val chapter = db.getChapter(it, mangaId).executeAsBlocking() ?: return
|
||||||
chapter.read = true
|
chapter.read = true
|
||||||
db.updateChapterProgress(chapter).executeAsBlocking()
|
db.updateChapterProgress(chapter).executeAsBlocking()
|
||||||
val preferences: PreferencesHelper = Injekt.get()
|
|
||||||
if (preferences.removeAfterMarkedAsRead()) {
|
if (preferences.removeAfterMarkedAsRead()) {
|
||||||
val manga = db.getManga(mangaId).executeAsBlocking() ?: return
|
val manga = db.getManga(mangaId).executeAsBlocking() ?: return
|
||||||
val sourceManager: SourceManager = Injekt.get()
|
val sourceManager: SourceManager = Injekt.get()
|
||||||
val source = sourceManager.get(manga.source) ?: return
|
val source = sourceManager.get(manga.source) ?: return
|
||||||
downloadManager.deleteChapters(listOf(chapter), manga, source)
|
downloadManager.deleteChapters(listOf(chapter), manga, source)
|
||||||
}
|
}
|
||||||
|
return@map chapter
|
||||||
}
|
}
|
||||||
|
val newLastChapter = chapters.maxByOrNull { it.chapter_number.toInt() }
|
||||||
|
updateTrackChapterMarkedAsRead(db, preferences, newLastChapter, mangaId, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Method called when user wants to stop a restore
|
/** Method called when user wants to stop a restore
|
||||||
|
|
|
@ -95,6 +95,8 @@ object PreferenceKeys {
|
||||||
|
|
||||||
const val autoUpdateTrack = "pref_auto_update_manga_sync_key"
|
const val autoUpdateTrack = "pref_auto_update_manga_sync_key"
|
||||||
|
|
||||||
|
const val trackMarkedAsRead = "track_marked_as_read"
|
||||||
|
|
||||||
const val trackingsToAddOnline = "pref_tracking_for_online"
|
const val trackingsToAddOnline = "pref_tracking_for_online"
|
||||||
|
|
||||||
const val lastUsedCatalogueSource = "last_catalogue_source"
|
const val lastUsedCatalogueSource = "last_catalogue_source"
|
||||||
|
|
|
@ -194,6 +194,8 @@ class PreferencesHelper(val context: Context) {
|
||||||
|
|
||||||
fun autoUpdateTrack() = prefs.getBoolean(Keys.autoUpdateTrack, true)
|
fun autoUpdateTrack() = prefs.getBoolean(Keys.autoUpdateTrack, true)
|
||||||
|
|
||||||
|
fun trackMarkedAsRead() = prefs.getBoolean(Keys.trackMarkedAsRead, false)
|
||||||
|
|
||||||
fun trackingsToAddOnline() = flowPrefs.getStringSet(Keys.trackingsToAddOnline, emptySet())
|
fun trackingsToAddOnline() = flowPrefs.getStringSet(Keys.trackingsToAddOnline, emptySet())
|
||||||
|
|
||||||
fun lastUsedCatalogueSource() = flowPrefs.getLong(Keys.lastUsedCatalogueSource, -1)
|
fun lastUsedCatalogueSource() = flowPrefs.getLong(Keys.lastUsedCatalogueSource, -1)
|
||||||
|
|
|
@ -44,9 +44,7 @@ import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.ArrayList
|
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Comparator
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
|
@ -80,6 +80,7 @@ import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController
|
||||||
import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchController
|
import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchController
|
||||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||||
import eu.kanade.tachiyomi.util.addOrRemoveToFavorites
|
import eu.kanade.tachiyomi.util.addOrRemoveToFavorites
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.updateTrackChapterMarkedAsRead
|
||||||
import eu.kanade.tachiyomi.util.isLocal
|
import eu.kanade.tachiyomi.util.isLocal
|
||||||
import eu.kanade.tachiyomi.util.moveCategories
|
import eu.kanade.tachiyomi.util.moveCategories
|
||||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
|
@ -864,6 +865,8 @@ class MangaDetailsController :
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleReadChapter(position: Int) {
|
fun toggleReadChapter(position: Int) {
|
||||||
|
val preferences = presenter.preferences
|
||||||
|
val db = presenter.db
|
||||||
val item = adapter?.getItem(position) as? ChapterItem ?: return
|
val item = adapter?.getItem(position) as? ChapterItem ?: return
|
||||||
val chapter = item.chapter
|
val chapter = item.chapter
|
||||||
val lastRead = chapter.last_page_read
|
val lastRead = chapter.last_page_read
|
||||||
|
@ -885,8 +888,13 @@ class MangaDetailsController :
|
||||||
object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||||
super.onDismissed(transientBottomBar, event)
|
super.onDismissed(transientBottomBar, event)
|
||||||
if (!undoing && !read && presenter.preferences.removeAfterMarkedAsRead()) {
|
if (!undoing && !read) {
|
||||||
presenter.deleteChapters(listOf(item))
|
if (preferences.removeAfterMarkedAsRead()) {
|
||||||
|
presenter.deleteChapters(listOf(item))
|
||||||
|
}
|
||||||
|
updateTrackChapterMarkedAsRead(db, preferences, chapter, manga?.id) {
|
||||||
|
presenter.fetchTracks()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ import eu.kanade.tachiyomi.util.chapter.ChapterSort
|
||||||
import eu.kanade.tachiyomi.util.chapter.ChapterUtil
|
import eu.kanade.tachiyomi.util.chapter.ChapterUtil
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithTrackServiceTwoWay
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithTrackServiceTwoWay
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.updateTrackChapterMarkedAsRead
|
||||||
import eu.kanade.tachiyomi.util.lang.trimOrNull
|
import eu.kanade.tachiyomi.util.lang.trimOrNull
|
||||||
import eu.kanade.tachiyomi.util.manga.MangaShortcutManager
|
import eu.kanade.tachiyomi.util.manga.MangaShortcutManager
|
||||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
||||||
|
@ -488,6 +489,12 @@ class MangaDetailsPresenter(
|
||||||
}
|
}
|
||||||
getChapters()
|
getChapters()
|
||||||
withContext(Dispatchers.Main) { controller?.updateChapters(chapters) }
|
withContext(Dispatchers.Main) { controller?.updateChapters(chapters) }
|
||||||
|
if (read && deleteNow) {
|
||||||
|
val latestReadChapter = selectedChapters.maxByOrNull { it.chapter_number.toInt() }?.chapter
|
||||||
|
updateTrackChapterMarkedAsRead(db, preferences, latestReadChapter, manga.id) {
|
||||||
|
fetchTracks()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -858,7 +865,7 @@ class MangaDetailsPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun fetchTracks() {
|
suspend fun fetchTracks() {
|
||||||
tracks = withContext(Dispatchers.IO) { db.getTracks(manga).executeAsBlocking() }
|
tracks = withContext(Dispatchers.IO) { db.getTracks(manga).executeAsBlocking() }
|
||||||
trackList = loggedServices.map { service ->
|
trackList = loggedServices.map { service ->
|
||||||
TrackItem(tracks.find { it.sync_id == service.id }, service)
|
TrackItem(tracks.find { it.sync_id == service.id }, service)
|
||||||
|
|
|
@ -17,8 +17,6 @@ import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.track.DelayedTrackingUpdateJob
|
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
@ -35,16 +33,16 @@ import eu.kanade.tachiyomi.ui.reader.settings.ReadingModeType
|
||||||
import eu.kanade.tachiyomi.util.chapter.ChapterFilter
|
import eu.kanade.tachiyomi.util.chapter.ChapterFilter
|
||||||
import eu.kanade.tachiyomi.util.chapter.ChapterSort
|
import eu.kanade.tachiyomi.util.chapter.ChapterSort
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.updateTrackChapterRead
|
||||||
import eu.kanade.tachiyomi.util.lang.getUrlWithoutDomain
|
import eu.kanade.tachiyomi.util.lang.getUrlWithoutDomain
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
import eu.kanade.tachiyomi.util.system.executeOnIO
|
import eu.kanade.tachiyomi.util.system.executeOnIO
|
||||||
import eu.kanade.tachiyomi.util.system.isOnline
|
import eu.kanade.tachiyomi.util.system.launchIO
|
||||||
import eu.kanade.tachiyomi.util.system.launchUI
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
import eu.kanade.tachiyomi.util.system.withUIContext
|
import eu.kanade.tachiyomi.util.system.withUIContext
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
@ -491,7 +489,7 @@ class ReaderPresenter(
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
selectedChapter.chapter.read = true
|
selectedChapter.chapter.read = true
|
||||||
updateTrackChapterRead(selectedChapter)
|
updateTrackChapterAfterReading(selectedChapter)
|
||||||
deleteChapterIfNeeded(selectedChapter)
|
deleteChapterIfNeeded(selectedChapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -877,41 +875,12 @@ class ReaderPresenter(
|
||||||
* Starts the service that updates the last chapter read in sync services. This operation
|
* Starts the service that updates the last chapter read in sync services. This operation
|
||||||
* will run in a background thread and errors are ignored.
|
* will run in a background thread and errors are ignored.
|
||||||
*/
|
*/
|
||||||
private fun updateTrackChapterRead(readerChapter: ReaderChapter) {
|
private fun updateTrackChapterAfterReading(readerChapter: ReaderChapter) {
|
||||||
if (!preferences.autoUpdateTrack()) return
|
if (!preferences.autoUpdateTrack()) return
|
||||||
val manga = manga ?: return
|
|
||||||
|
|
||||||
val chapterRead = readerChapter.chapter.chapter_number.toInt()
|
launchIO {
|
||||||
|
val newChapterRead = readerChapter.chapter.chapter_number.toInt()
|
||||||
val trackManager = Injekt.get<TrackManager>()
|
updateTrackChapterRead(db, preferences, manga?.id, newChapterRead, true)
|
||||||
|
|
||||||
// We want these to execute even if the presenter is destroyed so launch on GlobalScope
|
|
||||||
GlobalScope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
val trackList = db.getTracks(manga).executeAsBlocking()
|
|
||||||
trackList.map { track ->
|
|
||||||
val service = trackManager.getService(track.sync_id)
|
|
||||||
if (service != null && service.isLogged && chapterRead > track.last_chapter_read) {
|
|
||||||
if (!preferences.context.isOnline()) {
|
|
||||||
val mangaId = manga.id ?: return@map
|
|
||||||
val trackings = preferences.trackingsToAddOnline().get().toMutableSet()
|
|
||||||
val currentTracking = trackings.find { it.startsWith("$mangaId:${track.sync_id}:") }
|
|
||||||
trackings.remove(currentTracking)
|
|
||||||
trackings.add("$mangaId:${track.sync_id}:$chapterRead")
|
|
||||||
preferences.trackingsToAddOnline().set(trackings)
|
|
||||||
DelayedTrackingUpdateJob.setupTask(preferences.context)
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
track.last_chapter_read = chapterRead
|
|
||||||
service.update(track, true)
|
|
||||||
db.insertTrack(track).executeAsBlocking()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.ui.recents.options.TabbedRecentsOptionsSheet
|
import eu.kanade.tachiyomi.ui.recents.options.TabbedRecentsOptionsSheet
|
||||||
import eu.kanade.tachiyomi.ui.source.browse.ProgressItem
|
import eu.kanade.tachiyomi.ui.source.browse.ProgressItem
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.updateTrackChapterMarkedAsRead
|
||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.system.getBottomGestureInsets
|
import eu.kanade.tachiyomi.util.system.getBottomGestureInsets
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
|
@ -668,6 +669,8 @@ class RecentsController(bundle: Bundle? = null) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun markAsRead(position: Int) {
|
override fun markAsRead(position: Int) {
|
||||||
|
val preferences = presenter.preferences
|
||||||
|
val db = presenter.db
|
||||||
val item = adapter.getItem(position) as? RecentMangaItem ?: return
|
val item = adapter.getItem(position) as? RecentMangaItem ?: return
|
||||||
val chapter = item.chapter
|
val chapter = item.chapter
|
||||||
val manga = item.mch.manga
|
val manga = item.mch.manga
|
||||||
|
@ -691,11 +694,14 @@ class RecentsController(bundle: Bundle? = null) :
|
||||||
object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||||
super.onDismissed(transientBottomBar, event)
|
super.onDismissed(transientBottomBar, event)
|
||||||
if (!undoing && presenter.preferences.removeAfterMarkedAsRead() &&
|
if (!undoing && !wasRead) {
|
||||||
!wasRead
|
if (preferences.removeAfterMarkedAsRead()) {
|
||||||
) {
|
lastChapterId = chapter.id
|
||||||
lastChapterId = chapter.id
|
presenter.deleteChapter(chapter, manga)
|
||||||
presenter.deleteChapter(chapter, manga)
|
}
|
||||||
|
updateTrackChapterMarkedAsRead(db, preferences, chapter, manga.id) {
|
||||||
|
(router.backstack.lastOrNull()?.controller as? MangaDetailsController)?.presenter?.fetchTracks()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ import kotlin.math.abs
|
||||||
class RecentsPresenter(
|
class RecentsPresenter(
|
||||||
val preferences: PreferencesHelper = Injekt.get(),
|
val preferences: PreferencesHelper = Injekt.get(),
|
||||||
val downloadManager: DownloadManager = Injekt.get(),
|
val downloadManager: DownloadManager = Injekt.get(),
|
||||||
private val db: DatabaseHelper = Injekt.get(),
|
val db: DatabaseHelper = Injekt.get(),
|
||||||
private val chapterFilter: ChapterFilter = Injekt.get()
|
private val chapterFilter: ChapterFilter = Injekt.get()
|
||||||
) : BaseCoroutinePresenter<RecentsController>(), DownloadQueue.DownloadListener, LibraryServiceListener, DownloadServiceListener {
|
) : BaseCoroutinePresenter<RecentsController>(), DownloadQueue.DownloadListener, LibraryServiceListener, DownloadServiceListener {
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,14 @@ class SettingsTrackingController :
|
||||||
|
|
||||||
switchPreference {
|
switchPreference {
|
||||||
key = Keys.autoUpdateTrack
|
key = Keys.autoUpdateTrack
|
||||||
titleRes = R.string.sync_chapters_after_reading
|
titleRes = R.string.update_tracking_after_reading
|
||||||
defaultValue = true
|
defaultValue = true
|
||||||
}
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.trackMarkedAsRead
|
||||||
|
titleRes = R.string.update_tracking_marked_read
|
||||||
|
defaultValue = false
|
||||||
|
}
|
||||||
preferenceCategory {
|
preferenceCategory {
|
||||||
titleRes = R.string.services
|
titleRes = R.string.services
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,17 @@ package eu.kanade.tachiyomi.util.chapter
|
||||||
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
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.data.track.DelayedTrackingUpdateJob
|
||||||
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
|
import eu.kanade.tachiyomi.util.system.isOnline
|
||||||
import eu.kanade.tachiyomi.util.system.launchIO
|
import eu.kanade.tachiyomi.util.system.launchIO
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method for syncing a remote track with the local chapters, and back
|
* Helper method for syncing a remote track with the local chapters, and back
|
||||||
|
@ -40,3 +48,68 @@ fun syncChaptersWithTrackServiceTwoWay(db: DatabaseHelper, chapters: List<Chapte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var trackingJobs = HashMap<Long, Pair<Job?, Int?>>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the service that updates the last chapter read in sync services. This operation
|
||||||
|
* will run in a background thread and errors are ignored.
|
||||||
|
*/
|
||||||
|
fun updateTrackChapterMarkedAsRead(
|
||||||
|
db: DatabaseHelper,
|
||||||
|
preferences: PreferencesHelper,
|
||||||
|
newLastChapter: Chapter?,
|
||||||
|
mangaId: Long?,
|
||||||
|
delay: Long = 3000,
|
||||||
|
fetchTracks: (suspend () -> Unit)? = null
|
||||||
|
) {
|
||||||
|
if (!preferences.trackMarkedAsRead()) return
|
||||||
|
mangaId ?: return
|
||||||
|
|
||||||
|
val newChapterRead = newLastChapter?.chapter_number?.toInt() ?: 0
|
||||||
|
|
||||||
|
// To avoid unnecessary calls if multiple marked as read for same manga
|
||||||
|
if (trackingJobs[mangaId]?.second ?: 0 < newChapterRead) {
|
||||||
|
trackingJobs[mangaId]?.first?.cancel()
|
||||||
|
|
||||||
|
// We want these to execute even if the presenter is destroyed
|
||||||
|
trackingJobs[mangaId] = launchIO {
|
||||||
|
delay(delay)
|
||||||
|
updateTrackChapterRead(db, preferences, mangaId, newChapterRead)
|
||||||
|
fetchTracks?.invoke()
|
||||||
|
trackingJobs.remove(mangaId)
|
||||||
|
} to newChapterRead
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun updateTrackChapterRead(
|
||||||
|
db: DatabaseHelper,
|
||||||
|
preferences: PreferencesHelper,
|
||||||
|
mangaId: Long?,
|
||||||
|
newChapterRead: Int,
|
||||||
|
retryWhenOnline: Boolean = false
|
||||||
|
) {
|
||||||
|
val trackManager = Injekt.get<TrackManager>()
|
||||||
|
val trackList = db.getTracks(mangaId).executeAsBlocking()
|
||||||
|
trackList.map { track ->
|
||||||
|
val service = trackManager.getService(track.sync_id)
|
||||||
|
if (service != null && service.isLogged && newChapterRead > track.last_chapter_read) {
|
||||||
|
if (retryWhenOnline && !preferences.context.isOnline()) {
|
||||||
|
val trackings = preferences.trackingsToAddOnline().get().toMutableSet()
|
||||||
|
val currentTracking = trackings.find { it.startsWith("$mangaId:${track.sync_id}:") }
|
||||||
|
trackings.remove(currentTracking)
|
||||||
|
trackings.add("$mangaId:${track.sync_id}:$newChapterRead")
|
||||||
|
preferences.trackingsToAddOnline().set(trackings)
|
||||||
|
DelayedTrackingUpdateJob.setupTask(preferences.context)
|
||||||
|
} else if (preferences.context.isOnline()) {
|
||||||
|
try {
|
||||||
|
track.last_chapter_read = newChapterRead
|
||||||
|
service.update(track, true)
|
||||||
|
db.insertTrack(track).executeAsBlocking()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -562,7 +562,8 @@
|
||||||
<string name="tracking_info">One-way sync to update the chapter progress in tracking services. Set up tracking for individual manga entries from their tracking button.</string>
|
<string name="tracking_info">One-way sync to update the chapter progress in tracking services. Set up tracking for individual manga entries from their tracking button.</string>
|
||||||
<string name="enhanced_services">Enhanced services</string>
|
<string name="enhanced_services">Enhanced services</string>
|
||||||
<string name="enhanced_tracking_info">Services that provide enhanced features for specific sources. Manga are automatically tracked when added to your library.</string>
|
<string name="enhanced_tracking_info">Services that provide enhanced features for specific sources. Manga are automatically tracked when added to your library.</string>
|
||||||
<string name="sync_chapters_after_reading">Sync chapters after reading</string>
|
<string name="update_tracking_after_reading">Update tracking after reading</string>
|
||||||
|
<string name="update_tracking_marked_read">Update tracking when marked as read</string>
|
||||||
<string name="track_when_adding_to_library">Track when adding to library</string>
|
<string name="track_when_adding_to_library">Track when adding to library</string>
|
||||||
<string name="only_applies_silent_trackers">Only applies to silent trackers, such as Komga</string>
|
<string name="only_applies_silent_trackers">Only applies to silent trackers, such as Komga</string>
|
||||||
<string name="reading">Reading</string>
|
<string name="reading">Reading</string>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue