mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
refactor: Rewrite migrator
Should also fixed auto-backup, auto-update, and update checker being stuck when it failed Co-authored-by: Andreas <andreas.everos@gmail.com>
This commit is contained in:
parent
c17be3831c
commit
573015a4b9
39 changed files with 977 additions and 347 deletions
22
app/src/main/java/dev/yokai/core/migration/Migration.kt
Normal file
22
app/src/main/java/dev/yokai/core/migration/Migration.kt
Normal file
|
@ -0,0 +1,22 @@
|
|||
package dev.yokai.core.migration
|
||||
|
||||
interface Migration {
|
||||
val version: Float
|
||||
|
||||
suspend operator fun invoke(migrationContext: MigrationContext): Boolean
|
||||
|
||||
val isAlways: Boolean
|
||||
get() = version == ALWAYS
|
||||
|
||||
companion object {
|
||||
const val ALWAYS = -1f
|
||||
|
||||
fun of(version: Float, action: suspend (MigrationContext) -> Boolean): Migration = object : Migration {
|
||||
override val version: Float = version
|
||||
|
||||
override suspend operator fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
return action(migrationContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package dev.yokai.core.migration
|
||||
|
||||
typealias MigrationCompletedListener = () -> Unit
|
|
@ -0,0 +1,10 @@
|
|||
package dev.yokai.core.migration
|
||||
|
||||
import uy.kohesive.injekt.Injekt
|
||||
|
||||
class MigrationContext(val dryRun: Boolean) {
|
||||
|
||||
inline fun <reified T> get(): T? {
|
||||
return Injekt.getInstanceOrNull(T::class.java)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package dev.yokai.core.migration
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.async
|
||||
|
||||
class MigrationJobFactory(
|
||||
private val migrationContext: MigrationContext,
|
||||
private val scope: CoroutineScope
|
||||
) {
|
||||
|
||||
fun create(migrations: List<Migration>): Deferred<Boolean> = with(scope) {
|
||||
return migrations.sortedBy { it.version }
|
||||
.fold(CompletableDeferred(true)) { acc: Deferred<Boolean>, migration: Migration ->
|
||||
if (!migrationContext.dryRun) {
|
||||
Logger.i { "Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" }
|
||||
async {
|
||||
val prev = acc.await()
|
||||
migration(migrationContext) || prev
|
||||
}
|
||||
} else {
|
||||
Logger.i { "(Dry-run) Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" }
|
||||
CompletableDeferred(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package dev.yokai.core.migration
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
interface MigrationStrategy {
|
||||
operator fun invoke(migrations: List<Migration>): Deferred<Boolean>
|
||||
}
|
||||
|
||||
class DefaultMigrationStrategy(
|
||||
private val migrationJobFactory: MigrationJobFactory,
|
||||
private val migrationCompletedListener: MigrationCompletedListener,
|
||||
private val scope: CoroutineScope
|
||||
) : MigrationStrategy {
|
||||
|
||||
override operator fun invoke(migrations: List<Migration>): Deferred<Boolean> = with(scope) {
|
||||
if (migrations.isEmpty()) {
|
||||
return@with CompletableDeferred(false)
|
||||
}
|
||||
|
||||
val chain = migrationJobFactory.create(migrations)
|
||||
|
||||
launch {
|
||||
if (chain.await()) migrationCompletedListener()
|
||||
}.start()
|
||||
|
||||
chain
|
||||
}
|
||||
}
|
||||
|
||||
class InitialMigrationStrategy(private val strategy: DefaultMigrationStrategy) : MigrationStrategy {
|
||||
|
||||
override operator fun invoke(migrations: List<Migration>): Deferred<Boolean> {
|
||||
return strategy(migrations.filter { it.isAlways })
|
||||
}
|
||||
}
|
||||
|
||||
class NoopMigrationStrategy(val state: Boolean) : MigrationStrategy {
|
||||
|
||||
override fun invoke(migrations: List<Migration>): Deferred<Boolean> {
|
||||
return CompletableDeferred(state)
|
||||
}
|
||||
}
|
||||
|
||||
class VersionRangeMigrationStrategy(
|
||||
private val versions: IntRange,
|
||||
private val strategy: DefaultMigrationStrategy
|
||||
) : MigrationStrategy {
|
||||
|
||||
override operator fun invoke(migrations: List<Migration>): Deferred<Boolean> {
|
||||
return strategy(migrations.filter { it.isAlways || it.version.toInt() in versions })
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package dev.yokai.core.migration
|
||||
|
||||
class MigrationStrategyFactory(
|
||||
private val factory: MigrationJobFactory,
|
||||
private val migrationCompletedListener: MigrationCompletedListener,
|
||||
) {
|
||||
|
||||
fun create(old: Int, new: Int): MigrationStrategy {
|
||||
val versions = (old + 1)..new
|
||||
val strategy = when {
|
||||
old == 0 -> InitialMigrationStrategy(
|
||||
strategy = DefaultMigrationStrategy(factory, migrationCompletedListener, Migrator.scope),
|
||||
)
|
||||
|
||||
old >= new -> NoopMigrationStrategy(false)
|
||||
else -> VersionRangeMigrationStrategy(
|
||||
versions = versions,
|
||||
strategy = DefaultMigrationStrategy(factory, migrationCompletedListener, Migrator.scope),
|
||||
)
|
||||
}
|
||||
return strategy
|
||||
}
|
||||
}
|
40
app/src/main/java/dev/yokai/core/migration/Migrator.kt
Normal file
40
app/src/main/java/dev/yokai/core/migration/Migrator.kt
Normal file
|
@ -0,0 +1,40 @@
|
|||
package dev.yokai.core.migration
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
object Migrator {
|
||||
private var result: Deferred<Boolean>? = null
|
||||
val scope = CoroutineScope(Dispatchers.Main + Job())
|
||||
|
||||
fun initialize(
|
||||
old: Int,
|
||||
new: Int,
|
||||
migrations: List<Migration>,
|
||||
dryRun: Boolean = false,
|
||||
onMigrationComplete: () -> Unit
|
||||
) {
|
||||
val migrationContext = MigrationContext(dryRun)
|
||||
val migrationJobFactory = MigrationJobFactory(migrationContext, scope)
|
||||
val migrationStrategyFactory = MigrationStrategyFactory(migrationJobFactory, onMigrationComplete)
|
||||
val strategy = migrationStrategyFactory.create(old, new)
|
||||
result = strategy(migrations)
|
||||
}
|
||||
|
||||
suspend fun await(): Boolean {
|
||||
val result = result ?: CompletableDeferred(false)
|
||||
return result.await()
|
||||
}
|
||||
|
||||
fun release() {
|
||||
result = null
|
||||
}
|
||||
|
||||
fun awaitAndRelease(): Boolean = runBlocking {
|
||||
await().also { release() }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Delete external chapter cache dir.
|
||||
*/
|
||||
class ChapterCacheMigration : Migration {
|
||||
override val version: Float = 26f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val extCache = context.externalCacheDir
|
||||
if (extCache != null) {
|
||||
val chapterCache = File(extCache, "chapter_disk_cache")
|
||||
if (chapterCache.exists()) {
|
||||
chapterCache.deleteRecursively()
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Move covers to external files dir.
|
||||
*/
|
||||
class CoverCacheMigration : Migration {
|
||||
override val version: Float = 19f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val oldDir = File(context.externalCacheDir, "cover_disk_cache")
|
||||
if (oldDir.exists()) {
|
||||
val destDir = context.getExternalFilesDir("covers")
|
||||
if (destDir != null) {
|
||||
oldDir.listFiles()?.forEach {
|
||||
it.renameTo(File(destDir, it.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
||||
|
||||
class CustomInfoMigration : Migration {
|
||||
override val version: Float = 66f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
try {
|
||||
LibraryPresenter.updateCustoms()
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import dev.yokai.domain.ui.settings.ReaderPreferences
|
||||
import dev.yokai.domain.ui.settings.ReaderPreferences.CutoutBehaviour
|
||||
import dev.yokai.domain.ui.settings.ReaderPreferences.LandscapeCutoutBehaviour
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig
|
||||
|
||||
class CutoutMigration : Migration {
|
||||
override val version: Float = 121f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val readerPreferences: ReaderPreferences = migrationContext.get() ?: return false
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
try {
|
||||
val oldCutoutBehaviour = prefs.getInt(PreferenceKeys.pagerCutoutBehavior, 0)
|
||||
readerPreferences.pagerCutoutBehavior().set(
|
||||
when (oldCutoutBehaviour) {
|
||||
PagerConfig.CUTOUT_PAD -> CutoutBehaviour.HIDE
|
||||
PagerConfig.CUTOUT_IGNORE -> CutoutBehaviour.IGNORE
|
||||
else -> CutoutBehaviour.SHOW
|
||||
}
|
||||
)
|
||||
} catch (_: Exception) {
|
||||
readerPreferences.pagerCutoutBehavior().set(CutoutBehaviour.SHOW)
|
||||
}
|
||||
|
||||
try {
|
||||
val oldCutoutBehaviour = prefs.getInt("landscape_cutout_behavior", 0)
|
||||
readerPreferences.landscapeCutoutBehavior().set(
|
||||
when (oldCutoutBehaviour) {
|
||||
0 -> LandscapeCutoutBehaviour.HIDE
|
||||
else -> LandscapeCutoutBehaviour.DEFAULT
|
||||
}
|
||||
)
|
||||
} catch (_: Exception) {
|
||||
readerPreferences.landscapeCutoutBehavior().set(LandscapeCutoutBehaviour.DEFAULT)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
|
||||
|
||||
class DoHMigration : Migration {
|
||||
override val version: Float = 71f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
// Migrate DNS over HTTPS setting
|
||||
val wasDohEnabled = prefs.getBoolean("enable_doh", false)
|
||||
if (wasDohEnabled) {
|
||||
prefs.edit {
|
||||
putInt(PreferenceKeys.dohProvider, PREF_DOH_CLOUDFLARE)
|
||||
remove("enable_doh")
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.download.DownloadProvider
|
||||
|
||||
class DownloadedChaptersMigration : Migration {
|
||||
override val version: Float = 54f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
DownloadProvider(context).renameChapters()
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.plusAssign
|
||||
|
||||
class EnabledLanguageMigration : Migration {
|
||||
override val version: Float = 83f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val preferences: PreferencesHelper = migrationContext.get() ?: return false
|
||||
|
||||
if (preferences.enabledLanguages().isSet()) {
|
||||
preferences.enabledLanguages() += "all"
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.updater.AppUpdateJob
|
||||
|
||||
/**
|
||||
* Restore jobs after upgrading to evernote's job scheduler.
|
||||
*/
|
||||
class EvernoteJobUpgradeMigration : Migration {
|
||||
override val version: Float = 14f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
if (BuildConfig.INCLUDE_UPDATER) {
|
||||
AppUpdateJob.setupTask(context)
|
||||
}
|
||||
LibraryUpdateJob.setupTask(context)
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import dev.yokai.domain.base.BasePreferences
|
||||
import eu.kanade.tachiyomi.App
|
||||
|
||||
/**
|
||||
* Upstream no longer use Int for extension installer prefs, this solves incompatibility with upstreams backup
|
||||
*/
|
||||
class ExtensionInstallerEnumMigration : Migration {
|
||||
override val version: Float = 119f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val basePreferences: BasePreferences = migrationContext.get() ?: return false
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
try {
|
||||
val oldExtensionInstall = prefs.getInt("extension_installer", 0)
|
||||
basePreferences.extensionInstaller().set(
|
||||
when (oldExtensionInstall) {
|
||||
1 -> BasePreferences.ExtensionInstaller.SHIZUKU
|
||||
2 -> BasePreferences.ExtensionInstaller.PRIVATE
|
||||
else -> BasePreferences.ExtensionInstaller.PACKAGEINSTALLER
|
||||
}
|
||||
)
|
||||
} catch (_: Exception) {
|
||||
basePreferences.extensionInstaller().set(BasePreferences.ExtensionInstaller.PACKAGEINSTALLER)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Delete internal chapter cache dir.
|
||||
*/
|
||||
class InternalChapterCacheUpdateMigration : Migration {
|
||||
override val version: Float = 15f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
File(context.cacheDir, "chapter_disk_cache").deleteRecursively()
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.ui.library.LibrarySort
|
||||
|
||||
class LibrarySortMigration : Migration {
|
||||
override val version: Float = 110f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
try {
|
||||
val librarySortString = prefs.getString("library_sorting_mode", "")
|
||||
if (!librarySortString.isNullOrEmpty()) {
|
||||
prefs.edit {
|
||||
remove("library_sorting_mode")
|
||||
putInt(
|
||||
"library_sorting_mode",
|
||||
LibrarySort.deserialize(librarySortString).mainValue,
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
|
||||
class LibraryUpdateResetMigration : Migration {
|
||||
override val version: Float = 105f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
LibraryUpdateJob.cancelAllWorks(context)
|
||||
LibraryUpdateJob.setupTask(context)
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
val migrations: ImmutableList<Migration> = persistentListOf(
|
||||
SetupAppUpdateMigration(),
|
||||
SetupBackupCreateMigration(),
|
||||
SetupExtensionUpdateMigration(),
|
||||
SetupLibraryUpdateMigration(),
|
||||
|
||||
// For archive purposes
|
||||
EvernoteJobUpgradeMigration(),
|
||||
InternalChapterCacheUpdateMigration(),
|
||||
CoverCacheMigration(),
|
||||
ChapterCacheMigration(),
|
||||
DownloadedChaptersMigration(),
|
||||
WorkManagerMigration(),
|
||||
CustomInfoMigration(),
|
||||
MyAnimeListMigration(),
|
||||
DoHMigration(),
|
||||
RotationTypeMigration(),
|
||||
ShortcutsMigration(),
|
||||
RotationTypeEnumMigration(),
|
||||
EnabledLanguageMigration(),
|
||||
UpdateIntervalMigration(),
|
||||
ReaderUpdateMigration(),
|
||||
PrefsMigration(),
|
||||
LibraryUpdateResetMigration(),
|
||||
TrackerPrivateSettingsMigration(),
|
||||
LibrarySortMigration(),
|
||||
|
||||
// Yokai fork
|
||||
ThePurgeMigration(),
|
||||
ExtensionInstallerEnumMigration(),
|
||||
CutoutMigration(),
|
||||
RepoJsonMigration(),
|
||||
)
|
|
@ -0,0 +1,28 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
|
||||
/**
|
||||
* Force MAL log out due to login flow change
|
||||
* v67: switched from scraping to WebView
|
||||
* v68: switched from WebView to OAuth
|
||||
*/
|
||||
class MyAnimeListMigration : Migration {
|
||||
override val version: Float = 68f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val trackManager: TrackManager = migrationContext.get() ?: return false
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
|
||||
if (trackManager.myAnimeList.isLogged) {
|
||||
trackManager.myAnimeList.logout()
|
||||
context.toast(R.string.myanimelist_relogin)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.recents.RecentsPresenter
|
||||
import kotlin.math.max
|
||||
|
||||
class PrefsMigration : Migration {
|
||||
override val version: Float = 102f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val preferences: PreferencesHelper = migrationContext.get() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val oldSecureScreen = prefs.getBoolean("secure_screen", false)
|
||||
if (oldSecureScreen) {
|
||||
preferences.secureScreen().set(PreferenceValues.SecureScreenMode.ALWAYS)
|
||||
}
|
||||
|
||||
val oldDLAfterReading = prefs.getInt("auto_download_after_reading", 0)
|
||||
if (oldDLAfterReading > 0) {
|
||||
preferences.autoDownloadWhileReading().set(max(2, oldDLAfterReading))
|
||||
}
|
||||
|
||||
val oldGroupHistory = prefs.getBoolean("group_chapters_history", true)
|
||||
if (!oldGroupHistory) {
|
||||
preferences.groupChaptersHistory().set(RecentsPresenter.GroupType.Never)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
||||
import eu.kanade.tachiyomi.util.system.withIOContext
|
||||
|
||||
class ReaderUpdateMigration : Migration {
|
||||
override val version: Float = 88f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val preferences: PreferencesHelper = migrationContext.get() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
withIOContext {
|
||||
LibraryPresenter.updateRatiosAndColors()
|
||||
}
|
||||
val oldReaderTap = prefs.getBoolean("reader_tap", true)
|
||||
if (!oldReaderTap) {
|
||||
preferences.navigationModePager().set(5)
|
||||
preferences.navigationModeWebtoon().set(5)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import dev.yokai.domain.extension.repo.ExtensionRepoRepository
|
||||
import dev.yokai.domain.extension.repo.exception.SaveExtensionRepoException
|
||||
import eu.kanade.tachiyomi.core.preference.Preference
|
||||
import eu.kanade.tachiyomi.core.preference.PreferenceStore
|
||||
import eu.kanade.tachiyomi.util.system.withIOContext
|
||||
|
||||
class RepoJsonMigration : Migration {
|
||||
override val version: Float = 130f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean = withIOContext {
|
||||
val extensionRepoRepository: ExtensionRepoRepository = migrationContext.get() ?: return@withIOContext false
|
||||
val preferenceStore: PreferenceStore = migrationContext.get() ?: return@withIOContext false
|
||||
val extensionRepos: Preference<Set<String>> = preferenceStore.getStringSet("extension_repos", emptySet())
|
||||
|
||||
for ((index, source) in extensionRepos.get().withIndex()) {
|
||||
try {
|
||||
extensionRepoRepository.upsertRepository(
|
||||
source,
|
||||
"Repo #${index + 1}",
|
||||
null,
|
||||
source,
|
||||
"NOFINGERPRINT-${index + 1}",
|
||||
)
|
||||
} catch (e: SaveExtensionRepoException) {
|
||||
Logger.e(e) { "Error Migrating Extension Repo with baseUrl: $source" }
|
||||
}
|
||||
}
|
||||
extensionRepos.delete()
|
||||
|
||||
return@withIOContext true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.ui.reader.settings.OrientationType
|
||||
|
||||
class RotationTypeEnumMigration : Migration {
|
||||
override val version: Float = 77f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
// Migrate Rotation and Viewer values to default values for viewer_flags
|
||||
val newOrientation = when (prefs.getInt("pref_rotation_type_key", 1)) {
|
||||
1 -> OrientationType.FREE.flagValue
|
||||
2 -> OrientationType.PORTRAIT.flagValue
|
||||
3 -> OrientationType.LANDSCAPE.flagValue
|
||||
4 -> OrientationType.LOCKED_PORTRAIT.flagValue
|
||||
5 -> OrientationType.LOCKED_LANDSCAPE.flagValue
|
||||
else -> OrientationType.FREE.flagValue
|
||||
}
|
||||
|
||||
// Reading mode flag and prefValue is the same value
|
||||
val newReadingMode = prefs.getInt("pref_default_viewer_key", 1)
|
||||
|
||||
prefs.edit {
|
||||
putInt("pref_default_orientation_type_key", newOrientation)
|
||||
remove("pref_rotation_type_key")
|
||||
putInt("pref_default_reading_mode_key", newReadingMode)
|
||||
remove("pref_default_viewer_key")
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
|
||||
class RotationTypeMigration : Migration {
|
||||
override val version: Float = 73f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
if (prefs.contains("pref_rotation_type_key")) {
|
||||
prefs.edit {
|
||||
putInt("pref_rotation_type_key", 1)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.data.updater.AppUpdateJob
|
||||
|
||||
class SetupAppUpdateMigration : Migration {
|
||||
override val version: Float = Migration.ALWAYS
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
if (!BuildConfig.INCLUDE_UPDATER) return false
|
||||
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
AppUpdateJob.setupTask(context)
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreatorJob
|
||||
|
||||
class SetupBackupCreateMigration : Migration {
|
||||
override val version: Float = Migration.ALWAYS
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
BackupCreatorJob.setupTask(context)
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
||||
|
||||
class SetupExtensionUpdateMigration : Migration {
|
||||
override val version: Float = Migration.ALWAYS
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
ExtensionUpdateJob.setupTask(context)
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
|
||||
class SetupLibraryUpdateMigration : Migration {
|
||||
override val version: Float = Migration.ALWAYS
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
LibraryUpdateJob.setupTask(context)
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
|
||||
class ShortcutsMigration : Migration {
|
||||
override val version: Float = 75f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val preferences: PreferencesHelper = migrationContext.get() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val wasShortcutsDisabled = !prefs.getBoolean("show_manga_app_shortcuts", true)
|
||||
if (wasShortcutsDisabled) {
|
||||
prefs.edit {
|
||||
putBoolean(PreferenceKeys.showSourcesInShortcuts, false)
|
||||
putBoolean(PreferenceKeys.showSeriesInShortcuts, false)
|
||||
remove("show_manga_app_shortcuts")
|
||||
}
|
||||
}
|
||||
// Handle removed every 1 or 2 hour library updates
|
||||
val updateInterval = preferences.libraryUpdateInterval().get()
|
||||
if (updateInterval == 1 || updateInterval == 2) {
|
||||
preferences.libraryUpdateInterval().set(3)
|
||||
LibraryUpdateJob.setupTask(context, 3)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
|
||||
class ThePurgeMigration : Migration {
|
||||
override val version: Float = 112f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
prefs.edit {
|
||||
remove("trusted_signatures")
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.core.preference.Preference
|
||||
import eu.kanade.tachiyomi.core.preference.PreferenceStore
|
||||
|
||||
class TrackerPrivateSettingsMigration : Migration {
|
||||
override val version: Float = 108f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val preferenceStore: PreferenceStore = migrationContext.get() ?: return false
|
||||
preferenceStore.getAll()
|
||||
.filter { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") }
|
||||
.forEach { (key, value) ->
|
||||
if (value is String) {
|
||||
preferenceStore
|
||||
.getString(Preference.privateKey(key))
|
||||
.set(value)
|
||||
|
||||
preferenceStore.getString(key).delete()
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
|
||||
class UpdateIntervalMigration : Migration {
|
||||
override val version: Float = 86f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
val preferences: PreferencesHelper = migrationContext.get() ?: return false
|
||||
|
||||
// Handle removed every 3, 4, 6, and 8 hour library updates
|
||||
val updateInterval = preferences.libraryUpdateInterval().get()
|
||||
if (updateInterval in listOf(3, 4, 6, 8)) {
|
||||
preferences.libraryUpdateInterval().set(12)
|
||||
LibraryUpdateJob.setupTask(context, 12)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package dev.yokai.core.migration.migrations
|
||||
|
||||
import dev.yokai.core.migration.Migration
|
||||
import dev.yokai.core.migration.MigrationContext
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreatorJob
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.updater.AppUpdateJob
|
||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
||||
|
||||
/**
|
||||
* Restore jobs after migrating from Evernote's job scheduler to WorkManager.
|
||||
*/
|
||||
class WorkManagerMigration : Migration {
|
||||
override val version: Float = 62f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context: App = migrationContext.get() ?: return false
|
||||
LibraryPresenter.updateDB()
|
||||
if (BuildConfig.INCLUDE_UPDATER) {
|
||||
AppUpdateJob.setupTask(context)
|
||||
}
|
||||
LibraryUpdateJob.setupTask(context)
|
||||
BackupCreatorJob.setupTask(context)
|
||||
ExtensionUpdateJob.setupTask(context)
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -38,8 +38,12 @@ import dev.yokai.core.CrashlyticsLogWriter
|
|||
import dev.yokai.core.di.AppModule
|
||||
import dev.yokai.core.di.DomainModule
|
||||
import dev.yokai.core.di.PreferenceModule
|
||||
import dev.yokai.core.migration.Migrator
|
||||
import dev.yokai.core.migration.migrations.migrations
|
||||
import dev.yokai.domain.base.BasePreferences
|
||||
import eu.kanade.tachiyomi.appwidget.TachiyomiWidgetManager
|
||||
import eu.kanade.tachiyomi.core.preference.Preference
|
||||
import eu.kanade.tachiyomi.core.preference.PreferenceStore
|
||||
import eu.kanade.tachiyomi.data.coil.BufferedSourceFetcher
|
||||
import eu.kanade.tachiyomi.data.coil.CoilDiskCache
|
||||
import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher
|
||||
|
@ -154,6 +158,34 @@ open class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.F
|
|||
}
|
||||
}
|
||||
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
||||
|
||||
initializeMigrator()
|
||||
}
|
||||
|
||||
private fun initializeMigrator() {
|
||||
val preferenceStore = Injekt.get<PreferenceStore>()
|
||||
|
||||
val preference = preferenceStore.getInt(
|
||||
Preference.appStateKey("last_version_code"),
|
||||
0,
|
||||
)
|
||||
// TODO: Remove later
|
||||
val old = preferenceStore.getInt("last_version_code", -1)
|
||||
if (old.get() >= preference.get()) {
|
||||
preference.set(old.get())
|
||||
old.delete()
|
||||
}
|
||||
|
||||
Logger.i { "Migration from ${preference.get()} to ${BuildConfig.VERSION_CODE}" }
|
||||
Migrator.initialize(
|
||||
old = preference.get(),
|
||||
new = BuildConfig.VERSION_CODE,
|
||||
migrations = migrations,
|
||||
onMigrationComplete = {
|
||||
Logger.i { "Updating last version to ${BuildConfig.VERSION_CODE}" }
|
||||
preference.set(BuildConfig.VERSION_CODE)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPause(owner: LifecycleOwner) {
|
||||
|
|
|
@ -1,342 +0,0 @@
|
|||
package eu.kanade.tachiyomi
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import co.touchlab.kermit.Logger
|
||||
import dev.yokai.domain.base.BasePreferences
|
||||
import dev.yokai.domain.extension.repo.ExtensionRepoRepository
|
||||
import dev.yokai.domain.extension.repo.exception.SaveExtensionRepoException
|
||||
import dev.yokai.domain.ui.settings.ReaderPreferences
|
||||
import dev.yokai.domain.ui.settings.ReaderPreferences.CutoutBehaviour
|
||||
import dev.yokai.domain.ui.settings.ReaderPreferences.LandscapeCutoutBehaviour
|
||||
import eu.kanade.tachiyomi.core.preference.Preference
|
||||
import eu.kanade.tachiyomi.core.preference.PreferenceStore
|
||||
import eu.kanade.tachiyomi.core.preference.plusAssign
|
||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreatorJob
|
||||
import eu.kanade.tachiyomi.data.download.DownloadProvider
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.updater.AppDownloadInstallJob
|
||||
import eu.kanade.tachiyomi.data.updater.AppUpdateJob
|
||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
||||
import eu.kanade.tachiyomi.ui.library.LibrarySort
|
||||
import eu.kanade.tachiyomi.ui.reader.settings.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig
|
||||
import eu.kanade.tachiyomi.ui.recents.RecentsPresenter
|
||||
import eu.kanade.tachiyomi.util.system.launchIO
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import kotlin.math.max
|
||||
|
||||
object Migrations {
|
||||
|
||||
/**
|
||||
* Performs a migration when the application is updated.
|
||||
*
|
||||
* @param preferences Preferences of the application.
|
||||
* @return true if a migration is performed, false otherwise.
|
||||
*/
|
||||
fun upgrade(
|
||||
preferences: PreferencesHelper,
|
||||
preferenceStore: PreferenceStore,
|
||||
scope: CoroutineScope,
|
||||
): Boolean {
|
||||
val context = preferences.context
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
prefs.edit {
|
||||
remove(AppDownloadInstallJob.NOTIFY_ON_INSTALL_KEY)
|
||||
}
|
||||
val oldVersion = preferences.lastVersionCode().get()
|
||||
if (oldVersion < BuildConfig.VERSION_CODE) {
|
||||
preferences.lastVersionCode().set(BuildConfig.VERSION_CODE)
|
||||
|
||||
// Always set up background tasks to ensure they're running
|
||||
if (BuildConfig.INCLUDE_UPDATER) {
|
||||
AppUpdateJob.setupTask(context)
|
||||
}
|
||||
ExtensionUpdateJob.setupTask(context)
|
||||
LibraryUpdateJob.setupTask(context)
|
||||
BackupCreatorJob.setupTask(context)
|
||||
|
||||
if (oldVersion == 0) {
|
||||
return BuildConfig.DEBUG
|
||||
}
|
||||
|
||||
if (oldVersion < 14) {
|
||||
// Restore jobs after upgrading to evernote's job scheduler.
|
||||
if (BuildConfig.INCLUDE_UPDATER) {
|
||||
AppUpdateJob.setupTask(context)
|
||||
}
|
||||
LibraryUpdateJob.setupTask(context)
|
||||
}
|
||||
if (oldVersion < 15) {
|
||||
// Delete internal chapter cache dir.
|
||||
File(context.cacheDir, "chapter_disk_cache").deleteRecursively()
|
||||
}
|
||||
if (oldVersion < 19) {
|
||||
// Move covers to external files dir.
|
||||
val oldDir = File(context.externalCacheDir, "cover_disk_cache")
|
||||
if (oldDir.exists()) {
|
||||
val destDir = context.getExternalFilesDir("covers")
|
||||
if (destDir != null) {
|
||||
oldDir.listFiles()?.forEach {
|
||||
it.renameTo(File(destDir, it.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 26) {
|
||||
// Delete external chapter cache dir.
|
||||
val extCache = context.externalCacheDir
|
||||
if (extCache != null) {
|
||||
val chapterCache = File(extCache, "chapter_disk_cache")
|
||||
if (chapterCache.exists()) {
|
||||
chapterCache.deleteRecursively()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 54) {
|
||||
DownloadProvider(context).renameChapters()
|
||||
}
|
||||
if (oldVersion < 62) {
|
||||
LibraryPresenter.updateDB()
|
||||
// Restore jobs after migrating from Evernote's job scheduler to WorkManager.
|
||||
if (BuildConfig.INCLUDE_UPDATER) {
|
||||
AppUpdateJob.setupTask(context)
|
||||
}
|
||||
LibraryUpdateJob.setupTask(context)
|
||||
BackupCreatorJob.setupTask(context)
|
||||
ExtensionUpdateJob.setupTask(context)
|
||||
}
|
||||
if (oldVersion < 66) {
|
||||
LibraryPresenter.updateCustoms()
|
||||
}
|
||||
if (oldVersion < 68) {
|
||||
// Force MAL log out due to login flow change
|
||||
// v67: switched from scraping to WebView
|
||||
// v68: switched from WebView to OAuth
|
||||
val trackManager = Injekt.get<TrackManager>()
|
||||
if (trackManager.myAnimeList.isLogged) {
|
||||
trackManager.myAnimeList.logout()
|
||||
context.toast(R.string.myanimelist_relogin)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 71) {
|
||||
// Migrate DNS over HTTPS setting
|
||||
val wasDohEnabled = prefs.getBoolean("enable_doh", false)
|
||||
if (wasDohEnabled) {
|
||||
prefs.edit {
|
||||
putInt(PreferenceKeys.dohProvider, PREF_DOH_CLOUDFLARE)
|
||||
remove("enable_doh")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 73) {
|
||||
// Reset rotation to Free after replacing Lock
|
||||
if (prefs.contains("pref_rotation_type_key")) {
|
||||
prefs.edit {
|
||||
putInt("pref_rotation_type_key", 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 74) {
|
||||
// Turn on auto updates for all users
|
||||
if (BuildConfig.INCLUDE_UPDATER) {
|
||||
AppUpdateJob.setupTask(context)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 75) {
|
||||
val wasShortcutsDisabled = !prefs.getBoolean("show_manga_app_shortcuts", true)
|
||||
if (wasShortcutsDisabled) {
|
||||
prefs.edit {
|
||||
putBoolean(PreferenceKeys.showSourcesInShortcuts, false)
|
||||
putBoolean(PreferenceKeys.showSeriesInShortcuts, false)
|
||||
remove("show_manga_app_shortcuts")
|
||||
}
|
||||
}
|
||||
// Handle removed every 1 or 2 hour library updates
|
||||
val updateInterval = preferences.libraryUpdateInterval().get()
|
||||
if (updateInterval == 1 || updateInterval == 2) {
|
||||
preferences.libraryUpdateInterval().set(3)
|
||||
LibraryUpdateJob.setupTask(context, 3)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 77) {
|
||||
// Migrate Rotation and Viewer values to default values for viewer_flags
|
||||
val newOrientation = when (prefs.getInt("pref_rotation_type_key", 1)) {
|
||||
1 -> OrientationType.FREE.flagValue
|
||||
2 -> OrientationType.PORTRAIT.flagValue
|
||||
3 -> OrientationType.LANDSCAPE.flagValue
|
||||
4 -> OrientationType.LOCKED_PORTRAIT.flagValue
|
||||
5 -> OrientationType.LOCKED_LANDSCAPE.flagValue
|
||||
else -> OrientationType.FREE.flagValue
|
||||
}
|
||||
|
||||
// Reading mode flag and prefValue is the same value
|
||||
val newReadingMode = prefs.getInt("pref_default_viewer_key", 1)
|
||||
|
||||
prefs.edit {
|
||||
putInt("pref_default_orientation_type_key", newOrientation)
|
||||
remove("pref_rotation_type_key")
|
||||
putInt("pref_default_reading_mode_key", newReadingMode)
|
||||
remove("pref_default_viewer_key")
|
||||
}
|
||||
}
|
||||
if (oldVersion < 83) {
|
||||
if (preferences.enabledLanguages().isSet()) {
|
||||
preferences.enabledLanguages() += "all"
|
||||
}
|
||||
}
|
||||
if (oldVersion < 86) {
|
||||
// Handle removed every 3, 4, 6, and 8 hour library updates
|
||||
val updateInterval = preferences.libraryUpdateInterval().get()
|
||||
if (updateInterval in listOf(3, 4, 6, 8)) {
|
||||
preferences.libraryUpdateInterval().set(12)
|
||||
LibraryUpdateJob.setupTask(context, 12)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 88) {
|
||||
scope.launchIO {
|
||||
LibraryPresenter.updateRatiosAndColors()
|
||||
}
|
||||
val oldReaderTap = prefs.getBoolean("reader_tap", true)
|
||||
if (!oldReaderTap) {
|
||||
preferences.navigationModePager().set(5)
|
||||
preferences.navigationModeWebtoon().set(5)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 90) {
|
||||
val oldSecureScreen = prefs.getBoolean("secure_screen", false)
|
||||
if (oldSecureScreen) {
|
||||
preferences.secureScreen().set(PreferenceValues.SecureScreenMode.ALWAYS)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 97) {
|
||||
val oldDLAfterReading = prefs.getInt("auto_download_after_reading", 0)
|
||||
if (oldDLAfterReading > 0) {
|
||||
preferences.autoDownloadWhileReading().set(max(2, oldDLAfterReading))
|
||||
}
|
||||
}
|
||||
if (oldVersion < 102) {
|
||||
val oldGroupHistory = prefs.getBoolean("group_chapters_history", true)
|
||||
if (!oldGroupHistory) {
|
||||
preferences.groupChaptersHistory().set(RecentsPresenter.GroupType.Never)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 105) {
|
||||
LibraryUpdateJob.cancelAllWorks(context)
|
||||
LibraryUpdateJob.setupTask(context)
|
||||
}
|
||||
if (oldVersion < 108) {
|
||||
preferenceStore.getAll()
|
||||
.filter { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") }
|
||||
.forEach { (key, value) ->
|
||||
if (value is String) {
|
||||
preferenceStore
|
||||
.getString(Preference.privateKey(key))
|
||||
.set(value)
|
||||
|
||||
preferenceStore.getString(key).delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 110) {
|
||||
try {
|
||||
val librarySortString = prefs.getString("library_sorting_mode", "")
|
||||
if (!librarySortString.isNullOrEmpty()) {
|
||||
prefs.edit {
|
||||
remove("library_sorting_mode")
|
||||
putInt(
|
||||
"library_sorting_mode",
|
||||
LibrarySort.deserialize(librarySortString).mainValue,
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
if (oldVersion < 112) {
|
||||
prefs.edit {
|
||||
remove("trusted_signatures")
|
||||
}
|
||||
}
|
||||
if (oldVersion < 119) {
|
||||
val basePreferences: BasePreferences = Injekt.get()
|
||||
try {
|
||||
val oldExtensionInstall = prefs.getInt("extension_installer", 0)
|
||||
basePreferences.extensionInstaller().set(
|
||||
when (oldExtensionInstall) {
|
||||
1 -> BasePreferences.ExtensionInstaller.SHIZUKU
|
||||
2 -> BasePreferences.ExtensionInstaller.PRIVATE
|
||||
else -> BasePreferences.ExtensionInstaller.PACKAGEINSTALLER
|
||||
}
|
||||
)
|
||||
} catch (_: Exception) {
|
||||
basePreferences.extensionInstaller().set(BasePreferences.ExtensionInstaller.PACKAGEINSTALLER)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 121) {
|
||||
val readerPreferences: ReaderPreferences = Injekt.get()
|
||||
try {
|
||||
val oldCutoutBehaviour = prefs.getInt(PreferenceKeys.pagerCutoutBehavior, 0)
|
||||
readerPreferences.pagerCutoutBehavior().set(
|
||||
when (oldCutoutBehaviour) {
|
||||
PagerConfig.CUTOUT_PAD -> CutoutBehaviour.HIDE
|
||||
PagerConfig.CUTOUT_IGNORE -> CutoutBehaviour.IGNORE
|
||||
else -> CutoutBehaviour.SHOW
|
||||
}
|
||||
)
|
||||
} catch (_: Exception) {
|
||||
readerPreferences.pagerCutoutBehavior().set(CutoutBehaviour.SHOW)
|
||||
}
|
||||
|
||||
try {
|
||||
val oldCutoutBehaviour = prefs.getInt("landscape_cutout_behavior", 0)
|
||||
readerPreferences.landscapeCutoutBehavior().set(
|
||||
when (oldCutoutBehaviour) {
|
||||
0 -> LandscapeCutoutBehaviour.HIDE
|
||||
else -> LandscapeCutoutBehaviour.DEFAULT
|
||||
}
|
||||
)
|
||||
} catch (_: Exception) {
|
||||
readerPreferences.landscapeCutoutBehavior().set(LandscapeCutoutBehaviour.DEFAULT)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 130) {
|
||||
val coroutineScope = CoroutineScope(Dispatchers.IO)
|
||||
val extensionRepoRepository: ExtensionRepoRepository by injectLazy()
|
||||
val extensionRepos: Preference<Set<String>> = preferenceStore.getStringSet("extension_repos", emptySet())
|
||||
|
||||
coroutineScope.launchIO {
|
||||
for ((index, source) in extensionRepos.get().withIndex()) {
|
||||
try {
|
||||
extensionRepoRepository.upsertRepository(
|
||||
source,
|
||||
"Repo #${index + 1}",
|
||||
null,
|
||||
source,
|
||||
"NOFINGERPRINT-${index + 1}",
|
||||
)
|
||||
} catch (e: SaveExtensionRepoException) {
|
||||
Logger.e(e) { "Error Migrating Extension Repo with baseUrl: $source" }
|
||||
}
|
||||
}
|
||||
extensionRepos.delete()
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ import eu.kanade.tachiyomi.extension.api.ExtensionApi
|
|||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.util.ExtensionLoader
|
||||
import eu.kanade.tachiyomi.util.system.connectivityManager
|
||||
import eu.kanade.tachiyomi.util.system.jobIsRunning
|
||||
import eu.kanade.tachiyomi.util.system.localeContext
|
||||
import eu.kanade.tachiyomi.util.system.notification
|
||||
import eu.kanade.tachiyomi.util.system.toInt
|
||||
|
@ -38,7 +39,7 @@ import rikka.shizuku.Shizuku
|
|||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.*
|
||||
|
||||
class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
||||
CoroutineWorker(context, workerParams) {
|
||||
|
@ -179,6 +180,7 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
|
|||
fun setupTask(context: Context, forceAutoUpdateJob: Boolean? = null) {
|
||||
val preferences = Injekt.get<PreferencesHelper>()
|
||||
val autoUpdateJob = forceAutoUpdateJob ?: preferences.automaticExtUpdates().get()
|
||||
WorkManager.getInstance(context).jobIsRunning(TAG)
|
||||
if (autoUpdateJob) {
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
|
|
|
@ -67,11 +67,11 @@ import com.google.android.material.snackbar.Snackbar
|
|||
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
|
||||
import com.google.common.primitives.Floats.max
|
||||
import com.google.common.primitives.Ints.max
|
||||
import dev.yokai.core.migration.Migrator
|
||||
import dev.yokai.domain.base.BasePreferences
|
||||
import dev.yokai.presentation.extension.repo.ExtensionRepoController
|
||||
import dev.yokai.presentation.onboarding.OnboardingController
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.Migrations
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.download.DownloadJob
|
||||
|
@ -142,9 +142,22 @@ import kotlinx.coroutines.delay
|
|||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.withContext
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.collections.List
|
||||
import kotlin.collections.MutableList
|
||||
import kotlin.collections.MutableMap
|
||||
import kotlin.collections.distinct
|
||||
import kotlin.collections.filterNotNull
|
||||
import kotlin.collections.firstOrNull
|
||||
import kotlin.collections.forEach
|
||||
import kotlin.collections.forEachIndexed
|
||||
import kotlin.collections.lastOrNull
|
||||
import kotlin.collections.listOf
|
||||
import kotlin.collections.map
|
||||
import kotlin.collections.maxByOrNull
|
||||
import kotlin.collections.orEmpty
|
||||
import kotlin.collections.plus
|
||||
import kotlin.collections.set
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToLong
|
||||
|
@ -442,8 +455,10 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
|
|||
// Reset Incognito Mode on relaunch
|
||||
preferences.incognitoMode().set(false)
|
||||
|
||||
val didMigration = Migrator.awaitAndRelease()
|
||||
|
||||
// Show changelog if needed
|
||||
if (Migrations.upgrade(preferences, Injekt.get(), lifecycleScope)) {
|
||||
if (didMigration) {
|
||||
if (!BuildConfig.DEBUG) {
|
||||
content.post {
|
||||
whatsNewSheet().show()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue