Fuck motion layout

This commit is contained in:
Jobobby04 2021-08-27 01:17:33 -04:00
parent 77138aba72
commit 14be5c75ee
17 changed files with 1234 additions and 567 deletions

View File

@ -2,15 +2,10 @@ package eu.kanade.tachiyomi.ui.manga
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Point
import android.graphics.Rect
import android.graphics.RectF
import android.graphics.drawable.BitmapDrawable
import android.os.Bundle
import android.view.LayoutInflater
@ -18,8 +13,6 @@ import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.FloatRange
import androidx.appcompat.app.AppCompatActivity
@ -31,7 +24,6 @@ import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import coil.imageLoader
import coil.loadAny
import coil.request.ImageRequest
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
@ -85,7 +77,6 @@ import eu.kanade.tachiyomi.ui.manga.chapter.MangaChaptersHeaderAdapter
import eu.kanade.tachiyomi.ui.manga.chapter.base.BaseChaptersAdapter
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoButtonsAdapter
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoHeaderAdapter
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoItemAdapter
import eu.kanade.tachiyomi.ui.manga.merged.EditMergedSettingsDialog
import eu.kanade.tachiyomi.ui.manga.track.TrackItem
import eu.kanade.tachiyomi.ui.manga.track.TrackSearchDialog
@ -107,6 +98,7 @@ import eu.kanade.tachiyomi.util.view.snack
import exh.log.xLogD
import exh.md.similar.MangaDexSimilarController
import exh.metadata.metadata.base.FlatMetadata
import exh.metadata.metadata.base.RaisedSearchMetadata
import exh.recs.RecommendsController
import exh.source.MERGED_SOURCE_ID
import exh.source.getMainSource
@ -117,7 +109,6 @@ import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
import reactivecircus.flowbinding.android.view.clicks
import reactivecircus.flowbinding.recyclerview.scrollEvents
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
import timber.log.Timber
@ -192,15 +183,13 @@ class MangaController :
private var mangaInfoAdapter: MangaInfoHeaderAdapter? = null
// SY >--
private var mangaInfoItemAdapter: MangaInfoItemAdapter? = null
private var mangaInfoButtonsAdapter: MangaInfoButtonsAdapter? = null
private var mangaMetaInfoAdapter: RecyclerView.Adapter<*>? = null
// SY <--
private var chaptersHeaderAdapter: MangaChaptersHeaderAdapter? = null
private var chaptersAdapter: ChaptersAdapter? = null
// SY -->
private var mangaInfoButtonsAdapter: MangaInfoButtonsAdapter? = null
// SY <--
// Sheet containing filter/sort/display items.
private var settingsSheet: ChaptersSettingsSheet? = null
@ -237,8 +226,6 @@ class MangaController :
private var editMangaDialog: EditMangaDialog? = null
private var editMergedSettingsDialog: EditMergedSettingsDialog? = null
private var currentAnimator: Animator? = null
// EXH <--
init {
@ -298,18 +285,13 @@ class MangaController :
if (manga == null || source == null) return
// Init RecyclerView and adapter
mangaInfoAdapter = MangaInfoHeaderAdapter(this, binding.infoRecycler != null)
mangaInfoAdapter = MangaInfoHeaderAdapter(this, fromSource, binding.infoRecycler != null)
chaptersHeaderAdapter = MangaChaptersHeaderAdapter(this)
chaptersAdapter = ChaptersAdapter(this, view.context)
// SY -->
val mainSource = presenter.source.getMainSource<MetadataSource<*, *>>()
if (mainSource != null) {
mangaMetaInfoAdapter = mainSource.getDescriptionAdapter(this)
}
if (!preferences.recommendsInOverflow().get() || smartSearchConfig != null) {
mangaInfoButtonsAdapter = MangaInfoButtonsAdapter(this)
}
mangaInfoItemAdapter = MangaInfoItemAdapter(this, fromSource, binding.infoRecycler != null)
// SY <--
// Phone layout
@ -317,8 +299,6 @@ class MangaController :
it.adapter = ConcatAdapter(
listOfNotNull(
mangaInfoAdapter,
mangaMetaInfoAdapter,
mangaInfoItemAdapter,
mangaInfoButtonsAdapter,
chaptersHeaderAdapter,
chaptersAdapter
@ -346,9 +326,7 @@ class MangaController :
it.adapter = ConcatAdapter(
listOfNotNull(
mangaInfoAdapter,
mangaInfoButtonsAdapter,
mangaMetaInfoAdapter,
mangaInfoItemAdapter
mangaInfoButtonsAdapter
)
)
@ -459,11 +437,6 @@ class MangaController :
chaptersHeaderAdapter = null
chaptersAdapter = null
settingsSheet = null
// SY -->
mangaInfoButtonsAdapter = null
mangaInfoItemAdapter = null
mangaMetaInfoAdapter = null
// SY <--
addSnackbar?.dismiss()
updateToolbarTitleAlpha(1F)
toolbarTextView = null
@ -559,7 +532,7 @@ class MangaController :
val mainSource = presenter.source.getMainSource<MetadataSource<*, *>>()
if (mainSource != null) {
presenter.meta = flatMetadata.raise(mainSource.metaClass)
mangaMetaInfoAdapter?.notifyDataSetChanged()
mangaInfoAdapter?.notifyMetaAdapter()
updateFilterIconState()
}
}
@ -573,13 +546,10 @@ class MangaController :
* @param manga manga object containing information about manga.
* @param source the source of the manga.
*/
fun onNextMangaInfo(manga: Manga, source: Source) {
fun onNextMangaInfo(manga: Manga, source: Source, metadata: RaisedSearchMetadata?) {
if (manga.initialized) {
// Update view.
mangaInfoAdapter?.update(manga, source)
mangaInfoItemAdapter?.update(manga, source, presenter.meta)
binding.expandedImage.loadAny(manga)
mangaInfoAdapter?.update(manga, source, metadata, presenter.mergedMangaReferences)
} else {
// Initialize manga.
fetchMangaInfoFromSource()
@ -843,110 +813,6 @@ class MangaController :
presenter.moveMangaToCategories(manga, categories)
}
// SY -->
fun onThumbnailClick(thumbView: ImageView) {
if (!presenter.manga.initialized || presenter.manga.thumbnail_url == null) return
currentAnimator?.cancel()
val startBoundsInt = Rect()
val finalBoundsInt = Rect()
val globalOffset = Point()
thumbView.getGlobalVisibleRect(startBoundsInt)
binding.root.getGlobalVisibleRect(finalBoundsInt, globalOffset)
startBoundsInt.offset(-globalOffset.x, -globalOffset.y)
finalBoundsInt.offset(-globalOffset.x, -globalOffset.y)
val startBounds = RectF(startBoundsInt)
val finalBounds = RectF(finalBoundsInt)
val startScale: Float
if ((finalBounds.width() / finalBounds.height() > startBounds.width() / startBounds.height())) {
startScale = startBounds.height() / finalBounds.height()
val startWidth: Float = startScale * finalBounds.width()
val deltaWidth: Float = (startWidth - startBounds.width()) / 2
startBounds.left -= deltaWidth.toInt()
startBounds.right += deltaWidth.toInt()
} else {
startScale = startBounds.width() / finalBounds.width()
val startHeight: Float = startScale * finalBounds.height()
val deltaHeight: Float = (startHeight - startBounds.height()) / 2f
startBounds.top -= deltaHeight.toInt()
startBounds.bottom += deltaHeight.toInt()
}
thumbView.alpha = 0f
actionFab?.isVisible = false
binding.expandedImage.isVisible = true
binding.expandedImage.pivotX = 0f
binding.expandedImage.pivotY = 0f
currentAnimator = AnimatorSet().apply {
play(
ObjectAnimator.ofFloat(
binding.expandedImage,
View.X,
startBounds.left,
finalBounds.left
)
).apply {
with(ObjectAnimator.ofFloat(binding.expandedImage, View.Y, startBounds.top, finalBounds.top))
with(ObjectAnimator.ofFloat(binding.expandedImage, View.SCALE_X, startScale, 1f))
with(ObjectAnimator.ofFloat(binding.expandedImage, View.SCALE_Y, startScale, 1f))
}
duration = resources?.getInteger(android.R.integer.config_shortAnimTime)?.toLong() ?: 150L
interpolator = DecelerateInterpolator()
addListener(
object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
currentAnimator = null
}
override fun onAnimationCancel(animation: Animator) {
currentAnimator = null
}
}
)
start()
}
binding.expandedImage.clicks()
.onEach {
currentAnimator?.cancel()
currentAnimator = AnimatorSet().apply {
play(ObjectAnimator.ofFloat(binding.expandedImage, View.X, startBounds.left)).apply {
with(ObjectAnimator.ofFloat(binding.expandedImage, View.Y, startBounds.top))
with(ObjectAnimator.ofFloat(binding.expandedImage, View.SCALE_X, startScale))
with(ObjectAnimator.ofFloat(binding.expandedImage, View.SCALE_Y, startScale))
}
duration = resources?.getInteger(android.R.integer.config_shortAnimTime)?.toLong() ?: 150L
interpolator = DecelerateInterpolator()
addListener(
object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
thumbView.alpha = 1f
binding.expandedImage.isVisible = false
actionFab?.isVisible = presenter.filteredAndSortedChapters.any { !it.read }
currentAnimator = null
}
override fun onAnimationCancel(animation: Animator) {
thumbView.alpha = 1f
binding.expandedImage.isVisible = false
actionFab?.isVisible = presenter.filteredAndSortedChapters.any { !it.read }
currentAnimator = null
}
}
)
start()
}
}
.launchIn(viewScope)
}
// SY <--
/**
* Perform a global search using the provided query.
*

View File

@ -154,6 +154,8 @@ class MangaPresenter(
var mergedManga = emptyMap<Long, Manga>()
private set
var mergedMangaReferences = emptyList<MergedMangaReference>()
private set
var dedupe: Boolean = true
@ -166,6 +168,7 @@ class MangaPresenter(
// SY -->
if (source is MergedSource) {
launchIO { mergedManga = db.getMergedMangas(manga.id!!).executeAsBlocking().associateBy { it.id!! } }
launchIO { mergedMangaReferences = db.getMergedMangaReferences(manga.id!!).executeAsBlocking() }
}
// SY <--
@ -188,11 +191,13 @@ class MangaPresenter(
}
}
.subscribeLatestCache({ view, (manga, flatMetadata) ->
flatMetadata?.let { metadata ->
view.onNextMetaInfo(metadata)
}
val mainSource = source.getMainSource<MetadataSource<*, *>>()
val meta = if (mainSource != null) {
flatMetadata?.raise(mainSource.metaClass)
} else null
this.meta = meta
// SY <--
view.onNextMangaInfo(manga, source)
view.onNextMangaInfo(manga, source, meta)
})
getTrackingObservable()
@ -383,7 +388,7 @@ class MangaPresenter(
.observeOn(AndroidSchedulers.mainThread())
.subscribeLatestCache(
{ view, _ ->
view.onNextMangaInfo(manga, source)
view.onNextMangaInfo(manga, source, meta)
}
)
}

View File

@ -4,11 +4,13 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import coil.loadAny
import coil.target.ImageViewTarget
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.davidea.flexibleadapter.FlexibleAdapter
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.track.TrackManager
import eu.kanade.tachiyomi.databinding.MangaInfoHeaderBinding
@ -16,38 +18,48 @@ import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.source.online.all.MergedSource
import eu.kanade.tachiyomi.source.online.MetadataSource
import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.system.copyToClipboard
import eu.kanade.tachiyomi.util.view.setChips
import exh.merged.sql.models.MergedMangaReference
import exh.metadata.metadata.base.RaisedSearchMetadata
import exh.source.MERGED_SOURCE_ID
import exh.source.getMainSource
import exh.util.SourceTagsUtil
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.view.clicks
import reactivecircus.flowbinding.android.view.longClicks
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
class MangaInfoHeaderAdapter(
private val controller: MangaController,
private val isTablet: Boolean
private val fromSource: Boolean,
private val isTablet: Boolean,
) :
RecyclerView.Adapter<MangaInfoHeaderAdapter.HeaderViewHolder>() {
private val trackManager: TrackManager by injectLazy()
// SY -->
private val db: DatabaseHelper by injectLazy()
private val sourceManager: SourceManager by injectLazy()
private var mergedMangaReferences: List<MergedMangaReference> = emptyList()
// SY <--
private var manga: Manga = controller.presenter.manga
private var source: Source = controller.presenter.source
// SY -->
private var meta: RaisedSearchMetadata? = controller.presenter.meta
private var mergedMangaReferences: List<MergedMangaReference> = controller.presenter.mergedMangaReferences
// SY <--
private var trackCount: Int = 0
private var metaInfoAdapter: RecyclerView.Adapter<*>? = null
private var mangaTagsInfoAdapter: NamespaceTagsAdapter = NamespaceTagsAdapter(controller, source)
private lateinit var binding: MangaInfoHeaderBinding
@ -55,6 +67,20 @@ class MangaInfoHeaderAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder {
binding = MangaInfoHeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
// SY -->
metaInfoAdapter = source.getMainSource<MetadataSource<*, *>>()?.getDescriptionAdapter(controller)
binding.metadataView.isVisible = if (metaInfoAdapter != null) {
binding.metadataView.layoutManager = LinearLayoutManager(binding.root.context)
binding.metadataView.adapter = metaInfoAdapter
true
} else {
false
}
binding.genreGroups.layoutManager = LinearLayoutManager(binding.root.context)
binding.genreGroups.adapter = mangaTagsInfoAdapter
// SY <--
return HeaderViewHolder(binding.root)
}
@ -70,16 +96,16 @@ class MangaInfoHeaderAdapter(
* @param manga manga object containing information about manga.
* @param source the source of the manga.
*/
fun update(manga: Manga, source: Source) {
fun update(manga: Manga, source: Source, meta: RaisedSearchMetadata?, mergedMangaReferences: List<MergedMangaReference>) {
this.manga = manga
this.source = source
// SY -->
if (source is MergedSource) {
mergedMangaReferences = db.getMergedMangaReferences(manga.id!!).executeAsBlocking()
}
this.meta = meta
this.mergedMangaReferences = mergedMangaReferences
// SY <--
notifyDataSetChanged()
notifyMetaAdapter()
}
fun setTrackingCount(trackCount: Int) {
@ -88,14 +114,22 @@ class MangaInfoHeaderAdapter(
notifyDataSetChanged()
}
fun notifyMetaAdapter() {
metaInfoAdapter?.notifyDataSetChanged()
}
inner class HeaderViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
fun bind() {
// For rounded corners
binding.mangaCover.clipToOutline = true
// SY -->
binding.mangaCover.clicks()
.onEach { controller.onThumbnailClick(binding.mangaCover) }
.launchIn(controller.viewScope)
mangaTagsInfoAdapter.mItemClickListener = FlexibleAdapter.OnItemClickListener { _, _ ->
controller.viewScope.launchUI {
toggleMangaInfo()
}
false
}
// SY <--
binding.btnFavorite.clicks()
@ -209,13 +243,22 @@ class MangaInfoHeaderAdapter(
}
.launchIn(controller.viewScope)
binding.mangaSummaryText.longClicks()
.onEach {
controller.activity?.copyToClipboard(
view.context.getString(R.string.description),
binding.mangaSummaryText.text.toString()
)
}
.launchIn(controller.viewScope)
binding.mangaCover.longClicks()
.onEach {
showCoverOptionsDialog()
}
.launchIn(controller.viewScope)
setMangaInfo(manga, source)
setMangaInfo(manga, source, meta)
}
private fun showCoverOptionsDialog() {
@ -245,7 +288,7 @@ class MangaInfoHeaderAdapter(
* @param manga manga object containing information about manga.
* @param source the source of the manga.
*/
private fun setMangaInfo(manga: Manga, source: Source?) {
private fun setMangaInfo(manga: Manga, source: Source?, meta: RaisedSearchMetadata?) {
// Update full title TextView.
binding.mangaFullTitle.text = if (manga.title.isBlank()) {
view.context.getString(R.string.unknown)
@ -278,7 +321,6 @@ class MangaInfoHeaderAdapter(
} else /* SY <-- */ if (mangaSource != null) {
text = mangaSource
setOnClickListener {
val sourceManager = Injekt.get<SourceManager>()
controller.performSearch(sourceManager.getOrStub(source.id).name)
}
} else {
@ -305,16 +347,141 @@ class MangaInfoHeaderAdapter(
setFavoriteButtonState(manga.favorite)
// Set cover if changed.
listOf(binding.mangaCover, binding.backdrop).forEach {
it.loadAny(manga)
binding.backdrop.loadAny(manga)
binding.mangaCover.loadAny(manga) {
listener(
onSuccess = { request, _ ->
(request.target as? ImageViewTarget)?.drawable?.let { drawable ->
val ratio = drawable.minimumWidth / drawable.minimumHeight.toFloat()
binding.root.getConstraintSet(R.id.end)
?.setDimensionRatio(R.id.manga_cover, ratio.toString())
}
}
)
}
if (initialLoad && isTablet) {
initialLoad = false
// wrap_content and autoFixTextSize can cause unwanted behaviour this tries to solve it
binding.mangaFullTitle.requestLayout()
// Manga info section
val hasInfoContent = !manga.description.isNullOrBlank() || !manga.genre.isNullOrBlank()
showMangaInfo(hasInfoContent)
if (hasInfoContent) {
// Update description TextView.
binding.mangaSummaryText.text = if (manga.description.isNullOrBlank()) {
view.context.getString(R.string.unknown)
} else {
manga.description
}
// SY -->
if (manga.description == "meta") {
binding.mangaSummaryText.text = ""
/*binding.mangaInfoToggleLess.updateLayoutParams<ConstraintLayout.LayoutParams> {
topToBottom = -1
bottomToBottom = binding.mangaSummaryText.id
}*/
}
// SY <--
// Update genres list
if (!manga.genre.isNullOrBlank()) {
binding.mangaGenresTagsCompactChips.setChips(
manga.getGenres(),
controller::performGenreSearch
)
// SY -->
// if (source?.getMainSource<NamespaceSource>() != null) {
setChipsWithNamespace(
manga.genre,
meta
)
// binding.mangaGenresTagsFullChips.isVisible = false
/*} else {
binding.mangaGenresTagsFullChips.setChips(
manga.getGenres(),
controller::performGenreSearch
)
binding.genreGroups.isVisible = false
}*/
// SY <--
} else {
binding.mangaGenresTagsCompactChips.isVisible = false
// binding.mangaGenresTagsFullChips.isVisible = false
// SY -->
binding.genreGroups.isVisible = false
// SY <--
}
// Handle showing more or less info
merge(
binding.mangaSummaryText.clicks(),
binding.mangaInfoToggleMore.clicks(),
binding.mangaInfoToggleLess.clicks(),
binding.mangaSummarySection.clicks()
)
.onEach { toggleMangaInfo() }
.launchIn(controller.viewScope)
// Expand manga info if navigated from source listing or explicitly set to
// (e.g. on tablets)
if (initialLoad && (fromSource || isTablet)) {
toggleMangaInfo()
initialLoad = false
// wrap_content and autoFixTextSize can cause unwanted behaviour this tries to solve it
binding.mangaFullTitle.requestLayout()
}
// Refreshes will change the state and it needs to be set to correct state to display correctly
if (binding.mangaSummaryText.maxLines == 2) {
binding.mangaSummarySection.transitionToState(R.id.start)
} else {
binding.mangaSummarySection.transitionToState(R.id.end)
}
}
}
private fun showMangaInfo(visible: Boolean) {
binding.mangaSummarySection.isVisible = visible
}
private fun toggleMangaInfo() {
val isCurrentlyExpanded = binding.mangaSummaryText.maxLines != 2
if (isCurrentlyExpanded) {
binding.mangaSummarySection.transitionToStart()
} else {
binding.mangaSummarySection.transitionToEnd()
}
binding.mangaSummaryText.maxLines = if (isCurrentlyExpanded) {
2
} else {
Int.MAX_VALUE
}
}
private fun setChipsWithNamespace(genre: String?, meta: RaisedSearchMetadata?) {
val namespaceTags = when {
meta != null -> {
meta.tags
.filterNot { it.type == RaisedSearchMetadata.TAG_TYPE_VIRTUAL }
.groupBy { it.namespace }
.map { (namespace, tags) ->
NamespaceTagsItem(
namespace,
tags.map {
it.name to it.type
}
)
}
}
genre != null -> {
listOf(NamespaceTagsItem(null, genre.split(",").map { it.trim() to null }))
}
else -> emptyList()
}
mangaTagsInfoAdapter.updateDataSet(namespaceTags)
}
/**
* Update favorite button with correct drawable and text.
*

View File

@ -1,229 +0,0 @@
package eu.kanade.tachiyomi.ui.manga.info
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.databinding.MangaInfoItemBinding
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.online.NamespaceSource
import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.system.copyToClipboard
import exh.metadata.metadata.base.RaisedSearchMetadata
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
import exh.source.getMainSource
import exh.source.isEhBasedSource
import exh.util.getRaisedTags
import exh.util.makeSearchChip
import exh.util.setChipsExtended
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import reactivecircus.flowbinding.android.view.clicks
import reactivecircus.flowbinding.android.view.longClicks
class MangaInfoItemAdapter(
private val controller: MangaController,
private val fromSource: Boolean,
private val isTablet: Boolean
) :
RecyclerView.Adapter<MangaInfoItemAdapter.HeaderViewHolder>() {
private var manga: Manga = controller.presenter.manga
private var source: Source = controller.presenter.source
private var meta: RaisedSearchMetadata? = controller.presenter.meta
private lateinit var binding: MangaInfoItemBinding
private var initialLoad: Boolean = true
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder {
binding = MangaInfoItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return HeaderViewHolder(binding.root)
}
private var mangaTagsInfoAdapter: FlexibleAdapter<IFlexible<*>>? = FlexibleAdapter(null)
override fun getItemCount(): Int = 1
override fun onBindViewHolder(holder: HeaderViewHolder, position: Int) {
holder.bind()
}
/**
* Update the view with manga information.
*
* @param manga manga object containing information about manga.
* @param source the source of the manga.
*/
fun update(manga: Manga, source: Source, meta: RaisedSearchMetadata?) {
this.manga = manga
this.source = source
this.meta = meta
notifyDataSetChanged()
}
inner class HeaderViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
fun bind() {
binding.mangaSummaryText.longClicks()
.onEach {
controller.activity?.copyToClipboard(
view.context.getString(R.string.description),
binding.mangaSummaryText.text.toString()
)
}
.launchIn(controller.viewScope)
binding.genreGroups.layoutManager = LinearLayoutManager(itemView.context)
binding.genreGroups.adapter = mangaTagsInfoAdapter
// SY -->
mangaTagsInfoAdapter?.mItemClickListener = FlexibleAdapter.OnItemClickListener { _, _ ->
controller.viewScope.launch {
toggleMangaInfo()
}
false
}
// SY <--
setMangaInfo(manga, source)
}
/**
* Update the view with manga information.
*
* @param manga manga object containing information about manga.
* @param source the source of the manga.
*/
private fun setMangaInfo(manga: Manga, source: Source?) {
// Manga info section
val hasInfoContent = !manga.description.isNullOrBlank() || !manga.genre.isNullOrBlank()
showMangaInfo(hasInfoContent)
if (hasInfoContent) {
// Update description TextView.
binding.mangaSummaryText.text = if (manga.description.isNullOrBlank()) {
view.context.getString(R.string.unknown)
} else {
manga.description
}
// SY -->
if (binding.mangaSummaryText.text == "meta") {
binding.mangaSummaryText.text = ""
binding.mangaSummaryText.maxLines = 1
binding.mangaInfoToggleLess.updateLayoutParams<ConstraintLayout.LayoutParams> {
topToBottom = -1
bottomToBottom = binding.mangaSummaryText.id
}
}
// SY <--
// Update genres list
if (!manga.genre.isNullOrBlank()) {
// SY -->
if (source != null && source.getMainSource() is NamespaceSource) {
val metaTags = meta?.tags?.filterNot { it.type == TAG_TYPE_VIRTUAL }?.groupBy { it.namespace }
var namespaceTags: List<NamespaceTagsItem> = emptyList()
if (source.isEhBasedSource() && metaTags != null && metaTags.all { it.key != null }) {
namespaceTags = metaTags
.mapValues { values ->
values.value.map {
itemView.context.makeSearchChip(
it.name,
controller::performSearch,
controller::performGlobalSearch,
source.id,
it.namespace,
it.type
)
}
}
.map { NamespaceTagsItem(it.key!!, it.value) }
} else {
val genre = manga.getRaisedTags()
if (!genre.isNullOrEmpty()) {
namespaceTags = genre
.groupBy { it.namespace }
.mapValues { values ->
values.value.map {
itemView.context.makeSearchChip(
it.name,
controller::performSearch,
controller::performGlobalSearch,
source.id,
it.namespace
)
}
}
.map { NamespaceTagsItem(it.key, it.value) }
}
}
mangaTagsInfoAdapter?.updateDataSet(namespaceTags)
}
binding.mangaGenresTagsFullChips.setChipsExtended(manga.getGenres(), controller::performGenreSearch, controller::performGlobalSearch, source?.id ?: 0)
binding.mangaGenresTagsCompactChips.setChipsExtended(manga.getGenres(), controller::performGenreSearch, controller::performGlobalSearch, source?.id ?: 0)
// SY <--
} else {
binding.mangaGenresTagsCompactChips.isVisible = false
binding.mangaGenresTagsFullChips.isVisible = false
// SY -->
binding.genreGroups.isVisible = false
// SY <--
}
// Handle showing more or less info
merge(
binding.mangaSummarySection.clicks(),
binding.mangaSummaryText.clicks(),
binding.mangaInfoToggleMore.clicks(),
binding.mangaInfoToggleLess.clicks()
)
.onEach { toggleMangaInfo() }
.launchIn(controller.viewScope)
// Expand manga info if navigated from source listing
if (initialLoad && (fromSource || isTablet)) {
toggleMangaInfo()
initialLoad = false
}
}
}
private fun showMangaInfo(visible: Boolean) {
binding.mangaSummarySection.isVisible = visible
}
private fun toggleMangaInfo() {
val isCurrentlyExpanded = binding.mangaSummaryText.maxLines != 2 /* SY --> */ && binding.mangaSummaryText.maxLines != 1 /* SY <-- */
binding.mangaInfoToggleMoreScrim.isVisible = isCurrentlyExpanded
binding.mangaInfoToggleMore.isVisible = isCurrentlyExpanded
binding.mangaInfoToggleLess.isVisible = !isCurrentlyExpanded
binding.mangaSummaryText.maxLines = if (isCurrentlyExpanded) {
/* SY --> */ if (binding.mangaSummaryText.text.isBlank()) 1 else /* SY <-- */ 2
} else {
Int.MAX_VALUE
}
binding.mangaGenresTagsCompact.isVisible = isCurrentlyExpanded
// SY -->
if (source.getMainSource() !is NamespaceSource) {
binding.mangaGenresTagsFullChips.isVisible = !isCurrentlyExpanded
} else {
binding.genreGroups.isVisible = !isCurrentlyExpanded
}
// SY <--
}
}
}

View File

@ -0,0 +1,8 @@
package eu.kanade.tachiyomi.ui.manga.info
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.ui.manga.MangaController
class NamespaceTagsAdapter(val controller: MangaController, val source: Source) :
FlexibleAdapter<NamespaceTagsItem>(null, controller, true)

View File

@ -0,0 +1,40 @@
package eu.kanade.tachiyomi.ui.manga.info
import android.view.View
import com.google.android.material.chip.Chip
import eu.davidea.viewholders.FlexibleViewHolder
import eu.kanade.tachiyomi.databinding.MangaInfoGenreGroupingBinding
import exh.util.makeSearchChip
class NamespaceTagsHolder(
view: View,
val adapter: NamespaceTagsAdapter
) : FlexibleViewHolder(view, adapter) {
val binding = MangaInfoGenreGroupingBinding.bind(view)
fun bind(item: NamespaceTagsItem) {
binding.namespace.removeAllViews()
val namespace = item.namespace
if (namespace != null) {
binding.namespace.addView(
Chip(binding.root.context).apply {
text = namespace
}
)
}
binding.tags.removeAllViews()
item.tags.map { (tag, type) ->
binding.root.context.makeSearchChip(
tag,
adapter.controller::performSearch,
adapter.controller::performGlobalSearch,
adapter.source.id,
namespace,
type
)
}.forEach {
binding.tags.addView(it)
}
}
}

View File

@ -2,46 +2,43 @@ package eu.kanade.tachiyomi.ui.manga.info
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder
import eu.kanade.tachiyomi.R
open class NamespaceTagsItem(val namespace: String?, val tags: List<Chip>) : AbstractFlexibleItem<NamespaceTagsItem.Holder>() {
class NamespaceTagsItem(val namespace: String?, val tags: List<Pair<String, Int?>>) :
AbstractFlexibleItem<NamespaceTagsHolder>() {
override fun getLayoutRes(): Int {
return R.layout.manga_info_genre_grouping
}
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
return Holder(view, adapter)
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): NamespaceTagsHolder {
return NamespaceTagsHolder(view, adapter as NamespaceTagsAdapter)
}
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: List<Any?>?) {
val namespaceChip = Chip(holder.itemView.context)
namespaceChip.text = namespace ?: holder.itemView.context.getString(R.string.unknown)
holder.namespaceChipGroup.addView(namespaceChip)
tags.forEach {
holder.tagsChipGroup.addView(it)
}
override fun bindViewHolder(
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
holder: NamespaceTagsHolder,
position: Int,
payloads: List<Any?>?
) {
holder.bind(this)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
return namespace == (other as NamespaceTagsItem).namespace
other as NamespaceTagsItem
if (namespace != other.namespace) return false
return true
}
override fun hashCode(): Int {
return namespace.hashCode()
}
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
val namespaceChipGroup: ChipGroup = itemView.findViewById(R.id.namespace)
val tagsChipGroup: ChipGroup = itemView.findViewById(R.id.tags)
}
}

View File

@ -122,5 +122,3 @@ fun Date.toRelativeString(
else -> dateFormat.format(this)
}
}

View File

@ -12,7 +12,12 @@ import exh.source.nHentaiSourceIds
import java.util.Locale
object SourceTagsUtil {
fun getWrappedTag(sourceId: Long, namespace: String? = null, tag: String? = null, fullTag: String? = null): String? {
fun getWrappedTag(
sourceId: Long?,
namespace: String? = null,
tag: String? = null,
fullTag: String? = null
): String? {
return if (sourceId == EXH_SOURCE_ID || sourceId == EH_SOURCE_ID || sourceId in nHentaiSourceIds || sourceId in hitomiSourceIds) {
val parsed = when {
fullTag != null -> parseTag(fullTag)

View File

@ -24,7 +24,14 @@ fun ChipGroup.setChipsExtended(items: List<String>?, onClick: (item: String) ->
}
}
fun Context.makeSearchChip(item: String, onClick: (item: String) -> Unit = {}, onLongClick: (item: String) -> Unit = {}, sourceId: Long, namespace: String? = null, type: Int? = null): Chip {
fun Context.makeSearchChip(
item: String,
onClick: (item: String) -> Unit = {},
onLongClick: (item: String) -> Unit = {},
sourceId: Long,
namespace: String? = null,
type: Int? = null
): Chip {
return Chip(this).apply {
text = item
val search = if (namespace != null) {

View File

@ -74,10 +74,4 @@
app:fastScrollerBubbleEnabled="false"
tools:visibility="visible" />
<ImageView
android:id="@+id/expanded_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,317 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout 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:orientation="vertical"
app:layoutDescription="@xml/manga_info_header_scene_sw720dp"
tools:context=".ui.browse.source.browse.BrowseSourceController">
<ImageView
android:id="@+id/backdrop"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="-32dp"
android:alpha="0.2"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="@+id/manga_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:background="@mipmap/ic_launcher"
tools:ignore="ContentDescription" />
<View
android:id="@+id/backdrop_overlay"
android:layout_width="0dp"
android:layout_height="0dp"
android:alpha="1"
android:background="@drawable/manga_info_gradient"
android:backgroundTint="?android:attr/colorBackground"
app:layout_constraintBottom_toBottomOf="@+id/backdrop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/manga_cover"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="@dimen/tablet_horizontal_cover_margin"
android:layout_marginTop="32dp"
android:layout_marginEnd="@dimen/tablet_horizontal_cover_margin"
android:background="@drawable/rounded_rectangle"
android:contentDescription="@string/description_cover"
android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="w,3:2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@mipmap/ic_launcher" />
<LinearLayout
android:id="@+id/manga_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="-8dp"
android:layout_marginEnd="16dp"
android:gravity="center_horizontal"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/backdrop">
<TextView
android:id="@+id/manga_full_title"
style="@style/TextAppearance.Medium.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:gravity="center"
android:text="@string/manga_info_full_title_label"
android:textIsSelectable="false" />
<TextView
android:id="@+id/manga_author"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textIsSelectable="false"
tools:text="Author" />
<TextView
android:id="@+id/manga_artist"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:textIsSelectable="false"
tools:text="Artist" />
<LinearLayout
android:id="@+id/manga_status_row"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/manga_status"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:ellipsize="end"
android:maxLines="1"
android:textIsSelectable="false"
tools:text="Status" />
<TextView
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:text="•"
android:textIsSelectable="false"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/manga_source"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textIsSelectable="false"
tools:text="Source" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/manga_actions"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_detail">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_favorite"
style="@style/Widget.Tachiyomi.Button.ActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/add_to_library"
app:icon="@drawable/ic_favorite_border_24dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_tracking"
style="@style/Widget.Tachiyomi.Button.ActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/manga_tracking_tab"
android:visibility="gone"
app:icon="@drawable/ic_sync_24dp"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_webview"
style="@style/Widget.Tachiyomi.Button.ActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/action_web_view"
android:visibility="gone"
app:icon="@drawable/ic_public_24dp"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_merge"
style="@style/Widget.Tachiyomi.Button.ActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/merge"
android:visibility="gone"
app:icon="@drawable/ic_merge_type_24dp"
tools:visibility="visible" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/metadata_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_actions"
tools:visibility="gone" />
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/manga_summary_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layoutDescription="@xml/manga_summary_section_scene"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/metadata_view">
<TextView
android:id="@+id/manga_summary_text"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:clickable="true"
android:focusable="true"
android:maxLines="2"
android:textIsSelectable="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_cover"
tools:text="Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content" />
<View
android:id="@+id/manga_info_toggle_more_scrim"
android:layout_width="20dp"
android:layout_height="0dp"
android:background="@drawable/manga_info_more_gradient"
android:backgroundTint="?android:attr/colorBackground"
app:layout_constraintBottom_toBottomOf="@+id/manga_info_toggle_more"
app:layout_constraintEnd_toStartOf="@+id/manga_info_toggle_more"
app:layout_constraintTop_toTopOf="@+id/manga_info_toggle_more" />
<com.google.android.material.button.MaterialButton
android:id="@+id/manga_info_toggle_more"
style="@style/Widget.Tachiyomi.Button.InlineButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="16dp"
android:text="@string/manga_info_expand"
android:textAlignment="viewEnd"
app:layout_constraintBottom_toBottomOf="@+id/manga_summary_text"
app:layout_constraintEnd_toEndOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/manga_info_toggle_less"
style="@style/Widget.Tachiyomi.Button.InlineButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="16dp"
android:text="@string/manga_info_collapse"
android:textAlignment="viewEnd"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_summary_text"
tools:visibility="gone" />
<HorizontalScrollView
android:id="@+id/manga_genres_tags_compact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:requiresFadingEdge="horizontal"
android:scrollbars="none"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_summary_text">
<com.google.android.material.chip.ChipGroup
android:id="@+id/manga_genres_tags_compact_chips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
app:chipSpacingHorizontal="4dp"
app:singleLine="true" />
</HorizontalScrollView>
<!--<com.google.android.material.chip.ChipGroup
android:id="@+id/manga_genres_tags_full_chips"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:visibility="gone"
app:chipSpacingHorizontal="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less"
tools:visibility="gone" />-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/genre_groups"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:visibility="gone"
android:nestedScrollingEnabled="false"
tools:listitem="@layout/manga_info_genre_grouping"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
</androidx.constraintlayout.motion.widget.MotionLayout>

View File

@ -48,10 +48,4 @@
android:layout_gravity="bottom"
app:layout_dodgeInsetEdges="bottom" />
<ImageView
android:id="@+id/expanded_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -1,161 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.motion.widget.MotionLayout 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:orientation="vertical"
app:layoutDescription="@xml/manga_info_header_scene"
tools:context=".ui.browse.source.browse.BrowseSourceController">
<androidx.constraintlayout.widget.ConstraintLayout
<ImageView
android:id="@+id/backdrop"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="-8dp"
android:alpha="0.2"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="@+id/manga_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:background="@mipmap/ic_launcher"
tools:ignore="ContentDescription" />
<View
android:id="@+id/backdrop_overlay"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="160dp"
android:background="@drawable/manga_info_gradient"
android:backgroundTint="?android:attr/colorBackground"
app:layout_constraintBottom_toBottomOf="@+id/backdrop" />
<ImageView
android:id="@+id/backdrop"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="44dp"
android:alpha="0.2"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:background="@mipmap/ic_launcher" />
<ImageView
android:id="@+id/manga_cover"
android:layout_width="100dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="48dp"
android:background="@drawable/rounded_rectangle"
android:contentDescription="@string/description_cover"
android:maxWidth="100dp"
android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="w,3:2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_height="133dp"
tools:src="@mipmap/ic_launcher" />
<View
android:id="@+id/backdrop_overlay"
<LinearLayout
android:id="@+id/manga_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@+id/manga_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/manga_cover">
<TextView
android:id="@+id/manga_full_title"
style="@style/TextAppearance.Medium.Title"
android:layout_width="match_parent"
android:layout_height="160dp"
android:layout_marginBottom="44dp"
android:background="@drawable/manga_info_gradient"
android:backgroundTint="?android:attr/colorBackground"
app:layout_constraintBottom_toBottomOf="parent" />
android:layout_height="60sp"
android:layout_marginBottom="4dp"
android:gravity="bottom"
android:text="@string/manga_info_full_title_label"
android:textIsSelectable="false"
app:autoSizeMaxTextSize="20sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform" />
<TextView
android:id="@+id/manga_author"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="false"
tools:text="Author" />
<TextView
android:id="@+id/manga_artist"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="false"
tools:text="Artist" />
<LinearLayout
android:id="@+id/manga_info"
android:layout_width="match_parent"
android:id="@+id/manga_status_row"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingTop="48dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
app:layout_constraintTop_toTopOf="parent">
android:layout_marginTop="4dp">
<eu.kanade.tachiyomi.ui.manga.info.MangaCoverImageView
android:id="@+id/manga_cover"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/rounded_rectangle"
android:contentDescription="@string/description_cover"
android:maxWidth="100dp"
android:scaleType="centerCrop"
tools:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/manga_status"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:ellipsize="end"
android:maxLines="1"
android:textIsSelectable="false"
tools:text="Status" />
<LinearLayout
<TextView
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginStart="16dp"
android:layout_marginBottom="16dp"
android:orientation="vertical">
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:text="•"
android:textIsSelectable="false"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/manga_full_title"
style="@style/TextAppearance.Medium.Title"
android:layout_width="wrap_content"
android:layout_height="60sp"
android:gravity="bottom"
android:text="@string/manga_info_full_title_label"
android:textIsSelectable="false"
app:autoSizeMaxTextSize="20sp"
app:autoSizeMinTextSize="12sp"
app:autoSizeStepGranularity="2sp"
app:autoSizeTextType="uniform" />
<TextView
android:id="@+id/manga_author"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textIsSelectable="false"
tools:text="Author" />
<TextView
android:id="@+id/manga_artist"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="false"
tools:text="Artist" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp">
<TextView
android:id="@+id/manga_status"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:ellipsize="end"
android:maxLines="1"
android:textIsSelectable="false"
tools:text="Status" />
<TextView
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:text="•"
android:textIsSelectable="false"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/manga_source"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textIsSelectable="false"
tools:text="Source" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/manga_source"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textIsSelectable="false"
tools:text="Source" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/manga_actions"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/backdrop">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_favorite"
style="@style/Widget.Tachiyomi.Button.ActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:text="@string/add_to_library"
app:icon="@drawable/ic_favorite_border_24dp"
app:layout_constraintEnd_toStartOf="@+id/btn_tracking"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_info" />
app:icon="@drawable/ic_favorite_border_24dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_tracking"
style="@style/Widget.Tachiyomi.Button.ActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/manga_tracking_tab"
android:visibility="gone"
app:icon="@drawable/ic_sync_24dp"
app:layout_constraintEnd_toStartOf="@+id/btn_webview"
app:layout_constraintStart_toEndOf="@+id/btn_favorite"
app:layout_constraintTop_toBottomOf="@+id/manga_info"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
@ -163,29 +161,150 @@
style="@style/Widget.Tachiyomi.Button.ActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/action_web_view"
android:visibility="gone"
app:icon="@drawable/ic_public_24dp"
app:layout_constraintEnd_toStartOf="@+id/btn_merge"
app:layout_constraintStart_toEndOf="@+id/btn_tracking"
app:layout_constraintTop_toBottomOf="@+id/manga_info"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_merge"
style="@style/Widget.Tachiyomi.Button.ActionButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:text="@string/merge"
android:visibility="gone"
app:icon="@drawable/ic_merge_type_24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/btn_webview"
app:layout_constraintTop_toBottomOf="@+id/manga_info"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/metadata_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_actions"
tools:visibility="gone" />
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/manga_summary_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutDescription="@xml/manga_summary_section_scene"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/metadata_view">
<TextView
android:id="@+id/manga_summary_text"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:clickable="true"
android:focusable="true"
android:maxLines="2"
android:textIsSelectable="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_cover"
tools:text="Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content" />
<View
android:id="@+id/manga_info_toggle_more_scrim"
android:layout_width="20dp"
android:layout_height="0dp"
android:background="@drawable/manga_info_more_gradient"
android:backgroundTint="?android:attr/colorBackground"
app:layout_constraintBottom_toBottomOf="@+id/manga_info_toggle_more"
app:layout_constraintEnd_toStartOf="@+id/manga_info_toggle_more"
app:layout_constraintTop_toTopOf="@+id/manga_info_toggle_more" />
<com.google.android.material.button.MaterialButton
android:id="@+id/manga_info_toggle_more"
style="@style/Widget.Tachiyomi.Button.InlineButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="16dp"
android:text="@string/manga_info_expand"
android:textAlignment="viewEnd"
app:layout_constraintBottom_toBottomOf="@+id/manga_summary_text"
app:layout_constraintEnd_toEndOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/manga_info_toggle_less"
style="@style/Widget.Tachiyomi.Button.InlineButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="16dp"
android:text="@string/manga_info_collapse"
android:textAlignment="viewEnd"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_summary_text"
tools:visibility="gone" />
<HorizontalScrollView
android:id="@+id/manga_genres_tags_compact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:requiresFadingEdge="horizontal"
android:scrollbars="none"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_summary_text">
<com.google.android.material.chip.ChipGroup
android:id="@+id/manga_genres_tags_compact_chips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
app:chipSpacingHorizontal="4dp"
app:singleLine="true" />
</HorizontalScrollView>
<!--<com.google.android.material.chip.ChipGroup
android:id="@+id/manga_genres_tags_full_chips"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:visibility="gone"
app:chipSpacingHorizontal="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less"
tools:visibility="gone" />-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/genre_groups"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:visibility="gone"
android:nestedScrollingEnabled="false"
tools:listitem="@layout/manga_info_genre_grouping"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
</androidx.constraintlayout.motion.widget.MotionLayout>

View File

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="@android:integer/config_mediumAnimTime">
<KeyFrameSet></KeyFrameSet>
<OnClick motion:targetId="@+id/manga_cover" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/metadata_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/manga_actions"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/manga_summary_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/metadata_view"
motion:visibilityMode="ignore" />
<Constraint
motion:layout_constraintEnd_toEndOf="parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
motion:layout_constraintTop_toBottomOf="@id/backdrop"
motion:layout_constraintStart_toStartOf="parent"
android:id="@+id/manga_actions"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp" />
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/backdrop"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="-8dp"
android:alpha="0"
motion:layout_constraintBottom_toBottomOf="@+id/manga_cover"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:transitionEasing="cubic(0,1,0,1)" />
<Constraint
android:id="@+id/backdrop_overlay"
android:layout_width="match_parent"
android:layout_height="160dp"
android:layout_marginBottom="-16dp"
android:alpha="0"
motion:layout_constraintBottom_toBottomOf="@+id/backdrop"
motion:transitionEasing="cubic(0,1,0,1)" />
<Constraint
android:id="@+id/manga_cover"
android:layout_marginStart="0dp"
android:layout_marginTop="0dp"
motion:layout_constraintDimensionRatio="2:3"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<Constraint
android:id="@+id/btn_favorite"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
motion:layout_constraintEnd_toStartOf="@+id/btn_tracking"
motion:layout_constraintHorizontal_bias="0.5"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/manga_detail"
android:layout_marginStart="16dp" />
<Constraint
android:id="@+id/manga_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/manga_cover" />
<Constraint
android:id="@+id/btn_tracking"
android:layout_width="0dp"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toStartOf="@+id/btn_webview"
motion:layout_constraintHorizontal_bias="0.5"
motion:layout_constraintStart_toEndOf="@+id/btn_favorite"
motion:layout_constraintTop_toTopOf="@+id/btn_favorite"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/btn_tracking"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:visibility="visible"
motion:layout_constraintEnd_toStartOf="@+id/btn_webview"
motion:layout_constraintHorizontal_bias="0.5"
motion:layout_constraintStart_toEndOf="@+id/btn_favorite"
motion:layout_constraintTop_toTopOf="@+id/btn_favorite"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/btn_webview"
android:layout_width="0dp"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintHorizontal_bias="0.5"
motion:layout_constraintStart_toEndOf="@+id/btn_tracking"
motion:layout_constraintTop_toTopOf="@+id/btn_favorite"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/btn_merge"
android:layout_width="0dp"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintHorizontal_bias="0.5"
motion:layout_constraintStart_toEndOf="@+id/btn_webview"
motion:layout_constraintTop_toTopOf="@+id/btn_favorite"
motion:visibilityMode="ignore"
android:layout_marginEnd="16dp" />
<Constraint
android:id="@+id/metadata_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/manga_actions"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/manga_summary_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/metadata_view"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/manga_actions"
motion:layout_constraintEnd_toEndOf="parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
motion:layout_constraintTop_toBottomOf="@id/manga_detail"
motion:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="8dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp" />
</ConstraintSet>
</MotionScene>

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="@android:integer/config_mediumAnimTime">
<KeyFrameSet></KeyFrameSet>
<OnClick motion:targetId="@+id/manga_cover" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/manga_summary_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/metadata_view"
motion:visibilityMode="ignore" />
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/manga_summary_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/metadata_view"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/manga_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_cover" />
<Constraint
motion:layout_constraintEnd_toEndOf="parent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="0dp"
android:layout_marginStart="0dp"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintDimensionRatio="w,3:2"
android:layout_marginTop="0dp"
android:id="@+id/manga_cover" />
</ConstraintSet>
</MotionScene>

View File

@ -0,0 +1,162 @@
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1">
<KeyFrameSet></KeyFrameSet>
<OnClick motion:clickAction="toggle" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/manga_info_toggle_more_scrim"
android:layout_width="20dp"
android:layout_height="0dp"
android:visibility="visible"
motion:layout_constraintBottom_toBottomOf="@+id/manga_info_toggle_more"
motion:layout_constraintEnd_toStartOf="@+id/manga_info_toggle_more"
motion:layout_constraintTop_toTopOf="@+id/manga_info_toggle_more" />
<Constraint
android:id="@+id/manga_info_toggle_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
motion:layout_constraintBottom_toBottomOf="@+id/manga_summary_text"
motion:layout_constraintEnd_toEndOf="parent" />
<Constraint
android:id="@+id/manga_info_toggle_less"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text" />
<Constraint
android:id="@+id/manga_genres_tags_compact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text" />
<!--<Constraint
android:id="@+id/manga_genres_tags_full_chips"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:visibility="gone"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less" />-->
<Constraint
android:id="@+id/genre_groups"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:visibility="gone"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less" />
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/manga_info_toggle_more_scrim"
android:layout_width="20dp"
android:layout_height="0dp"
android:visibility="gone"
motion:layout_constraintBottom_toBottomOf="@+id/manga_info_toggle_more"
motion:layout_constraintEnd_toStartOf="@+id/manga_info_toggle_more"
motion:layout_constraintTop_toTopOf="@+id/manga_info_toggle_more" />
<Constraint
android:id="@+id/manga_info_toggle_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
motion:layout_constraintBottom_toBottomOf="@+id/manga_summary_text"
motion:layout_constraintEnd_toEndOf="parent" />
<Constraint
android:id="@+id/manga_info_toggle_less"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text" />
<Constraint
android:id="@+id/manga_genres_tags_compact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text" />
<!-- <Constraint
android:id="@+id/manga_genres_tags_full_chips"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:visibility="visible"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less" />-->
<Constraint
android:id="@+id/genre_groups"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:visibility="visible"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less" />
<Constraint
android:id="@+id/manga_summary_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_cover"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/manga_summary_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_cover"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/manga_summary_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_cover"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/manga_summary_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/manga_cover"
motion:visibilityMode="ignore" />
</ConstraintSet>
</MotionScene>