mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 06:17:57 +01:00 
			
		
		
		
	Fixes and such for integration to AZ
This commit is contained in:
		| @@ -5,7 +5,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.source.CatalogueSource | ||||
| import eu.kanade.tachiyomi.source.model.FilterList | ||||
| import eu.kanade.tachiyomi.source.model.SManga | ||||
| import eu.kanade.tachiyomi.util.await | ||||
| import exh.util.await | ||||
| import info.debatty.java.stringsimilarity.NormalizedLevenshtein | ||||
| import kotlin.coroutines.CoroutineContext | ||||
| import kotlinx.coroutines.CoroutineScope | ||||
|   | ||||
| @@ -22,11 +22,11 @@ class MigrationMangaDialog<T>(bundle: Bundle? = null) : DialogController(bundle) | ||||
|     } | ||||
|  | ||||
|     override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|         val confirmRes = if (copy) R.string.confirm_copy else R.string.confirm_migration | ||||
|         val confirmString = applicationContext?.getString(confirmRes, mangaSet, ( | ||||
|             if (mangaSkipped > 0) | ||||
|                 " " + applicationContext?.getString(R.string.skipping_x, mangaSkipped) ?: "" | ||||
|             else "")) ?: "" | ||||
|         val confirmRes = if (copy) R.plurals.copy_manga else R.plurals.migrate_manga | ||||
|         val confirmString = applicationContext?.resources?.getQuantityString(confirmRes, mangaSet, | ||||
|             mangaSet, ( | ||||
|                 if (mangaSkipped > 0) " " + applicationContext?.getString(R.string.skipping_, mangaSkipped) | ||||
|                 else "")) ?: "" | ||||
|         return MaterialDialog.Builder(activity!!) | ||||
|             .content(confirmString) | ||||
|             .positiveText(if (copy) R.string.copy else R.string.migrate) | ||||
|   | ||||
| @@ -1,34 +1,16 @@ | ||||
| package eu.kanade.tachiyomi.ui.migration | ||||
|  | ||||
| import android.os.Bundle | ||||
| import com.jakewharton.rxrelay.BehaviorRelay | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.database.models.MangaCategory | ||||
| import eu.kanade.tachiyomi.source.CatalogueSource | ||||
| import eu.kanade.tachiyomi.source.Source | ||||
| import eu.kanade.tachiyomi.source.model.SChapter | ||||
| import eu.kanade.tachiyomi.source.model.SManga | ||||
| import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchCardItem | ||||
| import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchItem | ||||
| import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchPresenter | ||||
| import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource | ||||
| import rx.Observable | ||||
| import rx.android.schedulers.AndroidSchedulers | ||||
| import rx.schedulers.Schedulers | ||||
| import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchCardItem | ||||
| import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchItem | ||||
| import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchPresenter | ||||
|  | ||||
| class SearchPresenter( | ||||
|     initialQuery: String? = "", | ||||
|     private val manga: Manga | ||||
| ) : GlobalSearchPresenter(initialQuery) { | ||||
|  | ||||
|     private val replacingMangaRelay = BehaviorRelay.create<Boolean>() | ||||
|  | ||||
|     override fun onCreate(savedState: Bundle?) { | ||||
|         super.onCreate(savedState) | ||||
|  | ||||
|         replacingMangaRelay.subscribeLatestCache({ controller, isReplacingManga -> (controller as? SearchController)?.renderIsReplacingManga(isReplacingManga) }) | ||||
|     } | ||||
|  | ||||
|     override fun getEnabledSources(): List<CatalogueSource> { | ||||
|         // Put the source of the selected manga at the top | ||||
|         return super.getEnabledSources() | ||||
| @@ -39,106 +21,4 @@ class SearchPresenter( | ||||
|         // Set the catalogue search item as highlighted if the source matches that of the selected manga | ||||
|         return GlobalSearchItem(source, results, source.id == manga.source) | ||||
|     } | ||||
|  | ||||
|     override fun networkToLocalManga(sManga: SManga, sourceId: Long): Manga { | ||||
|         val localManga = super.networkToLocalManga(sManga, sourceId) | ||||
|         // For migration, displayed title should always match source rather than local DB | ||||
|         localManga.title = sManga.title | ||||
|         return localManga | ||||
|     } | ||||
|  | ||||
|     fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean) { | ||||
|         val source = sourceManager.get(manga.source) ?: return | ||||
|  | ||||
|         replacingMangaRelay.call(true) | ||||
|  | ||||
|         Observable.defer { source.fetchChapterList(manga) } | ||||
|             .onErrorReturn { emptyList() } | ||||
|             .doOnNext { migrateMangaInternal(source, it, prevManga, manga, replace) } | ||||
|             .onErrorReturn { emptyList() } | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .doOnUnsubscribe { replacingMangaRelay.call(false) } | ||||
|             .subscribe() | ||||
|     } | ||||
|  | ||||
|     private fun migrateMangaInternal( | ||||
|         source: Source, | ||||
|         sourceChapters: List<SChapter>, | ||||
|         prevManga: Manga, | ||||
|         manga: Manga, | ||||
|         replace: Boolean | ||||
|     ) { | ||||
|         val flags = preferences.migrateFlags().get() | ||||
|         val migrateChapters = MigrationFlags.hasChapters(flags) | ||||
|         val migrateCategories = MigrationFlags.hasCategories(flags) | ||||
|         val migrateTracks = MigrationFlags.hasTracks(flags) | ||||
|  | ||||
|         db.inTransaction { | ||||
|             // Update chapters read | ||||
|             if (migrateChapters) { | ||||
|                 try { | ||||
|                     syncChaptersWithSource(db, sourceChapters, manga, source) | ||||
|                 } catch (e: Exception) { | ||||
|                     // Worst case, chapters won't be synced | ||||
|                 } | ||||
|  | ||||
|                 val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking() | ||||
|                 val maxChapterRead = prevMangaChapters | ||||
|                     .filter { it.read } | ||||
|                     .maxBy { it.chapter_number }?.chapter_number | ||||
|                 val bookmarkedChapters = prevMangaChapters | ||||
|                     .filter { it.bookmark && it.isRecognizedNumber } | ||||
|                     .map { it.chapter_number } | ||||
|                 if (maxChapterRead != null) { | ||||
|                     val dbChapters = db.getChapters(manga).executeAsBlocking() | ||||
|                     for (chapter in dbChapters) { | ||||
|                         if (chapter.isRecognizedNumber) { | ||||
|                             if (chapter.chapter_number <= maxChapterRead) { | ||||
|                                 chapter.read = true | ||||
|                             } | ||||
|                             if (chapter.chapter_number in bookmarkedChapters) { | ||||
|                                 chapter.bookmark = true | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     db.insertChapters(dbChapters).executeAsBlocking() | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // Update categories | ||||
|             if (migrateCategories) { | ||||
|                 val categories = db.getCategoriesForManga(prevManga).executeAsBlocking() | ||||
|                 val mangaCategories = categories.map { MangaCategory.create(manga, it) } | ||||
|                 db.setMangaCategories(mangaCategories, listOf(manga)) | ||||
|             } | ||||
|  | ||||
|             // Update track | ||||
|             if (migrateTracks) { | ||||
|                 val tracks = db.getTracks(prevManga).executeAsBlocking() | ||||
|                 for (track in tracks) { | ||||
|                     track.id = null | ||||
|                     track.manga_id = manga.id!! | ||||
|                 } | ||||
|                 db.insertTracks(tracks).executeAsBlocking() | ||||
|             } | ||||
|  | ||||
|             // Update favorite status | ||||
|             if (replace) { | ||||
|                 prevManga.favorite = false | ||||
|                 db.updateMangaFavorite(prevManga).executeAsBlocking() | ||||
|             } | ||||
|             manga.favorite = true | ||||
|             db.updateMangaFavorite(manga).executeAsBlocking() | ||||
|  | ||||
|             // Update reading preferences | ||||
|             manga.chapter_flags = prevManga.chapter_flags | ||||
|             db.updateFlags(manga).executeAsBlocking() | ||||
|             manga.viewer = prevManga.viewer | ||||
|             db.updateMangaViewer(manga).executeAsBlocking() | ||||
|  | ||||
|             // SearchPresenter#networkToLocalManga may have updated the manga title, so ensure db gets updated title | ||||
|             db.updateMangaTitle(manga).executeAsBlocking() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -7,7 +7,7 @@ import eu.davidea.flexibleadapter.items.AbstractHeaderItem | ||||
| import eu.davidea.flexibleadapter.items.IFlexible | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder | ||||
| import kotlinx.android.synthetic.main.source_main_controller_card_header.title | ||||
| import kotlinx.android.synthetic.main.source_main_controller_card.title | ||||
|  | ||||
| /** | ||||
|  * Item that contains the selection header. | ||||
| @@ -18,7 +18,7 @@ class SelectionHeader : AbstractHeaderItem<SelectionHeader.Holder>() { | ||||
|      * Returns the layout resource of this item. | ||||
|      */ | ||||
|     override fun getLayoutRes(): Int { | ||||
|         return R.layout.source_main_controller_card_header | ||||
|         return R.layout.source_main_controller_card | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -35,14 +35,14 @@ class SelectionHeader : AbstractHeaderItem<SelectionHeader.Holder>() { | ||||
|         adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, | ||||
|         holder: Holder, | ||||
|         position: Int, | ||||
|         payloads: List<Any?>? | ||||
|         payloads: MutableList<Any?>? | ||||
|     ) { | ||||
|         // Intentionally empty | ||||
|     } | ||||
|  | ||||
|     class Holder(view: View, adapter: FlexibleAdapter<*>) : BaseFlexibleViewHolder(view, adapter) { | ||||
|     class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : BaseFlexibleViewHolder(view, adapter) { | ||||
|         init { | ||||
|             title.text = view.context.getString(R.string.migration_selection_prompt) | ||||
|             title.text = view.context.getString(R.string.select_a_source_to_migrate_from) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -19,12 +19,12 @@ import eu.kanade.tachiyomi.ui.base.controller.BaseController | ||||
| import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction | ||||
| import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController | ||||
| import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig | ||||
| import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets | ||||
| import eu.kanade.tachiyomi.util.view.marginBottom | ||||
| import eu.kanade.tachiyomi.util.view.updateLayoutParams | ||||
| import eu.kanade.tachiyomi.util.view.updatePaddingRelative | ||||
| import kotlinx.android.synthetic.main.pre_migration_controller.fab | ||||
| import kotlinx.android.synthetic.main.pre_migration_controller.recycler | ||||
| import exh.util.applyWindowInsetsForController | ||||
| import exh.util.doOnApplyWindowInsets | ||||
| import exh.util.marginBottom | ||||
| import exh.util.updateLayoutParams | ||||
| import exh.util.updatePaddingRelative | ||||
| import kotlinx.android.synthetic.main.pre_migration_controller.* | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| class PreMigrationController(bundle: Bundle? = null) : BaseController(bundle), FlexibleAdapter | ||||
| @@ -48,10 +48,11 @@ class PreMigrationController(bundle: Bundle? = null) : BaseController(bundle), F | ||||
|  | ||||
|     override fun onViewCreated(view: View) { | ||||
|         super.onViewCreated(view) | ||||
|         view.applyWindowInsetsForController() | ||||
|  | ||||
|         val ourAdapter = adapter ?: MigrationSourceAdapter( | ||||
|                 getEnabledSources().map { MigrationSourceItem(it, isEnabled(it.id.toString())) }, | ||||
|                 this | ||||
|             getEnabledSources().map { MigrationSourceItem(it, isEnabled(it.id.toString())) }, | ||||
|             this | ||||
|         ) | ||||
|         adapter = ourAdapter | ||||
|         recycler.layoutManager = LinearLayoutManager(view.context) | ||||
| @@ -99,7 +100,7 @@ class PreMigrationController(bundle: Bundle? = null) : BaseController(bundle), F | ||||
|                     config.toList(), | ||||
|                     extraSearchParams = extraParam | ||||
|                 ) | ||||
|             ).withFadeTransaction()) | ||||
|             ).withFadeTransaction().tag(MigrationListController.TAG)) | ||||
|     } | ||||
|  | ||||
|     override fun onSaveInstanceState(outState: Bundle) { | ||||
| @@ -129,7 +130,7 @@ class PreMigrationController(bundle: Bundle? = null) : BaseController(bundle), F | ||||
|     private fun getEnabledSources(): List<HttpSource> { | ||||
|         val languages = prefs.enabledLanguages().getOrDefault() | ||||
|         val sourcesSaved = prefs.migrationSources().getOrDefault().split("/") | ||||
|         var sources = sourceManager.getCatalogueSources() | ||||
|         var sources = sourceManager.getVisibleCatalogueSources() | ||||
|             .filterIsInstance<HttpSource>() | ||||
|             .filter { it.lang in languages } | ||||
|             .sortedBy { "(${it.lang}) ${it.name}" } | ||||
|   | ||||
| @@ -31,12 +31,14 @@ import eu.kanade.tachiyomi.ui.manga.MangaController | ||||
| import eu.kanade.tachiyomi.ui.migration.MigrationMangaDialog | ||||
| import eu.kanade.tachiyomi.ui.migration.SearchController | ||||
| import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController | ||||
| import eu.kanade.tachiyomi.util.await | ||||
| import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource | ||||
| import eu.kanade.tachiyomi.util.lang.launchUI | ||||
| import eu.kanade.tachiyomi.util.system.executeOnIO | ||||
| import eu.kanade.tachiyomi.util.system.getResourceColor | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener | ||||
| import exh.util.RecyclerWindowInsetsListener | ||||
| import exh.util.applyWindowInsetsForController | ||||
| import exh.util.await | ||||
| import exh.util.executeOnIO | ||||
| import java.util.concurrent.atomic.AtomicInteger | ||||
| import kotlin.coroutines.CoroutineContext | ||||
| import kotlinx.android.synthetic.main.chapters_controller.* | ||||
| @@ -55,8 +57,7 @@ import timber.log.Timber | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|     MigrationProcessAdapter.MigrationProcessInterface, | ||||
|     CoroutineScope { | ||||
|     MigrationProcessAdapter.MigrationProcessInterface, CoroutineScope { | ||||
|  | ||||
|     init { | ||||
|         setHasOptionsMenu(true) | ||||
| @@ -74,7 +75,8 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|  | ||||
|     private val smartSearchEngine = SmartSearchEngine(coroutineContext, config?.extraSearchParams) | ||||
|  | ||||
|     private var migrationsJob: Job? = null | ||||
|     var migrationsJob: Job? = null | ||||
|         private set | ||||
|     private var migratingManga: MutableList<MigratingManga>? = null | ||||
|     private var selectedPosition: Int? = null | ||||
|     private var manaulMigrations = 0 | ||||
| @@ -84,12 +86,15 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|     } | ||||
|  | ||||
|     override fun getTitle(): String? { | ||||
|         return resources?.getString(R.string.migration) + " (${adapter?.items?.count { it.manga | ||||
|             .migrationStatus != MigrationStatus.RUNNUNG }}/${adapter?.itemCount ?: 0})" | ||||
|         return resources?.getString(R.string.migration) + " (${adapter?.items?.count { | ||||
|             it.manga.migrationStatus != MigrationStatus.RUNNUNG | ||||
|         }}/${adapter?.itemCount ?: 0})" | ||||
|     } | ||||
|  | ||||
|     override fun onViewCreated(view: View) { | ||||
|  | ||||
|         super.onViewCreated(view) | ||||
|         view.applyWindowInsetsForController() | ||||
|         setTitle() | ||||
|         val config = this.config ?: return | ||||
|  | ||||
| @@ -101,7 +106,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|             new | ||||
|         } | ||||
|  | ||||
|         adapter = MigrationProcessAdapter(this, view.context) | ||||
|         adapter = MigrationProcessAdapter(this) | ||||
|  | ||||
|         recycler.adapter = adapter | ||||
|         recycler.layoutManager = LinearLayoutManager(view.context) | ||||
| @@ -117,23 +122,14 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun migrationFailure() { | ||||
|         activity?.let { | ||||
|             MaterialDialog.Builder(it) | ||||
|                 .title("Migration failure") | ||||
|                 .content("An unknown error occured while migrating this manga!") | ||||
|                 .positiveText("Ok") | ||||
|                 .show() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     suspend fun runMigrations(mangas: List<MigratingManga>) { | ||||
|     private suspend fun runMigrations(mangas: List<MigratingManga>) { | ||||
|         val useSourceWithMost = preferences.useSourceWithMost().getOrDefault() | ||||
|         val useSmartSearch = preferences.smartMigration().getOrDefault() | ||||
|  | ||||
|         val sources = preferences.migrationSources().getOrDefault().split("/").mapNotNull { | ||||
|             val value = it.toLongOrNull() ?: return | ||||
|             sourceManager.get(value) as? CatalogueSource } | ||||
|             sourceManager.get(value) as? CatalogueSource | ||||
|         } | ||||
|         if (config == null) return | ||||
|         for (manga in mangas) { | ||||
|             if (migrationsJob?.isCancelled == true) { | ||||
| @@ -173,11 +169,23 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|                                             } | ||||
|  | ||||
|                                             if (searchResult != null) { | ||||
|                                                 val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id) | ||||
|                                                 val chapters = source.fetchChapterList(localManga).toSingle().await( | ||||
|                                                     Schedulers.io()) | ||||
|                                                 val localManga = | ||||
|                                                     smartSearchEngine.networkToLocalManga( | ||||
|                                                         searchResult, | ||||
|                                                         source.id | ||||
|                                                     ) | ||||
|                                                 val chapters = | ||||
|                                                     source.fetchChapterList(localManga).toSingle() | ||||
|                                                         .await( | ||||
|                                                             Schedulers.io() | ||||
|                                                         ) | ||||
|                                                 try { | ||||
|                                                     syncChaptersWithSource(db, chapters, localManga, source) | ||||
|                                                     syncChaptersWithSource( | ||||
|                                                         db, | ||||
|                                                         chapters, | ||||
|                                                         localManga, | ||||
|                                                         source | ||||
|                                                     ) | ||||
|                                                 } catch (e: Exception) { | ||||
|                                                     return@async null | ||||
|                                                 } | ||||
| @@ -208,7 +216,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|                                         val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id) | ||||
|                                         val chapters = try { | ||||
|                                             source.fetchChapterList(localManga) | ||||
|                                             .toSingle().await(Schedulers.io()) } catch (e: java.lang.Exception) { | ||||
|                                                 .toSingle().await(Schedulers.io()) } catch (e: java.lang.Exception) { | ||||
|                                             Timber.e(e) | ||||
|                                             emptyList<SChapter>() | ||||
|                                         } ?: emptyList() | ||||
| @@ -239,10 +247,9 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|  | ||||
|                 if (result != null && result.thumbnail_url == null) { | ||||
|                     try { | ||||
|                         val newManga = sourceManager.getOrStub(result.source) | ||||
|                             .fetchMangaDetails(result) | ||||
|                             .toSingle() | ||||
|                             .await() | ||||
|                         val newManga = | ||||
|                             sourceManager.getOrStub(result.source).fetchMangaDetails(result) | ||||
|                                 .toSingle().await() | ||||
|                         result.copyFrom(newManga) | ||||
|  | ||||
|                         db.insertManga(result).executeAsBlocking() | ||||
| @@ -253,8 +260,8 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 manga.migrationStatus = if (result == null) MigrationStatus.MANGA_NOT_FOUND else | ||||
|                     MigrationStatus.MANGA_FOUND | ||||
|                 manga.migrationStatus = | ||||
|                     if (result == null) MigrationStatus.MANGA_NOT_FOUND else MigrationStatus.MANGA_FOUND | ||||
|                 adapter?.sourceFinished() | ||||
|                 manga.searchResult.initialize(result?.id) | ||||
|             } | ||||
| @@ -286,8 +293,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|             ids.removeAt(index) | ||||
|             config.mangaIds = ids | ||||
|             val index2 = migratingManga?.indexOf(item.manga) ?: return | ||||
|             if (index2 > -1) | ||||
|                 migratingManga?.removeAt(index2) | ||||
|             if (index2 > -1) migratingManga?.removeAt(index2) | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -296,8 +302,9 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|             val res = resources | ||||
|             if (res != null) { | ||||
|                 activity?.toast( | ||||
|                     res.getQuantityString(R.plurals.manga_migrated, | ||||
|                         manaulMigrations, manaulMigrations) | ||||
|                     res.getQuantityString( | ||||
|                         R.plurals.manga_migrated, manaulMigrations, manaulMigrations | ||||
|                     ) | ||||
|                 ) | ||||
|             } | ||||
|             router.popCurrentController() | ||||
| @@ -366,7 +373,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|                 adapter?.notifyDataSetChanged() | ||||
|             } else { | ||||
|                 migratingManga.manga.migrationStatus = MigrationStatus.MANGA_NOT_FOUND | ||||
|                 activity?.toast(R.string.error_fetching_migration, Toast.LENGTH_LONG) | ||||
|                 activity?.toast(R.string.no_chapters_found_for_migration, Toast.LENGTH_LONG) | ||||
|                 adapter?.notifyDataSetChanged() | ||||
|             } | ||||
|         } | ||||
| @@ -397,8 +404,8 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|                     if (manga != null) { | ||||
|                         val newStack = router.backstack.filter { | ||||
|                             it.controller() !is MangaController && | ||||
|                             it.controller() !is MigrationListController && | ||||
|                             it.controller() !is PreMigrationController | ||||
|                                 it.controller() !is MigrationListController && | ||||
|                                 it.controller() !is PreMigrationController | ||||
|                         } + MangaController(manga).withFadeTransaction() | ||||
|                         router.setBackstack(newStack, FadeChangeHandler()) | ||||
|                         return@launchUI | ||||
| @@ -411,7 +418,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|  | ||||
|     override fun handleBack(): Boolean { | ||||
|         activity?.let { | ||||
|             MaterialDialog.Builder(it).title(R.string.stop_migration) | ||||
|             MaterialDialog.Builder(it).title(R.string.stop_migrating) | ||||
|                 .positiveText(R.string.action_stop) | ||||
|                 .negativeText(android.R.string.cancel) | ||||
|                 .onPositive { _, _ -> | ||||
| @@ -441,12 +448,16 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|  | ||||
|         if (adapter?.itemCount == 1) { | ||||
|             menuMigrate.icon = VectorDrawableCompat.create( | ||||
|                 resources!!, R.drawable.ic_done, null | ||||
|                 resources!!, R.drawable.ic_done_24dp, null | ||||
|             ) | ||||
|         } | ||||
|         val translucentWhite = ColorUtils.setAlphaComponent(Color.WHITE, 127) | ||||
|         menuCopy.icon?.setTint(if (allMangasDone) Color.WHITE else translucentWhite) | ||||
|         menuMigrate?.icon?.setTint(if (allMangasDone) Color.WHITE else translucentWhite) | ||||
|  | ||||
|         menuCopy.icon.mutate() | ||||
|         menuMigrate.icon.mutate() | ||||
|         val tintColor = activity?.getResourceColor(R.attr.colorPrimary) ?: Color.WHITE | ||||
|         val translucentWhite = ColorUtils.setAlphaComponent(tintColor, 127) | ||||
|         menuCopy.icon?.setTint(if (allMangasDone) tintColor else translucentWhite) | ||||
|         menuMigrate?.icon?.setTint(if (allMangasDone) tintColor else translucentWhite) | ||||
|         menuCopy.isEnabled = allMangasDone | ||||
|         menuMigrate.isEnabled = allMangasDone | ||||
|     } | ||||
| @@ -455,10 +466,18 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|         val totalManga = adapter?.itemCount ?: 0 | ||||
|         val mangaSkipped = adapter?.mangasSkipped() ?: 0 | ||||
|         when (item.itemId) { | ||||
|             R.id.action_copy_manga -> MigrationMangaDialog(this, true, totalManga, mangaSkipped) | ||||
|                 .showDialog(router) | ||||
|             R.id.action_migrate_manga -> MigrationMangaDialog(this, false, totalManga, mangaSkipped) | ||||
|                 .showDialog(router) | ||||
|             R.id.action_copy_manga -> MigrationMangaDialog( | ||||
|                 this, | ||||
|                 true, | ||||
|                 totalManga, | ||||
|                 mangaSkipped | ||||
|             ).showDialog(router) | ||||
|             R.id.action_migrate_manga -> MigrationMangaDialog( | ||||
|                 this, | ||||
|                 false, | ||||
|                 totalManga, | ||||
|                 mangaSkipped | ||||
|             ).showDialog(router) | ||||
|             else -> return super.onOptionsItemSelected(item) | ||||
|         } | ||||
|         return true | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| package eu.kanade.tachiyomi.ui.migration.manga.process | ||||
|  | ||||
| import android.content.Context | ||||
| import android.view.MenuItem | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| @@ -16,8 +15,7 @@ import kotlinx.coroutines.withContext | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| class MigrationProcessAdapter( | ||||
|     val controller: MigrationListController, | ||||
|     context: Context | ||||
|     val controller: MigrationListController | ||||
| ) : FlexibleAdapter<MigrationProcessItem>(null, controller, true) { | ||||
|  | ||||
|     private val db: DatabaseHelper by injectLazy() | ||||
| @@ -73,8 +71,9 @@ class MigrationProcessAdapter( | ||||
|         launchUI { | ||||
|             val manga = getItem(position)?.manga ?: return@launchUI | ||||
|             db.inTransaction { | ||||
|                 val toMangaObj = db.getManga(manga.searchResult.get() ?: return@launchUI).executeAsBlocking() | ||||
|                     ?: return@launchUI | ||||
|                 val toMangaObj = | ||||
|                     db.getManga(manga.searchResult.get() ?: return@launchUI).executeAsBlocking() | ||||
|                         ?: return@launchUI | ||||
|                 migrateMangaInternal( | ||||
|                     manga.manga() ?: return@launchUI, toMangaObj, !copy | ||||
|                 ) | ||||
| @@ -135,8 +134,8 @@ class MigrationProcessAdapter( | ||||
|             db.updateMangaFavorite(prevManga).executeAsBlocking() | ||||
|         } | ||||
|         manga.favorite = true | ||||
|         // SearchPresenter#networkToLocalManga may have updated the manga title, so ensure db gets updated title | ||||
|  | ||||
|         db.updateMangaFavorite(manga).executeAsBlocking() | ||||
|         db.updateMangaTitle(manga).executeAsBlocking() | ||||
|         // } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -152,10 +152,10 @@ class MigrationProcessHolder( | ||||
|         val latestChapter = mangaChapters.maxBy { it.chapter_number }?.chapter_number ?: -1f | ||||
|  | ||||
|         if (latestChapter > 0f) { | ||||
|             manga_last_chapter_label.text = context.getString(R.string.latest_x, | ||||
|             manga_last_chapter_label.text = context.getString(R.string.latest_, | ||||
|                 DecimalFormat("#.#").format(latestChapter)) | ||||
|         } else { | ||||
|             manga_last_chapter_label.text = context.getString(R.string.latest_x, | ||||
|             manga_last_chapter_label.text = context.getString(R.string.latest_, | ||||
|                 context.getString(R.string.unknown)) | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| package eu.kanade.tachiyomi.util.system | ||||
| package exh.util | ||||
| 
 | ||||
| import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects | ||||
| import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject | ||||
							
								
								
									
										101
									
								
								app/src/main/java/exh/util/ViewExtensions.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								app/src/main/java/exh/util/ViewExtensions.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| package exh.util | ||||
|  | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import android.view.WindowInsets | ||||
| import android.widget.FrameLayout | ||||
| import androidx.annotation.Px | ||||
|  | ||||
| inline val View.marginTop: Int | ||||
|     get() = (layoutParams as? ViewGroup.MarginLayoutParams)?.topMargin ?: 0 | ||||
|  | ||||
| inline val View.marginBottom: Int | ||||
|     get() = (layoutParams as? ViewGroup.MarginLayoutParams)?.bottomMargin ?: 0 | ||||
|  | ||||
| inline val View.marginRight: Int | ||||
|     get() = (layoutParams as? ViewGroup.MarginLayoutParams)?.rightMargin ?: 0 | ||||
|  | ||||
| inline val View.marginLeft: Int | ||||
|     get() = (layoutParams as? ViewGroup.MarginLayoutParams)?.leftMargin ?: 0 | ||||
|  | ||||
| fun View.doOnApplyWindowInsets(f: (View, WindowInsets, ViewPaddingState) -> Unit) { | ||||
|     // Create a snapshot of the view's padding state | ||||
|     val paddingState = createStateForView(this) | ||||
|     setOnApplyWindowInsetsListener { v, insets -> | ||||
|         f(v, insets, paddingState) | ||||
|         insets | ||||
|     } | ||||
|     requestApplyInsetsWhenAttached() | ||||
| } | ||||
|  | ||||
| object ControllerViewWindowInsetsListener : View.OnApplyWindowInsetsListener { | ||||
|     override fun onApplyWindowInsets(v: View, insets: WindowInsets): WindowInsets { | ||||
|         v.updateLayoutParams<FrameLayout.LayoutParams> { | ||||
|             val attrsArray = intArrayOf(android.R.attr.actionBarSize) | ||||
|             val array = v.context.obtainStyledAttributes(attrsArray) | ||||
|             topMargin = insets.systemWindowInsetTop + array.getDimensionPixelSize(0, 0) | ||||
|             array.recycle() | ||||
|         } | ||||
|         return insets | ||||
|     } | ||||
| } | ||||
|  | ||||
| fun View.requestApplyInsetsWhenAttached() { | ||||
|     if (isAttachedToWindow) { | ||||
|         requestApplyInsets() | ||||
|     } else { | ||||
|         addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { | ||||
|             override fun onViewAttachedToWindow(v: View) { | ||||
|                 v.requestApplyInsets() | ||||
|             } | ||||
|  | ||||
|             override fun onViewDetachedFromWindow(v: View) = Unit | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| inline fun <reified T : ViewGroup.LayoutParams> View.updateLayoutParams(block: T.() -> Unit) { | ||||
|     val params = layoutParams as T | ||||
|     block(params) | ||||
|     layoutParams = params | ||||
| } | ||||
|  | ||||
| fun View.applyWindowInsetsForController() { | ||||
|     setOnApplyWindowInsetsListener(ControllerViewWindowInsetsListener) | ||||
|     requestApplyInsetsWhenAttached() | ||||
| } | ||||
|  | ||||
| inline fun View.updatePaddingRelative( | ||||
|     @Px start: Int = paddingStart, | ||||
|     @Px top: Int = paddingTop, | ||||
|     @Px end: Int = paddingEnd, | ||||
|     @Px bottom: Int = paddingBottom | ||||
| ) { | ||||
|     setPaddingRelative(start, top, end, bottom) | ||||
| } | ||||
|  | ||||
| private fun createStateForView(view: View) = ViewPaddingState( | ||||
|     view.paddingLeft, | ||||
|     view.paddingTop, | ||||
|     view.paddingRight, | ||||
|     view.paddingBottom, | ||||
|     view.paddingStart, | ||||
|     view.paddingEnd | ||||
| ) | ||||
|  | ||||
| data class ViewPaddingState( | ||||
|     val left: Int, | ||||
|     val top: Int, | ||||
|     val right: Int, | ||||
|     val bottom: Int, | ||||
|     val start: Int, | ||||
|     val end: Int | ||||
| ) | ||||
|  | ||||
| object RecyclerWindowInsetsListener : View.OnApplyWindowInsetsListener { | ||||
|     override fun onApplyWindowInsets(v: View, insets: WindowInsets): WindowInsets { | ||||
|         v.updatePaddingRelative(bottom = insets.systemWindowInsetBottom) | ||||
|         // v.updatePaddingRelative(bottom = v.paddingBottom + insets.systemWindowInsetBottom) | ||||
|         return insets | ||||
|     } | ||||
| } | ||||
| @@ -333,12 +333,18 @@ | ||||
|                     app:layout_constraintTop_toBottomOf="@id/manga_genres_tags_wrapper" /> | ||||
|  | ||||
|                 <Button | ||||
|                     android:id="@+id/smartsearch_merge_btn" | ||||
|                     style="@style/Widget.AppCompat.Button.Colored" | ||||
|                     android:id="@+id/merge_btn" | ||||
|                     style="@style/Widget.MaterialComponents.Button" | ||||
|                     android:layout_width="match_parent" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_height="0dp" | ||||
|                     android:layout_weight="1" | ||||
|                     android:text="Merge with current" /> | ||||
|                     app:layout_constraintEnd_toEndOf="parent" | ||||
|                     app:layout_constraintStart_toStartOf="parent" | ||||
|                     app:layout_constraintTop_toBottomOf="@+id/manga_info_toggle" | ||||
|                     android:text="@string/merge" | ||||
|                     android:visibility="gone" | ||||
|                     tools:visibility="visible"/> | ||||
|  | ||||
|  | ||||
|             </androidx.constraintlayout.widget.ConstraintLayout> | ||||
|  | ||||
|   | ||||
| @@ -357,12 +357,14 @@ | ||||
|                 android:textSize="12sp" /> | ||||
|  | ||||
|             <Button | ||||
|                 android:id="@+id/smartsearch_replace_btn" | ||||
|                 style="@style/Widget.AppCompat.Button.Colored" | ||||
|                 android:id="@+id/merge_btn" | ||||
|                 style="@style/Widget.MaterialComponents.Button" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_height="0dp" | ||||
|                 android:layout_weight="1" | ||||
|                 android:text="Migrate from current" /> | ||||
|                 android:text="@string/merge" | ||||
|                 android:visibility="gone" | ||||
|                 tools:visibility="visible"/> | ||||
|  | ||||
|         </LinearLayout> | ||||
|  | ||||
|   | ||||
| @@ -488,17 +488,6 @@ | ||||
|     <string name="download_unread">Unread</string> | ||||
|     <string name="confirm_delete_chapters">Are you sure you want to delete the selected chapters?</string> | ||||
|     <string name="invalid_download_dir">Invalid download location</string> | ||||
|     <string name="confirm_migration">Migrate %1$d%2$s manga?</string> | ||||
|     <string name="confirm_copy">Copy %1$d%2$s manga?</string> | ||||
|     <string name="skipping_x">(skipping %1$d)</string> | ||||
|     <plurals name="manga_migrated"> | ||||
|         <item quantity="one">%d manga migrated</item> | ||||
|         <item quantity="other">%d manga migrated</item> | ||||
|     </plurals> | ||||
|     <string name="error_fetching_migration">No chapters found, this manga cannot be used for | ||||
|         migration</string> | ||||
|     <string name="no_alternatives_found">No Alternatives Found</string> | ||||
|     <string name="stop_migration">Stop migrating?</string> | ||||
|  | ||||
|     <!-- Tracking Screen --> | ||||
|     <string name="manga_tracking_tab">Tracking</string> | ||||
| @@ -567,18 +556,6 @@ | ||||
|     <!-- History fragment --> | ||||
|     <string name="recent_manga_time">Ch. %1$s - %2$s</string> | ||||
|  | ||||
|     <!-- Source migration screen --> | ||||
|     <string name="migration_info">Tap to select the source to migrate from</string> | ||||
|     <string name="migration_dialog_what_to_include">Select data to include</string> | ||||
|     <string name="migration_selection_prompt">Select a source to migrate from</string> | ||||
|     <string name="select">Select</string> | ||||
|     <string name="migrate">Migrate</string> | ||||
|     <string name="migrate_">Migrate %1$s</string> | ||||
|     <string name="copy">Copy</string> | ||||
|     <string name="migrating">Migrating…</string> | ||||
|     <string name="migration">Migration</string> | ||||
|     <string name="latest_x">Latest: %1$s</string> | ||||
|  | ||||
|     <!-- Downloads activity and service --> | ||||
|     <string name="download_queue_error">Could not download chapters. You can try again in the downloads section</string> | ||||
|  | ||||
| @@ -662,18 +639,50 @@ | ||||
|     <string name="channel_downloader">Downloader</string> | ||||
|     <string name="channel_new_chapters">Chapter updates</string> | ||||
|     <string name="channel_ext_updates">Extension updates</string> | ||||
|     <string name="channel_backup_restore">Backup and restore</string> | ||||
|     <string name="channel_backup_restore_progress">Progress</string> | ||||
|     <string name="channel_backup_restore_complete">Complete</string> | ||||
|     <string name="data_to_include_in_migration">Data to include in migration</string> | ||||
|     <string name="search_parameter">Search parameter (e.g. language:english)</string> | ||||
|     <string name="include_extra_search_parameter">Include extra search parameter when searching</string> | ||||
|      | ||||
|     <!-- Migration --> | ||||
|     <string name="source_migration">Source migration</string> | ||||
|     <string name="migration">Migration</string> | ||||
|     <string name="skip_pre_migration">Skip pre-migration</string> | ||||
|     <string name="pre_migration_skip_toast">To show this screen again, go to Settings -> Library.</string> | ||||
|     <string name="select_a_source_to_migrate_from">Select a source to migrate from</string> | ||||
|     <string name="use_intelligent_search">Search title + keywords of title</string> | ||||
|     <string name="migrating_to">migrating to</string> | ||||
|     <string name="data_to_include_in_migration">Data to include in migration</string> | ||||
|     <string name="search_parameter_eg">Search parameter (e.g. language:english)</string> | ||||
|     <string name="include_extra_search_parameter">Include extra search parameter when searching</string> | ||||
|     <string name="use_most_chapters">Use source with the most chapters (slower)</string> | ||||
|     <string name="use_first_source">Use first source with alternative</string> | ||||
|     <string name="skip_this_step_next_time">Skip this step next time</string> | ||||
|     <string name="pre_migration_skip_toast">To show this screen again, go to Settings -> Library.</string> | ||||
|     <string name="search_parameter">Search parameter (e.g. language:english)</string> | ||||
|     <string name="include_extra_search_parameter">Include extra search parameter when searching</string> | ||||
|     <string name="to_show_again_setting_library">To show this screen again, go to Settings -> Library.</string> | ||||
|     <string name="latest_">Latest: %1$s</string> | ||||
|     <string name="migrating_to">migrating to</string> | ||||
|     <string name="dont_migrate">Don\'t migrate</string> | ||||
|     <string name="search_manually">Search manually</string> | ||||
|     <string name="migrate_now">Migrate now</string> | ||||
|     <string name="copy_now">Copy now</string> | ||||
|     <string name="select">Select</string> | ||||
|     <string name="migrate">Migrate</string> | ||||
|     <string name="migrate_">Migrate %1$s</string> | ||||
|     <string name="copy_value">Copy</string> | ||||
|     <string name="no_chapters_found_for_migration">No chapters found, this manga cannot be used for | ||||
|         migration</string> | ||||
|     <string name="no_alternatives_found">No Alternatives Found</string> | ||||
|     <string name="stop_migrating">Stop migrating?</string> | ||||
|     <plurals name="migrate_manga"> | ||||
|         <item quantity="one">Migrate %1$d%2$s manga?</item> | ||||
|         <item quantity="other">Migrate %1$d%2$s manga?</item> | ||||
|     </plurals> | ||||
|     <plurals name="copy_manga"> | ||||
|         <item quantity="one">Copy %1$d%2$s manga?</item> | ||||
|         <item quantity="other">Copy %1$d%2$s manga?</item> | ||||
|     </plurals> | ||||
|     <string name="skipping_">(skipping %1$d)</string> | ||||
|     <plurals name="manga_migrated"> | ||||
|         <item quantity="one">%d manga migrated</item> | ||||
|         <item quantity="other">%d manga migrated</item> | ||||
|     </plurals> | ||||
|  | ||||
|     <!-- EXH --> | ||||
|     <string name="label_login">Login</string> | ||||
| @@ -699,7 +708,8 @@ | ||||
|     <string name="eh_rounded_corner_9">Radius of 9</string> | ||||
|     <string name="eh_rounded_corner_10">Radius of 10</string> | ||||
|     <string name="eh_rounded_corners_desc">The level of radius that the corners are rounded to. Current value is: %s</string> | ||||
|  | ||||
|     <string name="merge">Merge with current</string> | ||||
|     <string name="eh_merge_with_another_source">Merge With Another</string> | ||||
|  | ||||
|  | ||||
| </resources> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user