mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-23 13:23:28 +03:00
Rewrite Migrations (#577)
* Rewrite Migrations * Fix Detekt errors * Do migrations synchronous * Filter and sort migrations * Review changes * Review changes 2 * Fix Detekt errors Co-authored-by: Andreas <6576096+ghostbear@users.noreply.github.com>
This commit is contained in:
parent
92f16c913e
commit
486db1fd53
48 changed files with 1578 additions and 721 deletions
|
@ -1,696 +0,0 @@
|
|||
package eu.kanade.tachiyomi
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.domain.ui.model.NavStyle
|
||||
import eu.kanade.domain.ui.model.StartScreen
|
||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
|
||||
import eu.kanade.tachiyomi.data.library.anime.AnimeLibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.library.manga.MangaLibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
|
||||
import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences
|
||||
import eu.kanade.tachiyomi.ui.player.viewer.AspectState
|
||||
import eu.kanade.tachiyomi.ui.player.viewer.HwDecState
|
||||
import eu.kanade.tachiyomi.ui.player.viewer.InvertedPlayback
|
||||
import eu.kanade.tachiyomi.ui.player.viewer.VideoDebanding
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.workManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import logcat.LogPriority
|
||||
import mihon.domain.extensionrepo.anime.repository.AnimeExtensionRepoRepository
|
||||
import mihon.domain.extensionrepo.exception.SaveExtensionRepoException
|
||||
import mihon.domain.extensionrepo.manga.repository.MangaExtensionRepoRepository
|
||||
import tachiyomi.core.common.preference.Preference
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
import tachiyomi.core.common.preference.TriState
|
||||
import tachiyomi.core.common.preference.getAndSet
|
||||
import tachiyomi.core.common.preference.getEnum
|
||||
import tachiyomi.core.common.preference.minusAssign
|
||||
import tachiyomi.core.common.preference.plusAssign
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.core.common.util.system.logcat
|
||||
import tachiyomi.domain.backup.service.BackupPreferences
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.library.service.LibraryPreferences.Companion.ENTRY_NON_COMPLETED
|
||||
import java.io.File
|
||||
|
||||
object Migrations {
|
||||
|
||||
/**
|
||||
* Performs a migration when the application is updated.
|
||||
*
|
||||
* @return true if a migration is performed, false otherwise.
|
||||
*/
|
||||
@Suppress(
|
||||
"SameReturnValue",
|
||||
"MagicNumber",
|
||||
"CyclomaticComplexMethod",
|
||||
"LongMethod",
|
||||
"LongParameterList",
|
||||
"NestedBlockDepth",
|
||||
"ReturnCount",
|
||||
)
|
||||
fun upgrade(
|
||||
context: Context,
|
||||
preferenceStore: PreferenceStore,
|
||||
basePreferences: BasePreferences,
|
||||
uiPreferences: UiPreferences,
|
||||
networkPreferences: NetworkPreferences,
|
||||
sourcePreferences: SourcePreferences,
|
||||
securityPreferences: SecurityPreferences,
|
||||
libraryPreferences: LibraryPreferences,
|
||||
readerPreferences: ReaderPreferences,
|
||||
playerPreferences: PlayerPreferences,
|
||||
backupPreferences: BackupPreferences,
|
||||
trackerManager: TrackerManager,
|
||||
animeExtensionRepoRepository: AnimeExtensionRepoRepository,
|
||||
mangaExtensionRepoRepository: MangaExtensionRepoRepository,
|
||||
): Boolean {
|
||||
val lastVersionCode = preferenceStore.getInt(Preference.appStateKey("last_version_code"), 0)
|
||||
val oldVersion = lastVersionCode.get()
|
||||
if (oldVersion < BuildConfig.VERSION_CODE) {
|
||||
lastVersionCode.set(BuildConfig.VERSION_CODE)
|
||||
|
||||
// Always set up background tasks to ensure they're running
|
||||
MangaLibraryUpdateJob.setupTask(context)
|
||||
AnimeLibraryUpdateJob.setupTask(context)
|
||||
BackupCreateJob.setupTask(context)
|
||||
|
||||
// Fresh install
|
||||
if (oldVersion == 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(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 < 44) {
|
||||
// Reset sorting preference if using removed sort by source
|
||||
val oldMangaSortingMode = prefs.getInt(
|
||||
libraryPreferences.mangaSortingMode().key(),
|
||||
0,
|
||||
)
|
||||
|
||||
if (oldMangaSortingMode == 5) { // SOURCE = 5
|
||||
prefs.edit {
|
||||
putInt(libraryPreferences.mangaSortingMode().key(), 0) // ALPHABETICAL = 0
|
||||
}
|
||||
}
|
||||
|
||||
val oldAnimeSortingMode = prefs.getInt(
|
||||
libraryPreferences.animeSortingMode().key(),
|
||||
0,
|
||||
)
|
||||
|
||||
if (oldAnimeSortingMode == 5) { // SOURCE = 5
|
||||
prefs.edit {
|
||||
putInt(libraryPreferences.animeSortingMode().key(), 0) // ALPHABETICAL = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 52) {
|
||||
// Migrate library filters to tri-state versions
|
||||
fun convertBooleanPrefToTriState(key: String): Int {
|
||||
val oldPrefValue = prefs.getBoolean(key, false)
|
||||
return if (oldPrefValue) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
prefs.edit {
|
||||
putInt(
|
||||
libraryPreferences.filterDownloadedManga().key(),
|
||||
convertBooleanPrefToTriState("pref_filter_downloaded_key"),
|
||||
)
|
||||
remove("pref_filter_downloaded_key")
|
||||
|
||||
putInt(
|
||||
libraryPreferences.filterUnread().key(),
|
||||
convertBooleanPrefToTriState("pref_filter_unread_key"),
|
||||
)
|
||||
remove("pref_filter_unread_key")
|
||||
|
||||
putInt(
|
||||
libraryPreferences.filterCompletedManga().key(),
|
||||
convertBooleanPrefToTriState("pref_filter_completed_key"),
|
||||
)
|
||||
remove("pref_filter_completed_key")
|
||||
}
|
||||
}
|
||||
if (oldVersion < 54) {
|
||||
// Force MAL log out due to login flow change
|
||||
// v52: switched from scraping to WebView
|
||||
// v53: switched from WebView to OAuth
|
||||
if (trackerManager.myAnimeList.isLoggedIn) {
|
||||
trackerManager.myAnimeList.logout()
|
||||
}
|
||||
}
|
||||
if (oldVersion < 57) {
|
||||
// Migrate DNS over HTTPS setting
|
||||
val wasDohEnabled = prefs.getBoolean("enable_doh", false)
|
||||
if (wasDohEnabled) {
|
||||
prefs.edit {
|
||||
putInt(networkPreferences.dohProvider().key(), PREF_DOH_CLOUDFLARE)
|
||||
remove("enable_doh")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 59) {
|
||||
// Reset rotation to Free after replacing Lock
|
||||
if (prefs.contains("pref_rotation_type_key")) {
|
||||
prefs.edit {
|
||||
putInt("pref_rotation_type_key", 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 60) {
|
||||
// Migrate Rotation and Viewer values to default values for viewer_flags
|
||||
val newOrientation = when (prefs.getInt("pref_rotation_type_key", 1)) {
|
||||
1 -> ReaderOrientation.FREE.flagValue
|
||||
2 -> ReaderOrientation.PORTRAIT.flagValue
|
||||
3 -> ReaderOrientation.LANDSCAPE.flagValue
|
||||
4 -> ReaderOrientation.LOCKED_PORTRAIT.flagValue
|
||||
5 -> ReaderOrientation.LOCKED_LANDSCAPE.flagValue
|
||||
else -> ReaderOrientation.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 < 61) {
|
||||
// Handle removed every 1 or 2 hour library updates
|
||||
val updateInterval = libraryPreferences.autoUpdateInterval().get()
|
||||
if (updateInterval == 1 || updateInterval == 2) {
|
||||
libraryPreferences.autoUpdateInterval().set(3)
|
||||
MangaLibraryUpdateJob.setupTask(context, 3)
|
||||
AnimeLibraryUpdateJob.setupTask(context, 3)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 64) {
|
||||
// Set up background tasks
|
||||
MangaLibraryUpdateJob.setupTask(context)
|
||||
AnimeLibraryUpdateJob.setupTask(context)
|
||||
}
|
||||
if (oldVersion < 64) {
|
||||
val oldMangaSortingMode = prefs.getInt(
|
||||
libraryPreferences.mangaSortingMode().key(),
|
||||
0,
|
||||
)
|
||||
val oldAnimeSortingMode = prefs.getInt(
|
||||
libraryPreferences.animeSortingMode().key(),
|
||||
0,
|
||||
)
|
||||
val oldSortingDirection = prefs.getBoolean("library_sorting_ascending", true)
|
||||
|
||||
val newMangaSortingMode = when (oldMangaSortingMode) {
|
||||
0 -> "ALPHABETICAL"
|
||||
1 -> "LAST_READ"
|
||||
2 -> "LAST_CHECKED"
|
||||
3 -> "UNREAD"
|
||||
4 -> "TOTAL_CHAPTERS"
|
||||
6 -> "LATEST_CHAPTER"
|
||||
8 -> "DATE_FETCHED"
|
||||
7 -> "DATE_ADDED"
|
||||
else -> "ALPHABETICAL"
|
||||
}
|
||||
|
||||
val newAnimeSortingMode = when (oldAnimeSortingMode) {
|
||||
0 -> "ALPHABETICAL"
|
||||
1 -> "LAST_SEEN"
|
||||
2 -> "LAST_CHECKED"
|
||||
3 -> "UNSEEN"
|
||||
4 -> "TOTAL_EPISODES"
|
||||
6 -> "LATEST_EPISODE"
|
||||
8 -> "DATE_FETCHED"
|
||||
7 -> "DATE_ADDED"
|
||||
else -> "ALPHABETICAL"
|
||||
}
|
||||
|
||||
val newSortingDirection = when (oldSortingDirection) {
|
||||
true -> "ASCENDING"
|
||||
else -> "DESCENDING"
|
||||
}
|
||||
|
||||
prefs.edit(commit = true) {
|
||||
remove(libraryPreferences.mangaSortingMode().key())
|
||||
remove(libraryPreferences.animeSortingMode().key())
|
||||
remove("library_sorting_ascending")
|
||||
}
|
||||
|
||||
prefs.edit {
|
||||
putString(libraryPreferences.mangaSortingMode().key(), newMangaSortingMode)
|
||||
putString(libraryPreferences.animeSortingMode().key(), newAnimeSortingMode)
|
||||
putString("library_sorting_ascending", newSortingDirection)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 70) {
|
||||
if (sourcePreferences.enabledLanguages().isSet()) {
|
||||
sourcePreferences.enabledLanguages() += "all"
|
||||
}
|
||||
}
|
||||
if (oldVersion < 71) {
|
||||
// Handle removed every 3, 4, 6, and 8 hour library updates
|
||||
val updateInterval = libraryPreferences.autoUpdateInterval().get()
|
||||
if (updateInterval in listOf(3, 4, 6, 8)) {
|
||||
libraryPreferences.autoUpdateInterval().set(12)
|
||||
MangaLibraryUpdateJob.setupTask(context, 12)
|
||||
AnimeLibraryUpdateJob.setupTask(context, 12)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 72) {
|
||||
val oldUpdateOngoingOnly = prefs.getBoolean(
|
||||
"pref_update_only_non_completed_key",
|
||||
true,
|
||||
)
|
||||
if (!oldUpdateOngoingOnly) {
|
||||
libraryPreferences.autoUpdateItemRestrictions() -= ENTRY_NON_COMPLETED
|
||||
}
|
||||
}
|
||||
if (oldVersion < 75) {
|
||||
val oldSecureScreen = prefs.getBoolean("secure_screen", false)
|
||||
if (oldSecureScreen) {
|
||||
securityPreferences.secureScreen().set(
|
||||
SecurityPreferences.SecureScreenMode.ALWAYS,
|
||||
)
|
||||
}
|
||||
if (DeviceUtil.isMiui &&
|
||||
basePreferences.extensionInstaller().get() == BasePreferences.ExtensionInstaller.PACKAGEINSTALLER
|
||||
) {
|
||||
basePreferences.extensionInstaller().set(
|
||||
BasePreferences.ExtensionInstaller.LEGACY,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 77) {
|
||||
val oldReaderTap = prefs.getBoolean("reader_tap", false)
|
||||
if (!oldReaderTap) {
|
||||
readerPreferences.navigationModePager().set(5)
|
||||
readerPreferences.navigationModeWebtoon().set(5)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 81) {
|
||||
// Handle renamed enum values
|
||||
prefs.edit {
|
||||
val newMangaSortingMode = when (
|
||||
val oldSortingMode = prefs.getString(
|
||||
libraryPreferences.mangaSortingMode().key(),
|
||||
"ALPHABETICAL",
|
||||
)
|
||||
) {
|
||||
"LAST_CHECKED" -> "LAST_MANGA_UPDATE"
|
||||
"UNREAD" -> "UNREAD_COUNT"
|
||||
"DATE_FETCHED" -> "CHAPTER_FETCH_DATE"
|
||||
else -> oldSortingMode
|
||||
}
|
||||
val newAnimeSortingMode = when (
|
||||
val oldSortingMode = prefs.getString(
|
||||
libraryPreferences.animeSortingMode().key(),
|
||||
"ALPHABETICAL",
|
||||
)
|
||||
) {
|
||||
"LAST_CHECKED" -> "LAST_MANGA_UPDATE"
|
||||
"UNREAD" -> "UNREAD_COUNT"
|
||||
"DATE_FETCHED" -> "CHAPTER_FETCH_DATE"
|
||||
else -> oldSortingMode
|
||||
}
|
||||
putString(libraryPreferences.mangaSortingMode().key(), newMangaSortingMode)
|
||||
putString(libraryPreferences.animeSortingMode().key(), newAnimeSortingMode)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 82) {
|
||||
prefs.edit {
|
||||
val mangasort = prefs.getString(
|
||||
libraryPreferences.mangaSortingMode().key(),
|
||||
null,
|
||||
) ?: return@edit
|
||||
val animesort = prefs.getString(
|
||||
libraryPreferences.animeSortingMode().key(),
|
||||
null,
|
||||
) ?: return@edit
|
||||
val direction = prefs.getString("library_sorting_ascending", "ASCENDING")!!
|
||||
putString(libraryPreferences.mangaSortingMode().key(), "$mangasort,$direction")
|
||||
putString(libraryPreferences.animeSortingMode().key(), "$animesort,$direction")
|
||||
remove("library_sorting_ascending")
|
||||
}
|
||||
}
|
||||
if (oldVersion < 84) {
|
||||
if (backupPreferences.backupInterval().get() == 0) {
|
||||
backupPreferences.backupInterval().set(12)
|
||||
BackupCreateJob.setupTask(context)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 85) {
|
||||
val preferences = listOf(
|
||||
libraryPreferences.filterChapterByRead(),
|
||||
libraryPreferences.filterChapterByDownloaded(),
|
||||
libraryPreferences.filterChapterByBookmarked(),
|
||||
libraryPreferences.sortChapterBySourceOrNumber(),
|
||||
libraryPreferences.displayChapterByNameOrNumber(),
|
||||
libraryPreferences.sortChapterByAscendingOrDescending(),
|
||||
libraryPreferences.filterEpisodeBySeen(),
|
||||
libraryPreferences.filterEpisodeByDownloaded(),
|
||||
libraryPreferences.filterEpisodeByBookmarked(),
|
||||
libraryPreferences.sortEpisodeBySourceOrNumber(),
|
||||
libraryPreferences.displayEpisodeByNameOrNumber(),
|
||||
libraryPreferences.sortEpisodeByAscendingOrDescending(),
|
||||
)
|
||||
|
||||
prefs.edit {
|
||||
preferences.forEach { preference ->
|
||||
val key = preference.key()
|
||||
val value = prefs.getInt(key, Int.MIN_VALUE)
|
||||
if (value == Int.MIN_VALUE) return@forEach
|
||||
remove(key)
|
||||
putLong(key, value.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 86) {
|
||||
if (uiPreferences.themeMode().isSet()) {
|
||||
prefs.edit {
|
||||
val themeMode = prefs.getString(uiPreferences.themeMode().key(), null) ?: return@edit
|
||||
putString(uiPreferences.themeMode().key(), themeMode.uppercase())
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 92) {
|
||||
if (playerPreferences.progressPreference().isSet()) {
|
||||
prefs.edit {
|
||||
val progressString = try {
|
||||
prefs.getString(playerPreferences.progressPreference().key(), null)
|
||||
} catch (e: ClassCastException) {
|
||||
null
|
||||
} ?: return@edit
|
||||
val newProgress = progressString.toFloatOrNull() ?: return@edit
|
||||
putFloat(playerPreferences.progressPreference().key(), newProgress)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 93) {
|
||||
listOf(
|
||||
playerPreferences.defaultPlayerOrientationType(),
|
||||
playerPreferences.defaultPlayerOrientationLandscape(),
|
||||
playerPreferences.defaultPlayerOrientationPortrait(),
|
||||
playerPreferences.skipLengthPreference(),
|
||||
).forEach { pref ->
|
||||
if (pref.isSet()) {
|
||||
prefs.edit {
|
||||
val oldString = try {
|
||||
prefs.getString(pref.key(), null)
|
||||
} catch (e: ClassCastException) {
|
||||
null
|
||||
} ?: return@edit
|
||||
val newInt = oldString.toIntOrNull() ?: return@edit
|
||||
putInt(pref.key(), newInt)
|
||||
}
|
||||
val trackingQueuePref =
|
||||
context.getSharedPreferences("tracking_queue", Context.MODE_PRIVATE)
|
||||
trackingQueuePref.all.forEach {
|
||||
val (_, lastChapterRead) = it.value.toString().split(":")
|
||||
trackingQueuePref.edit {
|
||||
remove(it.key)
|
||||
putFloat(it.key, lastChapterRead.toFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 96) {
|
||||
MangaLibraryUpdateJob.cancelAllWorks(context)
|
||||
AnimeLibraryUpdateJob.cancelAllWorks(context)
|
||||
MangaLibraryUpdateJob.setupTask(context)
|
||||
AnimeLibraryUpdateJob.setupTask(context)
|
||||
}
|
||||
if (oldVersion < 97) {
|
||||
// Removed background jobs
|
||||
context.workManager.cancelAllWorkByTag("UpdateChecker")
|
||||
context.workManager.cancelAllWorkByTag("ExtensionUpdate")
|
||||
prefs.edit {
|
||||
remove("automatic_ext_updates")
|
||||
}
|
||||
}
|
||||
if (oldVersion < 99) {
|
||||
val prefKeys = listOf(
|
||||
"pref_filter_library_downloaded",
|
||||
"pref_filter_library_unread",
|
||||
"pref_filter_library_unseen",
|
||||
"pref_filter_library_started",
|
||||
"pref_filter_library_bookmarked",
|
||||
"pref_filter_library_completed",
|
||||
) + trackerManager.trackers.map { "pref_filter_library_tracked_${it.id}" }
|
||||
|
||||
prefKeys.forEach { key ->
|
||||
val pref = preferenceStore.getInt(key, 0)
|
||||
prefs.edit {
|
||||
remove(key)
|
||||
|
||||
val newValue = when (pref.get()) {
|
||||
1 -> TriState.ENABLED_IS
|
||||
2 -> TriState.ENABLED_NOT
|
||||
else -> TriState.DISABLED
|
||||
}
|
||||
|
||||
preferenceStore.getEnum("${key}_v2", TriState.DISABLED).set(
|
||||
newValue,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldVersion < 105) {
|
||||
val pref = libraryPreferences.autoUpdateDeviceRestrictions()
|
||||
if (pref.isSet() && "battery_not_low" in pref.get()) {
|
||||
pref.getAndSet { it - "battery_not_low" }
|
||||
}
|
||||
}
|
||||
if (oldVersion < 106) {
|
||||
val pref = preferenceStore.getInt("relative_time", 7)
|
||||
if (pref.get() == 0) {
|
||||
uiPreferences.relativeTime().set(false)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 113) {
|
||||
val prefsToReplace = listOf(
|
||||
"pref_download_only",
|
||||
"incognito_mode",
|
||||
"last_catalogue_source",
|
||||
"trusted_signatures",
|
||||
"last_app_closed",
|
||||
"library_update_last_timestamp",
|
||||
"library_unseen_updates_count",
|
||||
"last_used_category",
|
||||
"last_app_check",
|
||||
"last_ext_check",
|
||||
"last_version_code",
|
||||
"storage_dir",
|
||||
)
|
||||
replacePreferences(
|
||||
preferenceStore = preferenceStore,
|
||||
filterPredicate = { it.key in prefsToReplace },
|
||||
newKey = { Preference.appStateKey(it) },
|
||||
)
|
||||
|
||||
// Deleting old download cache index files, but might as well clear it all out
|
||||
context.cacheDir.deleteRecursively()
|
||||
}
|
||||
if (oldVersion < 114) {
|
||||
sourcePreferences.mangaExtensionRepos().getAndSet {
|
||||
it.map { repo -> "https://raw.githubusercontent.com/$repo/repo" }.toSet()
|
||||
}
|
||||
}
|
||||
if (oldVersion < 116) {
|
||||
replacePreferences(
|
||||
preferenceStore = preferenceStore,
|
||||
filterPredicate = { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") },
|
||||
newKey = { Preference.privateKey(it) },
|
||||
)
|
||||
}
|
||||
if (oldVersion < 117) {
|
||||
prefs.edit {
|
||||
remove(Preference.appStateKey("trusted_signatures"))
|
||||
}
|
||||
}
|
||||
|
||||
if (oldVersion < 120) {
|
||||
val bottomNavStyle = preferenceStore.getInt("bottom_nav_style", 0)
|
||||
|
||||
val isDefaultTabManga = preferenceStore.getBoolean("default_home_tab_library", false)
|
||||
prefs.edit {
|
||||
remove("bottom_nav_style")
|
||||
remove("default_home_tab_library")
|
||||
|
||||
val startScreen = if (isDefaultTabManga.get()) StartScreen.MANGA else StartScreen.ANIME
|
||||
val navStyle = when (bottomNavStyle.get()) {
|
||||
0 -> NavStyle.MOVE_HISTORY_TO_MORE
|
||||
1 -> NavStyle.MOVE_UPDATES_TO_MORE
|
||||
else -> NavStyle.MOVE_MANGA_TO_MORE
|
||||
}
|
||||
|
||||
preferenceStore.getEnum("start_screen", StartScreen.ANIME).set(startScreen)
|
||||
preferenceStore.getEnum("bottom_rail_nav_style", NavStyle.MOVE_HISTORY_TO_MORE).set(navStyle)
|
||||
}
|
||||
}
|
||||
|
||||
if (oldVersion < 121) {
|
||||
if (trackerManager.myAnimeList.isLoggedIn) {
|
||||
trackerManager.myAnimeList.logout()
|
||||
}
|
||||
}
|
||||
|
||||
if (oldVersion < 123) {
|
||||
val invertedPosition = preferenceStore.getBoolean("pref_invert_playback_txt", false)
|
||||
val invertedDuration = preferenceStore.getBoolean("pref_invert_duration_txt", false)
|
||||
val hwDec = preferenceStore.getString("pref_hwdec", HwDecState.defaultHwDec.mpvValue)
|
||||
val deband = preferenceStore.getInt("pref_deband", 0)
|
||||
val playerViewMode = preferenceStore.getInt("pref_player_view_mode", 1)
|
||||
val gpuNext = preferenceStore.getBoolean("gpu_next", false)
|
||||
|
||||
prefs.edit {
|
||||
remove("pref_invert_playback_txt")
|
||||
remove("pref_invert_duration_txt")
|
||||
remove("pref_hwdec")
|
||||
remove("pref_deband")
|
||||
remove("pref_player_view_mode")
|
||||
remove("gpu_next")
|
||||
|
||||
val invertedPlayback = when {
|
||||
invertedPosition.get() -> InvertedPlayback.POSITION
|
||||
invertedDuration.get() -> InvertedPlayback.DURATION
|
||||
else -> InvertedPlayback.NONE
|
||||
}
|
||||
val hardwareDecoding = HwDecState.entries.first { it.mpvValue == hwDec.get() }
|
||||
val videoDebanding = VideoDebanding.entries.first { it.ordinal == deband.get() }
|
||||
val aspectState = AspectState.entries.first { it.ordinal == playerViewMode.get() }
|
||||
|
||||
preferenceStore.getEnum("pref_inverted_playback", InvertedPlayback.NONE).set(invertedPlayback)
|
||||
preferenceStore.getEnum("pref_hardware_decoding", HwDecState.defaultHwDec).set(hardwareDecoding)
|
||||
preferenceStore.getEnum("pref_video_debanding", VideoDebanding.DISABLED).set(videoDebanding)
|
||||
preferenceStore.getEnum("pref_player_aspect_state", AspectState.FIT).set(aspectState)
|
||||
preferenceStore.getBoolean("pref_gpu_next", false).set(gpuNext.get())
|
||||
}
|
||||
}
|
||||
|
||||
val coroutineScope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
if (oldVersion < 125) {
|
||||
coroutineScope.launchIO {
|
||||
for ((index, source) in sourcePreferences.animeExtensionRepos().get().withIndex()) {
|
||||
try {
|
||||
animeExtensionRepoRepository.upsertRepo(
|
||||
source,
|
||||
"Repo #${index + 1}",
|
||||
null,
|
||||
source,
|
||||
"NOFINGERPRINT-${index + 1}",
|
||||
)
|
||||
} catch (e: SaveExtensionRepoException) {
|
||||
logcat(LogPriority.ERROR, e) {
|
||||
"Error Migrating Anime Extension Repo with baseUrl: $source"
|
||||
}
|
||||
}
|
||||
}
|
||||
sourcePreferences.animeExtensionRepos().delete()
|
||||
|
||||
for ((index, source) in sourcePreferences.mangaExtensionRepos().get().withIndex()) {
|
||||
try {
|
||||
mangaExtensionRepoRepository.upsertRepo(
|
||||
source,
|
||||
"Repo #${index + 1}",
|
||||
null,
|
||||
source,
|
||||
"NOFINGERPRINT-${index + 1}",
|
||||
)
|
||||
} catch (e: SaveExtensionRepoException) {
|
||||
logcat(LogPriority.ERROR, e) {
|
||||
"Error Migrating Manga Extension Repo with baseUrl: $source"
|
||||
}
|
||||
}
|
||||
}
|
||||
sourcePreferences.mangaExtensionRepos().delete()
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun replacePreferences(
|
||||
preferenceStore: PreferenceStore,
|
||||
filterPredicate: (Map.Entry<String, Any?>) -> Boolean,
|
||||
newKey: (String) -> String,
|
||||
) {
|
||||
preferenceStore.getAll()
|
||||
.filter(filterPredicate)
|
||||
.forEach { (key, value) ->
|
||||
when (value) {
|
||||
is Int -> {
|
||||
preferenceStore.getInt(newKey(key)).set(value)
|
||||
preferenceStore.getInt(key).delete()
|
||||
}
|
||||
is Long -> {
|
||||
preferenceStore.getLong(newKey(key)).set(value)
|
||||
preferenceStore.getLong(key).delete()
|
||||
}
|
||||
is Float -> {
|
||||
preferenceStore.getFloat(newKey(key)).set(value)
|
||||
preferenceStore.getFloat(key).delete()
|
||||
}
|
||||
is String -> {
|
||||
preferenceStore.getString(newKey(key)).set(value)
|
||||
preferenceStore.getString(key).delete()
|
||||
}
|
||||
is Boolean -> {
|
||||
preferenceStore.getBoolean(newKey(key)).set(value)
|
||||
preferenceStore.getBoolean(key).delete()
|
||||
}
|
||||
is Set<*> -> (value as? Set<String>)?.let {
|
||||
preferenceStore.getStringSet(newKey(key)).set(value)
|
||||
preferenceStore.getStringSet(key).delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -55,8 +55,6 @@ import cafe.adriel.voyager.navigator.NavigatorDisposeBehavior
|
|||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.components.AppStateBanners
|
||||
import eu.kanade.presentation.components.DownloadedOnlyBannerBackgroundColor
|
||||
import eu.kanade.presentation.components.IncognitoModeBannerBackgroundColor
|
||||
|
@ -67,7 +65,6 @@ import eu.kanade.presentation.more.settings.screen.data.RestoreBackupScreen
|
|||
import eu.kanade.presentation.util.AssistContentScreen
|
||||
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.Migrations
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.core.common.Constants
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
|
@ -107,7 +104,11 @@ import kotlinx.coroutines.flow.launchIn
|
|||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import logcat.LogPriority
|
||||
import mihon.core.migration.Migrator
|
||||
import mihon.core.migration.migrations.migrations
|
||||
import tachiyomi.core.common.i18n.stringResource
|
||||
import tachiyomi.core.common.preference.Preference
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.core.common.util.lang.withUIContext
|
||||
import tachiyomi.core.common.util.system.logcat
|
||||
|
@ -123,9 +124,7 @@ import androidx.compose.ui.graphics.Color.Companion as ComposeColor
|
|||
|
||||
class MainActivity : BaseActivity() {
|
||||
|
||||
private val sourcePreferences: SourcePreferences by injectLazy()
|
||||
private val libraryPreferences: LibraryPreferences by injectLazy()
|
||||
private val uiPreferences: UiPreferences by injectLazy()
|
||||
private val preferences: BasePreferences by injectLazy()
|
||||
|
||||
private val animeDownloadCache: AnimeDownloadCache by injectLazy()
|
||||
|
@ -149,26 +148,7 @@ class MainActivity : BaseActivity() {
|
|||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val didMigration = if (isLaunch) {
|
||||
Migrations.upgrade(
|
||||
context = applicationContext,
|
||||
basePreferences = preferences,
|
||||
uiPreferences = uiPreferences,
|
||||
preferenceStore = Injekt.get(),
|
||||
networkPreferences = Injekt.get(),
|
||||
sourcePreferences = sourcePreferences,
|
||||
securityPreferences = Injekt.get(),
|
||||
libraryPreferences = libraryPreferences,
|
||||
readerPreferences = Injekt.get(),
|
||||
playerPreferences = Injekt.get(),
|
||||
backupPreferences = Injekt.get(),
|
||||
trackerManager = Injekt.get(),
|
||||
animeExtensionRepoRepository = Injekt.get(),
|
||||
mangaExtensionRepoRepository = Injekt.get(),
|
||||
)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
val didMigration = migrate()
|
||||
|
||||
// Do not let the launcher create a new activity http://stackoverflow.com/questions/16283079
|
||||
if (!isTaskRoot) {
|
||||
|
@ -403,6 +383,21 @@ class MainActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun migrate(): Boolean {
|
||||
val preferenceStore = Injekt.get<PreferenceStore>()
|
||||
val preference = preferenceStore.getInt(Preference.appStateKey("last_version_code"), 0)
|
||||
logcat { "Migration from ${preference.get()} to ${BuildConfig.VERSION_CODE}" }
|
||||
return Migrator.migrate(
|
||||
old = preference.get(),
|
||||
new = BuildConfig.VERSION_CODE,
|
||||
migrations = migrations,
|
||||
onMigrationComplete = {
|
||||
logcat { "Updating last version to ${BuildConfig.VERSION_CODE}" }
|
||||
preference.set(BuildConfig.VERSION_CODE)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets custom splash screen exit animation on devices prior to Android 12.
|
||||
*
|
||||
|
|
19
app/src/main/java/mihon/core/migration/Migration.kt
Normal file
19
app/src/main/java/mihon/core/migration/Migration.kt
Normal file
|
@ -0,0 +1,19 @@
|
|||
package mihon.core.migration
|
||||
|
||||
interface Migration {
|
||||
val version: Float
|
||||
|
||||
suspend operator fun invoke(migrationContext: MigrationContext): Boolean
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
app/src/main/java/mihon/core/migration/MigrationContext.kt
Normal file
10
app/src/main/java/mihon/core/migration/MigrationContext.kt
Normal file
|
@ -0,0 +1,10 @@
|
|||
package mihon.core.migration
|
||||
|
||||
import uy.kohesive.injekt.Injekt
|
||||
|
||||
class MigrationContext {
|
||||
|
||||
inline fun <reified T> get(): T? {
|
||||
return Injekt.getInstanceOrNull(T::class.java)
|
||||
}
|
||||
}
|
41
app/src/main/java/mihon/core/migration/MigrationUtils.kt
Normal file
41
app/src/main/java/mihon/core/migration/MigrationUtils.kt
Normal file
|
@ -0,0 +1,41 @@
|
|||
package mihon.core.migration
|
||||
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun replacePreferences(
|
||||
preferenceStore: PreferenceStore,
|
||||
filterPredicate: (Map.Entry<String, Any?>) -> Boolean,
|
||||
newKey: (String) -> String,
|
||||
) {
|
||||
preferenceStore.getAll()
|
||||
.filter(filterPredicate)
|
||||
.forEach { (key, value) ->
|
||||
when (value) {
|
||||
is Int -> {
|
||||
preferenceStore.getInt(newKey(key)).set(value)
|
||||
preferenceStore.getInt(key).delete()
|
||||
}
|
||||
is Long -> {
|
||||
preferenceStore.getLong(newKey(key)).set(value)
|
||||
preferenceStore.getLong(key).delete()
|
||||
}
|
||||
is Float -> {
|
||||
preferenceStore.getFloat(newKey(key)).set(value)
|
||||
preferenceStore.getFloat(key).delete()
|
||||
}
|
||||
is String -> {
|
||||
preferenceStore.getString(newKey(key)).set(value)
|
||||
preferenceStore.getString(key).delete()
|
||||
}
|
||||
is Boolean -> {
|
||||
preferenceStore.getBoolean(newKey(key)).set(value)
|
||||
preferenceStore.getBoolean(key).delete()
|
||||
}
|
||||
is Set<*> -> (value as? Set<String>)?.let {
|
||||
preferenceStore.getStringSet(newKey(key)).set(value)
|
||||
preferenceStore.getStringSet(key).delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
app/src/main/java/mihon/core/migration/Migrator.kt
Normal file
53
app/src/main/java/mihon/core/migration/Migrator.kt
Normal file
|
@ -0,0 +1,53 @@
|
|||
package mihon.core.migration
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import tachiyomi.core.common.util.system.logcat
|
||||
|
||||
object Migrator {
|
||||
|
||||
@SuppressWarnings("ReturnCount")
|
||||
fun migrate(
|
||||
old: Int,
|
||||
new: Int,
|
||||
migrations: List<Migration>,
|
||||
dryrun: Boolean = false,
|
||||
onMigrationComplete: () -> Unit
|
||||
): Boolean {
|
||||
val migrationContext = MigrationContext()
|
||||
|
||||
if (old == 0) {
|
||||
return migrationContext.migrate(
|
||||
migrations = migrations.filter { it.isAlways() },
|
||||
dryrun = dryrun
|
||||
)
|
||||
.also { onMigrationComplete() }
|
||||
}
|
||||
|
||||
if (old >= new) {
|
||||
return false
|
||||
}
|
||||
|
||||
return migrationContext.migrate(
|
||||
migrations = migrations.filter { it.isAlways() || it.version.toInt() in (old + 1)..new },
|
||||
dryrun = dryrun
|
||||
)
|
||||
.also { onMigrationComplete() }
|
||||
}
|
||||
|
||||
private fun Migration.isAlways() = version == Migration.ALWAYS
|
||||
|
||||
@SuppressWarnings("MaxLineLength")
|
||||
private fun MigrationContext.migrate(migrations: List<Migration>, dryrun: Boolean): Boolean {
|
||||
return migrations.sortedBy { it.version }
|
||||
.map { migration ->
|
||||
if (!dryrun) {
|
||||
logcat { "Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" }
|
||||
runBlocking { migration(this@migrate) }
|
||||
} else {
|
||||
logcat { "(Dry-run) Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" }
|
||||
true
|
||||
}
|
||||
}
|
||||
.reduce { acc, b -> acc || b }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.core.common.preference.plusAssign
|
||||
|
||||
class AddAllLangMigration : Migration {
|
||||
override val version = 70f
|
||||
|
||||
// Migration to add "all" to enabled langauges
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val sourcePreferences = migrationContext.get<SourcePreferences>() ?: return false
|
||||
|
||||
if (sourcePreferences.enabledLanguages().isSet()) {
|
||||
sourcePreferences.enabledLanguages() += "all"
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.core.common.preference.minusAssign
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.library.service.LibraryPreferences.Companion.ENTRY_NON_COMPLETED
|
||||
|
||||
class CombineUpdateRestrictionMigration : Migration {
|
||||
override val version = 72f
|
||||
|
||||
// Combine global update item restrictions
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val libraryPreferences = migrationContext.get<LibraryPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val oldUpdateOngoingOnly = prefs.getBoolean(
|
||||
"pref_update_only_non_completed_key",
|
||||
true,
|
||||
)
|
||||
if (!oldUpdateOngoingOnly) {
|
||||
libraryPreferences.autoUpdateItemRestrictions() -= ENTRY_NON_COMPLETED
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import java.io.File
|
||||
|
||||
class CoverToExternalFileMigration : Migration {
|
||||
override val version = 19f
|
||||
|
||||
// Move covers to external files dir.
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: 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,30 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class DOHMigration : Migration {
|
||||
override val version = 57f
|
||||
|
||||
// Migrate DNS over HTTPS setting
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val networkPreferences = migrationContext.get<NetworkPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val wasDohEnabled = prefs.getBoolean("enable_doh", false)
|
||||
if (wasDohEnabled) {
|
||||
prefs.edit {
|
||||
putInt(networkPreferences.dohProvider().key(), PREF_DOH_CLOUDFLARE)
|
||||
remove("enable_doh")
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import java.io.File
|
||||
|
||||
class DeleteExternalChapterCacheDirMigration : Migration {
|
||||
override val version = 26f
|
||||
|
||||
// Delete external chapter cache dir.
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: 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,22 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.core.common.preference.getAndSet
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
|
||||
class DontRunJobsMigration : Migration {
|
||||
override val version = 105f
|
||||
|
||||
// Don't run automatic backup or library update jobs if battery is low
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val libraryPreferences = migrationContext.get<LibraryPreferences>() ?: return false
|
||||
|
||||
val pref = libraryPreferences.autoUpdateDeviceRestrictions()
|
||||
if (pref.isSet() && "battery_not_low" in pref.get()) {
|
||||
pref.getAndSet { it - "battery_not_low" }
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.domain.backup.service.BackupPreferences
|
||||
|
||||
class EnableAutoBackupMigration : Migration {
|
||||
override val version = 84f
|
||||
|
||||
// Always attempt automatic backup creation
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val backupPreferences = migrationContext.get<BackupPreferences>() ?: return false
|
||||
|
||||
if (backupPreferences.backupInterval().get() == 0) {
|
||||
backupPreferences.backupInterval().set(12)
|
||||
BackupCreateJob.setupTask(context)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.ui.player.viewer.AspectState
|
||||
import eu.kanade.tachiyomi.ui.player.viewer.HwDecState
|
||||
import eu.kanade.tachiyomi.ui.player.viewer.InvertedPlayback
|
||||
import eu.kanade.tachiyomi.ui.player.viewer.VideoDebanding
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
import tachiyomi.core.common.preference.getEnum
|
||||
|
||||
class EnumsMigration : Migration {
|
||||
override val version = 123f
|
||||
|
||||
// refactor(player): Implement more enums
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val preferenceStore = migrationContext.get<PreferenceStore>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val invertedPosition = preferenceStore.getBoolean("pref_invert_playback_txt", false)
|
||||
val invertedDuration = preferenceStore.getBoolean("pref_invert_duration_txt", false)
|
||||
val hwDec = preferenceStore.getString("pref_hwdec", HwDecState.defaultHwDec.mpvValue)
|
||||
val deband = preferenceStore.getInt("pref_deband", 0)
|
||||
val playerViewMode = preferenceStore.getInt("pref_player_view_mode", 1)
|
||||
val gpuNext = preferenceStore.getBoolean("gpu_next", false)
|
||||
|
||||
prefs.edit {
|
||||
remove("pref_invert_playback_txt")
|
||||
remove("pref_invert_duration_txt")
|
||||
remove("pref_hwdec")
|
||||
remove("pref_deband")
|
||||
remove("pref_player_view_mode")
|
||||
remove("gpu_next")
|
||||
|
||||
val invertedPlayback = when {
|
||||
invertedPosition.get() -> InvertedPlayback.POSITION
|
||||
invertedDuration.get() -> InvertedPlayback.DURATION
|
||||
else -> InvertedPlayback.NONE
|
||||
}
|
||||
val hardwareDecoding = HwDecState.entries.first { it.mpvValue == hwDec.get() }
|
||||
val videoDebanding = VideoDebanding.entries.first { it.ordinal == deband.get() }
|
||||
val aspectState = AspectState.entries.first { it.ordinal == playerViewMode.get() }
|
||||
|
||||
preferenceStore.getEnum("pref_inverted_playback", InvertedPlayback.NONE).set(invertedPlayback)
|
||||
preferenceStore.getEnum("pref_hardware_decoding", HwDecState.defaultHwDec).set(hardwareDecoding)
|
||||
preferenceStore.getEnum("pref_video_debanding", VideoDebanding.DISABLED).set(videoDebanding)
|
||||
preferenceStore.getEnum("pref_player_aspect_state", AspectState.FIT).set(aspectState)
|
||||
preferenceStore.getBoolean("pref_gpu_next", false).set(gpuNext.get())
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.core.common.preference.getAndSet
|
||||
|
||||
class ExternalRepoMigration : Migration {
|
||||
override val version = 114f
|
||||
|
||||
// Clean up external repos
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val sourcePreferences = migrationContext.get<SourcePreferences>() ?: return false
|
||||
|
||||
sourcePreferences.mangaExtensionRepos().getAndSet {
|
||||
it.map { repo -> "https://raw.githubusercontent.com/$repo/repo" }.toSet()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class ForceMALLogOutMigration : Migration {
|
||||
override val version = 54f
|
||||
|
||||
// Force MAL log out due to login flow change
|
||||
// v52: switched from scraping to WebView
|
||||
// v53: switched from WebView to OAuth
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val trackerManager = migrationContext.get<TrackerManager>() ?: return false
|
||||
|
||||
if (trackerManager.myAnimeList.isLoggedIn) {
|
||||
trackerManager.myAnimeList.logout()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import java.io.File
|
||||
|
||||
class InternalChapterCacheDirMigration : Migration {
|
||||
override val version = 15f
|
||||
|
||||
// Delete internal chapter cache dir.
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
|
||||
File(context.cacheDir, "chapter_disk_cache").deleteRecursively()
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class LogOutMALMigration : Migration {
|
||||
override val version = 121f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val trackerManager = migrationContext.get<TrackerManager>() ?: return false
|
||||
|
||||
if (trackerManager.myAnimeList.isLoggedIn) {
|
||||
trackerManager.myAnimeList.logout()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
|
||||
class MergeSortTypeDirectionMigration : Migration {
|
||||
override val version = 82f
|
||||
|
||||
// Merge Sort Type and Direction into one class
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val libraryPreferences = migrationContext.get<LibraryPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
prefs.edit {
|
||||
val mangasort = prefs.getString(
|
||||
libraryPreferences.mangaSortingMode().key(),
|
||||
null,
|
||||
) ?: return@edit
|
||||
val animesort = prefs.getString(
|
||||
libraryPreferences.animeSortingMode().key(),
|
||||
null,
|
||||
) ?: return@edit
|
||||
val direction = prefs.getString("library_sorting_ascending", "ASCENDING")!!
|
||||
putString(libraryPreferences.mangaSortingMode().key(), "$mangasort,$direction")
|
||||
putString(libraryPreferences.animeSortingMode().key(), "$animesort,$direction")
|
||||
remove("library_sorting_ascending")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class MigrateRotationViewerValuesMigration : Migration {
|
||||
override val version = 60f
|
||||
|
||||
// Migrate Rotation and Viewer values to default values for viewer_flags
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val newOrientation = when (prefs.getInt("pref_rotation_type_key", 1)) {
|
||||
1 -> ReaderOrientation.FREE.flagValue
|
||||
2 -> ReaderOrientation.PORTRAIT.flagValue
|
||||
3 -> ReaderOrientation.LANDSCAPE.flagValue
|
||||
4 -> ReaderOrientation.LOCKED_PORTRAIT.flagValue
|
||||
5 -> ReaderOrientation.LOCKED_LANDSCAPE.flagValue
|
||||
else -> ReaderOrientation.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,37 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class MigrateSecureScreenMigration : Migration {
|
||||
override val version = 75f
|
||||
|
||||
// Allow disabling secure screen when incognito mode is on
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val securityPreferences = migrationContext.get<SecurityPreferences>() ?: return false
|
||||
val basePreferences = migrationContext.get<BasePreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val oldSecureScreen = prefs.getBoolean("secure_screen", false)
|
||||
if (oldSecureScreen) {
|
||||
securityPreferences.secureScreen().set(
|
||||
SecurityPreferences.SecureScreenMode.ALWAYS,
|
||||
)
|
||||
}
|
||||
if (DeviceUtil.isMiui &&
|
||||
basePreferences.extensionInstaller().get() == BasePreferences.ExtensionInstaller.PACKAGEINSTALLER
|
||||
) {
|
||||
basePreferences.extensionInstaller().set(
|
||||
BasePreferences.ExtensionInstaller.LEGACY,
|
||||
)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
|
||||
class MigrateSortingModeMigration : Migration {
|
||||
override val version = 64f
|
||||
|
||||
// Switch to sort per category
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val libraryPreferences = migrationContext.get<LibraryPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val oldMangaSortingMode = prefs.getInt(
|
||||
libraryPreferences.mangaSortingMode().key(),
|
||||
0,
|
||||
)
|
||||
val oldAnimeSortingMode = prefs.getInt(
|
||||
libraryPreferences.animeSortingMode().key(),
|
||||
0,
|
||||
)
|
||||
val oldSortingDirection = prefs.getBoolean("library_sorting_ascending", true)
|
||||
|
||||
val newMangaSortingMode = when (oldMangaSortingMode) {
|
||||
0 -> "ALPHABETICAL"
|
||||
1 -> "LAST_READ"
|
||||
2 -> "LAST_CHECKED"
|
||||
3 -> "UNREAD"
|
||||
4 -> "TOTAL_CHAPTERS"
|
||||
6 -> "LATEST_CHAPTER"
|
||||
8 -> "DATE_FETCHED"
|
||||
7 -> "DATE_ADDED"
|
||||
else -> "ALPHABETICAL"
|
||||
}
|
||||
|
||||
val newAnimeSortingMode = when (oldAnimeSortingMode) {
|
||||
0 -> "ALPHABETICAL"
|
||||
1 -> "LAST_SEEN"
|
||||
2 -> "LAST_CHECKED"
|
||||
3 -> "UNSEEN"
|
||||
4 -> "TOTAL_EPISODES"
|
||||
6 -> "LATEST_EPISODE"
|
||||
8 -> "DATE_FETCHED"
|
||||
7 -> "DATE_ADDED"
|
||||
else -> "ALPHABETICAL"
|
||||
}
|
||||
|
||||
val newSortingDirection = when (oldSortingDirection) {
|
||||
true -> "ASCENDING"
|
||||
else -> "DESCENDING"
|
||||
}
|
||||
|
||||
prefs.edit(commit = true) {
|
||||
remove(libraryPreferences.mangaSortingMode().key())
|
||||
remove(libraryPreferences.animeSortingMode().key())
|
||||
remove("library_sorting_ascending")
|
||||
}
|
||||
|
||||
prefs.edit {
|
||||
putString(libraryPreferences.mangaSortingMode().key(), newMangaSortingMode)
|
||||
putString(libraryPreferences.animeSortingMode().key(), newAnimeSortingMode)
|
||||
putString("library_sorting_ascending", newSortingDirection)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
|
||||
class MigrateToTriStateMigration : Migration {
|
||||
override val version = 52f
|
||||
|
||||
// Migrate library filters to tri-state versions
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val libraryPreferences = migrationContext.get<LibraryPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
prefs.edit {
|
||||
putInt(
|
||||
libraryPreferences.filterDownloadedManga().key(),
|
||||
convertBooleanPrefToTriState(prefs, "pref_filter_downloaded_key"),
|
||||
)
|
||||
remove("pref_filter_downloaded_key")
|
||||
|
||||
putInt(
|
||||
libraryPreferences.filterUnread().key(),
|
||||
convertBooleanPrefToTriState(prefs, "pref_filter_unread_key"),
|
||||
)
|
||||
remove("pref_filter_unread_key")
|
||||
|
||||
putInt(
|
||||
libraryPreferences.filterCompletedManga().key(),
|
||||
convertBooleanPrefToTriState(prefs, "pref_filter_completed_key"),
|
||||
)
|
||||
remove("pref_filter_completed_key")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun convertBooleanPrefToTriState(prefs: SharedPreferences, key: String): Int {
|
||||
val oldPrefValue = prefs.getBoolean(key, false)
|
||||
return if (oldPrefValue) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
import tachiyomi.core.common.preference.TriState
|
||||
import tachiyomi.core.common.preference.getEnum
|
||||
|
||||
class MigrateTriStateMigration : Migration {
|
||||
override val version = 99f
|
||||
|
||||
// Migrate TriState usages to TriStateFilter enum
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val trackerManager = migrationContext.get<TrackerManager>() ?: return false
|
||||
val preferenceStore = migrationContext.get<PreferenceStore>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val prefKeys = listOf(
|
||||
"pref_filter_library_downloaded",
|
||||
"pref_filter_library_unread",
|
||||
"pref_filter_library_unseen",
|
||||
"pref_filter_library_started",
|
||||
"pref_filter_library_bookmarked",
|
||||
"pref_filter_library_completed",
|
||||
) + trackerManager.trackers.map { "pref_filter_library_tracked_${it.id}" }
|
||||
|
||||
prefKeys.forEach { key ->
|
||||
val pref = preferenceStore.getInt(key, 0)
|
||||
prefs.edit {
|
||||
remove(key)
|
||||
|
||||
val newValue = when (pref.get()) {
|
||||
1 -> TriState.ENABLED_IS
|
||||
2 -> TriState.ENABLED_NOT
|
||||
else -> TriState.DISABLED
|
||||
}
|
||||
|
||||
preferenceStore.getEnum("${key}_v2", TriState.DISABLED).set(
|
||||
newValue,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import mihon.core.migration.Migration
|
||||
|
||||
val migrations: List<Migration>
|
||||
get() = listOf(
|
||||
SetupBackupCreateMigration(),
|
||||
SetupAnimeLibraryUpdateMigration(),
|
||||
SetupMangaLibraryUpdateMigration(),
|
||||
InternalChapterCacheDirMigration(),
|
||||
CoverToExternalFileMigration(),
|
||||
DeleteExternalChapterCacheDirMigration(),
|
||||
ResetSortPreferenceRemovedMigration(),
|
||||
MigrateToTriStateMigration(),
|
||||
ForceMALLogOutMigration(),
|
||||
DOHMigration(),
|
||||
ResetRotationMigration(),
|
||||
MigrateRotationViewerValuesMigration(),
|
||||
RemoveOneTwoHourUpdateMigration(),
|
||||
SetupBackgroundTasksMigration(),
|
||||
MigrateSortingModeMigration(),
|
||||
AddAllLangMigration(),
|
||||
RemoveQuickUpdateMigration(),
|
||||
CombineUpdateRestrictionMigration(),
|
||||
MigrateSecureScreenMigration(),
|
||||
RemoveReaderTapMigration(),
|
||||
RenameEnumMigration(),
|
||||
MergeSortTypeDirectionMigration(),
|
||||
EnableAutoBackupMigration(),
|
||||
MoveChapterPreferencesMigration(),
|
||||
SplitPreferencesMigration(),
|
||||
PlayerPreferenceMigration(),
|
||||
MovePlayerPreferencesMigration(),
|
||||
UseWorkManagerMigration(),
|
||||
RemoveBackgroundJobsMigration(),
|
||||
MigrateTriStateMigration(),
|
||||
DontRunJobsMigration(),
|
||||
RelativeTimestampMigration(),
|
||||
NoAppStateMigration(),
|
||||
ExternalRepoMigration(),
|
||||
PrivatePreferenceMigration(),
|
||||
PermaTrustExtensionsMigration(),
|
||||
NavigationOptionsMigration(),
|
||||
LogOutMALMigration(),
|
||||
EnumsMigration(),
|
||||
TrustExtensionRepositoryMigration(),
|
||||
)
|
|
@ -0,0 +1,46 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
|
||||
class MoveChapterPreferencesMigration : Migration {
|
||||
override val version = 85f
|
||||
|
||||
// Move chapter preferences from PreferencesHelper to LibraryPrefrences
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val libraryPreferences = migrationContext.get<LibraryPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val preferences = listOf(
|
||||
libraryPreferences.filterChapterByRead(),
|
||||
libraryPreferences.filterChapterByDownloaded(),
|
||||
libraryPreferences.filterChapterByBookmarked(),
|
||||
libraryPreferences.sortChapterBySourceOrNumber(),
|
||||
libraryPreferences.displayChapterByNameOrNumber(),
|
||||
libraryPreferences.sortChapterByAscendingOrDescending(),
|
||||
libraryPreferences.filterEpisodeBySeen(),
|
||||
libraryPreferences.filterEpisodeByDownloaded(),
|
||||
libraryPreferences.filterEpisodeByBookmarked(),
|
||||
libraryPreferences.sortEpisodeBySourceOrNumber(),
|
||||
libraryPreferences.displayEpisodeByNameOrNumber(),
|
||||
libraryPreferences.sortEpisodeByAscendingOrDescending(),
|
||||
)
|
||||
|
||||
prefs.edit {
|
||||
preferences.forEach { preference ->
|
||||
val key = preference.key()
|
||||
val value = prefs.getInt(key, Int.MIN_VALUE)
|
||||
if (value == Int.MIN_VALUE) return@forEach
|
||||
remove(key)
|
||||
putLong(key, value.toLong())
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class MovePlayerPreferencesMigration : Migration {
|
||||
override val version = 93f
|
||||
|
||||
// more migrations for player prefs
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val playerPreferences = migrationContext.get<PlayerPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
listOf(
|
||||
playerPreferences.defaultPlayerOrientationType(),
|
||||
playerPreferences.defaultPlayerOrientationLandscape(),
|
||||
playerPreferences.defaultPlayerOrientationPortrait(),
|
||||
playerPreferences.skipLengthPreference(),
|
||||
).forEach { pref ->
|
||||
if (pref.isSet()) {
|
||||
prefs.edit {
|
||||
val oldString = try {
|
||||
prefs.getString(pref.key(), null)
|
||||
} catch (e: ClassCastException) {
|
||||
null
|
||||
} ?: return@edit
|
||||
val newInt = oldString.toIntOrNull() ?: return@edit
|
||||
putInt(pref.key(), newInt)
|
||||
}
|
||||
val trackingQueuePref =
|
||||
context.getSharedPreferences("tracking_queue", Context.MODE_PRIVATE)
|
||||
trackingQueuePref.all.forEach {
|
||||
val (_, lastChapterRead) = it.value.toString().split(":")
|
||||
trackingQueuePref.edit {
|
||||
remove(it.key)
|
||||
putFloat(it.key, lastChapterRead.toFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.domain.ui.model.NavStyle
|
||||
import eu.kanade.domain.ui.model.StartScreen
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
import tachiyomi.core.common.preference.getEnum
|
||||
|
||||
class NavigationOptionsMigration : Migration {
|
||||
override val version = 120f
|
||||
|
||||
// Bring back navigation options
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val preferenceStore = migrationContext.get<PreferenceStore>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val bottomNavStyle = preferenceStore.getInt("bottom_nav_style", 0)
|
||||
|
||||
val isDefaultTabManga = preferenceStore.getBoolean("default_home_tab_library", false)
|
||||
prefs.edit {
|
||||
remove("bottom_nav_style")
|
||||
remove("default_home_tab_library")
|
||||
|
||||
val startScreen = if (isDefaultTabManga.get()) StartScreen.MANGA else StartScreen.ANIME
|
||||
val navStyle = when (bottomNavStyle.get()) {
|
||||
0 -> NavStyle.MOVE_HISTORY_TO_MORE
|
||||
1 -> NavStyle.MOVE_UPDATES_TO_MORE
|
||||
else -> NavStyle.MOVE_MANGA_TO_MORE
|
||||
}
|
||||
|
||||
preferenceStore.getEnum("start_screen", StartScreen.ANIME).set(startScreen)
|
||||
preferenceStore.getEnum("bottom_rail_nav_style", NavStyle.MOVE_HISTORY_TO_MORE).set(navStyle)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import mihon.core.migration.replacePreferences
|
||||
import tachiyomi.core.common.preference.Preference
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
|
||||
class NoAppStateMigration : Migration {
|
||||
override val version = 113f
|
||||
|
||||
// Don't include "app state" preferences in backups
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val preferenceStore = migrationContext.get<PreferenceStore>() ?: return false
|
||||
|
||||
val prefsToReplace = listOf(
|
||||
"pref_download_only",
|
||||
"incognito_mode",
|
||||
"last_catalogue_source",
|
||||
"trusted_signatures",
|
||||
"last_app_closed",
|
||||
"library_update_last_timestamp",
|
||||
"library_unseen_updates_count",
|
||||
"last_used_category",
|
||||
"last_app_check",
|
||||
"last_ext_check",
|
||||
"last_version_code",
|
||||
"storage_dir",
|
||||
)
|
||||
replacePreferences(
|
||||
preferenceStore = preferenceStore,
|
||||
filterPredicate = { it.key in prefsToReplace },
|
||||
newKey = { Preference.appStateKey(it) },
|
||||
)
|
||||
|
||||
// Deleting old download cache index files, but might as well clear it all out
|
||||
context.cacheDir.deleteRecursively()
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.core.common.preference.Preference
|
||||
|
||||
class PermaTrustExtensionsMigration : Migration {
|
||||
override val version = 117f
|
||||
|
||||
// Allow permanently trusting unofficial extensions by version code + signature
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
prefs.edit {
|
||||
remove(Preference.appStateKey("trusted_signatures"))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class PlayerPreferenceMigration : Migration {
|
||||
override val version = 92f
|
||||
|
||||
// add migration for player preference
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val playerPreferences = migrationContext.get<PlayerPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
if (playerPreferences.progressPreference().isSet()) {
|
||||
prefs.edit {
|
||||
val progressString = try {
|
||||
prefs.getString(playerPreferences.progressPreference().key(), null)
|
||||
} catch (e: ClassCastException) {
|
||||
null
|
||||
} ?: return@edit
|
||||
val newProgress = progressString.toFloatOrNull() ?: return@edit
|
||||
putFloat(playerPreferences.progressPreference().key(), newProgress)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import mihon.core.migration.replacePreferences
|
||||
import tachiyomi.core.common.preference.Preference
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
|
||||
class PrivatePreferenceMigration : Migration {
|
||||
override val version = 116f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val preferenceStore = migrationContext.get<PreferenceStore>() ?: return false
|
||||
|
||||
replacePreferences(
|
||||
preferenceStore = preferenceStore,
|
||||
filterPredicate = { it.key.startsWith("pref_mangasync_") || it.key.startsWith("track_token_") },
|
||||
newKey = { Preference.privateKey(it) },
|
||||
)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
|
||||
class RelativeTimestampMigration : Migration {
|
||||
override val version = 106f
|
||||
|
||||
// Bring back simplified relative timestamp setting
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val preferenceStore = migrationContext.get<PreferenceStore>() ?: return false
|
||||
val uiPreferences = migrationContext.get<UiPreferences>() ?: return false
|
||||
|
||||
val pref = preferenceStore.getInt("relative_time", 7)
|
||||
if (pref.get() == 0) {
|
||||
uiPreferences.relativeTime().set(false)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.util.system.workManager
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class RemoveBackgroundJobsMigration : Migration {
|
||||
override val version = 97f
|
||||
|
||||
// Removed background jobs
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
context.workManager.cancelAllWorkByTag("UpdateChecker")
|
||||
context.workManager.cancelAllWorkByTag("ExtensionUpdate")
|
||||
prefs.edit {
|
||||
remove("automatic_ext_updates")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.library.anime.AnimeLibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.library.manga.MangaLibraryUpdateJob
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
|
||||
class RemoveOneTwoHourUpdateMigration : Migration {
|
||||
override val version = 61f
|
||||
|
||||
// Handle removed every 1 or 2 hour library updates
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val libraryPreferences = migrationContext.get<LibraryPreferences>() ?: return false
|
||||
|
||||
val updateInterval = libraryPreferences.autoUpdateInterval().get()
|
||||
if (updateInterval == 1 || updateInterval == 2) {
|
||||
libraryPreferences.autoUpdateInterval().set(3)
|
||||
MangaLibraryUpdateJob.setupTask(context, 3)
|
||||
AnimeLibraryUpdateJob.setupTask(context, 3)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.library.anime.AnimeLibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.library.manga.MangaLibraryUpdateJob
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
|
||||
class RemoveQuickUpdateMigration : Migration {
|
||||
override val version = 71f
|
||||
|
||||
// Handle removed every 3, 4, 6, and 8 hour library updates
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val libraryPreferences = migrationContext.get<LibraryPreferences>() ?: return false
|
||||
|
||||
val updateInterval = libraryPreferences.autoUpdateInterval().get()
|
||||
if (updateInterval in listOf(3, 4, 6, 8)) {
|
||||
libraryPreferences.autoUpdateInterval().set(12)
|
||||
MangaLibraryUpdateJob.setupTask(context, 12)
|
||||
AnimeLibraryUpdateJob.setupTask(context, 12)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class RemoveReaderTapMigration : Migration {
|
||||
override val version = 77f
|
||||
|
||||
// Remove reader tapping option in favor of disabled nav layouts
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val readerPreferences = migrationContext.get<ReaderPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val oldReaderTap = prefs.getBoolean("reader_tap", false)
|
||||
if (!oldReaderTap) {
|
||||
readerPreferences.navigationModePager().set(5)
|
||||
readerPreferences.navigationModeWebtoon().set(5)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
|
||||
class RenameEnumMigration : Migration {
|
||||
override val version = 81f
|
||||
|
||||
// Handle renamed enum values
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val libraryPreferences = migrationContext.get<LibraryPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
prefs.edit {
|
||||
val newMangaSortingMode = when (
|
||||
val oldSortingMode = prefs.getString(
|
||||
libraryPreferences.mangaSortingMode().key(),
|
||||
"ALPHABETICAL",
|
||||
)
|
||||
) {
|
||||
"LAST_CHECKED" -> "LAST_MANGA_UPDATE"
|
||||
"UNREAD" -> "UNREAD_COUNT"
|
||||
"DATE_FETCHED" -> "CHAPTER_FETCH_DATE"
|
||||
else -> oldSortingMode
|
||||
}
|
||||
val newAnimeSortingMode = when (
|
||||
val oldSortingMode = prefs.getString(
|
||||
libraryPreferences.animeSortingMode().key(),
|
||||
"ALPHABETICAL",
|
||||
)
|
||||
) {
|
||||
"LAST_CHECKED" -> "LAST_MANGA_UPDATE"
|
||||
"UNREAD" -> "UNREAD_COUNT"
|
||||
"DATE_FETCHED" -> "CHAPTER_FETCH_DATE"
|
||||
else -> oldSortingMode
|
||||
}
|
||||
putString(libraryPreferences.mangaSortingMode().key(), newMangaSortingMode)
|
||||
putString(libraryPreferences.animeSortingMode().key(), newAnimeSortingMode)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class ResetRotationMigration : Migration {
|
||||
override val version = 59f
|
||||
|
||||
// Reset rotation to Free after replacing Lock
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: 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,43 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
|
||||
class ResetSortPreferenceRemovedMigration : Migration {
|
||||
override val version = 44f
|
||||
|
||||
// Reset sorting preference if using removed sort by source
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val libraryPreferences = migrationContext.get<LibraryPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val oldMangaSortingMode = prefs.getInt(
|
||||
libraryPreferences.mangaSortingMode().key(),
|
||||
0,
|
||||
)
|
||||
|
||||
if (oldMangaSortingMode == 5) { // SOURCE = 5
|
||||
prefs.edit {
|
||||
putInt(libraryPreferences.mangaSortingMode().key(), 0) // ALPHABETICAL = 0
|
||||
}
|
||||
}
|
||||
|
||||
val oldAnimeSortingMode = prefs.getInt(
|
||||
libraryPreferences.animeSortingMode().key(),
|
||||
0,
|
||||
)
|
||||
|
||||
if (oldAnimeSortingMode == 5) { // SOURCE = 5
|
||||
prefs.edit {
|
||||
putInt(libraryPreferences.animeSortingMode().key(), 0) // ALPHABETICAL = 0
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.library.anime.AnimeLibraryUpdateJob
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class SetupAnimeLibraryUpdateMigration : Migration {
|
||||
override val version: Float = Migration.ALWAYS
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
|
||||
AnimeLibraryUpdateJob.setupTask(context)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.library.anime.AnimeLibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.library.manga.MangaLibraryUpdateJob
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class SetupBackgroundTasksMigration : Migration {
|
||||
override val version = 64f
|
||||
|
||||
// Set up background tasks
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
|
||||
MangaLibraryUpdateJob.setupTask(context)
|
||||
AnimeLibraryUpdateJob.setupTask(context)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class SetupBackupCreateMigration : Migration {
|
||||
override val version: Float = Migration.ALWAYS
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
|
||||
BackupCreateJob.setupTask(context)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.library.manga.MangaLibraryUpdateJob
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class SetupMangaLibraryUpdateMigration : Migration {
|
||||
override val version: Float = Migration.ALWAYS
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
|
||||
MangaLibraryUpdateJob.setupTask(context)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.tachiyomi.App
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class SplitPreferencesMigration : Migration {
|
||||
override val version = 86f
|
||||
|
||||
// Split the rest of the preferences in PreferencesHelper
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
val uiPreferences = migrationContext.get<UiPreferences>() ?: return false
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
if (uiPreferences.themeMode().isSet()) {
|
||||
prefs.edit {
|
||||
val themeMode = prefs.getString(uiPreferences.themeMode().key(), null) ?: return@edit
|
||||
putString(uiPreferences.themeMode().key(), themeMode.uppercase())
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import logcat.LogPriority
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
import mihon.domain.extensionrepo.exception.SaveExtensionRepoException
|
||||
import mihon.domain.extensionrepo.anime.repository.AnimeExtensionRepoRepository
|
||||
import mihon.domain.extensionrepo.manga.repository.MangaExtensionRepoRepository
|
||||
import tachiyomi.core.common.util.lang.withIOContext
|
||||
import tachiyomi.core.common.util.system.logcat
|
||||
|
||||
class TrustExtensionRepositoryMigration : Migration {
|
||||
override val version: Float = 7f
|
||||
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean = withIOContext {
|
||||
val sourcePreferences = migrationContext.get<SourcePreferences>() ?: return@withIOContext false
|
||||
|
||||
val animeExtensionRepositoryRepository =
|
||||
migrationContext.get<AnimeExtensionRepoRepository>() ?: return@withIOContext false
|
||||
for ((index, source) in sourcePreferences.animeExtensionRepos().get().withIndex()) {
|
||||
try {
|
||||
animeExtensionRepositoryRepository.upsertRepo(
|
||||
source,
|
||||
"Repo #${index + 1}",
|
||||
null,
|
||||
source,
|
||||
"NOFINGERPRINT-${index + 1}",
|
||||
)
|
||||
} catch (e: SaveExtensionRepoException) {
|
||||
logcat(LogPriority.ERROR, e) { "Error Migrating Extension Repo with baseUrl: $source" }
|
||||
}
|
||||
}
|
||||
sourcePreferences.animeExtensionRepos().delete()
|
||||
|
||||
val mangaExtensionRepositoryRepository =
|
||||
migrationContext.get<MangaExtensionRepoRepository>() ?: return@withIOContext false
|
||||
for ((index, source) in sourcePreferences.mangaExtensionRepos().get().withIndex()) {
|
||||
try {
|
||||
mangaExtensionRepositoryRepository.upsertRepo(
|
||||
source,
|
||||
"Repo #${index + 1}",
|
||||
null,
|
||||
source,
|
||||
"NOFINGERPRINT-${index + 1}",
|
||||
)
|
||||
} catch (e: SaveExtensionRepoException) {
|
||||
logcat(LogPriority.ERROR, e) {
|
||||
"Error Migrating Manga Extension Repo with baseUrl: $source"
|
||||
}
|
||||
}
|
||||
}
|
||||
sourcePreferences.mangaExtensionRepos().delete()
|
||||
|
||||
return@withIOContext true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package mihon.core.migration.migrations
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.data.library.anime.AnimeLibraryUpdateJob
|
||||
import eu.kanade.tachiyomi.data.library.manga.MangaLibraryUpdateJob
|
||||
import mihon.core.migration.Migration
|
||||
import mihon.core.migration.MigrationContext
|
||||
|
||||
class UseWorkManagerMigration : Migration {
|
||||
override val version = 96f
|
||||
|
||||
// Fully utilize WorkManager for library updates
|
||||
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
|
||||
val context = migrationContext.get<App>() ?: return false
|
||||
|
||||
MangaLibraryUpdateJob.cancelAllWorks(context)
|
||||
AnimeLibraryUpdateJob.cancelAllWorks(context)
|
||||
MangaLibraryUpdateJob.setupTask(context)
|
||||
AnimeLibraryUpdateJob.setupTask(context)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
96
app/src/test/java/mihon/core/migration/MigratorTest.kt
Normal file
96
app/src/test/java/mihon/core/migration/MigratorTest.kt
Normal file
|
@ -0,0 +1,96 @@
|
|||
package mihon.core.migration
|
||||
|
||||
import io.mockk.Called
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class MigratorTest {
|
||||
|
||||
@Test
|
||||
fun initialVersion() {
|
||||
val onMigrationComplete: () -> Unit = {}
|
||||
val onMigrationCompleteSpy = spyk(onMigrationComplete)
|
||||
val didMigration = Migrator.migrate(
|
||||
old = 0,
|
||||
new = 1,
|
||||
migrations = listOf(Migration.of(Migration.ALWAYS) { true }, Migration.of(2f) { false }),
|
||||
onMigrationComplete = onMigrationCompleteSpy
|
||||
)
|
||||
verify { onMigrationCompleteSpy() }
|
||||
Assertions.assertTrue(didMigration)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sameVersion() {
|
||||
val onMigrationComplete: () -> Unit = {}
|
||||
val onMigrationCompleteSpy = spyk(onMigrationComplete)
|
||||
val didMigration = Migrator.migrate(
|
||||
old = 1,
|
||||
new = 1,
|
||||
migrations = listOf(Migration.of(Migration.ALWAYS) { true }, Migration.of(2f) { true }),
|
||||
onMigrationComplete = onMigrationCompleteSpy
|
||||
)
|
||||
verify { onMigrationCompleteSpy wasNot Called }
|
||||
Assertions.assertFalse(didMigration)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun smallMigration() {
|
||||
val onMigrationComplete: () -> Unit = {}
|
||||
val onMigrationCompleteSpy = spyk(onMigrationComplete)
|
||||
val didMigration = Migrator.migrate(
|
||||
old = 1,
|
||||
new = 2,
|
||||
migrations = listOf(Migration.of(Migration.ALWAYS) { true }, Migration.of(2f) { true }),
|
||||
onMigrationComplete = onMigrationCompleteSpy
|
||||
)
|
||||
verify { onMigrationCompleteSpy() }
|
||||
Assertions.assertTrue(didMigration)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun largeMigration() {
|
||||
val onMigrationComplete: () -> Unit = {}
|
||||
val onMigrationCompleteSpy = spyk(onMigrationComplete)
|
||||
val input = listOf(
|
||||
Migration.of(Migration.ALWAYS) { true },
|
||||
Migration.of(2f) { true },
|
||||
Migration.of(3f) { true },
|
||||
Migration.of(4f) { true },
|
||||
Migration.of(5f) { true },
|
||||
Migration.of(6f) { true },
|
||||
Migration.of(7f) { true },
|
||||
Migration.of(8f) { true },
|
||||
Migration.of(9f) { true },
|
||||
Migration.of(10f) { true },
|
||||
)
|
||||
val didMigration = Migrator.migrate(
|
||||
old = 1,
|
||||
new = 10,
|
||||
migrations = input,
|
||||
onMigrationComplete = onMigrationCompleteSpy
|
||||
)
|
||||
verify { onMigrationCompleteSpy() }
|
||||
Assertions.assertTrue(didMigration)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun withinRangeMigration() {
|
||||
val onMigrationComplete: () -> Unit = {}
|
||||
val onMigrationCompleteSpy = spyk(onMigrationComplete)
|
||||
val didMigration = Migrator.migrate(
|
||||
old = 1,
|
||||
new = 2,
|
||||
migrations = listOf(
|
||||
Migration.of(Migration.ALWAYS) { true },
|
||||
Migration.of(2f) { true },
|
||||
Migration.of(3f) { false }
|
||||
),
|
||||
onMigrationComplete = onMigrationCompleteSpy
|
||||
)
|
||||
verify { onMigrationCompleteSpy() }
|
||||
Assertions.assertTrue(didMigration)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue