mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-09-10 20:43:14 +02: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.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(" +")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.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()
|
||||
|
@ -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.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
|
||||
|
@ -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
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.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
|
||||
|
@ -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
|
||||
|
@ -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 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.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) {
|
||||
|
@ -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<MigrationProcessHolder>() {
|
||||
|
||||
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<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:clipToPadding="false"
|
||||
android:id="@+id/recycler"
|
||||
tools:listitem="@layout/migration_new_process_item" />
|
||||
tools:listitem="@layout/migration_process_item" />
|
||||
|
||||
</FrameLayout>
|
@ -1,270 +1,124 @@
|
||||
<?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:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
android:background="?selectable_library_drawable">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="false">
|
||||
<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/manga_cover"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:contentDescription="@string/description_cover"
|
||||
app:layout_constraintDimensionRatio="l,2:3"
|
||||
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>
|
||||
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/card_shim"
|
||||
android:layout_width="0dp"
|
||||
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:id="@+id/gradient"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
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" />
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@drawable/gradient_shape" />
|
||||
|
||||
<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: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"
|
||||
app:constraint_referenced_ids="card_shim,search_status,search_progress" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
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,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"?>
|
||||
<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:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true">
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<include
|
||||
android:id="@+id/migration_manga_card_from"
|
||||
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
|
||||
android:id="@+id/migration_manga_card_from"
|
||||
layout="@layout/migration_manga_card"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_max="450dp" />
|
||||
<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" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="50dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:contentDescription="migrating to"
|
||||
android:scaleType="center"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/migration_manga_card_from"
|
||||
app:srcCompat="@drawable/ic_arrow_down_white_32dp" />
|
||||
<include
|
||||
android:id="@+id/migration_manga_card_to"
|
||||
layout="@layout/migration_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" />
|
||||
|
||||
<include
|
||||
android:id="@+id/migration_manga_card_to"
|
||||
layout="@layout/migration_manga_card"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView"
|
||||
app:layout_constraintWidth_max="450dp" />
|
||||
<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"/>
|
||||
|
||||
<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
|
||||
android:id="@+id/accept_migration"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.5"
|
||||
android:drawableStart="@drawable/ic_check_box_24dp"
|
||||
android:drawablePadding="6dp"
|
||||
android:enabled="false"
|
||||
android:text="Migrate manga"
|
||||
android:textColor="#ffffff"
|
||||
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>
|
||||
<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>
|
Loading…
Reference in New Issue
Block a user