diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/SyncSettingsSelector.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/SyncSettingsSelector.kt index 86865113f..024ebc5f5 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/SyncSettingsSelector.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/SyncSettingsSelector.kt @@ -50,7 +50,7 @@ class SyncSettingsSelector : Screen() { actionLabel = stringResource(MR.strings.label_sync), actionEnabled = state.options.anyEnabled(), onClickAction = { - if (!SyncDataJob.isAnyJobRunning(context)) { + if (!SyncDataJob.isRunning(context)) { model.syncNow(context) navigator.pop() } else { diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/SyncTriggerOptionsScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/SyncTriggerOptionsScreen.kt index 27136eceb..ddcfbebd1 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/SyncTriggerOptionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/SyncTriggerOptionsScreen.kt @@ -43,7 +43,7 @@ class SyncTriggerOptionsScreen : Screen() { LazyColumnWithAction( contentPadding = contentPadding, actionLabel = stringResource(MR.strings.action_save), - actionEnabled = state.options.anyEnabled(), + actionEnabled = true, onClickAction = { navigator.pop() }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt index c8adc5337..2940a0c97 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt @@ -823,7 +823,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet // Always sync the data before library update if syncing is enabled. if (syncPreferences.isSyncEnabled()) { // Check if SyncDataJob is already running - if (wm.isRunning(SyncDataJob.TAG_MANUAL)) { + if (SyncDataJob.isRunning(context)) { // SyncDataJob is already running return false } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/sync/SyncDataJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/sync/SyncDataJob.kt index e1f949029..dae3a4b06 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/sync/SyncDataJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/sync/SyncDataJob.kt @@ -9,11 +9,14 @@ import androidx.work.ExistingWorkPolicy import androidx.work.ForegroundInfo import androidx.work.OneTimeWorkRequestBuilder import androidx.work.PeriodicWorkRequestBuilder +import androidx.work.WorkInfo +import androidx.work.WorkQuery import androidx.work.WorkerParameters import eu.kanade.domain.sync.SyncPreferences import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.util.system.cancelNotification import eu.kanade.tachiyomi.util.system.isRunning +import eu.kanade.tachiyomi.util.system.setForegroundSafely import eu.kanade.tachiyomi.util.system.workManager import logcat.LogPriority import tachiyomi.core.common.util.system.logcat @@ -27,12 +30,15 @@ class SyncDataJob(private val context: Context, workerParams: WorkerParameters) private val notifier = SyncNotifier(context) override suspend fun doWork(): Result { - try { - setForeground(getForegroundInfo()) - } catch (e: IllegalStateException) { - logcat(LogPriority.ERROR, e) { "Not allowed to run on foreground service" } + if (tags.contains(TAG_AUTO)) { + // Find a running manual worker. If exists, try again later + if (context.workManager.isRunning(TAG_MANUAL)) { + return Result.retry() + } } + setForegroundSafely() + return try { SyncManager(context).syncData() Result.success() @@ -62,10 +68,8 @@ class SyncDataJob(private val context: Context, workerParams: WorkerParameters) private const val TAG_AUTO = "$TAG_JOB:auto" const val TAG_MANUAL = "$TAG_JOB:manual" - private val jobTagList = listOf(TAG_AUTO, TAG_MANUAL) - - fun isAnyJobRunning(context: Context): Boolean { - return jobTagList.any { context.workManager.isRunning(it) } + fun isRunning(context: Context): Boolean { + return context.workManager.isRunning(TAG_JOB) } fun setupTask(context: Context, prefInterval: Int? = null) { @@ -79,6 +83,7 @@ class SyncDataJob(private val context: Context, workerParams: WorkerParameters) 10, TimeUnit.MINUTES, ) + .addTag(TAG_JOB) .addTag(TAG_AUTO) .build() @@ -89,14 +94,33 @@ class SyncDataJob(private val context: Context, workerParams: WorkerParameters) } fun startNow(context: Context) { + val wm = context.workManager + if (wm.isRunning(TAG_JOB)) { + // Already running either as a scheduled or manual job + return + } val request = OneTimeWorkRequestBuilder() + .addTag(TAG_JOB) .addTag(TAG_MANUAL) .build() context.workManager.enqueueUniqueWork(TAG_MANUAL, ExistingWorkPolicy.KEEP, request) } fun stop(context: Context) { - context.workManager.cancelUniqueWork(TAG_MANUAL) + val wm = context.workManager + val workQuery = WorkQuery.Builder.fromTags(listOf(TAG_JOB, TAG_AUTO, TAG_MANUAL)) + .addStates(listOf(WorkInfo.State.RUNNING)) + .build() + wm.getWorkInfos(workQuery).get() + // Should only return one work but just in case + .forEach { + wm.cancelWorkById(it.id) + + // Re-enqueue cancelled scheduled work + if (it.tags.contains(TAG_AUTO)) { + setupTask(context) + } + } } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt index cb78ffb7a..8e12ab072 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt @@ -164,7 +164,7 @@ object LibraryTab : Tab { } }, onClickSyncNow = { - if (!SyncDataJob.isAnyJobRunning(context)) { + if (!SyncDataJob.isRunning(context)) { SyncDataJob.startNow(context) } else { context.toast(MR.strings.sync_in_progress) diff --git a/app/src/main/java/exh/EXHMigrations.kt b/app/src/main/java/exh/EXHMigrations.kt index f1e57fbb3..ffbee0bfd 100644 --- a/app/src/main/java/exh/EXHMigrations.kt +++ b/app/src/main/java/exh/EXHMigrations.kt @@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.core.security.SecurityPreferences import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob import eu.kanade.tachiyomi.data.cache.PagePreviewCache import eu.kanade.tachiyomi.data.library.LibraryUpdateJob +import eu.kanade.tachiyomi.data.sync.SyncDataJob import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE @@ -114,6 +115,7 @@ object EXHMigrations { LibraryUpdateJob.setupTask(context) BackupCreateJob.setupTask(context) EHentaiUpdateWorker.scheduleBackground(context) + SyncDataJob.setupTask(context) // Fresh install if (oldVersion == 0) { diff --git a/app/src/main/java/exh/debug/DebugFunctions.kt b/app/src/main/java/exh/debug/DebugFunctions.kt index 1df0c3a61..b7b50fe87 100644 --- a/app/src/main/java/exh/debug/DebugFunctions.kt +++ b/app/src/main/java/exh/debug/DebugFunctions.kt @@ -9,6 +9,8 @@ import eu.kanade.domain.ui.UiPreferences import eu.kanade.tachiyomi.core.security.SecurityPreferences import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.cache.PagePreviewCache +import eu.kanade.tachiyomi.data.library.LibraryUpdateJob +import eu.kanade.tachiyomi.data.sync.SyncDataJob import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.source.AndroidSourceManager @@ -36,6 +38,8 @@ import tachiyomi.domain.manga.interactor.GetFlatMetadataById import tachiyomi.domain.manga.interactor.GetSearchMetadata import tachiyomi.domain.manga.interactor.InsertFlatMetadata import tachiyomi.domain.source.service.SourceManager +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import java.util.UUID @@ -340,4 +344,14 @@ object DebugFunctions { } fun exportProtobufScheme() = ProtoBufSchemaGenerator.generateSchemaText(Backup.serializer().descriptor) + + fun killSyncJobs() { + val context = Injekt.get() + SyncDataJob.stop(context) + } + + fun killLibraryJobs() { + val context = Injekt.get() + LibraryUpdateJob.stop(context) + } }