mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Part 2 of Auto-Migration Done
(cherry picked from commit c4321e3adfff1bdfdcd8ba209dd20549348be217)
This commit is contained in:
		| @@ -260,6 +260,14 @@ class PreferencesHelper(val context: Context) { | ||||
|  | ||||
|     fun skipPreMigration() = flowPrefs.getBoolean(Keys.skipPreMigration, false) | ||||
|  | ||||
|     fun migrationSources() = rxPrefs.getString("migrate_sources", "") | ||||
|  | ||||
|     fun smartMigration() = rxPrefs.getBoolean("smart_migrate", false) | ||||
|  | ||||
|     fun useSourceWithMost() = rxPrefs.getBoolean("use_source_with_most", false) | ||||
|  | ||||
|     fun skipPreMigration() = rxPrefs.getBoolean(Keys.skipPreMigration, false) | ||||
|  | ||||
|     fun upgradeFilters() { | ||||
|         val filterDl = rxPrefs.getBoolean(Keys.filterDownloaded, false).getOrDefault() | ||||
|         val filterUn = rxPrefs.getBoolean(Keys.filterUnread, false).getOrDefault() | ||||
|   | ||||
| @@ -11,6 +11,8 @@ import android.view.MenuInflater | ||||
| import android.view.MenuItem | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import android.view.WindowInsets | ||||
| import android.view.WindowManager | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| import androidx.appcompat.view.ActionMode | ||||
| import androidx.appcompat.widget.SearchView | ||||
| @@ -36,8 +38,9 @@ import eu.kanade.tachiyomi.ui.main.offsetFabAppbarHeight | ||||
| import eu.kanade.tachiyomi.ui.manga.MangaController | ||||
| import eu.kanade.tachiyomi.ui.migration.MigrationController | ||||
| import eu.kanade.tachiyomi.ui.migration.MigrationInterface | ||||
| import eu.kanade.tachiyomi.ui.migration.SearchController | ||||
| import eu.kanade.tachiyomi.ui.migration.manga.design.MigrationDesignController | ||||
| import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController | ||||
| import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig | ||||
| import eu.kanade.tachiyomi.util.system.getResourceColor | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| import eu.kanade.tachiyomi.util.view.inflate | ||||
| @@ -484,9 +487,15 @@ class LibraryController( | ||||
|             R.id.action_select_inverse -> selectInverseCategoryManga() | ||||
|             R.id.action_migrate -> { | ||||
|                 router.pushController( | ||||
|                     MigrationDesignController.create( | ||||
|                         selectedMangas.mapNotNull { it.id } | ||||
|                     ).withFadeTransaction()) | ||||
|                     if (preferences.skipPreMigration().getOrDefault()) { | ||||
|                         MigrationListController.create( | ||||
|                             MigrationProcedureConfig( | ||||
|                                 selectedMangas.mapNotNull { it.id }, null) | ||||
|                         ) | ||||
|                     } else { | ||||
|                         MigrationDesignController.create(selectedMangas.mapNotNull { it.id }) | ||||
|                     } | ||||
|                     .withFadeTransaction()) | ||||
|                 destroyActionModeIfNeeded() | ||||
|             } | ||||
|             else -> return false | ||||
| @@ -503,18 +512,6 @@ class LibraryController( | ||||
|         return nextManga | ||||
|     } | ||||
|  | ||||
|     private fun startMangaMigration() { | ||||
|         migratingMangas.clear() | ||||
|         migratingMangas.addAll(selectedMangas) | ||||
|         destroyActionModeIfNeeded() | ||||
|         val manga = migratingMangas.firstOrNull() ?: return | ||||
|         val searchController = SearchController(manga) | ||||
|         searchController.totalProgress = migratingMangas.size | ||||
|         searchController.targetController = this | ||||
|         router.pushController(searchController.withFadeTransaction()) | ||||
|         migratingMangas.remove(manga) | ||||
|     } | ||||
|  | ||||
|     override fun onDestroyActionMode(mode: ActionMode?) { | ||||
|         // Clear all the manga selections and notify child views. | ||||
|         selectedMangas.clear() | ||||
| @@ -788,3 +785,15 @@ class LibraryController( | ||||
|         const val REQUEST_IMAGE_OPEN = 101 | ||||
|     } | ||||
| } | ||||
|  | ||||
| object HeightTopWindowInsetsListener : View.OnApplyWindowInsetsListener { | ||||
|     override fun onApplyWindowInsets(v: View, insets: WindowInsets): WindowInsets { | ||||
|         val topInset = insets.systemWindowInsetTop | ||||
|         v.setPadding(0, topInset, 0, 0) | ||||
|         if (v.layoutParams.height != topInset) { | ||||
|             v.layoutParams.height = topInset | ||||
|             v.requestLayout() | ||||
|         } | ||||
|         return insets | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,137 @@ | ||||
| package eu.kanade.tachiyomi.ui.migration.manga.design | ||||
|  | ||||
| import android.app.Activity | ||||
| import android.content.res.Configuration | ||||
| import android.os.Bundle | ||||
| import android.widget.CompoundButton | ||||
| import android.widget.LinearLayout | ||||
| import android.widget.RadioButton | ||||
| import android.widget.RadioGroup | ||||
| import android.widget.Toast | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.f2prateek.rx.preferences.Preference | ||||
| import com.google.android.material.bottomsheet.BottomSheetDialog | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.preference.getOrDefault | ||||
| import eu.kanade.tachiyomi.ui.migration.MigrationFlags | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| import eu.kanade.tachiyomi.util.view.gone | ||||
| import eu.kanade.tachiyomi.util.view.visible | ||||
| import kotlinx.android.synthetic.main.migration_bottom_sheet.* | ||||
| import kotlinx.android.synthetic.main.migration_bottom_sheet.extra_search_param | ||||
| import kotlinx.android.synthetic.main.migration_bottom_sheet.extra_search_param_text | ||||
| import kotlinx.android.synthetic.main.migration_bottom_sheet.mig_categories | ||||
| import kotlinx.android.synthetic.main.migration_bottom_sheet.mig_chapters | ||||
| import kotlinx.android.synthetic.main.migration_bottom_sheet.mig_tracking | ||||
| import kotlinx.android.synthetic.main.migration_bottom_sheet.use_smart_search | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| class MigrationBottomSheetDialog( | ||||
|     activity: Activity, | ||||
|     theme: Int, | ||||
|     private val listener: | ||||
|     StartMigrationListener | ||||
| ) : | ||||
|     BottomSheetDialog(activity, | ||||
|     theme) { | ||||
|     /** | ||||
|      * Preferences helper. | ||||
|      */ | ||||
|     private val preferences by injectLazy<PreferencesHelper>() | ||||
|  | ||||
|     init { | ||||
|         // Use activity theme for this layout | ||||
|         val view = activity.layoutInflater.inflate(R.layout.migration_bottom_sheet, null) | ||||
|         // val scroll = NestedScrollView(context) | ||||
|         // scroll.addView(view) | ||||
|  | ||||
|         setContentView(view) | ||||
|         if (activity.resources.configuration?.orientation == Configuration.ORIENTATION_LANDSCAPE) | ||||
|             sourceGroup.orientation = LinearLayout.HORIZONTAL | ||||
|         window?.setBackgroundDrawable(null) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called when the sheet is created. It initializes the listeners and values of the preferences. | ||||
|      */ | ||||
|     override fun onCreate(savedInstanceState: Bundle?) { | ||||
|         super.onCreate(savedInstanceState) | ||||
|  | ||||
|         initPreferences() | ||||
|  | ||||
|         fab.setOnClickListener { | ||||
|             preferences.skipPreMigration().set(skip_step.isChecked) | ||||
|             listener.startMigration( | ||||
|                 if (use_smart_search.isChecked && extra_search_param_text.text.isNotBlank()) | ||||
|                     extra_search_param_text.text.toString() else null) | ||||
|             dismiss() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Init general reader preferences. | ||||
|      */ | ||||
|     private fun initPreferences() { | ||||
|         val flags = preferences.migrateFlags().getOrDefault() | ||||
|  | ||||
|         mig_chapters.isChecked = MigrationFlags.hasChapters(flags) | ||||
|         mig_categories.isChecked = MigrationFlags.hasCategories(flags) | ||||
|         mig_tracking.isChecked = MigrationFlags.hasTracks(flags) | ||||
|  | ||||
|         mig_chapters.setOnCheckedChangeListener { _, _ -> setFlags() } | ||||
|         mig_categories.setOnCheckedChangeListener { _, _ -> setFlags() } | ||||
|         mig_tracking.setOnCheckedChangeListener { _, _ -> setFlags() } | ||||
|  | ||||
|         use_smart_search.bindToPreference(preferences.smartMigration()) | ||||
|         extra_search_param_text.gone() | ||||
|         extra_search_param.setOnCheckedChangeListener { _, isChecked -> | ||||
|             if (isChecked) { | ||||
|                 extra_search_param_text.visible() | ||||
|             } else { | ||||
|                 extra_search_param_text.gone() | ||||
|             } | ||||
|         } | ||||
|         sourceGroup.bindToPreference(preferences.useSourceWithMost()) | ||||
|  | ||||
|         skip_step.isChecked = preferences.skipPreMigration().getOrDefault() | ||||
|         skip_step.setOnCheckedChangeListener { _, isChecked -> | ||||
|             if (isChecked) | ||||
|                 (listener as? Controller)?.activity?.toast(R.string.pre_migration_skip_toast, | ||||
|                     Toast.LENGTH_LONG) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun setFlags() { | ||||
|         var flags = 0 | ||||
|         if (mig_chapters.isChecked) flags = flags or MigrationFlags.CHAPTERS | ||||
|         if (mig_categories.isChecked) flags = flags or MigrationFlags.CATEGORIES | ||||
|         if (mig_categories.isChecked) flags = flags or MigrationFlags.TRACK | ||||
|         preferences.migrateFlags().set(flags) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Binds a checkbox or switch view with a boolean preference. | ||||
|      */ | ||||
|     private fun CompoundButton.bindToPreference(pref: Preference<Boolean>) { | ||||
|         isChecked = pref.getOrDefault() | ||||
|         setOnCheckedChangeListener { _, isChecked -> pref.set(isChecked) } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Binds a radio group with a boolean preference. | ||||
|      */ | ||||
|     private fun RadioGroup.bindToPreference(pref: Preference<Boolean>) { | ||||
|         (getChildAt(pref.getOrDefault().toInt()) as RadioButton).isChecked = true | ||||
|         setOnCheckedChangeListener { _, value -> | ||||
|             val index = indexOfChild(findViewById(value)) | ||||
|             pref.set(index == 1) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun Boolean.toInt() = if (this) 1 else 0 | ||||
| } | ||||
|  | ||||
| interface StartMigrationListener { | ||||
|     fun startMigration(extraParam: String?) | ||||
| } | ||||
| @@ -4,7 +4,9 @@ import android.os.Bundle | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import android.widget.FrameLayout | ||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||
| import com.google.android.material.bottomsheet.BottomSheetBehavior | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| @@ -13,27 +15,18 @@ import eu.kanade.tachiyomi.source.SourceManager | ||||
| import eu.kanade.tachiyomi.source.online.HttpSource | ||||
| import eu.kanade.tachiyomi.ui.base.controller.BaseController | ||||
| import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction | ||||
| import eu.kanade.tachiyomi.ui.migration.MigrationFlags | ||||
| import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController | ||||
| import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig | ||||
| import eu.kanade.tachiyomi.util.view.gone | ||||
| import eu.kanade.tachiyomi.util.view.visible | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.begin_migration_btn | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.extra_search_param | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.extra_search_param_desc | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.extra_search_param_text | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.fuzzy_search | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.mig_categories | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.mig_chapters | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.migration_mode | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.options_group | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.prioritize_chapter_count | ||||
| 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.migration_design_controller.fab | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.recycler | ||||
| import kotlinx.android.synthetic.main.migration_design_controller.use_smart_search | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| class MigrationDesignController(bundle: Bundle? = null) : BaseController(bundle), FlexibleAdapter | ||||
| .OnItemClickListener { | ||||
| .OnItemClickListener, StartMigrationListener { | ||||
|     private val sourceManager: SourceManager by injectLazy() | ||||
|     private val prefs: PreferencesHelper by injectLazy() | ||||
|  | ||||
| @@ -53,7 +46,7 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseController(bundle) | ||||
|         super.onViewCreated(view) | ||||
|  | ||||
|         val ourAdapter = adapter ?: MigrationSourceAdapter( | ||||
|                 getEnabledSources().map { MigrationSourceItem(it, true) }, | ||||
|                 getEnabledSources().map { MigrationSourceItem(it, isEnabled(it.id.toString())) }, | ||||
|                 this | ||||
|         ) | ||||
|         adapter = ourAdapter | ||||
| @@ -63,83 +56,42 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseController(bundle) | ||||
|         ourAdapter.itemTouchHelperCallback = null // Reset adapter touch adapter to fix drag after rotation | ||||
|         ourAdapter.isHandleDragEnabled = true | ||||
|  | ||||
|         migration_mode.setOnClickListener { | ||||
|             prioritize_chapter_count.toggle() | ||||
|         } | ||||
|         val fabBaseMarginBottom = fab?.marginBottom ?: 0 | ||||
|         recycler.doOnApplyWindowInsets { v, insets, padding -> | ||||
|  | ||||
|         fuzzy_search.setOnClickListener { | ||||
|             use_smart_search.toggle() | ||||
|         } | ||||
|  | ||||
|         extra_search_param_desc.setOnClickListener { | ||||
|             extra_search_param.toggle() | ||||
|         } | ||||
|  | ||||
|         prioritize_chapter_count.setOnCheckedChangeListener { _, b -> | ||||
|             updatePrioritizeChapterCount(b) | ||||
|         } | ||||
|  | ||||
|         extra_search_param.setOnCheckedChangeListener { _, b -> | ||||
|             updateOptionsState() | ||||
|         } | ||||
|  | ||||
|         updatePrioritizeChapterCount(prioritize_chapter_count.isChecked) | ||||
|  | ||||
|         updateOptionsState() | ||||
|  | ||||
|         begin_migration_btn.setOnClickListener { | ||||
|             if (!showingOptions) { | ||||
|                 showingOptions = true | ||||
|                 updateOptionsState() | ||||
|                 return@setOnClickListener | ||||
|             fab?.updateLayoutParams<ViewGroup.MarginLayoutParams> { | ||||
|                 bottomMargin = fabBaseMarginBottom + insets.systemWindowInsetBottom | ||||
|             } | ||||
|             // offset the recycler by the fab's inset + some inset on top | ||||
|             v.updatePaddingRelative(bottom = padding.bottom + (fab?.marginBottom ?: 0) + | ||||
|                 fabBaseMarginBottom + (fab?.height ?: 0)) | ||||
|         } | ||||
|  | ||||
|             var flags = 0 | ||||
|             if (mig_chapters.isChecked) flags = flags or MigrationFlags.CHAPTERS | ||||
|             if (mig_categories.isChecked) flags = flags or MigrationFlags.CATEGORIES | ||||
|             if (mig_categories.isChecked) flags = flags or MigrationFlags.TRACK | ||||
|         fab.setOnClickListener { | ||||
|             val dialog = MigrationBottomSheetDialog(activity!!, R.style.SheetDialog, this) | ||||
|             dialog.show() | ||||
|             val bottomSheet = | ||||
|                 dialog.findViewById<FrameLayout>(com.google.android.material.R.id | ||||
|                     .design_bottom_sheet) | ||||
|             val behavior: BottomSheetBehavior<*> = BottomSheetBehavior.from(bottomSheet!!) | ||||
|             behavior.state = BottomSheetBehavior.STATE_EXPANDED | ||||
|             behavior.skipCollapsed = true | ||||
|         } | ||||
|     } | ||||
|  | ||||
|             router.replaceTopController( | ||||
|                 MigrationListController.create( | ||||
|                     MigrationProcedureConfig( | ||||
|                             config.toList(), | ||||
|                             ourAdapter.items.filter { | ||||
|                                 it.sourceEnabled | ||||
|                             }.map { it.source.id }, | ||||
|                             useSourceWithMostChapters = prioritize_chapter_count.isChecked, | ||||
|                             enableLenientSearch = use_smart_search.isChecked, | ||||
|                             migrationFlags = flags, | ||||
|                             extraSearchParams = if (extra_search_param.isChecked && extra_search_param_text.text.isNotBlank()) { | ||||
|                                 extra_search_param_text.text.toString() | ||||
|                             } else null | ||||
|                     ) | ||||
|     override fun startMigration(extraParam: String?) { | ||||
|         val listOfSources = adapter?.items?.filter { | ||||
|             it.sourceEnabled | ||||
|         }?.joinToString("/") { it.source.id.toString() } | ||||
|         prefs.migrationSources().set(listOfSources) | ||||
|  | ||||
|         router.replaceTopController( | ||||
|             MigrationListController.create( | ||||
|                 MigrationProcedureConfig( | ||||
|                     config.toList(), | ||||
|                     extraSearchParams = extraParam | ||||
|                 ) | ||||
|             ).withFadeTransaction()) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun updateOptionsState() { | ||||
|         if (showingOptions) { | ||||
|             begin_migration_btn.text = "Begin migration" | ||||
|             options_group.visible() | ||||
|             if (extra_search_param.isChecked) { | ||||
|                 extra_search_param_text.visible() | ||||
|             } else { | ||||
|                 extra_search_param_text.gone() | ||||
|             } | ||||
|         } else { | ||||
|             begin_migration_btn.text = "Next step" | ||||
|             options_group.gone() | ||||
|             extra_search_param_text.gone() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun handleBack(): Boolean { | ||||
|         if (showingOptions) { | ||||
|             showingOptions = false | ||||
|             updateOptionsState() | ||||
|             return true | ||||
|         } | ||||
|         return super.handleBack() | ||||
|     } | ||||
|  | ||||
|     override fun onSaveInstanceState(outState: Bundle) { | ||||
| @@ -153,14 +105,6 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseController(bundle) | ||||
|         adapter?.onRestoreInstanceState(savedInstanceState) | ||||
|     } | ||||
|  | ||||
|     private fun updatePrioritizeChapterCount(migrationMode: Boolean) { | ||||
|         migration_mode.text = if (migrationMode) { | ||||
|             "Currently using the source with the most chapters and the above list to break ties (slow with many sources or smart search)" | ||||
|         } else { | ||||
|             "Currently using the first source in the list that has the manga" | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onItemClick(view: View, position: Int): Boolean { | ||||
|         adapter?.getItem(position)?.let { | ||||
|             it.sourceEnabled = !it.sourceEnabled | ||||
| @@ -176,13 +120,25 @@ class MigrationDesignController(bundle: Bundle? = null) : BaseController(bundle) | ||||
|      */ | ||||
|     private fun getEnabledSources(): List<HttpSource> { | ||||
|         val languages = prefs.enabledLanguages().getOrDefault() | ||||
|         val hiddenCatalogues = prefs.hiddenCatalogues().getOrDefault() | ||||
|         val sourcesSaved = prefs.migrationSources().getOrDefault().split("/") | ||||
|         var sources = sourceManager.getCatalogueSources() | ||||
|             .filterIsInstance<HttpSource>() | ||||
|             .filter { it.lang in languages } | ||||
|             .sortedBy { "(${it.lang}) ${it.name}" } | ||||
|         sources = | ||||
|             sources.filter { isEnabled(it.id.toString()) }.sortedBy { sourcesSaved.indexOf(it.id | ||||
|                 .toString()) | ||||
|             } + | ||||
|                 sources.filterNot { isEnabled(it.id.toString()) } | ||||
|  | ||||
|         return sourceManager.getVisibleCatalogueSources() | ||||
|                 .filterIsInstance<HttpSource>() | ||||
|                 .filter { it.lang in languages } | ||||
|                 .filterNot { it.id.toString() in hiddenCatalogues } | ||||
|                 .sortedBy { "(${it.lang}) ${it.name}" } | ||||
|         return sources | ||||
|     } | ||||
|  | ||||
|     fun isEnabled(id: String): Boolean { | ||||
|         val sourcesSaved = prefs.migrationSources().getOrDefault() | ||||
|         val hiddenCatalogues = prefs.hiddenCatalogues().getOrDefault() | ||||
|         return if (sourcesSaved.isEmpty()) id !in hiddenCatalogues | ||||
|         else sourcesSaved.split("/").contains(id) | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|   | ||||
| @@ -6,7 +6,7 @@ import eu.kanade.tachiyomi.source.SourceManager | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| class MigrationSourceAdapter( | ||||
|     val items: List<MigrationSourceItem>, | ||||
|     var items: List<MigrationSourceItem>, | ||||
|     val controller: MigrationDesignController | ||||
| ) : FlexibleAdapter<MigrationSourceItem>( | ||||
|         items, | ||||
| @@ -32,6 +32,10 @@ class MigrationSourceAdapter( | ||||
|         super.onRestoreInstanceState(savedInstanceState) | ||||
|     } | ||||
|  | ||||
|     fun updateItems() { | ||||
|         items = currentItems | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         private const val SELECTED_SOURCES_KEY = "selected_sources" | ||||
|     } | ||||
|   | ||||
| @@ -16,6 +16,8 @@ import com.afollestad.materialdialogs.MaterialDialog | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.preference.getOrDefault | ||||
| import eu.kanade.tachiyomi.smartsearch.SmartSearchEngine | ||||
| import eu.kanade.tachiyomi.source.CatalogueSource | ||||
| import eu.kanade.tachiyomi.source.Source | ||||
| @@ -62,6 +64,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|     val config: MigrationProcedureConfig? = args.getParcelable(CONFIG_EXTRA) | ||||
|  | ||||
|     private val db: DatabaseHelper by injectLazy() | ||||
|     private val preferences: PreferencesHelper by injectLazy() | ||||
|     private val sourceManager: SourceManager by injectLazy() | ||||
|  | ||||
|     private val smartSearchEngine = SmartSearchEngine(coroutineContext, config?.extraSearchParams) | ||||
| @@ -95,11 +98,8 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|  | ||||
|         recycler.adapter = adapter | ||||
|         recycler.layoutManager = LinearLayoutManager(view.context) | ||||
|         // recycler.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration | ||||
|             // .VERTICAL)) | ||||
|         recycler.setHasFixedSize(true) | ||||
|         recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener) | ||||
|         // recycler.isEnabled = false | ||||
|  | ||||
|         adapter?.updateDataSet(newMigratingManga.map { it.toModal() }) | ||||
|  | ||||
| @@ -110,21 +110,6 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /*fun nextMigration() { | ||||
|         adapter?.let { adapter -> | ||||
|             if(pager.currentItem >= adapter.count - 1) { | ||||
|                 applicationContext?.toast("All migrations complete!") | ||||
|                 router.popCurrentController() | ||||
|             } else { | ||||
|                 adapter.migratingManga[pager.currentItem].migrationJob.cancel() | ||||
|                 pager.setCurrentItem(pager.currentItem + 1, true) | ||||
|                 launch(Dispatchers.Main) { | ||||
|                     updateTitle() | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }*/ | ||||
|  | ||||
|     fun migrationFailure() { | ||||
|         activity?.let { | ||||
|             MaterialDialog.Builder(it) | ||||
| @@ -136,8 +121,13 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|     } | ||||
|  | ||||
|     suspend fun runMigrations(mangas: List<MigratingManga>) { | ||||
|         val sources = config?.targetSourceIds?.mapNotNull { sourceManager.get(it) as? CatalogueSource } ?: return | ||||
|         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 } | ||||
|         if (config == null) return | ||||
|         for (manga in mangas) { | ||||
|             if (!manga.searchResult.initialized && manga.migrationJob.isActive) { | ||||
|                 val mangaObj = manga.manga() | ||||
| @@ -154,7 +144,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|                         val validSources = sources.filter { | ||||
|                             it.id != mangaSource.id | ||||
|                         } | ||||
|                         if (config.useSourceWithMostChapters) { | ||||
|                         if (useSourceWithMost) { | ||||
|                             val sourceSemaphore = Semaphore(3) | ||||
|                             val processedSources = AtomicInteger() | ||||
|  | ||||
| @@ -162,7 +152,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|                                 async { | ||||
|                                     sourceSemaphore.withPermit { | ||||
|                                         try { | ||||
|                                             val searchResult = if (config.enableLenientSearch) { | ||||
|                                             val searchResult = if (useSmartSearch) { | ||||
|                                                 smartSearchEngine.smartSearch(source, mangaObj.title) | ||||
|                                             } else { | ||||
|                                                 smartSearchEngine.normalSearch(source, mangaObj.title) | ||||
| @@ -192,7 +182,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), | ||||
|                         } else { | ||||
|                             validSources.forEachIndexed { index, source -> | ||||
|                                 val searchResult = try { | ||||
|                                     val searchResult = if (config.enableLenientSearch) { | ||||
|                                     val searchResult = if (useSmartSearch) { | ||||
|                                         smartSearchEngine.smartSearch(source, mangaObj.title) | ||||
|                                     } else { | ||||
|                                         smartSearchEngine.normalSearch(source, mangaObj.title) | ||||
|   | ||||
| @@ -8,7 +8,6 @@ import com.google.gson.Gson | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.database.models.MangaCategory | ||||
| import eu.kanade.tachiyomi.data.glide.GlideApp | ||||
| import eu.kanade.tachiyomi.source.Source | ||||
| import eu.kanade.tachiyomi.source.SourceManager | ||||
| @@ -16,7 +15,6 @@ import eu.kanade.tachiyomi.source.model.SManga | ||||
| import eu.kanade.tachiyomi.source.online.all.MergedSource | ||||
| import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction | ||||
| import eu.kanade.tachiyomi.ui.manga.MangaController | ||||
| import eu.kanade.tachiyomi.ui.migration.MigrationFlags | ||||
| import eu.kanade.tachiyomi.util.view.gone | ||||
| import eu.kanade.tachiyomi.util.view.inflate | ||||
| import eu.kanade.tachiyomi.util.view.visible | ||||
| @@ -123,7 +121,7 @@ class MigrationProcedureAdapter( | ||||
|         val config = controller.config ?: return | ||||
|         // db.inTransaction { | ||||
|             // Update chapters read | ||||
|             if (MigrationFlags.hasChapters(controller.config.migrationFlags)) { | ||||
|             /* if (MigrationFlags.hasChapters(controller.config.migrationFlags)) { | ||||
|                 val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking() | ||||
|                 val maxChapterRead = prevMangaChapters.filter { it.read } | ||||
|                         .maxBy { it.chapter_number }?.chapter_number | ||||
| @@ -162,7 +160,7 @@ class MigrationProcedureAdapter( | ||||
|  | ||||
|             // SearchPresenter#networkToLocalManga may have updated the manga title, so ensure db gets updated title | ||||
|             db.updateMangaTitle(manga).executeAsBlocking() | ||||
|         // } | ||||
|         //}*/ | ||||
|     } | ||||
|  | ||||
|     fun View.setupView(tag: ViewTag, migratingManga: MigratingManga) { | ||||
|   | ||||
| @@ -6,9 +6,5 @@ import kotlinx.android.parcel.Parcelize | ||||
| @Parcelize | ||||
| data class MigrationProcedureConfig( | ||||
|     var mangaIds: List<Long>, | ||||
|     val targetSourceIds: List<Long>, | ||||
|     val useSourceWithMostChapters: Boolean, | ||||
|     val enableLenientSearch: Boolean, | ||||
|     val migrationFlags: Int, | ||||
|     val extraSearchParams: String? | ||||
| ) : Parcelable | ||||
|   | ||||
| @@ -9,27 +9,16 @@ import com.afollestad.materialdialogs.MaterialDialog | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| import eu.kanade.tachiyomi.smartsearch.SmartSearchEngine | ||||
| import eu.kanade.tachiyomi.source.CatalogueSource | ||||
| import eu.kanade.tachiyomi.source.SourceManager | ||||
| import eu.kanade.tachiyomi.ui.base.controller.BaseController | ||||
| import eu.kanade.tachiyomi.util.await | ||||
| import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| import java.util.concurrent.atomic.AtomicInteger | ||||
| import kotlin.coroutines.CoroutineContext | ||||
| import kotlinx.android.synthetic.main.migration_process.pager | ||||
| import kotlinx.coroutines.CancellationException | ||||
| import kotlinx.coroutines.CoroutineScope | ||||
| import kotlinx.coroutines.Dispatchers | ||||
| import kotlinx.coroutines.Job | ||||
| import kotlinx.coroutines.async | ||||
| import kotlinx.coroutines.cancel | ||||
| import kotlinx.coroutines.isActive | ||||
| import kotlinx.coroutines.launch | ||||
| import kotlinx.coroutines.sync.Semaphore | ||||
| import kotlinx.coroutines.sync.withPermit | ||||
| import kotlinx.coroutines.withContext | ||||
| import rx.schedulers.Schedulers | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| // TODO Will probably implode if activity is fully destroyed | ||||
| @@ -121,7 +110,7 @@ class MigrationProcedureController(bundle: Bundle? = null) : BaseController(bund | ||||
|     } | ||||
|  | ||||
|     suspend fun runMigrations(mangas: List<MigratingManga>) { | ||||
|         val sources = config?.targetSourceIds?.mapNotNull { sourceManager.get(it) as? | ||||
|         /*  val sources = config?.targetSourceIds?.mapNotNull { sourceManager.get(it) as? | ||||
|             CatalogueSource } ?: return | ||||
|  | ||||
|         for (manga in mangas) { | ||||
| @@ -229,7 +218,7 @@ class MigrationProcedureController(bundle: Bundle? = null) : BaseController(bund | ||||
|  | ||||
|                 manga.searchResult.initialize(result?.id) | ||||
|             } | ||||
|         } | ||||
|         }*/ | ||||
|     } | ||||
|  | ||||
|     override fun onDestroy() { | ||||
|   | ||||
| @@ -6,6 +6,8 @@ import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.database.models.MangaCategory | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.preference.getOrDefault | ||||
| import eu.kanade.tachiyomi.ui.migration.MigrationFlags | ||||
| import eu.kanade.tachiyomi.util.lang.launchUI | ||||
| import kotlinx.coroutines.Dispatchers | ||||
| @@ -21,6 +23,7 @@ class MigrationProcessAdapter( | ||||
|  | ||||
|     private val db: DatabaseHelper by injectLazy() | ||||
|     var items: List<MigrationProcessItem> = emptyList() | ||||
|     val preferences: PreferencesHelper by injectLazy() | ||||
|  | ||||
|     val menuItemListener: MigrationProcessInterface = controller | ||||
|  | ||||
| @@ -46,7 +49,7 @@ class MigrationProcessAdapter( | ||||
|         .searchResult.content != null }) | ||||
|  | ||||
|     fun mangasSkipped() = (items.count { (!it.manga.searchResult.initialized || it.manga | ||||
|         .searchResult.content == null) && !it.manga.migrationJob.isActive }) | ||||
|         .searchResult.content == null) }) | ||||
|  | ||||
|     suspend fun performMigrations(copy: Boolean) { | ||||
|         withContext(Dispatchers.IO) { | ||||
| @@ -95,9 +98,9 @@ class MigrationProcessAdapter( | ||||
|         replace: Boolean | ||||
|     ) { | ||||
|         if (controller.config == null) return | ||||
|         // db.inTransaction { | ||||
|         val flags = preferences.migrateFlags().getOrDefault() | ||||
|         // Update chapters read | ||||
|         if (MigrationFlags.hasChapters(controller.config.migrationFlags)) { | ||||
|         if (MigrationFlags.hasChapters(flags)) { | ||||
|             val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking() | ||||
|             val maxChapterRead = prevMangaChapters.filter { it.read } | ||||
|                 .maxBy { it.chapter_number }?.chapter_number | ||||
| @@ -112,13 +115,13 @@ class MigrationProcessAdapter( | ||||
|             } | ||||
|         } | ||||
|         // Update categories | ||||
|         if (MigrationFlags.hasCategories(controller.config.migrationFlags)) { | ||||
|         if (MigrationFlags.hasCategories(flags)) { | ||||
|             val categories = db.getCategoriesForManga(prevManga).executeAsBlocking() | ||||
|             val mangaCategories = categories.map { MangaCategory.create(manga, it) } | ||||
|             db.setMangaCategories(mangaCategories, listOf(manga)) | ||||
|         } | ||||
|         // Update track | ||||
|         if (MigrationFlags.hasTracks(controller.config.migrationFlags)) { | ||||
|         if (MigrationFlags.hasTracks(flags)) { | ||||
|             val tracks = db.getTracks(prevManga).executeAsBlocking() | ||||
|             for (track in tracks) { | ||||
|                 track.id = null | ||||
|   | ||||
| @@ -16,6 +16,7 @@ import eu.kanade.tachiyomi.util.preference.onChange | ||||
| import eu.kanade.tachiyomi.util.preference.onClick | ||||
| import eu.kanade.tachiyomi.util.preference.preference | ||||
| import eu.kanade.tachiyomi.util.preference.preferenceCategory | ||||
| import eu.kanade.tachiyomi.util.preference.summaryRes | ||||
| import eu.kanade.tachiyomi.util.preference.switchPreference | ||||
| import eu.kanade.tachiyomi.util.preference.titleRes | ||||
| import eu.kanade.tachiyomi.util.system.LocaleHelper | ||||
| @@ -191,6 +192,16 @@ class SettingsGeneralController : SettingsController() { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (preferences.skipPreMigration().getOrDefault() || preferences.migrationSources() | ||||
|                 .getOrDefault().isNotEmpty()) { | ||||
|             switchPreference { | ||||
|                 key = Keys.skipPreMigration | ||||
|                 titleRes = R.string.pref_skip_pre_migration | ||||
|                 summaryRes = R.string.pref_skip_pre_migration_summary | ||||
|                 defaultValue = false | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // --> EXH | ||||
|         switchPreference { | ||||
|             key = Keys.eh_expandFilters | ||||
|   | ||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/dialog_rounded_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/drawable/dialog_rounded_background.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:shape="rectangle" > | ||||
|  | ||||
|     <solid android:color="?attr/colorSurface" /> | ||||
|  | ||||
|     <corners android:radius="10dip" /> | ||||
|  | ||||
| </shape> | ||||
							
								
								
									
										164
									
								
								app/src/main/res/layout/migration_bottom_sheet.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								app/src/main/res/layout/migration_bottom_sheet.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:id="@+id/constraintLayout" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:background="@android:color/transparent" | ||||
|     android:orientation="vertical"> | ||||
|  | ||||
|  | ||||
|     <androidx.constraintlayout.widget.ConstraintLayout | ||||
|         android:id="@+id/constraintLayout2" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="32dp" | ||||
|         android:background="@drawable/dialog_rounded_background" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" | ||||
|         app:layout_constraintVertical_bias="0.0"> | ||||
|  | ||||
|         <TextView | ||||
|             android:id="@+id/data_label" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginStart="8dp" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:text="@string/data_to_include_in_migration" | ||||
|             android:textAppearance="@style/TextAppearance.Medium.Body2" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toTopOf="parent" /> | ||||
|  | ||||
|         <CheckBox | ||||
|             android:id="@+id/mig_chapters" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:checked="true" | ||||
|             android:text="@string/chapters" | ||||
|             app:layout_constraintStart_toStartOf="@+id/data_label" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/data_label" /> | ||||
|  | ||||
|         <CheckBox | ||||
|             android:id="@+id/mig_categories" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginStart="8dp" | ||||
|             android:checked="true" | ||||
|             android:text="@string/categories" | ||||
|             app:layout_constraintBottom_toBottomOf="@+id/mig_chapters" | ||||
|             app:layout_constraintStart_toEndOf="@+id/mig_chapters" | ||||
|             app:layout_constraintTop_toTopOf="@+id/mig_chapters" /> | ||||
|  | ||||
|         <CheckBox | ||||
|             android:id="@+id/mig_tracking" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginStart="8dp" | ||||
|             android:checked="true" | ||||
|             android:text="@string/track" | ||||
|             app:layout_constraintBottom_toBottomOf="@+id/mig_categories" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintHorizontal_bias="0.0" | ||||
|             app:layout_constraintStart_toEndOf="@+id/mig_categories" | ||||
|             app:layout_constraintTop_toTopOf="@+id/mig_categories" /> | ||||
|  | ||||
|         <TextView | ||||
|             android:id="@+id/options_label" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:text="@string/options" | ||||
|             android:textAppearance="@style/TextAppearance.Medium.Body2" | ||||
|             app:layout_constraintStart_toStartOf="@+id/mig_chapters" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/mig_chapters" /> | ||||
|  | ||||
|         <RadioGroup | ||||
|             android:id="@+id/sourceGroup" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginEnd="8dp" | ||||
|             android:orientation="vertical" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintStart_toStartOf="@+id/options_label" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/options_label"> | ||||
|  | ||||
|             <RadioButton | ||||
|                 android:id="@+id/radioButton" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:paddingStart="0dp" | ||||
|                 android:paddingEnd="8dp" | ||||
|                 android:text="@string/use_first_source" /> | ||||
|  | ||||
|             <RadioButton | ||||
|                 android:id="@+id/radioButton2" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:text="@string/use_most_chapters" /> | ||||
|         </RadioGroup> | ||||
|  | ||||
|         <androidx.appcompat.widget.SwitchCompat | ||||
|             android:id="@+id/use_smart_search" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginStart="6dp" | ||||
|             android:layout_marginTop="16dp" | ||||
|             android:text="@string/use_intelligent_search" | ||||
|             app:layout_constraintEnd_toEndOf="@+id/sourceGroup" | ||||
|             app:layout_constraintStart_toStartOf="@+id/sourceGroup" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/sourceGroup" /> | ||||
|  | ||||
|         <androidx.appcompat.widget.SwitchCompat | ||||
|             android:id="@+id/extra_search_param" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:text="@string/include_extra_search_parameter" | ||||
|             app:layout_constraintEnd_toEndOf="@+id/use_smart_search" | ||||
|             app:layout_constraintStart_toStartOf="@+id/use_smart_search" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/use_smart_search" /> | ||||
|  | ||||
|         <EditText | ||||
|             android:id="@+id/extra_search_param_text" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:layout_marginEnd="8dp" | ||||
|             android:ems="10" | ||||
|             android:hint="@string/search_parameter" | ||||
|             android:importantForAutofill="no" | ||||
|             android:inputType="textPersonName" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintHorizontal_bias="0.0" | ||||
|             app:layout_constraintStart_toStartOf="@+id/extra_search_param" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/extra_search_param" /> | ||||
|  | ||||
|         <Switch | ||||
|             android:id="@+id/skip_step" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:layout_marginBottom="8dp" | ||||
|             android:text="@string/skip_this_step_next_time" | ||||
|             app:layout_constraintBottom_toBottomOf="parent" | ||||
|             app:layout_constraintEnd_toEndOf="@+id/extra_search_param" | ||||
|             app:layout_constraintStart_toStartOf="@+id/extra_search_param" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/extra_search_param_text" /> | ||||
|     </androidx.constraintlayout.widget.ConstraintLayout> | ||||
|  | ||||
|     <com.google.android.material.floatingactionbutton.FloatingActionButton | ||||
|         android:id="@+id/fab" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginEnd="16dp" | ||||
|         android:src="@drawable/ic_arrow_forward_24dp" | ||||
|         app:layout_anchor="@id/constraintLayout" | ||||
|         app:layout_anchorGravity="bottom|end" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" /> | ||||
|  | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
| @@ -2,6 +2,7 @@ | ||||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:id="@+id/frameLayout" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:animateLayoutChanges="true"> | ||||
| @@ -10,174 +11,24 @@ | ||||
|         android:id="@+id/recycler" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="0dp" | ||||
|         android:layout_marginBottom="8dp" | ||||
|         app:layout_constraintBottom_toTopOf="@+id/textView2" | ||||
|         android:clipToPadding="false" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintHorizontal_bias="0.0" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" | ||||
|         tools:listitem="@layout/migration_source_item"> | ||||
|  | ||||
|     </androidx.recyclerview.widget.RecyclerView> | ||||
|  | ||||
|     <TextView | ||||
|         android:id="@+id/textView2" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginBottom="8dp" | ||||
|         android:text="@string/data_to_include_in_migration" | ||||
|         android:textAppearance="@style/TextAppearance.Medium.Body2" | ||||
|         app:layout_constraintBottom_toTopOf="@+id/mig_chapters" | ||||
|         app:layout_constraintStart_toStartOf="@+id/textView" /> | ||||
|  | ||||
|     <CheckBox | ||||
|         android:id="@+id/mig_chapters" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginBottom="8dp" | ||||
|         android:checked="true" | ||||
|         android:text="@string/chapters" | ||||
|         app:layout_constraintBottom_toTopOf="@+id/textView" | ||||
|         app:layout_constraintStart_toStartOf="@+id/textView2" /> | ||||
|  | ||||
|     <CheckBox | ||||
|         android:id="@+id/mig_categories" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="8dp" | ||||
|         android:checked="true" | ||||
|         android:text="@string/categories" | ||||
|         app:layout_constraintBottom_toBottomOf="@+id/mig_chapters" | ||||
|         app:layout_constraintStart_toEndOf="@+id/mig_chapters" /> | ||||
|  | ||||
|     <CheckBox | ||||
|         android:id="@+id/mig_tracking" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="8dp" | ||||
|         android:checked="true" | ||||
|         android:text="@string/track" | ||||
|         app:layout_constraintBottom_toBottomOf="@+id/mig_categories" | ||||
|         app:layout_constraintStart_toEndOf="@+id/mig_categories" /> | ||||
|  | ||||
|     <TextView | ||||
|         android:id="@+id/textView" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="8dp" | ||||
|         android:layout_marginBottom="8dp" | ||||
|         android:text="@string/options" | ||||
|         android:textAppearance="@style/TextAppearance.Medium.Body2" | ||||
|         app:layout_constraintBottom_toTopOf="@+id/prioritize_chapter_count" | ||||
|         app:layout_constraintStart_toStartOf="parent" /> | ||||
|  | ||||
|     <androidx.appcompat.widget.SwitchCompat | ||||
|         android:id="@+id/prioritize_chapter_count" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginBottom="8dp" | ||||
|         app:layout_constraintStart_toStartOf="@+id/textView" | ||||
|         app:layout_constraintTop_toTopOf="@+id/migration_mode" /> | ||||
|  | ||||
|     <TextView | ||||
|         android:id="@+id/migration_mode" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="8dp" | ||||
|         android:layout_marginLeft="8dp" | ||||
|         android:layout_marginEnd="8dp" | ||||
|         android:layout_marginRight="8dp" | ||||
|         android:layout_marginBottom="8dp" | ||||
|         android:gravity="start|center_vertical" | ||||
|     <com.google.android.material.floatingactionbutton.FloatingActionButton | ||||
|         android:id="@+id/fab" | ||||
|         style="@style/Theme.Widget.FAB" | ||||
|         android:clickable="true" | ||||
|         app:layout_constraintBottom_toTopOf="@+id/fuzzy_search" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toEndOf="@+id/prioritize_chapter_count" | ||||
|         android:focusable="true" /> | ||||
|  | ||||
|     <androidx.appcompat.widget.SwitchCompat | ||||
|         android:id="@+id/use_smart_search" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         app:layout_constraintStart_toStartOf="@+id/textView" | ||||
|         app:layout_constraintTop_toTopOf="@+id/fuzzy_search" /> | ||||
|  | ||||
|     <TextView | ||||
|         android:id="@+id/fuzzy_search" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="8dp" | ||||
|         android:layout_marginLeft="8dp" | ||||
|         android:layout_marginEnd="8dp" | ||||
|         android:layout_marginRight="8dp" | ||||
|         android:layout_marginBottom="8dp" | ||||
|         android:gravity="start|center_vertical" | ||||
|         android:text="@string/use_intelligent_search" | ||||
|         android:clickable="true" | ||||
|         app:layout_constraintBottom_toTopOf="@+id/extra_search_param" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toEndOf="@+id/prioritize_chapter_count" | ||||
|         android:focusable="true" /> | ||||
|  | ||||
|     <androidx.appcompat.widget.SwitchCompat | ||||
|         android:id="@+id/extra_search_param" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         app:layout_constraintStart_toStartOf="@+id/textView" | ||||
|         app:layout_constraintTop_toTopOf="@+id/extra_search_param_desc" /> | ||||
|  | ||||
|     <TextView | ||||
|         android:id="@+id/extra_search_param_desc" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="8dp" | ||||
|         android:layout_marginLeft="8dp" | ||||
|         android:layout_marginEnd="8dp" | ||||
|         android:layout_marginRight="8dp" | ||||
|         android:layout_marginBottom="8dp" | ||||
|         android:gravity="start|center_vertical" | ||||
|         android:text="@string/include_extra_search_parameter" | ||||
|         android:clickable="true" | ||||
|         app:layout_constraintBottom_toTopOf="@+id/extra_search_param_text" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toEndOf="@+id/prioritize_chapter_count" | ||||
|         android:focusable="true" /> | ||||
|  | ||||
|     <EditText | ||||
|         android:id="@+id/extra_search_param_text" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="8dp" | ||||
|         android:layout_marginLeft="8dp" | ||||
|         android:layout_marginEnd="8dp" | ||||
|         android:layout_marginRight="8dp" | ||||
|         android:ems="10" | ||||
|         android:hint="@string/search_parameter" | ||||
|         android:inputType="textPersonName" | ||||
|         app:layout_constraintBottom_toTopOf="@+id/begin_migration_btn" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         android:importantForAutofill="no" /> | ||||
|  | ||||
|     <Button | ||||
|         android:id="@+id/begin_migration_btn" | ||||
|         style="@style/Theme.Widget.Button.FilledAccent" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="8dp" | ||||
|         android:layout_marginLeft="8dp" | ||||
|         android:layout_marginEnd="8dp" | ||||
|         android:layout_marginRight="8dp" | ||||
|         android:layout_marginBottom="8dp" | ||||
|         android:text="@string/begin_migration" | ||||
|         android:focusable="true" | ||||
|         android:src="@drawable/ic_arrow_forward_24dp" | ||||
|         app:layout_anchor="@id/recycler" | ||||
|         app:layout_anchorGravity="bottom|right|end" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" /> | ||||
|  | ||||
|     <androidx.constraintlayout.widget.Group | ||||
|         android:id="@+id/options_group" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         app:constraint_referenced_ids="migration_mode,use_smart_search,fuzzy_search,action_copy_manga,extra_search_param_desc,mig_tracking,textView,mig_chapters,copy_manga_desc,textView2,prioritize_chapter_count,mig_categories,extra_search_param" /> | ||||
|         app:layout_constraintEnd_toEndOf="parent" /> | ||||
|  | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
| @@ -192,7 +192,9 @@ | ||||
|     <string name="wifi">Wi-Fi</string> | ||||
|     <string name="charging">Charging</string> | ||||
|     <string name="pref_update_only_non_completed">Only update ongoing manga</string> | ||||
|  | ||||
|     <string name="pref_skip_pre_migration">Skip pre-migration</string> | ||||
|     <string name="pref_skip_pre_migration_summary">Use last saved pre-migration preferences | ||||
|     and sources to mass migrate</string> | ||||
|     <string name="pref_category_library_categories">Categories</string> | ||||
|     <string name="default_category">Default category</string> | ||||
|     <string name="default_category_summary">Always ask</string> | ||||
| @@ -657,10 +659,12 @@ | ||||
|     <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> | ||||
|     <string name="keep_old_manga">Keep old manga</string> | ||||
|     <string name="use_intelligent_search">Use intelligent search algorithm</string> | ||||
|     <string name="begin_migration">Begin migration</string> | ||||
|     <string name="use_intelligent_search">Search title + keywords of title</string> | ||||
|     <string name="migrating_to">migrating to</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 -> General.</string> | ||||
|  | ||||
|     <!-- EXH --> | ||||
|     <string name="label_login">Login</string> | ||||
|   | ||||
| @@ -309,4 +309,25 @@ | ||||
|  | ||||
|     <style name="FilePickerAlertDialogTheme" parent="Theme.MaterialComponents.Light.Dialog.Alert" /> | ||||
|  | ||||
|     <style name="reader_settings_popup_animation"> | ||||
|         <item name="android:windowEnterAnimation">@anim/enter_from_right</item> | ||||
|         <item name="android:windowExitAnimation">@anim/exit_to_right</item> | ||||
|     </style> | ||||
|  | ||||
|     <style name="reader_brightness_popup_animation"> | ||||
|         <item name="android:windowEnterAnimation">@anim/enter_from_left</item> | ||||
|         <item name="android:windowExitAnimation">@anim/exit_to_left</item> | ||||
|     </style> | ||||
|  | ||||
|     <style name="SheetDialog" parent="Theme.Design.Light.BottomSheetDialog"> | ||||
|         <!--<item name="android:windowCloseOnTouchOutside">false</item>--> | ||||
|         <item name="android:windowIsTranslucent">true</item> | ||||
|         <item name="android:windowContentOverlay">@null</item> | ||||
|         <item name="android:colorBackground">     @android:color/transparent</item> | ||||
|         <item name="android:backgroundDimEnabled">true</item> | ||||
|         <item name="android:backgroundDimAmount">0.3</item> | ||||
|         <item name="android:windowFrame">@null</item> | ||||
|         <item name="android:windowIsFloating">true</item> | ||||
|     </style> | ||||
|  | ||||
| </resources> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user