From c14e18f12ab2f79e290a087707ab282e81df5d26 Mon Sep 17 00:00:00 2001 From: "a.batrakov" Date: Mon, 11 May 2026 23:46:00 +0300 Subject: [PATCH] do hw --- .../coins/feature/CoinListFragment.kt | 7 +++- .../feature/adapter/CoinHorizontalAdapter.kt | 38 +++++++++++++++++++ .../coins/feature/adapter/CoinsAdapter.kt | 33 ++++++++++++++-- .../coins/feature/adapter/CoinsAdapterItem.kt | 1 + .../adapter/CoinsHorizontalViewHolder.kt | 31 +++++++++++++++ .../res/layout/item_coin_horizontal_list.xml | 6 +++ 6 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinHorizontalAdapter.kt create mode 100644 app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsHorizontalViewHolder.kt create mode 100644 app/src/main/res/layout/item_coin_horizontal_list.xml diff --git a/app/src/main/java/ru/otus/cryptosample/coins/feature/CoinListFragment.kt b/app/src/main/java/ru/otus/cryptosample/coins/feature/CoinListFragment.kt index 093b01f..2dcd8c9 100644 --- a/app/src/main/java/ru/otus/cryptosample/coins/feature/CoinListFragment.kt +++ b/app/src/main/java/ru/otus/cryptosample/coins/feature/CoinListFragment.kt @@ -11,6 +11,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.launch import ru.otus.cryptosample.CoinsSampleApp import ru.otus.cryptosample.coins.feature.adapter.CoinsAdapter @@ -30,6 +31,8 @@ class CoinListFragment : Fragment() { private lateinit var coinsAdapter: CoinsAdapter + private val sharedPool = RecyclerView.RecycledViewPool() + override fun onAttach(context: Context) { super.onAttach(context) @@ -59,7 +62,7 @@ class CoinListFragment : Fragment() { } private fun setupRecyclerView() { - coinsAdapter = CoinsAdapter() + coinsAdapter = CoinsAdapter(sharedPool) val gridLayoutManager = GridLayoutManager(requireContext(), 2) gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { @@ -67,6 +70,7 @@ class CoinListFragment : Fragment() { return when (coinsAdapter.getItemViewType(position)) { 0 -> 2 // Category header spans full width 1 -> 1 // Coin item spans half width + 2 -> 2 else -> 1 } } @@ -75,6 +79,7 @@ class CoinListFragment : Fragment() { binding.recyclerView.apply { layoutManager = gridLayoutManager adapter = coinsAdapter + setRecycledViewPool(sharedPool) } } diff --git a/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinHorizontalAdapter.kt b/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinHorizontalAdapter.kt new file mode 100644 index 0000000..6a7f79d --- /dev/null +++ b/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinHorizontalAdapter.kt @@ -0,0 +1,38 @@ +package ru.otus.cryptosample.coins.feature.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import ru.otus.cryptosample.coins.feature.CoinState +import ru.otus.cryptosample.databinding.ItemCoinBinding +import ru.otus.cryptosample.databinding.ItemCoinHorizontalListBinding + +class CoinHorizontalAdapter : + ListAdapter(DiffCallback) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CoinViewHolder { + val binding = ItemCoinBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + return CoinViewHolder(binding) + } + + override fun onBindViewHolder(holder: CoinViewHolder, position: Int) { + holder.bind(getItem(position)) + } +} + +object DiffCallback : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: CoinState, newItem: CoinState): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: CoinState, newItem: CoinState): Boolean { + return oldItem == newItem + } +} diff --git a/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsAdapter.kt b/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsAdapter.kt index 9d6ab4f..4fe7e20 100644 --- a/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsAdapter.kt +++ b/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsAdapter.kt @@ -4,14 +4,20 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import ru.otus.cryptosample.coins.feature.CoinCategoryState +import ru.otus.cryptosample.coins.feature.CoinState import ru.otus.cryptosample.databinding.ItemCategoryHeaderBinding import ru.otus.cryptosample.databinding.ItemCoinBinding +import ru.otus.cryptosample.databinding.ItemCoinHorizontalListBinding -class CoinsAdapter : RecyclerView.Adapter() { +class CoinsAdapter( + private val sharedPool: RecyclerView.RecycledViewPool +) : RecyclerView.Adapter() { companion object { private const val VIEW_TYPE_CATEGORY = 0 private const val VIEW_TYPE_COIN = 1 + + private const val VIEW_TYPE_COINS_HORIZONTAL = 2 } private var items = listOf() @@ -21,8 +27,14 @@ class CoinsAdapter : RecyclerView.Adapter() { categories.forEach { category -> adapterItems.add(CoinsAdapterItem.CategoryHeader(category.name)) - category.coins.forEach { coin -> - adapterItems.add(CoinsAdapterItem.CoinItem(coin)) + if (category.coins.size > 10) { + adapterItems.add( + CoinsAdapterItem.CoinItemsHorizontalRV(category.coins) + ) + } else { + category.coins.forEach { coin -> + adapterItems.add(CoinsAdapterItem.CoinItem(coin)) + } } } @@ -36,6 +48,7 @@ class CoinsAdapter : RecyclerView.Adapter() { return when (items[position]) { is CoinsAdapterItem.CategoryHeader -> VIEW_TYPE_CATEGORY is CoinsAdapterItem.CoinItem -> VIEW_TYPE_COIN + is CoinsAdapterItem.CoinItemsHorizontalRV -> VIEW_TYPE_COINS_HORIZONTAL } } @@ -55,10 +68,18 @@ class CoinsAdapter : RecyclerView.Adapter() { false ) ) + VIEW_TYPE_COINS_HORIZONTAL -> CoinsHorizontalViewHolder( binding = + ItemCoinHorizontalListBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ), + sharedPool = sharedPool + ) else -> throw IllegalArgumentException("Unknown view type: $viewType") } } - + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (val item = items[position]) { is CoinsAdapterItem.CategoryHeader -> { @@ -67,6 +88,10 @@ class CoinsAdapter : RecyclerView.Adapter() { is CoinsAdapterItem.CoinItem -> { (holder as CoinViewHolder).bind(item.coin) } + + is CoinsAdapterItem.CoinItemsHorizontalRV -> { + (holder as CoinsHorizontalViewHolder).bind(item.coinsList) + } } } } \ No newline at end of file diff --git a/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsAdapterItem.kt b/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsAdapterItem.kt index c483d5e..b684ced 100644 --- a/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsAdapterItem.kt +++ b/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsAdapterItem.kt @@ -4,5 +4,6 @@ import ru.otus.cryptosample.coins.feature.CoinState sealed class CoinsAdapterItem { data class CategoryHeader(val categoryName: String) : CoinsAdapterItem() + data class CoinItemsHorizontalRV(val coinsList: List) : CoinsAdapterItem() data class CoinItem(val coin: CoinState) : CoinsAdapterItem() } \ No newline at end of file diff --git a/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsHorizontalViewHolder.kt b/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsHorizontalViewHolder.kt new file mode 100644 index 0000000..9232e90 --- /dev/null +++ b/app/src/main/java/ru/otus/cryptosample/coins/feature/adapter/CoinsHorizontalViewHolder.kt @@ -0,0 +1,31 @@ +package ru.otus.cryptosample.coins.feature.adapter + +import androidx.core.content.ContextCompat +import androidx.core.view.isVisible +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import coil.load +import ru.otus.cryptosample.R +import ru.otus.cryptosample.coins.feature.CoinState +import ru.otus.cryptosample.databinding.ItemCoinBinding +import ru.otus.cryptosample.databinding.ItemCoinHorizontalListBinding + +class CoinsHorizontalViewHolder( + private val binding: ItemCoinHorizontalListBinding, + private val sharedPool: RecyclerView.RecycledViewPool +) : RecyclerView.ViewHolder(binding.root) { + + private val adapter = CoinHorizontalAdapter() + + init { + binding.recyclerHorizontal.layoutManager = + LinearLayoutManager(binding.root.context, LinearLayoutManager.HORIZONTAL, false) + + binding.recyclerHorizontal.adapter = adapter + //binding.recyclerHorizontal.setRecycledViewPool(sharedPool) тут краш ClassCastException + } + + fun bind(items: List) { + adapter.submitList(items) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_coin_horizontal_list.xml b/app/src/main/res/layout/item_coin_horizontal_list.xml new file mode 100644 index 0000000..309b950 --- /dev/null +++ b/app/src/main/res/layout/item_coin_horizontal_list.xml @@ -0,0 +1,6 @@ + + \ No newline at end of file