Update manga details list item
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
package org.koitharu.kotatsu.list.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.appcompat.view.ActionMode
|
||||
@@ -15,7 +19,6 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import coil.ImageLoader
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.domain.reverseAsync
|
||||
@@ -42,13 +45,23 @@ import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
|
||||
import org.koitharu.kotatsu.list.ui.model.ListHeader
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.list.ui.model.MangaItemModel
|
||||
import org.koitharu.kotatsu.main.ui.MainActivity
|
||||
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
|
||||
import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner
|
||||
import org.koitharu.kotatsu.main.ui.MainActivity
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
import org.koitharu.kotatsu.search.ui.MangaListActivity
|
||||
import org.koitharu.kotatsu.utils.ShareHelper
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import org.koitharu.kotatsu.utils.ext.addMenuProvider
|
||||
import org.koitharu.kotatsu.utils.ext.clearItemDecorations
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.getThemeColor
|
||||
import org.koitharu.kotatsu.utils.ext.measureHeight
|
||||
import org.koitharu.kotatsu.utils.ext.resolveDp
|
||||
import org.koitharu.kotatsu.utils.ext.scaleUpActivityOptionsOf
|
||||
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
abstract class MangaListFragment :
|
||||
@@ -138,6 +151,20 @@ abstract class MangaListFragment :
|
||||
return selectionController?.onItemLongClick(item.id) ?: false
|
||||
}
|
||||
|
||||
override fun onReadClick(manga: Manga, view: View) {
|
||||
if (selectionController?.onItemClick(manga.id) != true) {
|
||||
val intent = ReaderActivity.newIntent(context ?: return, manga)
|
||||
startActivity(intent, scaleUpActivityOptionsOf(view).toBundle())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTagClick(manga: Manga, tag: MangaTag, view: View) {
|
||||
if (selectionController?.onItemClick(manga.id) != true) {
|
||||
val intent = MangaListActivity.newIntent(context ?: return, setOf(tag))
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onRefresh() {
|
||||
binding.swipeRefreshLayout.isRefreshing = true
|
||||
@@ -251,12 +278,14 @@ abstract class MangaListFragment :
|
||||
)
|
||||
addItemDecoration(decoration)
|
||||
}
|
||||
|
||||
ListMode.DETAILED_LIST -> {
|
||||
layoutManager = FitHeightLinearLayoutManager(context)
|
||||
val spacing = resources.getDimensionPixelOffset(R.dimen.list_spacing)
|
||||
updatePadding(left = spacing, right = spacing)
|
||||
addItemDecoration(SpacingItemDecoration(spacing))
|
||||
}
|
||||
|
||||
ListMode.GRID -> {
|
||||
layoutManager = FitHeightGridLayoutManager(context, checkNotNull(spanResolver).spanCount).also {
|
||||
it.spanSizeLookup = spanSizeLookup
|
||||
@@ -284,21 +313,25 @@ abstract class MangaListFragment :
|
||||
selectionController?.addAll(ids)
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_share -> {
|
||||
ShareHelper(requireContext()).shareMangaLinks(selectedItems)
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_favourite -> {
|
||||
FavouriteCategoriesBottomSheet.show(childFragmentManager, selectedItems)
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_save -> {
|
||||
DownloadService.confirmAndStart(requireContext(), selectedItems)
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,12 @@ open class MangaSelectionDecoration(context: Context) : AbstractSelectionItemDec
|
||||
|
||||
protected val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
protected val checkIcon = ContextCompat.getDrawable(context, materialR.drawable.ic_mtrl_checked_circle)
|
||||
protected val iconOffset = context.resources.getDimensionPixelOffset(R.dimen.grid_spacing_outer)
|
||||
protected val iconOffset = context.resources.getDimensionPixelOffset(R.dimen.card_indicator_offset)
|
||||
protected val iconSize = context.resources.getDimensionPixelOffset(R.dimen.card_indicator_size)
|
||||
protected val strokeColor = context.getThemeColor(materialR.attr.colorPrimary, Color.RED)
|
||||
protected val fillColor = ColorUtils.setAlphaComponent(
|
||||
ColorUtils.blendARGB(strokeColor, context.getThemeColor(materialR.attr.colorSurface), 0.8f),
|
||||
0x74
|
||||
0x74,
|
||||
)
|
||||
protected val defaultRadius = context.resources.getDimension(R.dimen.list_selector_corner)
|
||||
|
||||
@@ -65,11 +66,11 @@ open class MangaSelectionDecoration(context: Context) : AbstractSelectionItemDec
|
||||
setBounds(
|
||||
(bounds.left + iconOffset).toInt(),
|
||||
(bounds.top + iconOffset).toInt(),
|
||||
(bounds.left + iconOffset + intrinsicWidth).toInt(),
|
||||
(bounds.top + iconOffset + intrinsicHeight).toInt(),
|
||||
(bounds.left + iconOffset + iconSize).toInt(),
|
||||
(bounds.top + iconOffset + iconSize).toInt(),
|
||||
)
|
||||
draw(canvas)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.koitharu.kotatsu.list.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
|
||||
interface MangaDetailsClickListener : OnListItemClickListener<Manga> {
|
||||
|
||||
fun onReadClick(manga: Manga, view: View)
|
||||
|
||||
fun onTagClick(manga: Manga, tag: MangaTag, view: View)
|
||||
}
|
||||
@@ -1,34 +1,52 @@
|
||||
package org.koitharu.kotatsu.list.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import coil.ImageLoader
|
||||
import com.google.android.material.badge.BadgeDrawable
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.base.ui.widgets.ChipsView
|
||||
import org.koitharu.kotatsu.databinding.ItemMangaListDetailsBinding
|
||||
import org.koitharu.kotatsu.history.domain.PROGRESS_NONE
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.list.ui.model.MangaListDetailedModel
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.utils.ext.*
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.utils.ext.disposeImageRequest
|
||||
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
||||
import org.koitharu.kotatsu.utils.ext.referer
|
||||
import org.koitharu.kotatsu.utils.ext.textAndVisible
|
||||
import org.koitharu.kotatsu.utils.image.CoverSizeResolver
|
||||
|
||||
fun mangaListDetailedItemAD(
|
||||
coil: ImageLoader,
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
clickListener: OnListItemClickListener<Manga>,
|
||||
clickListener: MangaDetailsClickListener,
|
||||
) = adapterDelegateViewBinding<MangaListDetailedModel, ListModel, ItemMangaListDetailsBinding>(
|
||||
{ inflater, parent -> ItemMangaListDetailsBinding.inflate(inflater, parent, false) },
|
||||
) {
|
||||
var badge: BadgeDrawable? = null
|
||||
|
||||
itemView.setOnClickListener {
|
||||
clickListener.onItemClick(item.manga, it)
|
||||
}
|
||||
itemView.setOnLongClickListener {
|
||||
clickListener.onItemLongClick(item.manga, it)
|
||||
val listenerAdapter = object : View.OnClickListener, View.OnLongClickListener, ChipsView.OnChipClickListener {
|
||||
override fun onClick(v: View) = when (v.id) {
|
||||
R.id.button_read -> clickListener.onReadClick(item.manga, v)
|
||||
else -> clickListener.onItemClick(item.manga, v)
|
||||
}
|
||||
|
||||
override fun onLongClick(v: View): Boolean = clickListener.onItemLongClick(item.manga, v)
|
||||
|
||||
override fun onChipClick(chip: Chip, data: Any?) {
|
||||
val tag = data as? MangaTag ?: return
|
||||
clickListener.onTagClick(item.manga, tag, chip)
|
||||
}
|
||||
}
|
||||
itemView.setOnClickListener(listenerAdapter)
|
||||
itemView.setOnLongClickListener(listenerAdapter)
|
||||
binding.buttonRead.setOnClickListener(listenerAdapter)
|
||||
binding.chipsTags.onChipClickListener = listenerAdapter
|
||||
|
||||
bind { payloads ->
|
||||
binding.textViewTitle.text = item.title
|
||||
@@ -44,8 +62,9 @@ fun mangaListDetailedItemAD(
|
||||
lifecycle(lifecycleOwner)
|
||||
enqueueWith(coil)
|
||||
}
|
||||
binding.textViewRating.textAndVisible = item.rating
|
||||
binding.textViewTags.text = item.tags
|
||||
binding.chipsTags.setChips(item.tags)
|
||||
binding.ratingBar.isVisible = item.manga.hasRating
|
||||
binding.ratingBar.rating = binding.ratingBar.numStars * item.manga.rating
|
||||
badge = itemView.bindBadge(badge, item.counter)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package org.koitharu.kotatsu.list.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
|
||||
interface MangaListListener : OnListItemClickListener<Manga>, ListStateHolderListener, ListHeaderClickListener {
|
||||
interface MangaListListener : MangaDetailsClickListener, ListStateHolderListener, ListHeaderClickListener {
|
||||
|
||||
fun onUpdateFilter(tags: Set<MangaTag>)
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package org.koitharu.kotatsu.list.ui.model
|
||||
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.widgets.ChipsView
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
||||
import org.koitharu.kotatsu.core.prefs.ListMode
|
||||
@@ -11,6 +10,8 @@ import org.koitharu.kotatsu.list.domain.ListExtraProvider
|
||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.utils.ext.ifZero
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
|
||||
fun Manga.toListModel(counter: Int, progress: Float) = MangaListModel(
|
||||
id = id,
|
||||
@@ -26,12 +27,11 @@ fun Manga.toListDetailedModel(counter: Int, progress: Float) = MangaListDetailed
|
||||
id = id,
|
||||
title = title,
|
||||
subtitle = altTitle,
|
||||
rating = if (hasRating) String.format("%.1f", rating * 5) else null,
|
||||
tags = tags.joinToString(", ") { it.title },
|
||||
coverUrl = coverUrl,
|
||||
manga = this,
|
||||
counter = counter,
|
||||
progress = progress,
|
||||
tags = tags.map { ChipsView.ChipModel(0, it.title, false, false, it) },
|
||||
)
|
||||
|
||||
fun Manga.toGridModel(counter: Int, progress: Float) = MangaGridModel(
|
||||
@@ -69,9 +69,11 @@ suspend fun <C : MutableCollection<in MangaItemModel>> List<Manga>.toUi(
|
||||
ListMode.LIST -> mapTo(destination) {
|
||||
it.toListModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id))
|
||||
}
|
||||
|
||||
ListMode.DETAILED_LIST -> mapTo(destination) {
|
||||
it.toListDetailedModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id))
|
||||
}
|
||||
|
||||
ListMode.GRID -> mapTo(destination) {
|
||||
it.toGridModel(extraProvider.getCounter(it.id), extraProvider.getProgress(it.id))
|
||||
}
|
||||
@@ -95,5 +97,6 @@ private fun getErrorIcon(error: Throwable) = when (error) {
|
||||
is UnknownHostException,
|
||||
is SocketTimeoutException,
|
||||
-> R.drawable.ic_plug_large
|
||||
|
||||
else -> R.drawable.ic_error_large
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package org.koitharu.kotatsu.list.ui.model
|
||||
|
||||
import org.koitharu.kotatsu.base.ui.widgets.ChipsView
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
|
||||
data class MangaListDetailedModel(
|
||||
override val id: Long,
|
||||
override val title: String,
|
||||
val subtitle: String?,
|
||||
val tags: String,
|
||||
override val coverUrl: String,
|
||||
val rating: String?,
|
||||
override val manga: Manga,
|
||||
override val counter: Int,
|
||||
override val progress: Float,
|
||||
) : MangaItemModel
|
||||
val tags: List<ChipsView.ChipModel>,
|
||||
) : MangaItemModel
|
||||
|
||||
@@ -12,7 +12,6 @@ import androidx.core.graphics.Insets
|
||||
import androidx.core.view.updatePadding
|
||||
import coil.ImageLoader
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.base.ui.list.ListSelectionController
|
||||
@@ -27,11 +26,15 @@ import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
|
||||
import org.koitharu.kotatsu.list.ui.model.ListHeader
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
import org.koitharu.kotatsu.search.ui.MangaListActivity
|
||||
import org.koitharu.kotatsu.search.ui.SearchActivity
|
||||
import org.koitharu.kotatsu.search.ui.multi.adapter.MultiSearchAdapter
|
||||
import org.koitharu.kotatsu.utils.ShareHelper
|
||||
import org.koitharu.kotatsu.utils.ext.assistedViewModels
|
||||
import org.koitharu.kotatsu.utils.ext.invalidateNestedItemDecorations
|
||||
import org.koitharu.kotatsu.utils.ext.scaleUpActivityOptionsOf
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MultiSearchActivity :
|
||||
@@ -110,6 +113,20 @@ class MultiSearchActivity :
|
||||
return selectionController.onItemLongClick(item.id)
|
||||
}
|
||||
|
||||
override fun onReadClick(manga: Manga, view: View) {
|
||||
if (!selectionController.onItemClick(manga.id)) {
|
||||
val intent = ReaderActivity.newIntent(this, manga)
|
||||
startActivity(intent, scaleUpActivityOptionsOf(view).toBundle())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTagClick(manga: Manga, tag: MangaTag, view: View) {
|
||||
if (!selectionController.onItemClick(manga.id)) {
|
||||
val intent = MangaListActivity.newIntent(this, setOf(tag))
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRetryClick(error: Throwable) {
|
||||
viewModel.doSearch(viewModel.query.value.orEmpty())
|
||||
}
|
||||
@@ -139,16 +156,19 @@ class MultiSearchActivity :
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_favourite -> {
|
||||
FavouriteCategoriesBottomSheet.show(supportFragmentManager, collectSelectedItems())
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_save -> {
|
||||
DownloadService.confirmAndStart(this, collectSelectedItems())
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,10 @@ class FeedFragment :
|
||||
startActivity(DetailsActivity.newIntent(context ?: return, item))
|
||||
}
|
||||
|
||||
override fun onReadClick(manga: Manga, view: View) = Unit
|
||||
|
||||
override fun onTagClick(manga: Manga, tag: MangaTag, view: View) = Unit
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance() = FeedFragment()
|
||||
|
||||
Reference in New Issue
Block a user