Convert all SY specific things to use ViewBindings instead of synthetics

This commit is contained in:
Jobobby04 2020-10-29 23:43:24 -04:00
parent 528f6c7f65
commit 95c331b8b4
13 changed files with 203 additions and 224 deletions

View File

@ -3,18 +3,17 @@ package eu.kanade.tachiyomi.ui.browse.migration.advanced.design
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.view.View import android.view.View
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MigrationSourceItemBinding
import eu.kanade.tachiyomi.source.icon import eu.kanade.tachiyomi.source.icon
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import kotlinx.android.synthetic.main.migration_source_item.image
import kotlinx.android.synthetic.main.migration_source_item.reorder
import kotlinx.android.synthetic.main.migration_source_item.title
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
class MigrationSourceHolder(view: View, val adapter: MigrationSourceAdapter) : class MigrationSourceHolder(view: View, val adapter: MigrationSourceAdapter) :
BaseFlexibleViewHolder(view, adapter) { BaseFlexibleViewHolder(view, adapter) {
val binding = MigrationSourceItemBinding.bind(view)
init { init {
setDragHandleView(reorder) setDragHandleView(binding.reorder)
} }
fun bind(source: HttpSource, sourceEnabled: Boolean) { fun bind(source: HttpSource, sourceEnabled: Boolean) {
@ -22,23 +21,23 @@ class MigrationSourceHolder(view: View, val adapter: MigrationSourceAdapter) :
val isMultiLanguage = preferences.enabledLanguages().get().size > 1 val isMultiLanguage = preferences.enabledLanguages().get().size > 1
// Set capitalized title. // Set capitalized title.
val sourceName = if (isMultiLanguage) source.toString() else source.name.capitalize() val sourceName = if (isMultiLanguage) source.toString() else source.name.capitalize()
title.text = sourceName binding.title.text = sourceName
// Update circle letter image. // Update circle letter image.
itemView.post { itemView.post {
val icon = source.icon() val icon = source.icon()
if (icon != null) { if (icon != null) {
image.setImageDrawable(icon) binding.image.setImageDrawable(icon)
} }
} }
if (sourceEnabled) { if (sourceEnabled) {
title.alpha = 1.0f binding.title.alpha = 1.0f
image.alpha = 1.0f binding.image.alpha = 1.0f
title.paintFlags = title.paintFlags and STRIKE_THRU_TEXT_FLAG.inv() binding.title.paintFlags = binding.title.paintFlags and STRIKE_THRU_TEXT_FLAG.inv()
} else { } else {
title.alpha = DISABLED_ALPHA binding.title.alpha = DISABLED_ALPHA
image.alpha = DISABLED_ALPHA binding.image.alpha = DISABLED_ALPHA
title.paintFlags = title.paintFlags or STRIKE_THRU_TEXT_FLAG binding.title.paintFlags = binding.title.paintFlags or STRIKE_THRU_TEXT_FLAG
} }
} }

View File

@ -10,6 +10,8 @@ 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.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.databinding.MigrationMangaCardBinding
import eu.kanade.tachiyomi.databinding.MigrationProcessItemBinding
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.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
@ -20,17 +22,6 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.setVectorCompat import eu.kanade.tachiyomi.util.view.setVectorCompat
import exh.MERGED_SOURCE_ID import exh.MERGED_SOURCE_ID
import exh.util.await import exh.util.await
import kotlinx.android.synthetic.main.migration_manga_card.view.gradient
import kotlinx.android.synthetic.main.migration_manga_card.view.loading_group
import kotlinx.android.synthetic.main.migration_manga_card.view.manga_chapters
import kotlinx.android.synthetic.main.migration_manga_card.view.manga_last_chapter_label
import kotlinx.android.synthetic.main.migration_manga_card.view.manga_source_label
import kotlinx.android.synthetic.main.migration_manga_card.view.thumbnail
import kotlinx.android.synthetic.main.migration_manga_card.view.title
import kotlinx.android.synthetic.main.migration_process_item.migration_manga_card_from
import kotlinx.android.synthetic.main.migration_process_item.migration_manga_card_to
import kotlinx.android.synthetic.main.migration_process_item.migration_menu
import kotlinx.android.synthetic.main.migration_process_item.skip_manga
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -51,13 +42,14 @@ class MigrationProcessHolder(
private var item: MigrationProcessItem? = null private var item: MigrationProcessItem? = null
private val scope = CoroutineScope(Job() + Dispatchers.Main) private val scope = CoroutineScope(Job() + Dispatchers.Main)
private val binding = MigrationProcessItemBinding.bind(view)
init { init {
// We need to post a Runnable to show the popup to make sure that the PopupMenu is // We need to post a Runnable to show the popup to make sure that the PopupMenu is
// correctly positioned. The reason being that the view may change position before the // correctly positioned. The reason being that the view may change position before the
// PopupMenu is shown. // PopupMenu is shown.
migration_menu.setOnClickListener { it.post { showPopupMenu(it) } } binding.migrationMenu.setOnClickListener { it.post { showPopupMenu(it) } }
skip_manga.setOnClickListener { it.post { adapter.removeManga(bindingAdapterPosition) } } binding.skipManga.setOnClickListener { it.post { adapter.removeManga(bindingAdapterPosition) } }
} }
fun bind(item: MigrationProcessItem) { fun bind(item: MigrationProcessItem) {
@ -66,25 +58,25 @@ class MigrationProcessHolder(
val manga = item.manga.manga() val manga = item.manga.manga()
val source = item.manga.mangaSource() val source = item.manga.mangaSource()
migration_menu.setVectorCompat( binding.migrationMenu.setVectorCompat(
R.drawable.ic_more_vert_24dp, R.drawable.ic_more_vert_24dp,
view.context view.context
.getResourceColor(R.attr.colorOnPrimary) .getResourceColor(R.attr.colorOnPrimary)
) )
skip_manga.setVectorCompat( binding.skipManga.setVectorCompat(
R.drawable.ic_close_24dp, R.drawable.ic_close_24dp,
view.context.getResourceColor( view.context.getResourceColor(
R R
.attr.colorOnPrimary .attr.colorOnPrimary
) )
) )
migration_menu.isInvisible = true binding.migrationMenu.isInvisible = true
skip_manga.isVisible = true binding.skipManga.isVisible = true
migration_manga_card_to.resetManga() binding.migrationMangaCardTo.resetManga()
if (manga != null) { if (manga != null) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
migration_manga_card_from.attachManga(manga, source) binding.migrationMangaCardFrom.attachManga(manga, source)
migration_manga_card_from.clicks() binding.migrationMangaCardFrom.root.clicks()
.onEach { .onEach {
adapter.controller.router.pushController( adapter.controller.router.pushController(
MangaController( MangaController(
@ -119,8 +111,8 @@ class MigrationProcessHolder(
return@withContext return@withContext
} }
if (searchResult != null && resultSource != null) { if (searchResult != null && resultSource != null) {
migration_manga_card_to.attachManga(searchResult, resultSource) binding.migrationMangaCardTo.attachManga(searchResult, resultSource)
migration_manga_card_to.clicks() binding.migrationMangaCardTo.root.clicks()
.onEach { .onEach {
adapter.controller.router.pushController( adapter.controller.router.pushController(
MangaController( MangaController(
@ -130,30 +122,30 @@ class MigrationProcessHolder(
) )
}.launchIn(scope) }.launchIn(scope)
} else { } else {
migration_manga_card_to.loading_group.isVisible = false binding.migrationMangaCardTo.loadingGroup.isVisible = false
migration_manga_card_to.title.text = view.context.applicationContext binding.migrationMangaCardTo.title.text = view.context.applicationContext
.getString(R.string.no_alternatives_found) .getString(R.string.no_alternatives_found)
} }
migration_menu.isVisible = true binding.migrationMenu.isVisible = true
skip_manga.isVisible = false binding.skipManga.isVisible = false
adapter.sourceFinished() adapter.sourceFinished()
} }
} }
} }
} }
private fun View.resetManga() { private fun MigrationMangaCardBinding.resetManga() {
loading_group.isVisible = true loadingGroup.isVisible = true
thumbnail.setImageDrawable(null) thumbnail.setImageDrawable(null)
title.text = "" title.text = ""
manga_source_label.text = "" mangaSourceLabel.text = ""
manga_chapters.text = "" mangaChapters.text = ""
manga_chapters.isVisible = false mangaChapters.isVisible = false
manga_last_chapter_label.text = "" mangaLastChapterLabel.text = ""
} }
private suspend fun View.attachManga(manga: Manga, source: Source) { private suspend fun MigrationMangaCardBinding.attachManga(manga: Manga, source: Source) {
loading_group.isVisible = false loadingGroup.isVisible = false
GlideApp.with(view.context.applicationContext) GlideApp.with(view.context.applicationContext)
.load(manga.toMangaThumbnail()) .load(manga.toMangaThumbnail())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
@ -168,7 +160,7 @@ class MigrationProcessHolder(
} }
gradient.isVisible = true gradient.isVisible = true
manga_source_label.text = if (source.id == MERGED_SOURCE_ID) { mangaSourceLabel.text = if (source.id == MERGED_SOURCE_ID) {
db.getMergedMangaReferences(manga.id!!).await().map { db.getMergedMangaReferences(manga.id!!).await().map {
sourceManager.getOrStub(it.mangaSourceId).toString() sourceManager.getOrStub(it.mangaSourceId).toString()
}.distinct().joinToString() }.distinct().joinToString()
@ -176,20 +168,20 @@ class MigrationProcessHolder(
source.toString() source.toString()
} }
val mangaChapters = db.getChapters(manga).executeAsBlocking() val chapters = db.getChapters(manga).executeAsBlocking()
manga_chapters.isVisible = true mangaChapters.isVisible = true
manga_chapters.text = mangaChapters.size.toString() mangaChapters.text = chapters.size.toString()
val latestChapter = mangaChapters.maxByOrNull { it.chapter_number }?.chapter_number ?: -1f val latestChapter = chapters.maxByOrNull { it.chapter_number }?.chapter_number ?: -1f
if (latestChapter > 0f) { if (latestChapter > 0f) {
manga_last_chapter_label.text = context.getString( mangaLastChapterLabel.text = root.context.getString(
R.string.latest_, R.string.latest_,
DecimalFormat("#.#").format(latestChapter) DecimalFormat("#.#").format(latestChapter)
) )
} else { } else {
manga_last_chapter_label.text = context.getString( mangaLastChapterLabel.text = root.context.getString(
R.string.latest_, R.string.latest_,
context.getString(R.string.unknown) root.context.getString(R.string.unknown)
) )
} }
} }

View File

@ -9,27 +9,28 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.databinding.SourceListItemBinding
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import kotlinx.android.synthetic.main.source_list_item.thumbnail
import kotlinx.android.synthetic.main.source_list_item.title
class MangaHolder( class MangaHolder(
view: View, view: View,
adapter: FlexibleAdapter<*> adapter: FlexibleAdapter<*>
) : BaseFlexibleViewHolder(view, adapter) { ) : BaseFlexibleViewHolder(view, adapter) {
val binding = SourceListItemBinding.bind(view)
fun bind(item: MangaItem) { fun bind(item: MangaItem) {
// Update the title of the manga. // Update the title of the manga.
title.text = item.manga.originalTitle binding.title.text = item.manga.originalTitle
// Create thumbnail onclick to simulate long click // Create thumbnail onclick to simulate long click
thumbnail.setOnClickListener { binding.thumbnail.setOnClickListener {
// Simulate long click on this view to enter selection mode // Simulate long click on this view to enter selection mode
onLongClick(itemView) onLongClick(itemView)
} }
// Update the cover. // Update the cover.
GlideApp.with(itemView.context).clear(thumbnail) GlideApp.with(itemView.context).clear(binding.thumbnail)
val radius = itemView.context.resources.getDimensionPixelSize(R.dimen.card_radius) val radius = itemView.context.resources.getDimensionPixelSize(R.dimen.card_radius)
val requestOptions = RequestOptions().transform(CenterCrop(), RoundedCorners(radius)) val requestOptions = RequestOptions().transform(CenterCrop(), RoundedCorners(radius))
@ -38,6 +39,6 @@ class MangaHolder(
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.apply(requestOptions) .apply(requestOptions)
.dontAnimate() .dontAnimate()
.into(thumbnail) .into(binding.thumbnail)
} }
} }

View File

@ -6,8 +6,8 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractHeaderItem import eu.davidea.flexibleadapter.items.AbstractHeaderItem
import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.SourceMainControllerCardHeaderBinding
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import kotlinx.android.synthetic.main.source_main_controller_card_header.title
/** /**
* Item that contains the selection header. * Item that contains the selection header.
@ -46,8 +46,9 @@ class SelectionHeader : AbstractHeaderItem<SelectionHeader.Holder>() {
} }
class Holder(view: View, adapter: FlexibleAdapter</* SY --> */ IFlexible<RecyclerView.ViewHolder> /* SY <-- */>) : BaseFlexibleViewHolder(view, adapter) { class Holder(view: View, adapter: FlexibleAdapter</* SY --> */ IFlexible<RecyclerView.ViewHolder> /* SY <-- */>) : BaseFlexibleViewHolder(view, adapter) {
val binding = SourceMainControllerCardHeaderBinding.bind(view)
init { init {
title.text = view.context.getString(/* SY --> */ R.string.select_a_source_to_migrate_from /* SY <-- */) binding.title.text = view.context.getString(/* SY --> */ R.string.select_a_source_to_migrate_from /* SY <-- */)
} }
} }

View File

@ -3,20 +3,20 @@ package eu.kanade.tachiyomi.ui.browse.migration.sources
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.SourceMainControllerCardItemBinding
import eu.kanade.tachiyomi.source.icon import eu.kanade.tachiyomi.source.icon
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import kotlinx.android.synthetic.main.source_main_controller_card_item.image
import kotlinx.android.synthetic.main.source_main_controller_card_item.source_latest
import kotlinx.android.synthetic.main.source_main_controller_card_item.title
class SourceHolder(view: View, val adapter: SourceAdapter) : class SourceHolder(view: View, val adapter: SourceAdapter) :
BaseFlexibleViewHolder(view, adapter) { BaseFlexibleViewHolder(view, adapter) {
val binding = SourceMainControllerCardItemBinding.bind(view)
// SY --> // SY -->
init { init {
source_latest.isVisible = true binding.sourceLatest.isVisible = true
source_latest.text = view.context.getString(R.string.all) binding.sourceLatest.text = view.context.getString(R.string.all)
source_latest.setOnClickListener { binding.sourceLatest.setOnClickListener {
adapter.allClickListener?.onAllClick(bindingAdapterPosition) adapter.allClickListener?.onAllClick(bindingAdapterPosition)
} }
} }
@ -26,11 +26,11 @@ class SourceHolder(view: View, val adapter: SourceAdapter) :
val source = item.source val source = item.source
// Set source name // Set source name
title.text = source.name binding.title.text = source.name
// Set source icon // Set source icon
itemView.post { itemView.post {
image.setImageDrawable(source.icon()) binding.image.setImageDrawable(source.icon())
} }
} }
} }

View File

@ -4,7 +4,7 @@ import android.app.Dialog
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.InputType import android.text.InputType
import android.view.View import androidx.core.content.ContextCompat
import androidx.core.view.children import androidx.core.view.children
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
@ -19,21 +19,13 @@ 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.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.databinding.EditMangaDialogBinding
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.util.lang.chop import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import exh.util.trimOrNull import exh.util.trimOrNull
import kotlinx.android.synthetic.main.edit_manga_dialog.view.cover_layout
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_artist
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_author
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_cover
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_description
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_genres_tags
import kotlinx.android.synthetic.main.edit_manga_dialog.view.reset_cover
import kotlinx.android.synthetic.main.edit_manga_dialog.view.reset_tags
import kotlinx.android.synthetic.main.edit_manga_dialog.view.title
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.view.clicks import reactivecircus.flowbinding.android.view.clicks
@ -42,7 +34,7 @@ import uy.kohesive.injekt.api.get
class EditMangaDialog : DialogController { class EditMangaDialog : DialogController {
private var dialogView: View? = null private lateinit var binding: EditMangaDialogBinding
private val manga: Manga private val manga: Manga
@ -75,8 +67,8 @@ class EditMangaDialog : DialogController {
negativeButton(android.R.string.cancel) negativeButton(android.R.string.cancel)
positiveButton(R.string.action_save) { onPositiveButtonClick() } positiveButton(R.string.action_save) { onPositiveButtonClick() }
} }
dialogView = dialog.view binding = EditMangaDialogBinding.bind(dialog.view)
onViewCreated(dialog.view) onViewCreated()
dialog.setOnShowListener { dialog.setOnShowListener {
val dView = (it as? MaterialDialog)?.view val dView = (it as? MaterialDialog)?.view
dView?.contentLayout?.scrollView?.scrollTo(0, 0) dView?.contentLayout?.scrollView?.scrollTo(0, 0)
@ -84,101 +76,96 @@ class EditMangaDialog : DialogController {
return dialog return dialog
} }
fun onViewCreated(view: View) { fun onViewCreated() {
val mangaThumbnail = manga.toMangaThumbnail() val mangaThumbnail = manga.toMangaThumbnail()
GlideApp.with(view.context) GlideApp.with(binding.root.context)
.load(mangaThumbnail) .load(mangaThumbnail)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.centerCrop() .centerCrop()
.into(view.manga_cover) .into(binding.mangaCover)
val isLocal = manga.source == LocalSource.ID val isLocal = manga.source == LocalSource.ID
if (isLocal) { if (isLocal) {
if (manga.title != manga.url) { if (manga.title != manga.url) {
view.title.append(manga.title) binding.title.append(manga.title)
} }
view.title.hint = "${resources?.getString(R.string.title)}: ${manga.url}" binding.title.hint = "${resources?.getString(R.string.title)}: ${manga.url}"
view.manga_author.append(manga.author ?: "") binding.mangaAuthor.append(manga.author ?: "")
view.manga_artist.append(manga.artist ?: "") binding.mangaArtist.append(manga.artist ?: "")
view.manga_description.append(manga.description ?: "") binding.mangaDescription.append(manga.description ?: "")
view.manga_genres_tags.setChips(manga.getGenres()) binding.mangaGenresTags.setChips(manga.getGenres())
} else { } else {
if (manga.title != manga.originalTitle) { if (manga.title != manga.originalTitle) {
view.title.append(manga.title) binding.title.append(manga.title)
} }
if (manga.author != manga.originalAuthor) { if (manga.author != manga.originalAuthor) {
view.manga_author.append(manga.author ?: "") binding.mangaAuthor.append(manga.author ?: "")
} }
if (manga.artist != manga.originalArtist) { if (manga.artist != manga.originalArtist) {
view.manga_artist.append(manga.artist ?: "") binding.mangaArtist.append(manga.artist ?: "")
} }
if (manga.description != manga.originalDescription) { if (manga.description != manga.originalDescription) {
view.manga_description.append(manga.description ?: "") binding.mangaDescription.append(manga.description ?: "")
} }
view.manga_genres_tags.setChips(manga.getGenres()) binding.mangaGenresTags.setChips(manga.getGenres())
view.title.hint = "${resources?.getString(R.string.title)}: ${manga.originalTitle}" binding.title.hint = "${resources?.getString(R.string.title)}: ${manga.originalTitle}"
if (manga.originalAuthor != null) { if (manga.originalAuthor != null) {
view.manga_author.hint = "Author: ${manga.originalAuthor}" binding.mangaAuthor.hint = "Author: ${manga.originalAuthor}"
} }
if (manga.originalArtist != null) { if (manga.originalArtist != null) {
view.manga_artist.hint = "Artist: ${manga.originalArtist}" binding.mangaArtist.hint = "Artist: ${manga.originalArtist}"
} }
if (manga.originalDescription != null) { if (manga.originalDescription != null) {
view.manga_description.hint = binding.mangaDescription.hint =
"${resources?.getString(R.string.description)}: ${manga.originalDescription?.replace( "${resources?.getString(R.string.description)}: ${manga.originalDescription?.replace(
"\n", "\n",
" " " "
)?.chop(20)}" )?.chop(20)}"
} }
} }
view.manga_genres_tags.clearFocus() binding.mangaGenresTags.clearFocus()
view.cover_layout.clicks() binding.coverLayout.clicks()
.onEach { infoController.changeCover() } .onEach { infoController.changeCover() }
.launchIn(infoController.scope) .launchIn(infoController.scope)
view.reset_tags.clicks() binding.resetTags.clicks()
.onEach { resetTags() } .onEach { resetTags() }
.launchIn(infoController.scope) .launchIn(infoController.scope)
view.reset_cover.isVisible = !isLocal binding.resetCover.isVisible = !isLocal
view.reset_cover.clicks() binding.resetCover.clicks()
.onEach { .onEach {
view.context.toast(R.string.cover_reset_toast) binding.root.context.toast(R.string.cover_reset_toast)
customCoverUri = null customCoverUri = null
willResetCover = true willResetCover = true
}.launchIn(infoController.scope) }.launchIn(infoController.scope)
} }
private fun resetTags() { private fun resetTags() {
if (manga.genre.isNullOrBlank() || manga.source == LocalSource.ID) dialogView?.manga_genres_tags?.setChips( if (manga.genre.isNullOrBlank() || manga.source == LocalSource.ID) binding.mangaGenresTags.setChips(
emptyList() emptyList()
) )
else dialogView?.manga_genres_tags?.setChips(manga.getOriginalGenres()) else binding.mangaGenresTags.setChips(manga.getOriginalGenres())
} }
fun updateCover(uri: Uri) { fun updateCover(uri: Uri) {
willResetCover = false willResetCover = false
GlideApp.with(dialogView!!.context) GlideApp.with(binding.root.context)
.load(uri) .load(uri)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.centerCrop() .centerCrop()
.into(dialogView!!.manga_cover) .into(binding.mangaCover)
customCoverUri = uri customCoverUri = uri
} }
override fun onDestroyView(view: View) {
super.onDestroyView(view)
dialogView = null
}
private fun onPositiveButtonClick() { private fun onPositiveButtonClick() {
infoController.presenter.updateMangaInfo( infoController.presenter.updateMangaInfo(
dialogView?.title?.text.toString(), binding.title.text.toString(),
dialogView?.manga_author?.text.toString(), binding.mangaAuthor.text.toString(),
dialogView?.manga_artist?.text.toString(), binding.mangaArtist.text.toString(),
dialogView?.manga_description?.text.toString(), binding.mangaDescription.text.toString(),
dialogView?.manga_genres_tags?.getTextStrings(), binding.mangaGenresTags.getTextStrings(),
customCoverUri, customCoverUri,
willResetCover willResetCover
) )
@ -204,7 +191,7 @@ class EditMangaDialog : DialogController {
val addTagChip = Chip(context).apply { val addTagChip = Chip(context).apply {
setText(R.string.add_tag) setText(R.string.add_tag)
chipIcon = context.getDrawable(R.drawable.ic_add_24dp) chipIcon = ContextCompat.getDrawable(context, R.drawable.ic_add_24dp)
chipIcon?.setTint(context.getResourceColor(R.attr.colorAccent)) chipIcon?.setTint(context.getResourceColor(R.attr.colorAccent))
textStartPadding = 0F textStartPadding = 0F

View File

@ -5,33 +5,28 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.databinding.EditMergedSettingsItemBinding
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import exh.merged.sql.models.MergedMangaReference import exh.merged.sql.models.MergedMangaReference
import kotlinx.android.synthetic.main.edit_merged_settings_item.cover
import kotlinx.android.synthetic.main.edit_merged_settings_item.download
import kotlinx.android.synthetic.main.edit_merged_settings_item.get_chapter_updates
import kotlinx.android.synthetic.main.edit_merged_settings_item.remove
import kotlinx.android.synthetic.main.edit_merged_settings_item.reorder
import kotlinx.android.synthetic.main.edit_merged_settings_item.subtitle
import kotlinx.android.synthetic.main.edit_merged_settings_item.title
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
class EditMergedMangaHolder(view: View, val adapter: EditMergedMangaAdapter) : BaseFlexibleViewHolder(view, adapter) { class EditMergedMangaHolder(view: View, val adapter: EditMergedMangaAdapter) : BaseFlexibleViewHolder(view, adapter) {
lateinit var reference: MergedMangaReference lateinit var reference: MergedMangaReference
var binding = EditMergedSettingsItemBinding.bind(view)
init { init {
setDragHandleView(reorder) setDragHandleView(binding.reorder)
remove.setOnClickListener { binding.remove.setOnClickListener {
adapter.editMergedMangaItemListener.onDeleteClick(bindingAdapterPosition) adapter.editMergedMangaItemListener.onDeleteClick(bindingAdapterPosition)
} }
get_chapter_updates.setOnClickListener { binding.getChapterUpdates.setOnClickListener {
adapter.editMergedMangaItemListener.onToggleChapterUpdatesClicked(bindingAdapterPosition) adapter.editMergedMangaItemListener.onToggleChapterUpdatesClicked(bindingAdapterPosition)
} }
download.setOnClickListener { binding.download.setOnClickListener {
adapter.editMergedMangaItemListener.onToggleChapterDownloadsClicked(bindingAdapterPosition) adapter.editMergedMangaItemListener.onToggleChapterDownloadsClicked(bindingAdapterPosition)
} }
setHandelAlpha(adapter.isPriorityOrder) setHandelAlpha(adapter.isPriorityOrder)
@ -49,17 +44,17 @@ class EditMergedMangaHolder(view: View, val adapter: EditMergedMangaAdapter) : B
.load(it) .load(it)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.centerCrop() .centerCrop()
.into(cover) .into(binding.cover)
} }
title.text = Injekt.get<SourceManager>().getOrStub(item.mergedMangaReference.mangaSourceId).toString() binding.title.text = Injekt.get<SourceManager>().getOrStub(item.mergedMangaReference.mangaSourceId).toString()
subtitle.text = item.mergedManga?.title binding.subtitle.text = item.mergedManga?.title
updateDownloadChaptersIcon(item.mergedMangaReference.downloadChapters) updateDownloadChaptersIcon(item.mergedMangaReference.downloadChapters)
updateChapterUpdatesIcon(item.mergedMangaReference.getChapterUpdates) updateChapterUpdatesIcon(item.mergedMangaReference.getChapterUpdates)
} }
fun setHandelAlpha(isPriorityOrder: Boolean) { fun setHandelAlpha(isPriorityOrder: Boolean) {
reorder.alpha = when (isPriorityOrder) { binding.reorder.alpha = when (isPriorityOrder) {
true -> 1F true -> 1F
false -> 0.5F false -> 0.5F
} }
@ -70,7 +65,7 @@ class EditMergedMangaHolder(view: View, val adapter: EditMergedMangaAdapter) : B
itemView.context.getResourceColor(R.attr.colorAccent) itemView.context.getResourceColor(R.attr.colorAccent)
} else itemView.context.getResourceColor(R.attr.colorOnSurface) } else itemView.context.getResourceColor(R.attr.colorOnSurface)
download.drawable.setTint(color) binding.download.drawable.setTint(color)
} }
fun updateChapterUpdatesIcon(setTint: Boolean) { fun updateChapterUpdatesIcon(setTint: Boolean) {
@ -78,6 +73,6 @@ class EditMergedMangaHolder(view: View, val adapter: EditMergedMangaAdapter) : B
itemView.context.getResourceColor(R.attr.colorAccent) itemView.context.getResourceColor(R.attr.colorAccent)
} else itemView.context.getResourceColor(R.attr.colorOnSurface) } else itemView.context.getResourceColor(R.attr.colorOnSurface)
get_chapter_updates.drawable.setTint(color) binding.getChapterUpdates.drawable.setTint(color)
} }
} }

View File

@ -10,12 +10,12 @@ import com.afollestad.materialdialogs.customview.customView
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
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.databinding.EditMergedSettingsDialogBinding
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import exh.MERGED_SOURCE_ID import exh.MERGED_SOURCE_ID
import exh.merged.sql.models.MergedMangaReference import exh.merged.sql.models.MergedMangaReference
import kotlinx.android.synthetic.main.edit_merged_settings_dialog.view.recycler
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
class EditMergedSettingsDialog : DialogController, EditMergedMangaAdapter.EditMergedMangaItemListener { class EditMergedSettingsDialog : DialogController, EditMergedMangaAdapter.EditMergedMangaItemListener {
@ -28,6 +28,8 @@ class EditMergedSettingsDialog : DialogController, EditMergedMangaAdapter.EditMe
var mergeReference: MergedMangaReference? = null var mergeReference: MergedMangaReference? = null
lateinit var binding: EditMergedSettingsDialogBinding
private val db: DatabaseHelper by injectLazy() private val db: DatabaseHelper by injectLazy()
private val mangaController private val mangaController
@ -68,6 +70,7 @@ class EditMergedSettingsDialog : DialogController, EditMergedMangaAdapter.EditMe
} }
fun onViewCreated(view: View) { fun onViewCreated(view: View) {
binding = EditMergedSettingsDialogBinding.bind(view)
val mergedManga = db.getMergedMangas(manga.id!!).executeAsBlocking() val mergedManga = db.getMergedMangas(manga.id!!).executeAsBlocking()
val mergedReferences = db.getMergedMangaReferences(manga.id!!).executeAsBlocking() val mergedReferences = db.getMergedMangaReferences(manga.id!!).executeAsBlocking()
if (mergedReferences.isEmpty() || mergedReferences.size == 1) { if (mergedReferences.isEmpty() || mergedReferences.size == 1) {
@ -82,8 +85,8 @@ class EditMergedSettingsDialog : DialogController, EditMergedMangaAdapter.EditMe
mergedMangaAdapter = EditMergedMangaAdapter(this, isPriorityOrder) mergedMangaAdapter = EditMergedMangaAdapter(this, isPriorityOrder)
mergedHeaderAdapter = EditMergedSettingsHeaderAdapter(this, mergedMangaAdapter!!) mergedHeaderAdapter = EditMergedSettingsHeaderAdapter(this, mergedMangaAdapter!!)
view.recycler.adapter = ConcatAdapter(mergedHeaderAdapter, mergedMangaAdapter) binding.recycler.adapter = ConcatAdapter(mergedHeaderAdapter, mergedMangaAdapter)
view.recycler.layoutManager = LinearLayoutManager(view.context) binding.recycler.layoutManager = LinearLayoutManager(view.context)
mergedMangaAdapter?.isHandleDragEnabled = isPriorityOrder mergedMangaAdapter?.isHandleDragEnabled = isPriorityOrder

View File

@ -10,8 +10,6 @@ import eu.kanade.tachiyomi.databinding.EhFragmentBatchAddBinding
import eu.kanade.tachiyomi.ui.base.controller.NucleusController import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.util.lang.combineLatest import eu.kanade.tachiyomi.util.lang.combineLatest
import eu.kanade.tachiyomi.util.lang.plusAssign import eu.kanade.tachiyomi.util.lang.plusAssign
import kotlinx.android.synthetic.main.eh_fragment_batch_add.view.galleries_box
import kotlinx.android.synthetic.main.eh_fragment_batch_add.view.progress_log
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.view.clicks import reactivecircus.flowbinding.android.view.clicks
@ -55,7 +53,7 @@ class BatchAddController : NucleusController<EhFragmentBatchAddBinding, BatchAdd
.subscribeUntilDestroy { .subscribeUntilDestroy {
progressSubscriptions.clear() progressSubscriptions.clear()
if (it == BatchAddPresenter.STATE_INPUT_TO_PROGRESS) { if (it == BatchAddPresenter.STATE_INPUT_TO_PROGRESS) {
showProgress(this) showProgress(binding)
progressSubscriptions += presenter.progressRelay progressSubscriptions += presenter.progressRelay
.onBackpressureBuffer() .onBackpressureBuffer()
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
@ -96,45 +94,45 @@ class BatchAddController : NucleusController<EhFragmentBatchAddBinding, BatchAdd
progressSubscriptions += it progressSubscriptions += it
} }
} else if (it == BatchAddPresenter.STATE_PROGRESS_TO_INPUT) { } else if (it == BatchAddPresenter.STATE_PROGRESS_TO_INPUT) {
hideProgress(this) hideProgress(binding)
presenter.currentlyAddingRelay.call(BatchAddPresenter.STATE_IDLE) presenter.currentlyAddingRelay.call(BatchAddPresenter.STATE_IDLE)
} }
} }
} }
} }
private val View.progressViews private val EhFragmentBatchAddBinding.progressViews
get() = listOf( get() = listOf(
binding.progressTitleView, progressTitleView,
binding.progressLogWrapper, progressLogWrapper,
binding.progressBar, progressBar,
binding.progressText, progressText,
binding.progressDismissBtn progressDismissBtn
) )
private val View.inputViews private val EhFragmentBatchAddBinding.inputViews
get() = listOf( get() = listOf(
binding.inputTitleView, inputTitleView,
binding.galleriesBox, galleriesBox,
binding.btnAddGalleries btnAddGalleries
) )
private var List<View>.visibility: Int private var List<View>.visibility: Int
get() = throw UnsupportedOperationException() get() = throw UnsupportedOperationException()
set(v) { forEach { it.visibility = v } } set(v) { forEach { it.visibility = v } }
private fun showProgress(target: View? = view) { private fun showProgress(target: EhFragmentBatchAddBinding = binding) {
target?.apply { target.apply {
progressViews.visibility = View.VISIBLE progressViews.visibility = View.VISIBLE
inputViews.visibility = View.GONE inputViews.visibility = View.GONE
}?.progress_log?.text = "" }.progressLog.text = ""
} }
private fun hideProgress(target: View? = view) { private fun hideProgress(target: EhFragmentBatchAddBinding = binding) {
target?.apply { target.apply {
progressViews.visibility = View.GONE progressViews.visibility = View.GONE
inputViews.visibility = View.VISIBLE inputViews.visibility = View.VISIBLE
}?.galleries_box?.setText("", TextView.BufferType.EDITABLE) }.galleriesBox.setText("", TextView.BufferType.EDITABLE)
} }
private fun formatProgress(progress: Int, total: Int) = "$progress/$total" private fun formatProgress(progress: Int, total: Int) = "$progress/$total"

View File

@ -15,6 +15,7 @@ import com.afollestad.materialdialogs.MaterialDialog
import com.elvishew.xlog.XLog import com.elvishew.xlog.XLog
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.EhActivityCaptchaBinding
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
@ -23,8 +24,6 @@ import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.system.setDefaultSettings import eu.kanade.tachiyomi.util.system.setDefaultSettings
import exh.source.DelegatedHttpSource import exh.source.DelegatedHttpSource
import exh.util.melt import exh.util.melt
import kotlinx.android.synthetic.main.eh_activity_captcha.toolbar
import kotlinx.android.synthetic.main.eh_activity_captcha.webview
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -59,11 +58,14 @@ class BrowserActionActivity : AppCompatActivity() {
private var strictValidationStartTime: Long? = null private var strictValidationStartTime: Long? = null
private lateinit var credentialsObservable: Observable<String> private lateinit var credentialsObservable: Observable<String>
private lateinit var binding: EhActivityCaptchaBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.eh_activity_captcha) binding = EhActivityCaptchaBinding.inflate(layoutInflater)
setContentView(binding.root)
val sourceId = intent.getLongExtra(SOURCE_ID_EXTRA, -1) val sourceId = intent.getLongExtra(SOURCE_ID_EXTRA, -1)
val originalSource = if (sourceId != -1L) sourceManager.get(sourceId) else null val originalSource = if (sourceId != -1L) sourceManager.get(sourceId) else null
@ -102,7 +104,7 @@ class BrowserActionActivity : AppCompatActivity() {
val actionStr = actionName ?: "Solve captcha" val actionStr = actionName ?: "Solve captcha"
toolbar.title = if (source != null) { binding.toolbar.title = if (source != null) {
"${source.name}: $actionStr" "${source.name}: $actionStr"
} else actionStr } else actionStr
@ -115,14 +117,14 @@ class BrowserActionActivity : AppCompatActivity() {
cm.setCookie(url, cookieString) cm.setCookie(url, cookieString)
} }
webview.setDefaultSettings() binding.webview.setDefaultSettings()
headers.entries.find { it.key.equals("user-agent", true) }?.let { headers.entries.find { it.key.equals("user-agent", true) }?.let {
webview.settings.userAgentString = it.value binding.webview.settings.userAgentString = it.value
} }
var loadedInners = 0 var loadedInners = 0
webview.webChromeClient = object : WebChromeClient() { binding.webview.webChromeClient = object : WebChromeClient() {
override fun onJsAlert(view: WebView?, url: String?, message: String, result: JsResult): Boolean { override fun onJsAlert(view: WebView?, url: String?, message: String, result: JsResult): Boolean {
if (message.startsWith("exh-")) { if (message.startsWith("exh-")) {
loadedInners++ loadedInners++
@ -130,13 +132,13 @@ class BrowserActionActivity : AppCompatActivity() {
if (loadedInners >= 2) { if (loadedInners >= 2) {
// Attempt to autosolve captcha // Attempt to autosolve captcha
if (preferencesHelper.eh_autoSolveCaptchas().get()) { if (preferencesHelper.eh_autoSolveCaptchas().get()) {
webview.post { binding.webview.post {
// 10 seconds to auto-solve captcha // 10 seconds to auto-solve captcha
strictValidationStartTime = System.currentTimeMillis() + 1000 * 10 strictValidationStartTime = System.currentTimeMillis() + 1000 * 10
beginSolveLoop() beginSolveLoop()
beginValidateCaptchaLoop() beginValidateCaptchaLoop()
webview.evaluateJavascript(SOLVE_UI_SCRIPT_HIDE) { binding.webview.evaluateJavascript(SOLVE_UI_SCRIPT_HIDE) {
webview.evaluateJavascript(SOLVE_UI_SCRIPT_SHOW, null) binding.webview.evaluateJavascript(SOLVE_UI_SCRIPT_SHOW, null)
} }
} }
} }
@ -148,7 +150,7 @@ class BrowserActionActivity : AppCompatActivity() {
} }
} }
webview.webViewClient = if (actionName == null && preferencesHelper.eh_autoSolveCaptchas().get()) { binding.webview.webViewClient = if (actionName == null && preferencesHelper.eh_autoSolveCaptchas().get()) {
// Fetch auto-solve credentials early for speed // Fetch auto-solve credentials early for speed
credentialsObservable = httpClient.newCall( credentialsObservable = httpClient.newCall(
Request.Builder() Request.Builder()
@ -164,15 +166,15 @@ class BrowserActionActivity : AppCompatActivity() {
json["token"]!!.jsonPrimitive.content json["token"]!!.jsonPrimitive.content
}.melt() }.melt()
webview.addJavascriptInterface(this@BrowserActionActivity, "exh") binding.webview.addJavascriptInterface(this@BrowserActionActivity, "exh")
AutoSolvingWebViewClient(this, verifyComplete, script, headers) AutoSolvingWebViewClient(this, verifyComplete, script, headers)
} else { } else {
HeadersInjectingWebViewClient(this, verifyComplete, script, headers) HeadersInjectingWebViewClient(this, verifyComplete, script, headers)
} }
webview.loadUrl(url, headers) binding.webview.loadUrl(url, headers)
setSupportActionBar(toolbar) setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
} }
@ -187,7 +189,7 @@ class BrowserActionActivity : AppCompatActivity() {
validateCurrentLoopId = null validateCurrentLoopId = null
XLog.e(IllegalStateException("Captcha solve failure!")) XLog.e(IllegalStateException("Captcha solve failure!"))
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
webview.evaluateJavascript(SOLVE_UI_SCRIPT_HIDE, null) binding.webview.evaluateJavascript(SOLVE_UI_SCRIPT_HIDE, null)
MaterialDialog(this@BrowserActionActivity) MaterialDialog(this@BrowserActionActivity)
.title(R.string.captcha_solve_failure) .title(R.string.captcha_solve_failure)
.message(R.string.captcha_solve_failure_message) .message(R.string.captcha_solve_failure_message)
@ -205,14 +207,14 @@ class BrowserActionActivity : AppCompatActivity() {
when (stage) { when (stage) {
STAGE_CHECKBOX -> { STAGE_CHECKBOX -> {
if (result!!.toBoolean()) { if (result!!.toBoolean()) {
webview.postDelayed( binding.webview.postDelayed(
{ {
getAudioButtonLocation(loopId) getAudioButtonLocation(loopId)
}, },
250 250
) )
} else { } else {
webview.postDelayed( binding.webview.postDelayed(
{ {
doStageCheckbox(loopId) doStageCheckbox(loopId)
}, },
@ -227,15 +229,15 @@ class BrowserActionActivity : AppCompatActivity() {
val origY = splitResult[1] val origY = splitResult[1]
val iw = splitResult[2] val iw = splitResult[2]
val ih = splitResult[3] val ih = splitResult[3]
val x = webview.x + origX / iw * webview.width val x = binding.webview.x + origX / iw * binding.webview.width
val y = webview.y + origY / ih * webview.height val y = binding.webview.y + origY / ih * binding.webview.height
XLog.nst().d("Found audio button coords: %f %f", x, y) XLog.nst().d("Found audio button coords: %f %f", x, y)
simulateClick(x + 50, y + 50) simulateClick(x + 50, y + 50)
webview.post { binding.webview.post {
doStageDownloadAudio(loopId) doStageDownloadAudio(loopId)
} }
} else { } else {
webview.postDelayed( binding.webview.postDelayed(
{ {
getAudioButtonLocation(loopId) getAudioButtonLocation(loopId)
}, },
@ -251,7 +253,7 @@ class BrowserActionActivity : AppCompatActivity() {
.subscribe( .subscribe(
{ {
XLog.nst().d("Got audio transcript: $it") XLog.nst().d("Got audio transcript: $it")
webview.post { binding.webview.post {
typeResult( typeResult(
loopId, loopId,
it!! it!!
@ -266,7 +268,7 @@ class BrowserActionActivity : AppCompatActivity() {
} }
) )
} else { } else {
webview.postDelayed( binding.webview.postDelayed(
{ {
doStageDownloadAudio(loopId) doStageDownloadAudio(loopId)
}, },
@ -330,7 +332,7 @@ class BrowserActionActivity : AppCompatActivity() {
private fun doStageCheckbox(loopId: String) { private fun doStageCheckbox(loopId: String) {
if (loopId != currentLoopId) return if (loopId != currentLoopId) return
webview.evaluateJavascript( binding.webview.evaluateJavascript(
""" """
(function() { (function() {
$CROSS_WINDOW_SCRIPT_OUTER $CROSS_WINDOW_SCRIPT_OUTER
@ -359,7 +361,7 @@ class BrowserActionActivity : AppCompatActivity() {
} }
private fun getAudioButtonLocation(loopId: String) { private fun getAudioButtonLocation(loopId: String) {
webview.evaluateJavascript( binding.webview.evaluateJavascript(
""" """
(function() { (function() {
$CROSS_WINDOW_SCRIPT_OUTER $CROSS_WINDOW_SCRIPT_OUTER
@ -394,7 +396,7 @@ class BrowserActionActivity : AppCompatActivity() {
} }
private fun doStageDownloadAudio(loopId: String) { private fun doStageDownloadAudio(loopId: String) {
webview.evaluateJavascript( binding.webview.evaluateJavascript(
""" """
(function() { (function() {
$CROSS_WINDOW_SCRIPT_OUTER $CROSS_WINDOW_SCRIPT_OUTER
@ -422,7 +424,7 @@ class BrowserActionActivity : AppCompatActivity() {
} }
private fun typeResult(loopId: String, result: String) { private fun typeResult(loopId: String, result: String) {
webview.evaluateJavascript( binding.webview.evaluateJavascript(
""" """
(function() { (function() {
$CROSS_WINDOW_SCRIPT_OUTER $CROSS_WINDOW_SCRIPT_OUTER
@ -464,13 +466,13 @@ class BrowserActionActivity : AppCompatActivity() {
if (result) { if (result) {
XLog.nst().d("Captcha solved!") XLog.nst().d("Captcha solved!")
webview.post { binding.webview.post {
webview.evaluateJavascript(SOLVE_UI_SCRIPT_HIDE, null) binding.webview.evaluateJavascript(SOLVE_UI_SCRIPT_HIDE, null)
} }
val asbtn = intent.getStringExtra(ASBTN_EXTRA) val asbtn = intent.getStringExtra(ASBTN_EXTRA)
if (asbtn != null) { if (asbtn != null) {
webview.post { binding.webview.post {
webview.evaluateJavascript("(function() {document.querySelector('$asbtn').click();})();", null) binding.webview.evaluateJavascript("(function() {document.querySelector('$asbtn').click();})();", null)
} }
} }
} else { } else {
@ -480,7 +482,7 @@ class BrowserActionActivity : AppCompatActivity() {
) { ) {
captchaSolveFail() captchaSolveFail()
} else { } else {
webview.postDelayed( binding.webview.postDelayed(
{ {
runValidateCaptcha(loopId) runValidateCaptcha(loopId)
}, },
@ -493,7 +495,7 @@ class BrowserActionActivity : AppCompatActivity() {
private fun runValidateCaptcha(loopId: String) { private fun runValidateCaptcha(loopId: String) {
if (loopId != validateCurrentLoopId) return if (loopId != validateCurrentLoopId) return
webview.evaluateJavascript( binding.webview.evaluateJavascript(
""" """
(function() { (function() {
$CROSS_WINDOW_SCRIPT_OUTER $CROSS_WINDOW_SCRIPT_OUTER

View File

@ -6,9 +6,9 @@ import androidx.core.view.isVisible
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder import androidx.preference.PreferenceViewHolder
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.PrefItemMangadexBinding
import eu.kanade.tachiyomi.source.online.all.MangaDex import eu.kanade.tachiyomi.source.online.all.MangaDex
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import kotlinx.android.synthetic.main.pref_item_mangadex.view.*
class MangaDexLoginPreference @JvmOverloads constructor( class MangaDexLoginPreference @JvmOverloads constructor(
context: Context, context: Context,
@ -20,25 +20,28 @@ class MangaDexLoginPreference @JvmOverloads constructor(
layoutResource = R.layout.pref_item_mangadex layoutResource = R.layout.pref_item_mangadex
} }
var binding: PrefItemMangadexBinding? = null
private var onLoginClick: () -> Unit = {} private var onLoginClick: () -> Unit = {}
override fun onBindViewHolder(holder: PreferenceViewHolder) { override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder) super.onBindViewHolder(holder)
binding = PrefItemMangadexBinding.bind(holder.itemView)
holder.itemView.setOnClickListener { holder.itemView.setOnClickListener {
onLoginClick() onLoginClick()
} }
val loginFrame = holder.itemView.login_frame val loginFrame = binding?.loginFrame
val color = if (source.isLogged()) { val color = if (source.isLogged()) {
context.getResourceColor(R.attr.colorAccent) context.getResourceColor(R.attr.colorAccent)
} else { } else {
context.getResourceColor(R.attr.colorSecondary) context.getResourceColor(R.attr.colorSecondary)
} }
holder.itemView.login.setImageResource(R.drawable.ic_outline_people_alt_24dp) binding?.login?.setImageResource(R.drawable.ic_outline_people_alt_24dp)
holder.itemView.login.drawable.setTint(color) binding?.login?.drawable?.setTint(color)
loginFrame.isVisible = true loginFrame?.isVisible = true
loginFrame.setOnClickListener { loginFrame?.setOnClickListener {
onLoginClick() onLoginClick()
} }
} }

View File

@ -9,18 +9,13 @@ import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.customview.customView import com.afollestad.materialdialogs.customview.customView
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.databinding.PrefSiteLoginTwoFactorAuthBinding
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.source.online.all.MangaDex import eu.kanade.tachiyomi.source.online.all.MangaDex
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.widget.preference.LoginDialogPreference import eu.kanade.tachiyomi.widget.preference.LoginDialogPreference
import exh.source.getMainSource import exh.source.getMainSource
import kotlinx.android.synthetic.main.pref_site_login_two_factor_auth.view.login
import kotlinx.android.synthetic.main.pref_site_login_two_factor_auth.view.password
import kotlinx.android.synthetic.main.pref_site_login_two_factor_auth.view.two_factor_check
import kotlinx.android.synthetic.main.pref_site_login_two_factor_auth.view.two_factor_edit
import kotlinx.android.synthetic.main.pref_site_login_two_factor_auth.view.two_factor_holder
import kotlinx.android.synthetic.main.pref_site_login_two_factor_auth.view.username
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -36,6 +31,8 @@ class MangadexLoginDialog(bundle: Bundle? = null) : LoginDialogPreference(bundle
val scope = CoroutineScope(Job() + Dispatchers.Main) val scope = CoroutineScope(Job() + Dispatchers.Main)
var binding: PrefSiteLoginTwoFactorAuthBinding? = null
constructor(source: MangaDex) : this( constructor(source: MangaDex) : this(
bundleOf( bundleOf(
"key" to source.id "key" to source.id
@ -54,23 +51,24 @@ class MangadexLoginDialog(bundle: Bundle? = null) : LoginDialogPreference(bundle
override fun onViewCreated(view: View) { override fun onViewCreated(view: View) {
super.onViewCreated(view) super.onViewCreated(view)
v?.apply { v?.let { binding = PrefSiteLoginTwoFactorAuthBinding.bind(it) }
two_factor_check?.setOnCheckedChangeListener { _, isChecked -> binding?.apply {
two_factor_holder.isVisible = isChecked twoFactorCheck.setOnCheckedChangeListener { _, isChecked ->
twoFactorHolder.isVisible = isChecked
} }
} }
} }
override fun setCredentialsOnView(view: View) = with(view) { override fun setCredentialsOnView(view: View) {
username.setText(service.getUsername()) binding?.username?.setText(service.getUsername())
password.setText(service.getPassword()) binding?.password?.setText(service.getPassword())
} }
override fun checkLogin() { override fun checkLogin() {
v?.apply { binding?.apply {
if (username.text.isNullOrBlank() || password.text.isNullOrBlank() || (two_factor_check.isChecked && two_factor_edit.text.isNullOrBlank())) { if (username.text.isNullOrBlank() || password.text.isNullOrBlank() || (twoFactorCheck.isChecked && twoFactorEdit.text.isNullOrBlank())) {
errorResult() errorResult()
context.toast(R.string.fields_cannot_be_blank) root.context.toast(R.string.fields_cannot_be_blank)
return return
} }
@ -84,25 +82,25 @@ class MangadexLoginDialog(bundle: Bundle? = null) : LoginDialogPreference(bundle
val result = source?.login( val result = source?.login(
username.text.toString(), username.text.toString(),
password.text.toString(), password.text.toString(),
two_factor_edit.text.toString() twoFactorEdit.text.toString()
) ?: false ) ?: false
if (result) { if (result) {
dialog?.dismiss() dialog?.dismiss()
preferences.setTrackCredentials(Injekt.get<TrackManager>().mdList, username.toString(), password.toString()) preferences.setTrackCredentials(Injekt.get<TrackManager>().mdList, username.toString(), password.toString())
context.toast(R.string.login_success) root.context.toast(R.string.login_success)
} else { } else {
errorResult() errorResult()
} }
} catch (error: Exception) { } catch (error: Exception) {
errorResult() errorResult()
error.message?.let { context.toast(it) } error.message?.let { root.context.toast(it) }
} }
} }
} }
} }
private fun errorResult() { private fun errorResult() {
v?.apply { binding?.apply {
dialog?.setCancelable(true) dialog?.setCancelable(true)
dialog?.setCanceledOnTouchOutside(true) dialog?.setCanceledOnTouchOutside(true)
login.progress = -1 login.progress = -1

View File

@ -24,13 +24,13 @@
android:contentDescription="@string/migrating_to" android:contentDescription="@string/migrating_to"
android:scaleType="center" android:scaleType="center"
android:layout_marginBottom="45dp" android:layout_marginBottom="45dp"
android:tint="?attr/colorOnPrimary"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/migration_manga_card_to" app:layout_constraintEnd_toStartOf="@+id/migration_manga_card_to"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/migration_manga_card_from" app:layout_constraintStart_toEndOf="@+id/migration_manga_card_from"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_arrow_forward_24dp" /> app:srcCompat="@drawable/ic_arrow_forward_24dp"
app:tint="?attr/colorOnPrimary" />
<include <include
android:id="@+id/migration_manga_card_to" android:id="@+id/migration_manga_card_to"
@ -64,10 +64,10 @@
android:id="@+id/skip_manga" android:id="@+id/skip_manga"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:tint="?attr/colorOnPrimary"
app:layout_constraintBottom_toBottomOf="@+id/migration_menu" app:layout_constraintBottom_toBottomOf="@+id/migration_menu"
app:layout_constraintEnd_toEndOf="@+id/migration_menu" app:layout_constraintEnd_toEndOf="@+id/migration_menu"
app:layout_constraintStart_toStartOf="@+id/migration_menu" app:layout_constraintStart_toStartOf="@+id/migration_menu"
app:layout_constraintTop_toTopOf="@+id/migration_menu" app:layout_constraintTop_toTopOf="@+id/migration_menu"
app:srcCompat="@drawable/ic_close_24dp" /> app:srcCompat="@drawable/ic_close_24dp"
app:tint="?attr/colorOnPrimary" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>