diff --git a/.idea/misc.xml b/.idea/misc.xml
index b8f888114..56dc302cc 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -4,6 +4,8 @@
diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/ChipsView.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/ChipsView.kt
new file mode 100644
index 000000000..52ca53616
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/ChipsView.kt
@@ -0,0 +1,96 @@
+package org.koitharu.kotatsu.base.ui.widgets
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View.OnClickListener
+import androidx.annotation.DrawableRes
+import androidx.core.view.children
+import com.google.android.material.R
+import com.google.android.material.chip.Chip
+import com.google.android.material.chip.ChipGroup
+import org.koitharu.kotatsu.utils.ext.getThemeColor
+
+class ChipsView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = R.attr.chipGroupStyle
+) : ChipGroup(context, attrs, defStyleAttr) {
+
+ private var isLayoutSuppressedCompat = false
+ private var isLayoutCalledOnSuppressed = false
+ private var chipOnClickListener = OnClickListener {
+ onChipClickListener?.onChipClick(it as Chip, it.tag)
+ }
+ var onChipClickListener: OnChipClickListener? = null
+ set(value) {
+ field = value
+ val isChipClickable = value != null
+ children.forEach { it.isClickable = isChipClickable }
+ }
+
+ override fun requestLayout() {
+ if (isLayoutSuppressedCompat) {
+ isLayoutCalledOnSuppressed = true
+ } else {
+ super.requestLayout()
+ }
+ }
+
+ fun setChips(items: List) {
+ suppressLayoutCompat(true)
+ try {
+ for ((i, model) in items.withIndex()) {
+ val chip = getChildAt(i) as Chip? ?: addChip()
+ bindChip(chip, model)
+ }
+ for (i in items.size until childCount) {
+ removeViewAt(i)
+ }
+ } finally {
+ suppressLayoutCompat(false)
+ }
+ }
+
+ private fun bindChip(chip: Chip, model: ChipModel) {
+ chip.text = model.title
+ if (model.icon == 0) {
+ chip.isChipIconVisible = false
+ } else {
+ chip.isCheckedIconVisible = true
+ chip.setChipIconResource(model.icon)
+ }
+ chip.tag = model.data
+ }
+
+ private fun addChip(): Chip {
+ val chip = Chip(context)
+ chip.setTextColor(context.getThemeColor(android.R.attr.textColorPrimary))
+ chip.isCloseIconVisible = false
+ chip.setEnsureMinTouchTargetSize(false)
+ chip.setOnClickListener(chipOnClickListener)
+ chip.isClickable = onChipClickListener != null
+ addView(chip)
+ return chip
+ }
+
+ private fun suppressLayoutCompat(suppress: Boolean) {
+ isLayoutSuppressedCompat = suppress
+ if (!suppress) {
+ if (isLayoutCalledOnSuppressed) {
+ requestLayout()
+ isLayoutCalledOnSuppressed = false
+ }
+ }
+ }
+
+ data class ChipModel(
+ @DrawableRes val icon: Int,
+ val title: CharSequence,
+ val data: Any? = null
+ )
+
+ fun interface OnChipClickListener {
+
+ fun onChipClick(chip: Chip, data: Any?)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/core/ui/ChipsFactory.kt b/app/src/main/java/org/koitharu/kotatsu/core/ui/ChipsFactory.kt
deleted file mode 100644
index d18524e4b..000000000
--- a/app/src/main/java/org/koitharu/kotatsu/core/ui/ChipsFactory.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.koitharu.kotatsu.core.ui
-
-import android.content.Context
-import android.view.View
-import androidx.annotation.DrawableRes
-import com.google.android.material.chip.Chip
-import org.koitharu.kotatsu.utils.ext.getThemeColor
-
-class ChipsFactory(val context: Context) {
-
- fun create(
- convertView: Chip? = null,
- text: CharSequence,
- @DrawableRes iconRes: Int = 0,
- tag: Any? = null,
- onClickListener: View.OnClickListener? = null
- ): Chip {
- val chip = convertView ?: Chip(context).apply {
- setTextColor(context.getThemeColor(android.R.attr.textColorPrimary))
- isCloseIconVisible = false
- }
- chip.text = text
- if (iconRes == 0) {
- chip.isChipIconVisible = false
- } else {
- chip.isCheckedIconVisible = true
- chip.setChipIconResource(iconRes)
- }
- chip.tag = tag
- chip.setEnsureMinTouchTargetSize(false)
- chip.setOnClickListener(onClickListener)
- return chip
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt
index 5b712b1d6..00d3baa53 100644
--- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt
@@ -13,12 +13,14 @@ import androidx.core.view.updatePadding
import coil.ImageLoader
import coil.util.CoilUtils
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseFragment
+import org.koitharu.kotatsu.base.ui.widgets.ChipsView
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.databinding.FragmentDetailsBinding
@@ -34,6 +36,7 @@ class DetailsFragment : BaseFragment(), View.OnClickList
private val viewModel by sharedViewModel()
private val coil by inject()
+ private var tagsJob: Job? = null
override fun onInflateView(
inflater: LayoutInflater,
@@ -67,47 +70,11 @@ class DetailsFragment : BaseFragment(), View.OnClickList
ratingBar.progress = (ratingBar.max * manga.rating).roundToInt()
ratingBar.isVisible = true
}
- chipsTags.removeAllViews()
- manga.author?.let { a ->
- chipsTags.addChips(listOf(a)) {
- create(
- text = it,
- iconRes = R.drawable.ic_chip_user,
- tag = it
- )
- }
- }
- chipsTags.addChips(manga.tags) {
- create(
- text = it.title,
- iconRes = R.drawable.ic_chip_tag,
- tag = it
- )
- }
- manga.url.toUri().toFileOrNull()?.let { f ->
- viewLifecycleScope.launch {
- val size = withContext(Dispatchers.IO) {
- f.length()
- }
- chipsTags.addChips(listOf(f)) {
- create(
- text = FileSizeUtils.formatBytes(context, size),
- iconRes = R.drawable.ic_chip_storage,
- tag = it
- )
- }
- }
- } ?: chipsTags.addChips(listOf(manga.source)) {
- create(
- text = it.title,
- iconRes = R.drawable.ic_chip_web,
- tag = it
- )
- }
imageViewFavourite.setOnClickListener(this@DetailsFragment)
buttonRead.setOnClickListener(this@DetailsFragment)
buttonRead.setOnLongClickListener(this@DetailsFragment)
buttonRead.isEnabled = !manga.chapters.isNullOrEmpty()
+ bindTags(manga)
}
}
@@ -191,4 +158,39 @@ class DetailsFragment : BaseFragment(), View.OnClickList
bottom = insets.bottom
)
}
+
+ private fun bindTags(manga: Manga) {
+ tagsJob?.cancel()
+ tagsJob = viewLifecycleScope.launch {
+ val tags = ArrayList(manga.tags.size + 2)
+ if (manga.author != null) {
+ tags += ChipsView.ChipModel(
+ title = manga.author,
+ icon = R.drawable.ic_chip_user
+ )
+ }
+ for (tag in manga.tags) {
+ tags += ChipsView.ChipModel(
+ title = tag.title,
+ icon = R.drawable.ic_chip_tag
+ )
+ }
+ val file = manga.url.toUri().toFileOrNull()
+ if (file != null) {
+ val size = withContext(Dispatchers.IO) {
+ file.length()
+ }
+ tags += ChipsView.ChipModel(
+ title = FileSizeUtils.formatBytes(requireContext(), size),
+ icon = R.drawable.ic_chip_storage
+ )
+ } else {
+ tags += ChipsView.ChipModel(
+ title = manga.source.title,
+ icon = R.drawable.ic_chip_web
+ )
+ }
+ binding.chipsTags.setChips(tags)
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt
index 4a13722ec..43ea9b89d 100644
--- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt
@@ -22,7 +22,6 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
-import org.koitharu.kotatsu.core.ui.ChipsFactory
fun View.hideKeyboard() {
val imm = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
@@ -40,14 +39,6 @@ inline fun ViewGroup.inflate(@LayoutRes resId: Int) =
val RecyclerView.hasItems: Boolean
get() = (adapter?.itemCount ?: 0) > 0
-inline fun ChipGroup.addChips(data: Iterable, action: ChipsFactory.(T) -> Chip) {
- val factory = ChipsFactory(context)
- data.forEach {
- val chip = factory.action(it)
- addView(chip)
- }
-}
-
fun RecyclerView.clearItemDecorations() {
while (itemDecorationCount > 0) {
removeItemDecorationAt(0)
diff --git a/app/src/main/res/layout-w600dp/fragment_details.xml b/app/src/main/res/layout-w600dp/fragment_details.xml
index 2d2640a9c..354fda3a9 100644
--- a/app/src/main/res/layout-w600dp/fragment_details.xml
+++ b/app/src/main/res/layout-w600dp/fragment_details.xml
@@ -23,8 +23,7 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.3" />
-
-
-