diff --git a/app/src/main/java/eu/kanade/tachiyomi/smartsearch/SmartSearchEngine.kt b/app/src/main/java/eu/kanade/tachiyomi/smartsearch/SmartSearchEngine.kt index 25added1da..bf2835f5f5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/smartsearch/SmartSearchEngine.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/smartsearch/SmartSearchEngine.kt @@ -6,7 +6,6 @@ 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.ui.smartsearch.SmartSearchPresenter import eu.kanade.tachiyomi.util.await import info.debatty.java.stringsimilarity.NormalizedLevenshtein import kotlinx.coroutines.CoroutineScope @@ -44,7 +43,7 @@ class SmartSearchEngine(parentContext: CoroutineContext, searchResults.mangas.map { val cleanedMangaTitle = cleanSmartSearchTitle(it.title) val normalizedDistance = normalizedLevenshtein.similarity(cleanedTitle, cleanedMangaTitle) - SmartSearchPresenter.SearchEntry(it, normalizedDistance) + SearchEntry(it, normalizedDistance) }.filter { (_, normalizedDistance) -> normalizedDistance >= MIN_SMART_ELIGIBLE_THRESHOLD } @@ -64,7 +63,7 @@ class SmartSearchEngine(parentContext: CoroutineContext, searchResults.mangas.map { val normalizedDistance = normalizedLevenshtein.similarity(title, it.title) - SmartSearchPresenter.SearchEntry(it, normalizedDistance) + SearchEntry(it, normalizedDistance) }.filter { (_, normalizedDistance) -> normalizedDistance >= MIN_NORMAL_ELIGIBLE_THRESHOLD } @@ -189,4 +188,6 @@ class SmartSearchEngine(parentContext: CoroutineContext, private val titleRegex = Regex("[^a-zA-Z0-9- ]") private val consecutiveSpacesRegex = Regex(" +") } -} \ No newline at end of file +} + +data class SearchEntry(val manga: SManga, val dist: Double) \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index 8e348437aa..9154989115 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -44,9 +44,9 @@ import eu.kanade.tachiyomi.ui.main.MainActivity 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.doOnApplyWindowInsets import eu.kanade.tachiyomi.util.inflate import eu.kanade.tachiyomi.util.marginBottom @@ -54,7 +54,6 @@ import eu.kanade.tachiyomi.util.marginTop import eu.kanade.tachiyomi.util.snack import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.util.updatePaddingRelative -import exh.ui.migration.manga.process.MigrationProcedureConfig import kotlinx.android.synthetic.main.library_controller.* import kotlinx.android.synthetic.main.main_activity.* import rx.Subscription @@ -503,7 +502,7 @@ class LibraryController( migratingMangas.remove(nextManga) return nextManga } - + override fun onDestroyActionMode(mode: ActionMode?) { // Clear all the manga selections and notify child views. selectedMangas.clear() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MetadataFetchDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MetadataFetchDialog.kt deleted file mode 100644 index 5d231561ae..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MetadataFetchDialog.kt +++ /dev/null @@ -1,156 +0,0 @@ -package eu.kanade.tachiyomi.ui.migration - -import android.app.Activity -import android.content.pm.ActivityInfo -import android.text.Html -import com.afollestad.materialdialogs.MaterialDialog -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.database.DatabaseHelper -import eu.kanade.tachiyomi.source.SourceManager -import timber.log.Timber -import uy.kohesive.injekt.injectLazy -import kotlin.concurrent.thread - -class MetadataFetchDialog { - - val db: DatabaseHelper by injectLazy() - - val sourceManager: SourceManager by injectLazy() - - fun show(context: Activity) { - //Too lazy to actually deal with orientation changes - context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR - - var running = true - - val progressDialog = MaterialDialog.Builder(context) - .title("Fetching library metadata") - .content("Preparing library") - .progress(false, 0, true) - .negativeText("Stop") - .onNegative { dialog, which -> - running = false - dialog.dismiss() - notifyMigrationStopped(context) - } - .cancelable(false) - .canceledOnTouchOutside(false) - .show() - - thread { - val libraryMangas = db.getLibraryMangas().executeAsBlocking() - //.filter { isLewdSource(it.source) } - .distinctBy { it.id } - - context.runOnUiThread { - progressDialog.maxProgress = libraryMangas.size - } - - val mangaWithMissingMetadata = libraryMangas - .filterIndexed { index, libraryManga -> - if(index % 100 == 0) { - context.runOnUiThread { - progressDialog.setContent("[Stage 1/2] Scanning for missing metadata...") - progressDialog.setProgress(index + 1) - } - } - db.getSearchMetadataForManga(libraryManga.id!!).executeAsBlocking() == null - } - .toList() - - context.runOnUiThread { - progressDialog.maxProgress = mangaWithMissingMetadata.size - } - - //Actual metadata fetch code - for((i, manga) in mangaWithMissingMetadata.withIndex()) { - if(!running) break - context.runOnUiThread { - progressDialog.setContent("[Stage 2/2] Processing: ${manga.title}") - progressDialog.setProgress(i + 1) - } - try { - val source = sourceManager.get(manga.source) - source?.let { - manga.copyFrom(it.fetchMangaDetails(manga).toBlocking().first()) - } - } catch (t: Throwable) { - Timber.e(t, "Could not migrate manga!") - } - } - - context.runOnUiThread { - // Ensure activity still exists before we do anything to the activity - if(!context.isDestroyed) { - progressDialog.dismiss() - - //Enable orientation changes again - context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR - - if (running) displayMigrationComplete(context) - } - } - } - } - - fun askMigration(activity: Activity, explicit: Boolean) { - var extra = "" - db.getLibraryMangas().asRxSingle().subscribe { - /*if(!explicit && it.none { isLewdSource(it.source) }) { - // Do not open dialog on startup if no manga - // Also do not check again - preferenceHelper.migrateLibraryAsked().set(true) - } else {*/ - activity.runOnUiThread { - MaterialDialog.Builder(activity) - .title("Fetch library metadata") - .content(Html.fromHtml("You need to fetch your library's metadata before tag searching in the library will function.

" + - "This process may take a long time depending on your library size and will also use up a significant amount of internet bandwidth but can be stopped and started whenever you wish.

" + - extra + - "This process can be done later if required.")) - .positiveText("Migrate") - .negativeText("Later") - .onPositive { _, _ -> show(activity) } - .onNegative { _, _ -> adviseMigrationLater(activity) } - //.onAny { _, _ -> preferenceHelper.migrateLibraryAsked().set(true) } - .cancelable(false) - .canceledOnTouchOutside(false) - .show() - } - //} - } - - } - - fun adviseMigrationLater(activity: Activity) { - MaterialDialog.Builder(activity) - .title("Metadata fetch canceled") - .content("Library metadata fetch has been canceled.\n\n" + - "You can run this operation later by going to: Settings > Advanced > Migrate library metadata") - .positiveText("Ok") - .cancelable(true) - .canceledOnTouchOutside(true) - .show() - } - - fun notifyMigrationStopped(activity: Activity) { - MaterialDialog.Builder(activity) - .title("Metadata fetch stopped") - .content("Library metadata fetch has been stopped.\n\n" + - "You can continue this operation later by going to: Settings > Advanced > Migrate library metadata") - .positiveText("Ok") - .cancelable(true) - .canceledOnTouchOutside(true) - .show() - } - - fun displayMigrationComplete(activity: Activity) { - MaterialDialog.Builder(activity) - .title("Migration complete") - .content("${activity.getString(R.string.app_name)} is now ready for use!") - .positiveText("Ok") - .cancelable(true) - .canceledOnTouchOutside(true) - .show() - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationController.kt index 94b7d714b3..7b047bc50e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationController.kt @@ -22,7 +22,7 @@ import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController import eu.kanade.tachiyomi.util.RecyclerWindowInsetsListener import eu.kanade.tachiyomi.util.await import eu.kanade.tachiyomi.util.launchUI -import exh.ui.migration.manga.process.MigrationProcedureConfig +import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig import kotlinx.android.synthetic.main.migration_controller.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationStatus.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationStatus.kt deleted file mode 100644 index c360c3f08b..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationStatus.kt +++ /dev/null @@ -1,16 +0,0 @@ -package eu.kanade.tachiyomi.ui.migration - -class MigrationStatus { - companion object { - val NOT_INITIALIZED = -1 - val COMPLETED = 0 - - //Migration process - val NOTIFY_USER = 1 - val OPEN_BACKUP_MENU = 2 - val PERFORM_BACKUP = 3 - val FINALIZE_MIGRATION = 4 - - val MAX_MIGRATION_STEPS = 2 - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationBottomSheetDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationBottomSheetDialog.kt index 57a07f973c..0c76f2cbc7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationBottomSheetDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationBottomSheetDialog.kt @@ -102,7 +102,7 @@ StartMigrationListener) : 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 + if(mig_tracking.isChecked) flags = flags or MigrationFlags.TRACK preferences.migrateFlags().set(flags) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationDesignController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationDesignController.kt index ddf9171a11..0e1d6707ce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationDesignController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/design/MigrationDesignController.kt @@ -15,18 +15,12 @@ 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.util.RecyclerWindowInsetsListener import eu.kanade.tachiyomi.util.doOnApplyWindowInsets -import eu.kanade.tachiyomi.util.gone import eu.kanade.tachiyomi.util.marginBottom import eu.kanade.tachiyomi.util.updateLayoutParams import eu.kanade.tachiyomi.util.updatePaddingRelative -import eu.kanade.tachiyomi.util.visible -import exh.ui.migration.manga.process.MigrationProcedureConfig -import kotlinx.android.synthetic.main.chapters_controller.* -import kotlinx.android.synthetic.main.migration_design_controller.* +import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig import kotlinx.android.synthetic.main.migration_design_controller.fab import kotlinx.android.synthetic.main.migration_design_controller.recycler import uy.kohesive.injekt.injectLazy diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/DeactivatableViewPager.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/DeactivatableViewPager.kt deleted file mode 100644 index 7da7c5a844..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/DeactivatableViewPager.kt +++ /dev/null @@ -1,19 +0,0 @@ -package eu.kanade.tachiyomi.ui.migration.manga.process - -import android.content.Context -import android.util.AttributeSet -import android.view.MotionEvent -import androidx.viewpager.widget.ViewPager - -class DeactivatableViewPager: ViewPager { - constructor(context: Context): super(context) - constructor(context: Context, attrs: AttributeSet): super(context, attrs) - - override fun onTouchEvent(event: MotionEvent): Boolean { - return !isEnabled || super.onTouchEvent(event) - } - - override fun onInterceptTouchEvent(event: MotionEvent): Boolean { - return isEnabled && super.onInterceptTouchEvent(event) - } -} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigratingManga.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigratingManga.kt index 2a98fbb01f..1294afdb56 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigratingManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigratingManga.kt @@ -1,10 +1,9 @@ -package exh.ui.migration.manga.process +package eu.kanade.tachiyomi.ui.migration.manga.process import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcessItem import eu.kanade.tachiyomi.util.DeferredField import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt index 0baeb3b56e..30642cf234 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt @@ -31,8 +31,6 @@ import eu.kanade.tachiyomi.util.await import eu.kanade.tachiyomi.util.launchUI import eu.kanade.tachiyomi.util.syncChaptersWithSource import eu.kanade.tachiyomi.util.toast -import exh.ui.migration.manga.process.MigratingManga -import exh.ui.migration.manga.process.MigrationProcedureConfig import kotlinx.android.synthetic.main.chapters_controller.* import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcedureAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcedureAdapter.kt deleted file mode 100644 index 996f116981..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcedureAdapter.kt +++ /dev/null @@ -1,279 +0,0 @@ -package eu.kanade.tachiyomi.ui.migration.manga.process - -import android.view.View -import android.view.ViewGroup -import androidx.viewpager.widget.PagerAdapter -import com.bumptech.glide.load.engine.DiskCacheStrategy -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 -import eu.kanade.tachiyomi.source.model.SManga -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.gone -import eu.kanade.tachiyomi.util.inflate -import eu.kanade.tachiyomi.util.visible -import exh.ui.migration.manga.process.MigratingManga -import kotlinx.android.synthetic.main.migration_manga_card.view.* -import kotlinx.android.synthetic.main.migration_process_item.view.* -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.asFlow -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import uy.kohesive.injekt.injectLazy -import java.text.DateFormat -import java.text.DecimalFormat -import java.util.Date -import kotlin.coroutines.CoroutineContext - -class MigrationProcedureAdapter(val controller: MigrationProcedureController, - val migratingManga: List, - override val coroutineContext: CoroutineContext) : PagerAdapter(), CoroutineScope { - private val db: DatabaseHelper by injectLazy() - private val sourceManager: SourceManager by injectLazy() - - override fun isViewFromObject(p0: View, p1: Any): Boolean { - return p0 == p1 - } - - override fun getCount() = migratingManga.size - - override fun instantiateItem(container: ViewGroup, position: Int): Any { - val item = migratingManga[position] - val view = container.inflate(R.layout.migration_process_item) - container.addView(view) - - view.skip_migration.setOnClickListener { - //controller.nextMigration() - } - - val viewTag = ViewTag(coroutineContext) - view.tag = viewTag - view.setupView(viewTag, item) - - view.accept_migration.setOnClickListener { - viewTag.launch(Dispatchers.Main) { - view.migrating_frame.visible() - try { - withContext(Dispatchers.Default) { - performMigration(item) - } - controller.nextMigration() - } catch(e: Exception) { - controller.migrationFailure() - } - view.migrating_frame.gone() - } - } - - return view - } - - suspend fun performMigration(manga: MigratingManga) { - if(!manga.searchResult.initialized) { - return - } - - val toMangaObj = db.getManga(manga.searchResult.get() ?: return).executeAsBlocking() ?: return - - withContext(Dispatchers.IO) { - migrateMangaInternal( - manga.manga() ?: return@withContext, - toMangaObj, - false - ) - } - } - - private fun migrateMangaInternal(prevManga: Manga, - manga: Manga, - replace: Boolean) { - val config = controller.config ?: return - //db.inTransaction { - // Update chapters read - /* if (MigrationFlags.hasChapters(controller.config.migrationFlags)) { - val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking() - val maxChapterRead = prevMangaChapters.filter { it.read } - .maxBy { it.chapter_number }?.chapter_number - if (maxChapterRead != null) { - val dbChapters = db.getChapters(manga).executeAsBlocking() - for (chapter in dbChapters) { - if (chapter.isRecognizedNumber && chapter.chapter_number <= maxChapterRead) { - chapter.read = true - } - } - db.insertChapters(dbChapters).executeAsBlocking() - } - } - // Update categories - if (MigrationFlags.hasCategories(controller.config.migrationFlags)) { - 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)) { - 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() - - // 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) { - tag.launch { - val manga = migratingManga.manga() - val source = migratingManga.mangaSource() - if(manga != null) { - withContext(Dispatchers.Main) { - migration_manga_card_from.loading_group.gone() - migration_manga_card_from.attachManga(tag, manga, source) - migration_manga_card_from.setOnClickListener { - controller.router.pushController(MangaController(manga, true).withFadeTransaction()) - } - } - - tag.launch { - migratingManga.progress.asFlow().collect { (max, progress) -> - withContext(Dispatchers.Main) { - migration_manga_card_to.search_progress.let { progressBar -> - progressBar.max = max - progressBar.progress = progress - } - } - } - } - - val searchResult = migratingManga.searchResult.get()?.let { - db.getManga(it).executeAsBlocking() - } - val resultSource = searchResult?.source?.let { - sourceManager.get(it) - } - withContext(Dispatchers.Main) { - if(searchResult != null && resultSource != null) { - migration_manga_card_to.loading_group.gone() - migration_manga_card_to.attachManga(tag, searchResult, resultSource) - migration_manga_card_to.setOnClickListener { - controller.router.pushController(MangaController(searchResult, true).withFadeTransaction()) - } - accept_migration.isEnabled = true - accept_migration.alpha = 1.0f - } else { - migration_manga_card_to.search_progress.gone() - migration_manga_card_to.search_status.text = "Found no manga" - } - } - } - } - } - - suspend fun View.attachManga(tag: ViewTag, manga: Manga, source: Source) { - // TODO Duplicated in MangaInfoController - - GlideApp.with(context) - .load(manga) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) - .centerCrop() - .into(manga_cover) - - manga_full_title.text = if (manga.title.isBlank()) { - context.getString(R.string.unknown) - } else { - manga.title - } - - manga_artist.text = if (manga.artist.isNullOrBlank()) { - context.getString(R.string.unknown) - } else { - manga.artist - } - - manga_author.text = if (manga.author.isNullOrBlank()) { - context.getString(R.string.unknown) - } else { - manga.author - } - - manga_source.text = /*if (source.id == MERGED_SOURCE_ID) { - MergedSource.MangaConfig.readFromUrl(gson, manga.url).children.map { - sourceManager.getOrStub(it.source).toString() - }.distinct().joinToString() - } else {*/ - source.toString() - // } - - /*if (source.id == MERGED_SOURCE_ID) { - manga_source_label.text = "Sources" - } else {*/ - manga_source_label.setText(R.string.manga_info_source_label) - // } - - manga_status.setText(when (manga.status) { - SManga.ONGOING -> R.string.ongoing - SManga.COMPLETED -> R.string.completed - SManga.LICENSED -> R.string.licensed - else -> R.string.unknown - }) - - val mangaChapters = db.getChapters(manga).executeAsBlocking() - manga_chapters.text = mangaChapters.size.toString() - val latestChapter = mangaChapters.maxBy { it.chapter_number }?.chapter_number ?: -1f - val lastUpdate = Date(mangaChapters.maxBy { it.date_upload }?.date_upload ?: 0) - - if (latestChapter > 0f) { - manga_last_chapter.text = DecimalFormat("#.#").format(latestChapter) - } else { - manga_last_chapter.setText(R.string.unknown) - } - - if (lastUpdate.time != 0L) { - manga_last_update.text = DateFormat.getDateInstance(DateFormat.SHORT).format(lastUpdate) - } else { - manga_last_update.setText(R.string.unknown) - } - } - - override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { - val objectAsView = `object` as View - container.removeView(objectAsView) - (objectAsView.tag as? ViewTag)?.destroy() - } - - class ViewTag(parent: CoroutineContext): CoroutineScope { - /** - * The context of this scope. - * Context is encapsulated by the scope and used for implementation of coroutine builders that are extensions on the scope. - * Accessing this property in general code is not recommended for any purposes except accessing the [Job] instance for advanced usages. - * - * By convention, should contain an instance of a [job][Job] to enforce structured concurrency. - */ - override val coroutineContext = parent + Job() + Dispatchers.Default - - fun destroy() { - cancel() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcedureConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcedureConfig.kt index a088b2f376..75e7e57fce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcedureConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcedureConfig.kt @@ -1,4 +1,4 @@ -package exh.ui.migration.manga.process +package eu.kanade.tachiyomi.ui.migration.manga.process import android.os.Parcelable import kotlinx.android.parcel.Parcelize diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcedureController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcedureController.kt deleted file mode 100644 index 34f264da8d..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcedureController.kt +++ /dev/null @@ -1,252 +0,0 @@ -package eu.kanade.tachiyomi.ui.migration.manga.process - -import android.content.pm.ActivityInfo -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -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.syncChaptersWithSource -import eu.kanade.tachiyomi.util.toast -import exh.ui.migration.manga.process.MigratingManga -import exh.ui.migration.manga.process.MigrationProcedureConfig -import kotlinx.android.synthetic.main.migration_process.* -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 -import java.util.concurrent.atomic.AtomicInteger -import kotlin.coroutines.CoroutineContext - -// TODO Will probably implode if activity is fully destroyed -class MigrationProcedureController(bundle: Bundle? = null) : BaseController(bundle), CoroutineScope { - - private var titleText = "Migrate manga" - - private var adapter: MigrationProcedureAdapter? = null - - override val coroutineContext: CoroutineContext = Job() + Dispatchers.Default - - val config: MigrationProcedureConfig? = args.getParcelable(CONFIG_EXTRA) - - private val db: DatabaseHelper by injectLazy() - private val sourceManager: SourceManager by injectLazy() - - private val smartSearchEngine = SmartSearchEngine(coroutineContext, config?.extraSearchParams) - - private var migrationsJob: Job? = null - private var migratingManga: List? = null - - override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View { - return inflater.inflate(R.layout.migration_process, container, false) - } - - override fun getTitle(): String { - return titleText - } - - override fun onViewCreated(view: View) { - super.onViewCreated(view) - setTitle() - val config = this.config ?: return - activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT - - val newMigratingManga = migratingManga ?: run { - val new = config.mangaIds.map { - MigratingManga(db, sourceManager, it, coroutineContext) - } - migratingManga = new - new - } - - adapter = MigrationProcedureAdapter(this, newMigratingManga, coroutineContext) - - pager.adapter = adapter - pager.isEnabled = false - - if(migrationsJob == null) { - migrationsJob = launch { - runMigrations(newMigratingManga) - } - } - - pager.post { - // pager.currentItem doesn't appear to be valid if we don't do this in a post - updateTitle() - } - } - - fun updateTitle() { - titleText = "Migrate manga (${pager.currentItem + 1}/${adapter?.count ?: 0})" - setTitle() - } - - 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) - .title("Migration failure") - .content("An unknown error occured while migrating this manga!") - .positiveText("Ok") - .show() - } - } - - suspend fun runMigrations(mangas: List) { - /* val sources = config?.targetSourceIds?.mapNotNull { sourceManager.get(it) as? - CatalogueSource } ?: return - - for(manga in mangas) { - if(!manga.searchResult.initialized && manga.migrationJob.isActive) { - val mangaObj = manga.manga() - - if(mangaObj == null) { - manga.searchResult.initialize(null) - continue - } - - val mangaSource = manga.mangaSource() - - val result = try { - CoroutineScope(manga.migrationJob).async { - val validSources = sources.filter { - it.id != mangaSource.id - } - if(config.useSourceWithMostChapters) { - val sourceSemaphore = Semaphore(3) - val processedSources = AtomicInteger() - - validSources.map { source -> - async { - sourceSemaphore.withPermit { - try { - val searchResult = if (config.enableLenientSearch) { - smartSearchEngine.smartSearch(source, mangaObj.title) - } else { - smartSearchEngine.normalSearch(source, mangaObj.title) - } - - if(searchResult != null) { - val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id) - val chapters = source.fetchChapterList(localManga).toSingle().await(Schedulers.io()) - withContext(Dispatchers.IO) { - syncChaptersWithSource(db, chapters, localManga, source) - } - manga.progress.send(validSources.size to processedSources.incrementAndGet()) - localManga to chapters.size - } else { - null - } - } catch(e: CancellationException) { - // Ignore cancellations - throw e - } catch(e: Exception) { - null - } - } - } - }.mapNotNull { it.await() }.maxBy { it.second }?.first - } else { - validSources.forEachIndexed { index, source -> - val searchResult = try { - val searchResult = if (config.enableLenientSearch) { - smartSearchEngine.smartSearch(source, mangaObj.title) - } else { - smartSearchEngine.normalSearch(source, mangaObj.title) - } - - if (searchResult != null) { - val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id) - val chapters = source.fetchChapterList(localManga).toSingle().await(Schedulers.io()) - withContext(Dispatchers.IO) { - syncChaptersWithSource(db, chapters, localManga, source) - } - localManga - } else null - } catch(e: CancellationException) { - // Ignore cancellations - throw e - } catch(e: Exception) { - null - } - - manga.progress.send(validSources.size to (index + 1)) - - if(searchResult != null) return@async searchResult - } - - null - } - }.await() - } catch(e: CancellationException) { - // Ignore canceled migrations - continue - } - - if(result != null && result.thumbnail_url == null) { - try { - val newManga = sourceManager.getOrStub(result.source) - .fetchMangaDetails(result) - .toSingle() - .await() - result.copyFrom(newManga) - - db.insertManga(result).executeAsBlocking() - } catch(e: CancellationException) { - // Ignore cancellations - throw e - } catch(e: Exception) { - } - } - - manga.searchResult.initialize(result?.id) - } - }*/ - } - - override fun onDestroy() { - super.onDestroy() - - activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - } - - companion object { - const val CONFIG_EXTRA = "config_extra" - - fun create(config: MigrationProcedureConfig): MigrationProcedureController { - return MigrationProcedureController(Bundle().apply { - putParcelable(CONFIG_EXTRA, config) - }) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt index 7012a23266..d0254ae32f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt @@ -18,8 +18,8 @@ import eu.kanade.tachiyomi.util.invisible import eu.kanade.tachiyomi.util.launchUI import eu.kanade.tachiyomi.util.setVectorCompat import eu.kanade.tachiyomi.util.visible -import kotlinx.android.synthetic.main.migration_new_manga_card.view.* -import kotlinx.android.synthetic.main.migration_new_process_item.* +import kotlinx.android.synthetic.main.migration_manga_card.view.* +import kotlinx.android.synthetic.main.migration_process_item.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import uy.kohesive.injekt.injectLazy @@ -123,6 +123,7 @@ class MigrationProcessHolder( manga_chapters.text = "" manga_chapters.gone() manga_last_chapter_label.text = "" + migration_manga_card_to.setOnClickListener(null) } private fun View.attachManga(manga: Manga, source: Source) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessItem.kt index 57a2438c2e..28c171872d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessItem.kt @@ -6,14 +6,13 @@ import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import eu.davidea.flexibleadapter.items.IFlexible import eu.kanade.tachiyomi.R -import exh.ui.migration.manga.process.MigratingManga class MigrationProcessItem(val manga: MigratingManga) : AbstractFlexibleItem() { var holder:MigrationProcessHolder? = null override fun getLayoutRes(): Int { - return R.layout.migration_new_process_item + return R.layout.migration_process_item } override fun createViewHolder(view: View, adapter: FlexibleAdapter>): MigrationProcessHolder { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/smartsearch/SmartSearchController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/smartsearch/SmartSearchController.kt deleted file mode 100644 index 7c5bb2bf4f..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/smartsearch/SmartSearchController.kt +++ /dev/null @@ -1,92 +0,0 @@ -package eu.kanade.tachiyomi.ui.smartsearch - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.source.CatalogueSource -import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.ui.base.controller.NucleusController -import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction -import eu.kanade.tachiyomi.ui.catalogue.CatalogueController -import eu.kanade.tachiyomi.ui.catalogue.browse.BrowseCatalogueController -import eu.kanade.tachiyomi.ui.manga.MangaController -import eu.kanade.tachiyomi.util.toast -import kotlinx.android.synthetic.main.main_activity.* -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.NonCancellable -import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import uy.kohesive.injekt.injectLazy - -class SmartSearchController(bundle: Bundle? = null) : NucleusController(), CoroutineScope { - override val coroutineContext = Job() + Dispatchers.Main - - private val sourceManager: SourceManager by injectLazy() - - private val source = sourceManager.get(bundle?.getLong(ARG_SOURCE_ID, -1) ?: -1) as? CatalogueSource - private val smartSearchConfig: CatalogueController.SmartSearchConfig? = bundle?.getParcelable( - ARG_SMART_SEARCH_CONFIG - ) - - override fun inflateView(inflater: LayoutInflater, container: ViewGroup) = - inflater.inflate(R.layout.smart_search, container, false)!! - - override fun getTitle() = source?.name ?: "" - - override fun createPresenter() = SmartSearchPresenter(source, smartSearchConfig) - - override fun onViewCreated(view: View) { - super.onViewCreated(view) - - appbar.bringToFront() - - if(source == null || smartSearchConfig == null) { - router.popCurrentController() - applicationContext?.toast("Missing data!") - return - } - - // Init presenter now to resolve threading issues - presenter - - launch(Dispatchers.Default) { - for(event in presenter.smartSearchChannel) { - withContext(NonCancellable) { - if (event is SmartSearchPresenter.SearchResults.Found) { - val transaction = MangaController(event.manga, true, smartSearchConfig).withFadeTransaction() - withContext(Dispatchers.Main) { - router.replaceTopController(transaction) - } - } else { - if (event is SmartSearchPresenter.SearchResults.NotFound) { - applicationContext?.toast("Couldn't find the manga in the source!") - } else { - applicationContext?.toast("Error performing automatic search!") - } - - val transaction = BrowseCatalogueController(source, smartSearchConfig.origTitle, smartSearchConfig).withFadeTransaction() - withContext(Dispatchers.Main) { - router.replaceTopController(transaction) - } - } - } - } - } - } - - override fun onDestroy() { - super.onDestroy() - - cancel() - } - - companion object { - const val ARG_SOURCE_ID = "SOURCE_ID" - const val ARG_SMART_SEARCH_CONFIG = "SMART_SEARCH_CONFIG" - } -} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/smartsearch/SmartSearchPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/smartsearch/SmartSearchPresenter.kt deleted file mode 100644 index 5f78c6f764..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/smartsearch/SmartSearchPresenter.kt +++ /dev/null @@ -1,67 +0,0 @@ -package eu.kanade.tachiyomi.ui.smartsearch - -import android.os.Bundle -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.smartsearch.SmartSearchEngine -import eu.kanade.tachiyomi.source.CatalogueSource -import eu.kanade.tachiyomi.source.model.SManga -import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import eu.kanade.tachiyomi.ui.catalogue.CatalogueController -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancel -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.launch - -class SmartSearchPresenter(private val source: CatalogueSource?, private val config: CatalogueController.SmartSearchConfig?): - BasePresenter(), CoroutineScope { - - override val coroutineContext = Job() + Dispatchers.Main - - val smartSearchChannel = Channel() - - private val smartSearchEngine = SmartSearchEngine(coroutineContext) - - override fun onCreate(savedState: Bundle?) { - super.onCreate(savedState) - - if(source != null && config != null) { - launch(Dispatchers.Default) { - val result = try { - val resultManga = smartSearchEngine.smartSearch(source, config.origTitle) - if (resultManga != null) { - val localManga = smartSearchEngine.networkToLocalManga(resultManga, source.id) - SearchResults.Found(localManga) - } else { - SearchResults.NotFound - } - } catch (e: Exception) { - if (e is CancellationException) { - throw e - } else { - SearchResults.Error - } - } - - smartSearchChannel.send(result) - } - } - } - - - override fun onDestroy() { - super.onDestroy() - - cancel() - } - - data class SearchEntry(val manga: SManga, val dist: Double) - - sealed class SearchResults { - data class Found(val manga: Manga): SearchResults() - object NotFound: SearchResults() - object Error: SearchResults() - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/migration_list_controller.xml b/app/src/main/res/layout/migration_list_controller.xml index 7abb2eba76..cdaad5b500 100644 --- a/app/src/main/res/layout/migration_list_controller.xml +++ b/app/src/main/res/layout/migration_list_controller.xml @@ -11,6 +11,6 @@ android:layout_height="wrap_content" android:clipToPadding="false" android:id="@+id/recycler" - tools:listitem="@layout/migration_new_process_item" /> + tools:listitem="@layout/migration_process_item" /> \ No newline at end of file diff --git a/app/src/main/res/layout/migration_manga_card.xml b/app/src/main/res/layout/migration_manga_card.xml index 47c185b3b2..82e40e0b6e 100644 --- a/app/src/main/res/layout/migration_manga_card.xml +++ b/app/src/main/res/layout/migration_manga_card.xml @@ -1,270 +1,124 @@ - + android:background="?selectable_library_drawable"> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:id="@+id/thumbnail" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?android:attr/colorBackground" + tools:background="?android:attr/colorBackground" + tools:ignore="ContentDescription" + tools:src="@mipmap/ic_launcher" /> - - + android:layout_gravity="bottom" + android:background="@drawable/gradient_shape" /> - - + + - - \ No newline at end of file + android:background="@color/md_teal_500" + android:paddingBottom="1dp" + android:paddingLeft="3dp" + android:paddingRight="3dp" + android:paddingTop="1dp" + android:visibility="gone" + tools:visibility="visible" + android:text="101" + android:layout_marginStart="4dp" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toTopOf="parent" + android:layout_marginTop="4dp"/> + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/migration_new_manga_card.xml b/app/src/main/res/layout/migration_new_manga_card.xml deleted file mode 100644 index 82e40e0b6e..0000000000 --- a/app/src/main/res/layout/migration_new_manga_card.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/migration_new_process_item.xml b/app/src/main/res/layout/migration_new_process_item.xml deleted file mode 100644 index 2c405917b4..0000000000 --- a/app/src/main/res/layout/migration_new_process_item.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/migration_process.xml b/app/src/main/res/layout/migration_process.xml deleted file mode 100644 index 43ecb479bd..0000000000 --- a/app/src/main/res/layout/migration_process.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/migration_process_item.xml b/app/src/main/res/layout/migration_process_item.xml index b9c8c645b1..d6f6d0df04 100644 --- a/app/src/main/res/layout/migration_process_item.xml +++ b/app/src/main/res/layout/migration_process_item.xml @@ -1,108 +1,72 @@ - + android:layout_height="wrap_content" + android:gravity="center"> - + - + - + - + -