Fix tags on details screen
This commit is contained in:
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -4,6 +4,8 @@
|
|||||||
<option name="filePathToZoomLevelMap">
|
<option name="filePathToZoomLevelMap">
|
||||||
<map>
|
<map>
|
||||||
<entry key="../../../../../../layout/custom_preview.xml" value="0.1" />
|
<entry key="../../../../../../layout/custom_preview.xml" value="0.1" />
|
||||||
|
<entry key="app/src/main/res/layout-w600dp/fragment_details.xml" value="0.14583333333333334" />
|
||||||
|
<entry key="app/src/main/res/layout/fragment_details.xml" value="0.26145833333333335" />
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -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<ChipModel>) {
|
||||||
|
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?)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,12 +13,14 @@ import androidx.core.view.updatePadding
|
|||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.util.CoilUtils
|
import coil.util.CoilUtils
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.base.ui.BaseFragment
|
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.Manga
|
||||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||||
import org.koitharu.kotatsu.databinding.FragmentDetailsBinding
|
import org.koitharu.kotatsu.databinding.FragmentDetailsBinding
|
||||||
@@ -34,6 +36,7 @@ class DetailsFragment : BaseFragment<FragmentDetailsBinding>(), View.OnClickList
|
|||||||
|
|
||||||
private val viewModel by sharedViewModel<DetailsViewModel>()
|
private val viewModel by sharedViewModel<DetailsViewModel>()
|
||||||
private val coil by inject<ImageLoader>()
|
private val coil by inject<ImageLoader>()
|
||||||
|
private var tagsJob: Job? = null
|
||||||
|
|
||||||
override fun onInflateView(
|
override fun onInflateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
@@ -67,47 +70,11 @@ class DetailsFragment : BaseFragment<FragmentDetailsBinding>(), View.OnClickList
|
|||||||
ratingBar.progress = (ratingBar.max * manga.rating).roundToInt()
|
ratingBar.progress = (ratingBar.max * manga.rating).roundToInt()
|
||||||
ratingBar.isVisible = true
|
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)
|
imageViewFavourite.setOnClickListener(this@DetailsFragment)
|
||||||
buttonRead.setOnClickListener(this@DetailsFragment)
|
buttonRead.setOnClickListener(this@DetailsFragment)
|
||||||
buttonRead.setOnLongClickListener(this@DetailsFragment)
|
buttonRead.setOnLongClickListener(this@DetailsFragment)
|
||||||
buttonRead.isEnabled = !manga.chapters.isNullOrEmpty()
|
buttonRead.isEnabled = !manga.chapters.isNullOrEmpty()
|
||||||
|
bindTags(manga)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,4 +158,39 @@ class DetailsFragment : BaseFragment<FragmentDetailsBinding>(), View.OnClickList
|
|||||||
bottom = insets.bottom
|
bottom = insets.bottom
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun bindTags(manga: Manga) {
|
||||||
|
tagsJob?.cancel()
|
||||||
|
tagsJob = viewLifecycleScope.launch {
|
||||||
|
val tags = ArrayList<ChipsView.ChipModel>(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,6 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.chip.ChipGroup
|
import com.google.android.material.chip.ChipGroup
|
||||||
import org.koitharu.kotatsu.core.ui.ChipsFactory
|
|
||||||
|
|
||||||
fun View.hideKeyboard() {
|
fun View.hideKeyboard() {
|
||||||
val imm = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
|
val imm = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
@@ -40,14 +39,6 @@ inline fun <reified T : View> ViewGroup.inflate(@LayoutRes resId: Int) =
|
|||||||
val RecyclerView.hasItems: Boolean
|
val RecyclerView.hasItems: Boolean
|
||||||
get() = (adapter?.itemCount ?: 0) > 0
|
get() = (adapter?.itemCount ?: 0) > 0
|
||||||
|
|
||||||
inline fun <T> ChipGroup.addChips(data: Iterable<T>, action: ChipsFactory.(T) -> Chip) {
|
|
||||||
val factory = ChipsFactory(context)
|
|
||||||
data.forEach {
|
|
||||||
val chip = factory.action(it)
|
|
||||||
addView(chip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun RecyclerView.clearItemDecorations() {
|
fun RecyclerView.clearItemDecorations() {
|
||||||
while (itemDecorationCount > 0) {
|
while (itemDecorationCount > 0) {
|
||||||
removeItemDecorationAt(0)
|
removeItemDecorationAt(0)
|
||||||
|
|||||||
@@ -23,8 +23,7 @@
|
|||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintWidth_percent="0.3" />
|
app:layout_constraintWidth_percent="0.3" />
|
||||||
|
|
||||||
|
<org.koitharu.kotatsu.base.ui.widgets.ChipsView
|
||||||
<com.google.android.material.chip.ChipGroup
|
|
||||||
android:id="@+id/chips_tags"
|
android:id="@+id/chips_tags"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|||||||
@@ -113,7 +113,7 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/barrier_title" />
|
app:layout_constraintTop_toBottomOf="@id/barrier_title" />
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
<org.koitharu.kotatsu.base.ui.widgets.ChipsView
|
||||||
android:id="@+id/chips_tags"
|
android:id="@+id/chips_tags"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|||||||
Reference in New Issue
Block a user