From 6224dc293f3edfcb5b8fdc585c636184c3cdb0a0 Mon Sep 17 00:00:00 2001 From: Jays2Kings Date: Sat, 3 Jul 2021 21:20:26 -0400 Subject: [PATCH] Reading while offline will update trackers once back online --- .../data/preference/PreferenceKeys.kt | 2 + .../data/preference/PreferencesHelper.kt | 2 + .../data/track/DelayedTrackingUpdateJob.kt | 80 +++++++++++++++++++ .../tachiyomi/ui/reader/ReaderPresenter.kt | 26 ++++-- 4 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/track/DelayedTrackingUpdateJob.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 3610e46783..eb899f0f21 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -90,6 +90,8 @@ object PreferenceKeys { const val autoAddTrack = "pref_auto_add_track_key" + const val trackingsToAddOnline = "pref_tracking_for_online" + const val lastUsedCatalogueSource = "last_catalogue_source" const val lastUsedCategory = "last_used_category" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index d8cbc8c1a4..5086c4a3bf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -194,6 +194,8 @@ class PreferencesHelper(val context: Context) { fun autoAddTrack() = prefs.getBoolean(Keys.autoAddTrack, true) + fun trackingsToAddOnline() = flowPrefs.getStringSet(Keys.trackingsToAddOnline, emptySet()) + fun lastUsedCatalogueSource() = flowPrefs.getLong(Keys.lastUsedCatalogueSource, -1) fun lastUsedCategory() = rxPrefs.getInteger(Keys.lastUsedCategory, 0) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/DelayedTrackingUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/DelayedTrackingUpdateJob.kt new file mode 100644 index 0000000000..4911bef905 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/DelayedTrackingUpdateJob.kt @@ -0,0 +1,80 @@ +package eu.kanade.tachiyomi.data.track + +import android.content.Context +import androidx.work.BackoffPolicy +import androidx.work.Constraints +import androidx.work.CoroutineWorker +import androidx.work.ExistingWorkPolicy +import androidx.work.NetworkType +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkManager +import androidx.work.WorkerParameters +import eu.kanade.tachiyomi.data.database.DatabaseHelper +import eu.kanade.tachiyomi.data.preference.PreferencesHelper +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import timber.log.Timber +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import java.util.concurrent.TimeUnit + +class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters) : + CoroutineWorker(context, workerParams) { + + override suspend fun doWork(): Result { + val preferences = Injekt.get() + val db = Injekt.get() + val trackManager = Injekt.get() + val trackings = preferences.trackingsToAddOnline().get().toMutableSet().mapNotNull { + val items = it.split(":") + if (items.size != 3) { + null + } else { + val mangaId = items[0].toLongOrNull() ?: return@mapNotNull null + val trackId = items[1].toIntOrNull() ?: return@mapNotNull null + val chapterNumber = items[2].toIntOrNull() ?: return@mapNotNull null + mangaId to (trackId to chapterNumber) + } + }.groupBy { it.first } + withContext(Dispatchers.IO) { + trackings.forEach { + val mangaId = it.key + val manga = db.getManga(mangaId).executeAsBlocking() ?: return@withContext + val trackList = db.getTracks(manga).executeAsBlocking() + it.value.map { tC -> + val trackChapter = tC.second + val service = trackManager.getService(trackChapter.first) + val track = trackList.find { track -> track.sync_id == trackChapter.first } + if (service != null && track != null) { + try { + track.last_chapter_read = trackChapter.second + service.update(track, true) + db.insertTrack(track).executeAsBlocking() + } catch (e: Exception) { + Timber.e(e) + } + } + } + } + preferences.trackingsToAddOnline().set(emptySet()) + } + return Result.success() + } + + companion object { + private const val TAG = "DelayedTrackingUpdate" + + fun setupTask(context: Context) { + val constraints = + Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build() + val request = OneTimeWorkRequestBuilder() + .setConstraints(constraints) + .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 20, TimeUnit.SECONDS) + .addTag(TAG) + .build() + + WorkManager.getInstance(context) + .enqueueUniqueWork(TAG, ExistingWorkPolicy.REPLACE, request) + } + } +} 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 4d420602e8..eeecd69902 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 @@ -18,6 +18,7 @@ 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.data.track.DelayedTrackingUpdateJob import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.SourceManager @@ -34,6 +35,7 @@ import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.executeOnIO +import eu.kanade.tachiyomi.util.system.isOnline import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.withUIContext import kotlinx.coroutines.CoroutineScope @@ -858,19 +860,29 @@ class ReaderPresenter( val trackManager = Injekt.get() - // We wan't these to execute even if the presenter is destroyed so launch on GlobalScope + // 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) { - try { - track.last_chapter_read = chapterRead - service.update(track, true) - db.insertTrack(track).executeAsBlocking() - } catch (e: Exception) { - Timber.e(e) + 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) + } } } }