Grid items optimizations (#6641)

Use ConstraintLayout for ez size ratio calculation and merge cover-only view
holder with compact's

(cherry picked from commit fad1449de34952e12e2c5464dccf500d49fa7fa1)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceItem.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryComfortableGridHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCompactGridHolder.kt
#	app/src/main/res/layout/source_comfortable_grid_item.xml
#	app/src/main/res/layout/source_compact_grid_item.xml
This commit is contained in:
Ivan Iskandar 2022-02-13 23:09:49 +07:00 committed by Jobobby04
parent a12758579d
commit c293fd61b1
14 changed files with 280 additions and 522 deletions

View File

@ -113,7 +113,7 @@ class MigrationProcessHolder(
if (adapter.hideNotFound) { if (adapter.hideNotFound) {
adapter.removeManga(bindingAdapterPosition) adapter.removeManga(bindingAdapterPosition)
} else { } else {
binding.migrationMangaCardTo.loadingGroup.isVisible = false binding.migrationMangaCardTo.progress.isVisible = false
binding.migrationMangaCardTo.title.text = view.context.applicationContext binding.migrationMangaCardTo.title.text = view.context.applicationContext
.getString(R.string.no_alternatives_found) .getString(R.string.no_alternatives_found)
} }
@ -126,20 +126,18 @@ class MigrationProcessHolder(
} }
private fun MigrationMangaCardBinding.resetManga() { private fun MigrationMangaCardBinding.resetManga() {
loadingGroup.isVisible = true progress.isVisible = true
thumbnail.clear() thumbnail.clear()
thumbnail.setImageDrawable(null) thumbnail.setImageDrawable(null)
title.text = "" title.text = ""
mangaSourceLabel.text = "" mangaSourceLabel.text = ""
mangaChapters.text = "" badges.unreadText.text = ""
mangaChapters.isVisible = false badges.unreadText.isVisible = false
mangaLastChapterLabel.text = "" mangaLastChapterLabel.text = ""
} }
private suspend fun MigrationMangaCardBinding.attachManga(manga: Manga, source: Source) { private suspend fun MigrationMangaCardBinding.attachManga(manga: Manga, source: Source) {
loadingGroup.isVisible = false progress.isVisible = false
// For rounded corners
card.clipToOutline = true
thumbnail.loadAny(manga) thumbnail.loadAny(manga)
title.text = if (manga.title.isBlank()) { title.text = if (manga.title.isBlank()) {
@ -148,7 +146,6 @@ class MigrationProcessHolder(
manga.originalTitle manga.originalTitle
} }
gradient.isVisible = true
mangaSourceLabel.text = if (source.id == MERGED_SOURCE_ID) { mangaSourceLabel.text = if (source.id == MERGED_SOURCE_ID) {
db.getMergedMangaReferences(manga.id!!).executeOnIO().map { db.getMergedMangaReferences(manga.id!!).executeOnIO().map {
sourceManager.getOrStub(it.mangaSourceId).toString() sourceManager.getOrStub(it.mangaSourceId).toString()
@ -158,8 +155,8 @@ class MigrationProcessHolder(
} }
val chapters = db.getChapters(manga).executeAsBlocking() val chapters = db.getChapters(manga).executeAsBlocking()
mangaChapters.isVisible = true badges.unreadText.isVisible = true
mangaChapters.text = chapters.size.toString() badges.unreadText.text = chapters.size.toString()
val latestChapter = chapters.maxByOrNull { it.chapter_number }?.chapter_number ?: -1f val latestChapter = chapters.maxByOrNull { it.chapter_number }?.chapter_number ?: -1f
if (latestChapter > 0f) { if (latestChapter > 0f) {

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.ui.browse.source.browse package eu.kanade.tachiyomi.ui.browse.source.browse
import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import coil.clear import coil.clear
import coil.imageLoader import coil.imageLoader
@ -19,14 +18,14 @@ import exh.metadata.metadata.base.RaisedSearchMetadata
* Class used to hold the displayed data of a manga in the catalogue, like the cover or the title. * Class used to hold the displayed data of a manga in the catalogue, like the cover or the title.
* All the elements from the layout file "item_source_grid" are available in this class. * All the elements from the layout file "item_source_grid" are available in this class.
* *
* @param view the inflated view for this holder. * @param binding the inflated view for this holder.
* @param adapter the adapter handling this holder. * @param adapter the adapter handling this holder.
* @constructor creates a new catalogue holder. * @constructor creates a new catalogue holder.
*/ */
class SourceComfortableGridHolder(private val view: View, private val adapter: FlexibleAdapter<*>) : class SourceComfortableGridHolder(
SourceHolder<SourceComfortableGridItemBinding>(view, adapter) { override val binding: SourceComfortableGridItemBinding,
adapter: FlexibleAdapter<*>
override val binding = SourceComfortableGridItemBinding.bind(view) ) : SourceHolder<SourceComfortableGridItemBinding>(binding.root, adapter) {
/** /**
* Method called from [CatalogueAdapter.onBindViewHolder]. It updates the data for this * Method called from [CatalogueAdapter.onBindViewHolder]. It updates the data for this
@ -67,15 +66,12 @@ class SourceComfortableGridHolder(private val view: View, private val adapter: F
// SY <-- // SY <--
override fun setImage(manga: Manga) { override fun setImage(manga: Manga) {
// For rounded corners
binding.card.clipToOutline = true
binding.thumbnail.clear() binding.thumbnail.clear()
if (!manga.thumbnail_url.isNullOrEmpty()) { if (!manga.thumbnail_url.isNullOrEmpty()) {
val crossfadeDuration = view.context.imageLoader.defaults.transition.let { val crossfadeDuration = binding.root.context.imageLoader.defaults.transition.let {
if (it is CrossfadeTransition) it.durationMillis else 0 if (it is CrossfadeTransition) it.durationMillis else 0
} }
val request = ImageRequest.Builder(view.context) val request = ImageRequest.Builder(binding.root.context)
.data(manga) .data(manga)
.setParameter(MangaCoverFetcher.USE_CUSTOM_COVER, false) .setParameter(MangaCoverFetcher.USE_CUSTOM_COVER, false)
.target(StateImageViewTarget(binding.thumbnail, binding.progress, crossfadeDuration)) .target(StateImageViewTarget(binding.thumbnail, binding.progress, crossfadeDuration))

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.ui.browse.source.browse package eu.kanade.tachiyomi.ui.browse.source.browse
import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import coil.clear import coil.clear
import coil.imageLoader import coil.imageLoader
@ -19,14 +18,14 @@ import exh.metadata.metadata.base.RaisedSearchMetadata
* Class used to hold the displayed data of a manga in the catalogue, like the cover or the title. * Class used to hold the displayed data of a manga in the catalogue, like the cover or the title.
* All the elements from the layout file "item_source_grid" are available in this class. * All the elements from the layout file "item_source_grid" are available in this class.
* *
* @param view the inflated view for this holder. * @param binding the inflated view for this holder.
* @param adapter the adapter handling this holder. * @param adapter the adapter handling this holder.
* @constructor creates a new catalogue holder. * @constructor creates a new catalogue holder.
*/ */
open class SourceCompactGridHolder(private val view: View, private val adapter: FlexibleAdapter<*>) : class SourceCompactGridHolder(
SourceHolder<SourceCompactGridItemBinding>(view, adapter) { override val binding: SourceCompactGridItemBinding,
adapter: FlexibleAdapter<*>
override val binding = SourceCompactGridItemBinding.bind(view) ) : SourceHolder<SourceCompactGridItemBinding>(binding.root, adapter) {
/** /**
* Method called from [CatalogueAdapter.onBindViewHolder]. It updates the data for this * Method called from [CatalogueAdapter.onBindViewHolder]. It updates the data for this
@ -67,15 +66,12 @@ open class SourceCompactGridHolder(private val view: View, private val adapter:
// SY <-- // SY <--
override fun setImage(manga: Manga) { override fun setImage(manga: Manga) {
// For rounded corners
binding.card.clipToOutline = true
binding.thumbnail.clear() binding.thumbnail.clear()
if (!manga.thumbnail_url.isNullOrEmpty()) { if (!manga.thumbnail_url.isNullOrEmpty()) {
val crossfadeDuration = view.context.imageLoader.defaults.transition.let { val crossfadeDuration = binding.root.context.imageLoader.defaults.transition.let {
if (it is CrossfadeTransition) it.durationMillis else 0 if (it is CrossfadeTransition) it.durationMillis else 0
} }
val request = ImageRequest.Builder(view.context) val request = ImageRequest.Builder(binding.root.context)
.data(manga) .data(manga)
.setParameter(MangaCoverFetcher.USE_CUSTOM_COVER, false) .setParameter(MangaCoverFetcher.USE_CUSTOM_COVER, false)
.target(StateImageViewTarget(binding.thumbnail, binding.progress, crossfadeDuration)) .target(StateImageViewTarget(binding.thumbnail, binding.progress, crossfadeDuration))

View File

@ -1,10 +1,6 @@
package eu.kanade.tachiyomi.ui.browse.source.browse package eu.kanade.tachiyomi.ui.browse.source.browse
import android.view.Gravity
import android.view.View import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.FrameLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.fredporciuncula.flow.preferences.Preference import com.fredporciuncula.flow.preferences.Preference
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
@ -16,7 +12,6 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding
import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import exh.metadata.metadata.base.RaisedSearchMetadata import exh.metadata.metadata.base.RaisedSearchMetadata
import exh.source.isEhBasedManga import exh.source.isEhBasedManga
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -34,9 +29,9 @@ class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMo
} }
// SY <-- // SY <--
return when (displayMode.get()) { return when (displayMode.get()) {
DisplayModeSetting.LIST -> R.layout.source_list_item DisplayModeSetting.COMPACT_GRID, DisplayModeSetting.COVER_ONLY_GRID -> R.layout.source_compact_grid_item
DisplayModeSetting.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item DisplayModeSetting.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item
else -> R.layout.source_compact_grid_item DisplayModeSetting.LIST -> R.layout.source_list_item
} }
} }
@ -50,37 +45,14 @@ class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMo
} }
// SY <-- // SY <--
return when (displayMode.get()) { return when (displayMode.get()) {
DisplayModeSetting.LIST -> { DisplayModeSetting.COMPACT_GRID, DisplayModeSetting.COVER_ONLY_GRID -> {
SourceListHolder(view, adapter) SourceCompactGridHolder(SourceCompactGridItemBinding.bind(view), adapter)
} }
DisplayModeSetting.COMFORTABLE_GRID -> { DisplayModeSetting.COMFORTABLE_GRID -> {
val binding = SourceComfortableGridItemBinding.bind(view) SourceComfortableGridHolder(SourceComfortableGridItemBinding.bind(view), adapter)
val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4
view.apply {
binding.card.layoutParams = ConstraintLayout.LayoutParams(
MATCH_PARENT,
coverHeight
)
} }
SourceComfortableGridHolder(view, adapter) DisplayModeSetting.LIST -> {
} SourceListHolder(view, adapter)
else -> {
val binding = SourceCompactGridItemBinding.bind(view)
val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4
view.apply {
binding.card.layoutParams = FrameLayout.LayoutParams(
MATCH_PARENT,
coverHeight
)
binding.gradient.layoutParams = FrameLayout.LayoutParams(
MATCH_PARENT,
coverHeight / 2,
Gravity.BOTTOM
)
}
SourceCompactGridHolder(view, adapter)
} }
} }
} }

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.ui.library package eu.kanade.tachiyomi.ui.library
import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import coil.clear import coil.clear
@ -17,17 +16,15 @@ import reactivecircus.flowbinding.android.view.clicks
* Class used to hold the displayed data of a manga in the library, like the cover or the title. * Class used to hold the displayed data of a manga in the library, like the cover or the title.
* All the elements from the layout file "item_source_grid" are available in this class. * All the elements from the layout file "item_source_grid" are available in this class.
* *
* @param view the inflated view for this holder. * @param binding the inflated view for this holder.
* @param adapter the adapter handling this holder. * @param adapter the adapter handling this holder.
* @param listener a listener to react to single tap and long tap events. * @param listener a listener to react to single tap and long tap events.
* @constructor creates a new library holder. * @constructor creates a new library holder.
*/ */
class LibraryComfortableGridHolder( class LibraryComfortableGridHolder(
private val view: View, override val binding: SourceComfortableGridItemBinding,
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>> adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
) : LibraryHolder<SourceComfortableGridItemBinding>(view, adapter) { ) : LibraryHolder<SourceComfortableGridItemBinding>(binding.root, adapter) {
override val binding = SourceComfortableGridItemBinding.bind(view)
// SY --> // SY -->
var manga: Manga? = null var manga: Manga? = null
@ -80,9 +77,6 @@ class LibraryComfortableGridHolder(
binding.playLayout.isVisible = (item.manga.unreadCount > 0 && item.startReadingButton) binding.playLayout.isVisible = (item.manga.unreadCount > 0 && item.startReadingButton)
// SY <-- // SY <--
// For rounded corners
binding.card.clipToOutline = true
// Update the cover. // Update the cover.
binding.thumbnail.clear() binding.thumbnail.clear()
binding.thumbnail.loadAnyAutoPause(item.manga) binding.thumbnail.loadAnyAutoPause(item.manga)

View File

@ -1,17 +1,10 @@
package eu.kanade.tachiyomi.ui.library package eu.kanade.tachiyomi.ui.library
import android.view.View
import android.widget.FrameLayout
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updateMargins
import androidx.recyclerview.widget.RecyclerView
import coil.clear import coil.clear
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.view.loadAnyAutoPause import eu.kanade.tachiyomi.util.view.loadAnyAutoPause
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -19,21 +12,18 @@ import reactivecircus.flowbinding.android.view.clicks
/** /**
* Class used to hold the displayed data of a manga in the library, like the cover or the title. * Class used to hold the displayed data of a manga in the library, like the cover or the title.
* All the elements from the layout file "item_source_grid" are available in this class. * All the elements from the layout file "source_compact_grid_item" are available in this class.
* *
* @param view the inflated view for this holder. * @param binding the inflated view for this holder.
* @param adapter the adapter handling this holder. * @param adapter the adapter handling this holder.
* @param listener a listener to react to single tap and long tap events. * @param coverOnly true if title should be hidden a.k.a cover only mode.
* @constructor creates a new library holder. * @constructor creates a new library holder.
*/ */
class LibraryCompactGridHolder( class LibraryCompactGridHolder(
private val view: View, override val binding: SourceCompactGridItemBinding,
// SY --> adapter: FlexibleAdapter<*>,
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>> private val coverOnly: Boolean
// SY <-- ) : LibraryHolder<SourceCompactGridItemBinding>(binding.root, adapter) {
) : LibraryHolder<SourceCompactGridItemBinding>(view, adapter) {
override val binding = SourceCompactGridItemBinding.bind(view)
// SY --> // SY -->
var manga: Manga? = null var manga: Manga? = null
@ -83,23 +73,24 @@ class LibraryCompactGridHolder(
binding.badges.localText.isVisible = item.isLocal binding.badges.localText.isVisible = item.isLocal
// SY --> // SY -->
val topMargin = if (item.sourceLanguage.isNotEmpty()) {
16.dpToPx
} else {
0.dpToPx
}
binding.playLayout.updateLayoutParams<FrameLayout.LayoutParams> {
updateMargins(top = topMargin)
}
binding.playLayout.isVisible = (item.manga.unreadCount > 0 && item.startReadingButton) binding.playLayout.isVisible = (item.manga.unreadCount > 0 && item.startReadingButton)
// SY <-- // SY <--
// For rounded corners
binding.card.clipToOutline = true
// Update the cover. // Update the cover.
binding.thumbnail.clear() binding.thumbnail.clear()
if (coverOnly) {
// Cover only mode: Hides title text unless thumbnail is unavailable
if (!item.manga.thumbnail_url.isNullOrEmpty()) {
binding.thumbnail.loadAnyAutoPause(item.manga) binding.thumbnail.loadAnyAutoPause(item.manga)
binding.title.isVisible = false
} else {
binding.title.text = item.manga.title
binding.title.isVisible = true
}
binding.thumbnail.foreground = null
} else {
binding.thumbnail.loadAnyAutoPause(item.manga)
}
} }
// SY --> // SY -->

View File

@ -1,60 +0,0 @@
package eu.kanade.tachiyomi.ui.library
import android.view.View
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import coil.clear
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.databinding.SourceCoverOnlyGridItemBinding
import eu.kanade.tachiyomi.util.view.loadAnyAutoPause
class LibraryCoverOnlyGridHolder(
view: View,
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
) : LibraryHolder<SourceCoverOnlyGridItemBinding>(view, adapter) {
override val binding = SourceCoverOnlyGridItemBinding.bind(view)
/**
* Method called from [LibraryCategoryAdapter.onBindViewHolder]. It updates the data for this
* holder with the given manga.
*
* @param item the manga item to bind.
*/
override fun onSetValues(item: LibraryItem) {
// For rounded corners
binding.badges.leftBadges.clipToOutline = true
binding.badges.rightBadges.clipToOutline = true
// Update the unread count and its visibility.
with(binding.badges.unreadText) {
isVisible = item.unreadCount > 0
text = item.unreadCount.toString()
}
// Update the download count and its visibility.
with(binding.badges.downloadText) {
isVisible = item.downloadCount > 0
text = item.downloadCount.toString()
}
// Update the source language and its visibility
with(binding.badges.languageText) {
isVisible = item.sourceLanguage.isNotEmpty()
text = item.sourceLanguage
}
// set local visibility if its local manga
binding.badges.localText.isVisible = item.isLocal
// For rounded corners
binding.card.clipToOutline = true
// Update the cover.
binding.thumbnail.clear()
if (!item.manga.thumbnail_url.isNullOrEmpty()) {
binding.thumbnail.loadAnyAutoPause(item.manga)
} else {
// Set manga title
binding.title.text = item.manga.title
}
}
}

View File

@ -1,10 +1,8 @@
package eu.kanade.tachiyomi.ui.library package eu.kanade.tachiyomi.ui.library
import android.view.View import android.view.View
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder import eu.davidea.viewholders.FlexibleViewHolder
/** /**
@ -16,9 +14,7 @@ import eu.davidea.viewholders.FlexibleViewHolder
abstract class LibraryHolder<VB : ViewBinding>( abstract class LibraryHolder<VB : ViewBinding>(
view: View, view: View,
// SY --> val adapter: FlexibleAdapter<*>
val adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
// SY <--
) : FlexibleViewHolder(view, adapter) { ) : FlexibleViewHolder(view, adapter) {
abstract val binding: VB abstract val binding: VB

View File

@ -1,10 +1,6 @@
package eu.kanade.tachiyomi.ui.library package eu.kanade.tachiyomi.ui.library
import android.view.Gravity
import android.view.View import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.FrameLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.fredporciuncula.flow.preferences.Preference import com.fredporciuncula.flow.preferences.Preference
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
@ -15,10 +11,8 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding
import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding
import eu.kanade.tachiyomi.databinding.SourceCoverOnlyGridItemBinding
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -51,9 +45,8 @@ class LibraryItem(
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return when (getDisplayMode()) { return when (getDisplayMode()) {
DisplayModeSetting.COMPACT_GRID -> R.layout.source_compact_grid_item DisplayModeSetting.COMPACT_GRID, DisplayModeSetting.COVER_ONLY_GRID -> R.layout.source_compact_grid_item
DisplayModeSetting.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item DisplayModeSetting.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item
DisplayModeSetting.COVER_ONLY_GRID -> R.layout.source_cover_only_grid_item
DisplayModeSetting.LIST -> R.layout.source_list_item DisplayModeSetting.LIST -> R.layout.source_list_item
} }
} }
@ -61,42 +54,13 @@ class LibraryItem(
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LibraryHolder<*> { override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LibraryHolder<*> {
return when (getDisplayMode()) { return when (getDisplayMode()) {
DisplayModeSetting.COMPACT_GRID -> { DisplayModeSetting.COMPACT_GRID -> {
val binding = SourceCompactGridItemBinding.bind(view) LibraryCompactGridHolder(SourceCompactGridItemBinding.bind(view), adapter, coverOnly = false)
val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4
view.apply {
binding.card.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight)
binding.gradient.layoutParams = FrameLayout.LayoutParams(
MATCH_PARENT,
coverHeight / 2,
Gravity.BOTTOM
)
}
LibraryCompactGridHolder(view, adapter)
}
DisplayModeSetting.COMFORTABLE_GRID -> {
val binding = SourceComfortableGridItemBinding.bind(view)
val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4
view.apply {
binding.card.layoutParams = ConstraintLayout.LayoutParams(
MATCH_PARENT,
coverHeight
)
}
LibraryComfortableGridHolder(view, adapter)
} }
DisplayModeSetting.COVER_ONLY_GRID -> { DisplayModeSetting.COVER_ONLY_GRID -> {
val binding = SourceCoverOnlyGridItemBinding.bind(view) LibraryCompactGridHolder(SourceCompactGridItemBinding.bind(view), adapter, coverOnly = true)
val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4
view.apply {
binding.card.layoutParams = ConstraintLayout.LayoutParams(
MATCH_PARENT,
coverHeight
)
} }
LibraryCoverOnlyGridHolder(view, adapter) DisplayModeSetting.COMFORTABLE_GRID -> {
LibraryComfortableGridHolder(SourceComfortableGridItemBinding.bind(view), adapter)
} }
DisplayModeSetting.LIST -> { DisplayModeSetting.LIST -> {
LibraryListHolder(view, adapter) LibraryListHolder(view, adapter)

View File

@ -5,8 +5,9 @@
<gradient <gradient
android:angle="90" android:angle="90"
android:centerColor="#00000000" android:centerColor="#00000000"
android:centerY="0.3"
android:endColor="#00ffffff" android:endColor="#00ffffff"
android:startColor="#aa000000" /> android:startColor="#aa000000" />
<corners android:radius="0dp" /> <corners android:radius="@dimen/card_radius" />
</shape> </shape>

View File

@ -4,69 +4,37 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/library_item_selector"> android:layout_margin="2dp"
android:background="@drawable/library_item_selector"
android:foreground="@drawable/library_item_selector_overlay"
android:padding="4dp">
<FrameLayout <com.google.android.material.imageview.ShapeableImageView
android:id="@+id/card" android:id="@+id/thumbnail"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="220dp" android:layout_height="220dp"
android:background="@drawable/rounded_rectangle" android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="0.75" android:foreground="@drawable/card_gradient_shape"
app:layout_constraintDimensionRatio="w,2:3"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_min="100dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_min="100dp"> app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Cover"
tools:ignore="ContentDescription"
<ImageView
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:src="@mipmap/ic_launcher" /> tools:src="@mipmap/ic_launcher" />
<View <include
android:id="@+id/gradient" android:id="@+id/badges"
layout="@layout/source_grid_item_badges"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom" android:layout_marginHorizontal="4dp"
android:background="@drawable/gradient_shape" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/loading_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
app:indicatorSize="56dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:background="@drawable/rounded_rectangle" app:layout_constraintEnd_toEndOf="@+id/thumbnail"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintStart_toStartOf="@+id/thumbnail"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="@+id/thumbnail" />
<TextView <TextView
android:id="@+id/manga_chapters"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/colorSecondary"
android:paddingStart="3dp"
android:paddingTop="1dp"
android:paddingEnd="3dp"
android:paddingBottom="1dp"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textColor="?attr/colorOnSecondary"
android:textSize="12sp"
android:visibility="gone"
tools:text="101"
tools:visibility="visible" />
</LinearLayout>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title" android:id="@+id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -81,19 +49,11 @@
android:textAppearance="?attr/textAppearanceTitleSmall" android:textAppearance="?attr/textAppearanceTitleSmall"
android:textColor="@color/md_white_1000" android:textColor="@color/md_white_1000"
android:textSize="12sp" android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/thumbnail"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="Sample name" /> tools:text="Sample name" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progress"
style="@style/Widget.Tachiyomi.CircularProgressIndicator.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="gone" />
</FrameLayout>
<LinearLayout <LinearLayout
android:id="@+id/card_scroll_content" android:id="@+id/card_scroll_content"
android:layout_width="0dp" android:layout_width="0dp"
@ -101,10 +61,9 @@
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:gravity="start" android:gravity="start"
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintEnd_toEndOf="@id/card" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintStart_toStartOf="@id/card" app:layout_constraintTop_toBottomOf="@id/thumbnail">
app:layout_constraintTop_toBottomOf="@id/card">
<TextView <TextView
android:id="@+id/manga_source_label" android:id="@+id/manga_source_label"
@ -116,9 +75,7 @@
android:paddingTop="4dp" android:paddingTop="4dp"
android:paddingBottom="1dp" android:paddingBottom="1dp"
android:textAppearance="?attr/textAppearanceTitleSmall" android:textAppearance="?attr/textAppearanceTitleSmall"
android:textIsSelectable="false" android:textIsSelectable="false" />
app:layout_constraintLeft_toLeftOf="parent"
tools:layout_editor_absoluteY="57dp" />
<TextView <TextView
android:id="@+id/manga_last_chapter_label" android:id="@+id/manga_last_chapter_label"
@ -132,4 +89,18 @@
android:textIsSelectable="false" /> android:textIsSelectable="false" />
</LinearLayout> </LinearLayout>
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progress"
style="@style/Widget.Tachiyomi.CircularProgressIndicator.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -9,28 +9,43 @@
android:foreground="@drawable/library_item_selector_overlay" android:foreground="@drawable/library_item_selector_overlay"
android:padding="4dp"> android:padding="4dp">
<androidx.constraintlayout.widget.ConstraintLayout <com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="match_parent" android:id="@+id/progress"
android:layout_height="wrap_content"> style="@style/Widget.Tachiyomi.CircularProgressIndicator.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/thumbnail"
app:layout_constraintEnd_toEndOf="@+id/thumbnail"
app:layout_constraintStart_toStartOf="@+id/thumbnail"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<FrameLayout <com.google.android.material.imageview.ShapeableImageView
android:id="@+id/card" android:id="@+id/thumbnail"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="220dp" android:layout_height="0dp"
android:background="@drawable/rounded_rectangle" android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="w,3:2"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Cover"
<ImageView
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:scaleType="centerCrop"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@mipmap/ic_launcher" /> tools:src="@mipmap/ic_launcher" />
<include
android:id="@+id/badges"
layout="@layout/source_grid_item_badges"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4dp"
android:layout_marginTop="4dp"
app:layout_constraintEnd_toEndOf="@+id/thumbnail"
app:layout_constraintStart_toStartOf="@+id/thumbnail"
app:layout_constraintTop_toTopOf="@+id/thumbnail" />
<FrameLayout <FrameLayout
android:id="@+id/play_layout" android:id="@+id/play_layout"
android:layout_width="50dp" android:layout_width="50dp"
@ -39,6 +54,8 @@
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/thumbnail"
app:layout_constraintEnd_toEndOf="@+id/thumbnail"
tools:visibility="visible"> tools:visibility="visible">
<ImageView <ImageView
@ -46,9 +63,9 @@
android:layout_width="30dp" android:layout_width="30dp"
android:layout_height="30dp" android:layout_height="30dp"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginStart="6dp"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:layout_marginEnd="6dp" android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:layout_marginBottom="6dp" android:layout_marginBottom="6dp"
android:background="@drawable/round_play_background" android:background="@drawable/round_play_background"
android:contentDescription="@string/action_start_reading" android:contentDescription="@string/action_start_reading"
@ -57,21 +74,6 @@
app:tint="@android:color/white" /> app:tint="@android:color/white" />
</FrameLayout> </FrameLayout>
<include
android:id="@+id/badges"
layout="@layout/source_grid_item_badges" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progress"
style="@style/Widget.Tachiyomi.CircularProgressIndicator.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="gone" />
</FrameLayout>
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -80,12 +82,10 @@
android:maxLines="2" android:maxLines="2"
android:padding="4dp" android:padding="4dp"
android:textAppearance="?attr/textAppearanceTitleSmall" android:textAppearance="?attr/textAppearanceTitleSmall"
android:textSize="12sp"
android:textColor="@color/source_comfortable_item_title" android:textColor="@color/source_comfortable_item_title"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/card" app:layout_constraintTop_toBottomOf="@+id/thumbnail"
tools:text="Sample name" /> tools:text="Sample name" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -9,27 +9,31 @@
android:foreground="@drawable/library_item_selector_overlay" android:foreground="@drawable/library_item_selector_overlay"
android:padding="4dp"> android:padding="4dp">
<FrameLayout <com.google.android.material.imageview.ShapeableImageView
android:id="@+id/card"
android:layout_width="wrap_content"
android:layout_height="220dp"
android:background="@drawable/rounded_rectangle">
<ImageView
android:id="@+id/thumbnail" android:id="@+id/thumbnail"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="0dp"
android:background="?attr/colorSurface"
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:foreground="@drawable/card_gradient_shape"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="w,2:3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Cover"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@mipmap/ic_launcher" /> tools:src="@mipmap/ic_launcher" />
<View <include
android:id="@+id/gradient" android:id="@+id/badges"
layout="@layout/source_grid_item_badges"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom" android:layout_marginHorizontal="4dp"
android:background="@drawable/gradient_shape" /> android:layout_marginTop="4dp"
app:layout_constraintEnd_toEndOf="@+id/thumbnail"
app:layout_constraintStart_toStartOf="@+id/thumbnail"
app:layout_constraintTop_toTopOf="@+id/thumbnail" />
<FrameLayout <FrameLayout
android:id="@+id/play_layout" android:id="@+id/play_layout"
@ -39,6 +43,8 @@
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="@id/thumbnail"
app:layout_constraintTop_toBottomOf="@+id/badges"
tools:visibility="visible"> tools:visibility="visible">
<ImageView <ImageView
@ -46,9 +52,9 @@
android:layout_width="30dp" android:layout_width="30dp"
android:layout_height="30dp" android:layout_height="30dp"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginStart="6dp"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:layout_marginEnd="6dp" android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:layout_marginBottom="6dp" android:layout_marginBottom="6dp"
android:background="@drawable/round_play_background" android:background="@drawable/round_play_background"
android:contentDescription="@string/action_start_reading" android:contentDescription="@string/action_start_reading"
@ -57,10 +63,6 @@
app:tint="@android:color/white" /> app:tint="@android:color/white" />
</FrameLayout> </FrameLayout>
<include
android:id="@+id/badges"
layout="@layout/source_grid_item_badges" />
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -74,8 +76,11 @@
android:shadowDy="0" android:shadowDy="0"
android:shadowRadius="4" android:shadowRadius="4"
android:textAppearance="?attr/textAppearanceTitleSmall" android:textAppearance="?attr/textAppearanceTitleSmall"
android:textSize="12sp"
android:textColor="@color/md_white_1000" android:textColor="@color/md_white_1000"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/thumbnail"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="Sample name" /> tools:text="Sample name" />
<com.google.android.material.progressindicator.CircularProgressIndicator <com.google.android.material.progressindicator.CircularProgressIndicator
@ -85,8 +90,11 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:indeterminate="true" android:indeterminate="true"
android:visibility="gone" /> android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
</FrameLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@ -1,68 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:layout_margin="2dp"
android:background="@drawable/library_item_selector"
android:foreground="@drawable/library_item_selector_overlay"
android:padding="4dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="220dp"
android:background="@drawable/rounded_rectangle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:scaleType="centerCrop"
tools:ignore="ContentDescription"
tools:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:ellipsize="end"
android:maxLines="2"
android:padding="8dp"
android:shadowColor="@color/md_black_1000"
android:shadowDx="0"
android:shadowDy="0"
android:shadowRadius="4"
android:textAppearance="?attr/textAppearanceTitleSmall"
android:textSize="12sp"
android:textColor="@color/md_white_1000"
tools:text="Sample name" />
<include
android:id="@+id/badges"
layout="@layout/source_grid_item_badges" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progress"
style="@style/Widget.Tachiyomi.CircularProgressIndicator.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="gone" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>