mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-04 08:55:06 +01:00
Cleanup of olf auto migration
This commit is contained in:
parent
c4321e3adf
commit
d64754e3e0
@ -6,7 +6,6 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.ui.smartsearch.SmartSearchPresenter
|
|
||||||
import eu.kanade.tachiyomi.util.await
|
import eu.kanade.tachiyomi.util.await
|
||||||
import info.debatty.java.stringsimilarity.NormalizedLevenshtein
|
import info.debatty.java.stringsimilarity.NormalizedLevenshtein
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@ -44,7 +43,7 @@ class SmartSearchEngine(parentContext: CoroutineContext,
|
|||||||
searchResults.mangas.map {
|
searchResults.mangas.map {
|
||||||
val cleanedMangaTitle = cleanSmartSearchTitle(it.title)
|
val cleanedMangaTitle = cleanSmartSearchTitle(it.title)
|
||||||
val normalizedDistance = normalizedLevenshtein.similarity(cleanedTitle, cleanedMangaTitle)
|
val normalizedDistance = normalizedLevenshtein.similarity(cleanedTitle, cleanedMangaTitle)
|
||||||
SmartSearchPresenter.SearchEntry(it, normalizedDistance)
|
SearchEntry(it, normalizedDistance)
|
||||||
}.filter { (_, normalizedDistance) ->
|
}.filter { (_, normalizedDistance) ->
|
||||||
normalizedDistance >= MIN_SMART_ELIGIBLE_THRESHOLD
|
normalizedDistance >= MIN_SMART_ELIGIBLE_THRESHOLD
|
||||||
}
|
}
|
||||||
@ -64,7 +63,7 @@ class SmartSearchEngine(parentContext: CoroutineContext,
|
|||||||
|
|
||||||
searchResults.mangas.map {
|
searchResults.mangas.map {
|
||||||
val normalizedDistance = normalizedLevenshtein.similarity(title, it.title)
|
val normalizedDistance = normalizedLevenshtein.similarity(title, it.title)
|
||||||
SmartSearchPresenter.SearchEntry(it, normalizedDistance)
|
SearchEntry(it, normalizedDistance)
|
||||||
}.filter { (_, normalizedDistance) ->
|
}.filter { (_, normalizedDistance) ->
|
||||||
normalizedDistance >= MIN_NORMAL_ELIGIBLE_THRESHOLD
|
normalizedDistance >= MIN_NORMAL_ELIGIBLE_THRESHOLD
|
||||||
}
|
}
|
||||||
@ -189,4 +188,6 @@ class SmartSearchEngine(parentContext: CoroutineContext,
|
|||||||
private val titleRegex = Regex("[^a-zA-Z0-9- ]")
|
private val titleRegex = Regex("[^a-zA-Z0-9- ]")
|
||||||
private val consecutiveSpacesRegex = Regex(" +")
|
private val consecutiveSpacesRegex = Regex(" +")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class SearchEntry(val manga: SManga, val dist: Double)
|
@ -44,9 +44,9 @@ import eu.kanade.tachiyomi.ui.main.MainActivity
|
|||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.ui.migration.MigrationController
|
import eu.kanade.tachiyomi.ui.migration.MigrationController
|
||||||
import eu.kanade.tachiyomi.ui.migration.MigrationInterface
|
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.design.MigrationDesignController
|
||||||
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController
|
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.doOnApplyWindowInsets
|
||||||
import eu.kanade.tachiyomi.util.inflate
|
import eu.kanade.tachiyomi.util.inflate
|
||||||
import eu.kanade.tachiyomi.util.marginBottom
|
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.snack
|
||||||
import eu.kanade.tachiyomi.util.toast
|
import eu.kanade.tachiyomi.util.toast
|
||||||
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
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.library_controller.*
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
@ -503,7 +502,7 @@ class LibraryController(
|
|||||||
migratingMangas.remove(nextManga)
|
migratingMangas.remove(nextManga)
|
||||||
return nextManga
|
return nextManga
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||||
// Clear all the manga selections and notify child views.
|
// Clear all the manga selections and notify child views.
|
||||||
selectedMangas.clear()
|
selectedMangas.clear()
|
||||||
|
@ -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.<br><br>" +
|
|
||||||
"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.<br><br>" +
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
@ -22,7 +22,7 @@ import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController
|
|||||||
import eu.kanade.tachiyomi.util.RecyclerWindowInsetsListener
|
import eu.kanade.tachiyomi.util.RecyclerWindowInsetsListener
|
||||||
import eu.kanade.tachiyomi.util.await
|
import eu.kanade.tachiyomi.util.await
|
||||||
import eu.kanade.tachiyomi.util.launchUI
|
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.android.synthetic.main.migration_controller.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -102,7 +102,7 @@ StartMigrationListener) :
|
|||||||
var flags = 0
|
var flags = 0
|
||||||
if(mig_chapters.isChecked) flags = flags or MigrationFlags.CHAPTERS
|
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.CATEGORIES
|
||||||
if(mig_categories.isChecked) flags = flags or MigrationFlags.TRACK
|
if(mig_tracking.isChecked) flags = flags or MigrationFlags.TRACK
|
||||||
preferences.migrateFlags().set(flags)
|
preferences.migrateFlags().set(flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,18 +15,12 @@ import eu.kanade.tachiyomi.source.SourceManager
|
|||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
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.MigrationListController
|
||||||
import eu.kanade.tachiyomi.util.RecyclerWindowInsetsListener
|
|
||||||
import eu.kanade.tachiyomi.util.doOnApplyWindowInsets
|
import eu.kanade.tachiyomi.util.doOnApplyWindowInsets
|
||||||
import eu.kanade.tachiyomi.util.gone
|
|
||||||
import eu.kanade.tachiyomi.util.marginBottom
|
import eu.kanade.tachiyomi.util.marginBottom
|
||||||
import eu.kanade.tachiyomi.util.updateLayoutParams
|
import eu.kanade.tachiyomi.util.updateLayoutParams
|
||||||
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
||||||
import eu.kanade.tachiyomi.util.visible
|
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig
|
||||||
import exh.ui.migration.manga.process.MigrationProcedureConfig
|
|
||||||
import kotlinx.android.synthetic.main.chapters_controller.*
|
|
||||||
import kotlinx.android.synthetic.main.migration_design_controller.*
|
|
||||||
import kotlinx.android.synthetic.main.migration_design_controller.fab
|
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.recycler
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcessItem
|
|
||||||
import eu.kanade.tachiyomi.util.DeferredField
|
import eu.kanade.tachiyomi.util.DeferredField
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
@ -31,8 +31,6 @@ import eu.kanade.tachiyomi.util.await
|
|||||||
import eu.kanade.tachiyomi.util.launchUI
|
import eu.kanade.tachiyomi.util.launchUI
|
||||||
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
||||||
import eu.kanade.tachiyomi.util.toast
|
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.android.synthetic.main.chapters_controller.*
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
@ -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<MigratingManga>,
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package exh.ui.migration.manga.process
|
package eu.kanade.tachiyomi.ui.migration.manga.process
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
@ -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<MigratingManga>? = 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<MigratingManga>) {
|
|
||||||
/* 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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,8 +18,8 @@ import eu.kanade.tachiyomi.util.invisible
|
|||||||
import eu.kanade.tachiyomi.util.launchUI
|
import eu.kanade.tachiyomi.util.launchUI
|
||||||
import eu.kanade.tachiyomi.util.setVectorCompat
|
import eu.kanade.tachiyomi.util.setVectorCompat
|
||||||
import eu.kanade.tachiyomi.util.visible
|
import eu.kanade.tachiyomi.util.visible
|
||||||
import kotlinx.android.synthetic.main.migration_new_manga_card.view.*
|
import kotlinx.android.synthetic.main.migration_manga_card.view.*
|
||||||
import kotlinx.android.synthetic.main.migration_new_process_item.*
|
import kotlinx.android.synthetic.main.migration_process_item.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -123,6 +123,7 @@ class MigrationProcessHolder(
|
|||||||
manga_chapters.text = ""
|
manga_chapters.text = ""
|
||||||
manga_chapters.gone()
|
manga_chapters.gone()
|
||||||
manga_last_chapter_label.text = ""
|
manga_last_chapter_label.text = ""
|
||||||
|
migration_manga_card_to.setOnClickListener(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun View.attachManga(manga: Manga, source: Source) {
|
private fun View.attachManga(manga: Manga, source: Source) {
|
||||||
|
@ -6,14 +6,13 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
|||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import exh.ui.migration.manga.process.MigratingManga
|
|
||||||
|
|
||||||
class MigrationProcessItem(val manga: MigratingManga) :
|
class MigrationProcessItem(val manga: MigratingManga) :
|
||||||
AbstractFlexibleItem<MigrationProcessHolder>() {
|
AbstractFlexibleItem<MigrationProcessHolder>() {
|
||||||
|
|
||||||
var holder:MigrationProcessHolder? = null
|
var holder:MigrationProcessHolder? = null
|
||||||
override fun getLayoutRes(): Int {
|
override fun getLayoutRes(): Int {
|
||||||
return R.layout.migration_new_process_item
|
return R.layout.migration_process_item
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): MigrationProcessHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): MigrationProcessHolder {
|
||||||
|
@ -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<SmartSearchPresenter>(), 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"
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<SmartSearchController>(), CoroutineScope {
|
|
||||||
|
|
||||||
override val coroutineContext = Job() + Dispatchers.Main
|
|
||||||
|
|
||||||
val smartSearchChannel = Channel<SearchResults>()
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,6 +11,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:id="@+id/recycler"
|
android:id="@+id/recycler"
|
||||||
tools:listitem="@layout/migration_new_process_item" />
|
tools:listitem="@layout/migration_process_item" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
@ -1,270 +1,124 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:foreground="?android:attr/selectableItemBackground"
|
android:background="?selectable_library_drawable">
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/card"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:clickable="false">
|
android:layout_height="220dp"
|
||||||
|
android:background="@drawable/card_background"
|
||||||
|
app:layout_constraintDimensionRatio="0.75"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintWidth_min="100dp"
|
||||||
|
app:layout_constraintHeight_min="100dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/manga_cover"
|
android:id="@+id/thumbnail"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginStart="16dp"
|
android:background="?android:attr/colorBackground"
|
||||||
android:layout_marginTop="16dp"
|
tools:background="?android:attr/colorBackground"
|
||||||
android:contentDescription="@string/description_cover"
|
tools:ignore="ContentDescription"
|
||||||
app:layout_constraintDimensionRatio="l,2:3"
|
tools:src="@mipmap/ic_launcher" />
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toLeftOf="@+id/card_scroll_content"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintWidth_min="100dp"
|
|
||||||
tools:background="@color/material_grey_700" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/card_scroll_content"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="16dp"
|
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:paddingBottom="16dp"
|
|
||||||
app:layout_constraintHorizontal_weight="2"
|
|
||||||
app:layout_constraintLeft_toRightOf="@+id/manga_cover"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/manga_cover">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_full_title"
|
|
||||||
style="@style/TextAppearance.Medium.Title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="false"
|
|
||||||
android:maxLines="2"
|
|
||||||
android:text="@string/manga_info_full_title_label"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:autoSizeMaxTextSize="20sp"
|
|
||||||
app:autoSizeMinTextSize="12sp"
|
|
||||||
app:autoSizeStepGranularity="2sp"
|
|
||||||
app:autoSizeTextType="uniform"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_author_label"
|
|
||||||
style="@style/TextAppearance.Medium.Body2"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="false"
|
|
||||||
android:text="@string/manga_info_author_label"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_full_title" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_author"
|
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:clickable="false"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintBaseline_toBaselineOf="@+id/manga_author_label"
|
|
||||||
app:layout_constraintLeft_toRightOf="@+id/manga_author_label"
|
|
||||||
app:layout_constraintRight_toRightOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_artist_label"
|
|
||||||
style="@style/TextAppearance.Medium.Body2"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="false"
|
|
||||||
android:text="@string/manga_info_artist_label"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_author_label" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_artist"
|
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:clickable="false"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintBaseline_toBaselineOf="@+id/manga_artist_label"
|
|
||||||
app:layout_constraintLeft_toRightOf="@+id/manga_artist_label"
|
|
||||||
app:layout_constraintRight_toRightOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_status_label"
|
|
||||||
style="@style/TextAppearance.Medium.Body2"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="false"
|
|
||||||
android:text="@string/manga_info_status_label"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_artist_label" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_status"
|
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:clickable="false"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintBaseline_toBaselineOf="@+id/manga_status_label"
|
|
||||||
app:layout_constraintLeft_toRightOf="@+id/manga_status_label"
|
|
||||||
app:layout_constraintRight_toRightOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_chapters_label"
|
|
||||||
style="@style/TextAppearance.Medium.Body2"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="false"
|
|
||||||
android:text="@string/manga_info_chapters_label"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_status_label" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_chapters"
|
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:clickable="false"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toRightOf="@+id/manga_chapters_label"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_status_label" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_last_chapter_label"
|
|
||||||
style="@style/TextAppearance.Medium.Body2"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="false"
|
|
||||||
android:text="@string/manga_info_last_chapter_label"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_chapters_label" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_last_chapter"
|
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:clickable="false"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toRightOf="@+id/manga_last_chapter_label"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_chapters_label" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_last_update_label"
|
|
||||||
style="@style/TextAppearance.Medium.Body2"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="false"
|
|
||||||
android:text="@string/manga_info_latest_data_label"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_last_chapter_label" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_last_update"
|
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:clickable="false"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toRightOf="@+id/manga_last_update_label"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_last_chapter_label" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_source_label"
|
|
||||||
style="@style/TextAppearance.Medium.Body2"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="false"
|
|
||||||
android:text="@string/manga_info_source_label"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_last_update_label" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_source"
|
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:clickable="false"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toRightOf="@+id/manga_source_label"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/manga_last_update_label" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/card_shim"
|
android:id="@+id/gradient"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
|
||||||
android:alpha="0.9"
|
|
||||||
android:background="?attr/background_card"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/search_status"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_gravity="bottom"
|
||||||
android:layout_marginLeft="8dp"
|
android:background="@drawable/gradient_shape" />
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginRight="8dp"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:text="Searching..."
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/search_progress"
|
|
||||||
app:layout_constraintEnd_toEndOf="@+id/card_shim"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/card_shim" />
|
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/search_progress"
|
|
||||||
style="?android:attr/progressBarStyleHorizontal"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/card_shim"
|
|
||||||
app:layout_constraintEnd_toEndOf="@+id/card_shim"
|
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Group
|
|
||||||
android:id="@+id/loading_group"
|
android:id="@+id/loading_group"
|
||||||
|
android:layout_width="56dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/manga_chapters"
|
||||||
|
style="@style/TextAppearance.Regular.Caption.Light"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:constraint_referenced_ids="card_shim,search_status,search_progress" />
|
android:background="@color/md_teal_500"
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
android:paddingBottom="1dp"
|
||||||
</androidx.cardview.widget.CardView>
|
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"/>
|
||||||
|
|
||||||
|
<eu.kanade.tachiyomi.widget.PTSansTextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
style="@style/TextAppearance.Regular.Body1.Light"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lineSpacingExtra="-4dp"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:shadowColor="@color/textColorPrimaryLight"
|
||||||
|
android:shadowDx="0"
|
||||||
|
android:shadowDy="0"
|
||||||
|
android:shadowRadius="4"
|
||||||
|
app:typeface="ptsansNarrowBold"
|
||||||
|
tools:text="Sample name" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress"
|
||||||
|
style="?android:attr/progressBarStyleSmall"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/card_scroll_content"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:paddingBottom="20dp"
|
||||||
|
android:gravity="start"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/card"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/card"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/card">
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/manga_source_label"
|
||||||
|
style="@style/TextAppearance.Medium.Body2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="false"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
tools:layout_editor_absoluteY="57dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/manga_last_chapter_label"
|
||||||
|
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="false"
|
||||||
|
android:textIsSelectable="false" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,124 +0,0 @@
|
|||||||
<?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:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?selectable_library_drawable">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/card"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="220dp"
|
|
||||||
android:background="@drawable/card_background"
|
|
||||||
app:layout_constraintDimensionRatio="0.75"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintWidth_min="100dp"
|
|
||||||
app:layout_constraintHeight_min="100dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
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" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/gradient"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:background="@drawable/gradient_shape" />
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/loading_group"
|
|
||||||
android:layout_width="56dp"
|
|
||||||
android:layout_height="56dp"
|
|
||||||
android:layout_gravity="center" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_chapters"
|
|
||||||
style="@style/TextAppearance.Regular.Caption.Light"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
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"/>
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.PTSansTextView
|
|
||||||
android:id="@+id/title"
|
|
||||||
style="@style/TextAppearance.Regular.Body1.Light"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:lineSpacingExtra="-4dp"
|
|
||||||
android:maxLines="2"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:shadowColor="@color/textColorPrimaryLight"
|
|
||||||
android:shadowDx="0"
|
|
||||||
android:shadowDy="0"
|
|
||||||
android:shadowRadius="4"
|
|
||||||
app:typeface="ptsansNarrowBold"
|
|
||||||
tools:text="Sample name" />
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progress"
|
|
||||||
style="?android:attr/progressBarStyleSmall"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/card_scroll_content"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:paddingBottom="20dp"
|
|
||||||
android:gravity="start"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="@id/card"
|
|
||||||
app:layout_constraintStart_toStartOf="@id/card"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/card">
|
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_source_label"
|
|
||||||
style="@style/TextAppearance.Medium.Body2"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="false"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:maxLines="1"
|
|
||||||
tools:layout_editor_absoluteY="57dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_last_chapter_label"
|
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="false"
|
|
||||||
android:textIsSelectable="false" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,72 +0,0 @@
|
|||||||
<?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:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center">
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/migration_manga_card_from"
|
|
||||||
layout="@layout/migration_new_manga_card"
|
|
||||||
android:layout_width="150dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/imageView"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/imageView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="25dp"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:contentDescription="@string/migrating_to"
|
|
||||||
android:scaleType="center"
|
|
||||||
android:layout_marginBottom="45dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/migration_manga_card_to"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/migration_manga_card_from"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:srcCompat="@drawable/ic_keyboard_arrow_right_black_24dp" />
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/migration_manga_card_to"
|
|
||||||
layout="@layout/migration_new_manga_card"
|
|
||||||
android:layout_width="150dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/migration_menu"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/imageView"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/migration_menu"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:contentDescription="@string/description_cover"
|
|
||||||
android:paddingTop="30dp"
|
|
||||||
android:paddingBottom="30dp"
|
|
||||||
android:layout_marginBottom="45dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/migration_manga_card_to"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:srcCompat="@drawable/ic_more_vert_black_24dp"
|
|
||||||
android:visibility="invisible"/>
|
|
||||||
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/skip_manga"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/migration_menu"
|
|
||||||
app:layout_constraintEnd_toEndOf="@+id/migration_menu"
|
|
||||||
app:layout_constraintStart_toStartOf="@+id/migration_menu"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/migration_menu"
|
|
||||||
app:srcCompat="@drawable/baseline_close_24" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,18 +0,0 @@
|
|||||||
<?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:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/colorPrimary" >
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.ui.migration.manga.process.DeactivatableViewPager
|
|
||||||
android:id="@+id/pager"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,108 +1,72 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:animateLayoutChanges="true">
|
android:gravity="center">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<include
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/migration_manga_card_from"
|
||||||
android:layout_height="match_parent">
|
layout="@layout/migration_manga_card"
|
||||||
|
android:layout_width="150dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/imageView"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<include
|
<ImageView
|
||||||
android:id="@+id/migration_manga_card_from"
|
android:id="@+id/imageView"
|
||||||
layout="@layout/migration_manga_card"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="0dp"
|
android:layout_height="25dp"
|
||||||
android:layout_height="wrap_content"
|
android:adjustViewBounds="true"
|
||||||
android:layout_marginStart="16dp"
|
android:contentDescription="@string/migrating_to"
|
||||||
android:layout_marginLeft="16dp"
|
android:scaleType="center"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginBottom="45dp"
|
||||||
android:layout_marginEnd="16dp"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:layout_marginRight="16dp"
|
app:layout_constraintEnd_toStartOf="@+id/migration_manga_card_to"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toEndOf="@+id/migration_manga_card_from"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintWidth_max="450dp" />
|
app:srcCompat="@drawable/ic_keyboard_arrow_right_black_24dp" />
|
||||||
|
|
||||||
<ImageView
|
<include
|
||||||
android:id="@+id/imageView"
|
android:id="@+id/migration_manga_card_to"
|
||||||
android:layout_width="wrap_content"
|
layout="@layout/migration_manga_card"
|
||||||
android:layout_height="50dp"
|
android:layout_width="150dp"
|
||||||
android:adjustViewBounds="true"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="migrating to"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:scaleType="center"
|
app:layout_constraintEnd_toStartOf="@+id/migration_menu"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toEndOf="@+id/imageView"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/migration_manga_card_from"
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
app:srcCompat="@drawable/ic_arrow_down_white_32dp" />
|
|
||||||
|
|
||||||
<include
|
<ImageView
|
||||||
android:id="@+id/migration_manga_card_to"
|
android:id="@+id/migration_menu"
|
||||||
layout="@layout/migration_manga_card"
|
android:layout_width="48dp"
|
||||||
android:layout_width="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:contentDescription="@string/description_cover"
|
||||||
android:layout_marginStart="16dp"
|
android:paddingTop="30dp"
|
||||||
android:layout_marginLeft="16dp"
|
android:paddingBottom="30dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginBottom="45dp"
|
||||||
android:layout_marginRight="16dp"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/imageView"
|
app:layout_constraintStart_toEndOf="@+id/migration_manga_card_to"
|
||||||
app:layout_constraintWidth_max="450dp" />
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_more_vert_black_24dp"
|
||||||
|
android:visibility="invisible"/>
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/skip_migration"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:drawableStart="@drawable/ic_clear_grey_24dp_img"
|
|
||||||
android:drawablePadding="6dp"
|
|
||||||
android:text="Skip manga"
|
|
||||||
android:textColor="#ffffff"
|
|
||||||
app:backgroundTint="#E53935"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/accept_migration"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
|
||||||
|
|
||||||
<Button
|
<ImageView
|
||||||
android:id="@+id/accept_migration"
|
android:id="@+id/skip_manga"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="48dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:alpha="0.5"
|
app:layout_constraintBottom_toBottomOf="@+id/migration_menu"
|
||||||
android:drawableStart="@drawable/ic_check_box_24dp"
|
app:layout_constraintEnd_toEndOf="@+id/migration_menu"
|
||||||
android:drawablePadding="6dp"
|
app:layout_constraintStart_toStartOf="@+id/migration_menu"
|
||||||
android:enabled="false"
|
app:layout_constraintTop_toTopOf="@+id/migration_menu"
|
||||||
android:text="Migrate manga"
|
app:srcCompat="@drawable/baseline_close_24" />
|
||||||
android:textColor="#ffffff"
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
app:backgroundTint="#00C853"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/skip_migration"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/skip_migration" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/migrating_frame"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/migrating_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="#E6FFFFFF" />
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/migrating_progress"
|
|
||||||
style="?android:attr/progressBarStyle"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center" />
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
Loading…
Reference in New Issue
Block a user