Last active
August 30, 2023 09:36
-
-
Save sme-shyl001/1122797d67922ff2febaef92d7e6bfc1 to your computer and use it in GitHub Desktop.
Adapter for switching items
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class FavoriteItemsListAdapter( | |
private val activity: Activity, | |
private val listener: (section: FavoriteSection) -> Unit | |
) : ListAdapter<FavoriteItem, FavoriteItemsListAdapter.FavoriteViewHolder>(DiffCallback()) { | |
private var recyclerView: RecyclerView? = null | |
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { | |
super.onAttachedToRecyclerView(recyclerView) | |
this.recyclerView = recyclerView | |
} | |
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavoriteViewHolder { | |
val binding = ItemFavoriteBinding.inflate(parent.getInflater(), parent, false) | |
if (itemCount == 2) binding.root.setTwoItemsWidth() | |
return FavoriteViewHolder(binding) | |
} | |
override fun onBindViewHolder(holder: FavoriteViewHolder, position: Int) { | |
super.onBindViewHolder(holder, position, emptyList()) | |
} | |
override fun onBindViewHolder( | |
holder: FavoriteViewHolder, | |
position: Int, | |
payloads: MutableList<Any> | |
) { | |
val payload = payloads.firstOrNull() as? FavoritePayload | |
if (payload == null) { | |
holder.bind(currentList[position]) | |
} else { | |
holder.updateSelection(payload.backgroundRes, payload.selected) | |
} | |
} | |
override fun getItemCount() = currentList.size | |
private fun ViewGroup.setTwoItemsWidth() { | |
if (activity.isTablet) { | |
val width = resources.getDimensionPixelSize(R.dimen.top_lists_selectors_container_width) | |
layoutParams.width = width / 2 | |
} else { | |
val screenWidth = activity.getScreenParams().widthPixels | |
val padding = recyclerView?.paddingStart ?: 0 | |
layoutParams.width = screenWidth / 2 - padding | |
} | |
} | |
inner class FavoriteViewHolder( | |
private val binding: ItemFavoriteBinding, | |
) : RecyclerView.ViewHolder(binding.root) { | |
fun bind(item: FavoriteItem) { | |
with(binding) { | |
updateSelection(item.backgroundRes, item.selected) | |
tvTitle.text = item.type.title.string() | |
root.setOnClickListener { listener.invoke(item.type) } | |
} | |
} | |
fun updateSelection(@DrawableRes backgroundRes: Int, selected: Boolean) { | |
with(binding) { | |
selector.visibleOrGone(selected) | |
root.setBackgroundResource(backgroundRes) | |
} | |
} | |
} | |
private class DiffCallback : DiffUtil.ItemCallback<FavoriteItem>() { | |
override fun areItemsTheSame(oldItem: FavoriteItem, newItem: FavoriteItem) = | |
oldItem.type == newItem.type | |
override fun areContentsTheSame(oldItem: FavoriteItem, newItem: FavoriteItem) = | |
oldItem == newItem | |
override fun getChangePayload(oldItem: FavoriteItem, newItem: FavoriteItem): Any? { | |
return when { | |
oldItem.selected != newItem.selected -> { | |
FavoritePayload(newItem.backgroundRes, newItem.selected) | |
} | |
else -> null | |
} | |
} | |
} | |
private data class FavoritePayload( | |
@DrawableRes val backgroundRes: Int, | |
val selected: Boolean | |
) | |
} | |
class FavoriteItemsLayoutManager( | |
context: Context | |
) : LinearLayoutManager(context, RecyclerView.HORIZONTAL, false) { | |
private val smoothScroller: RecyclerView.SmoothScroller by lazy { | |
CenterSmoothScroller(context) | |
} | |
override fun smoothScrollToPosition( | |
recyclerView: RecyclerView, | |
state: RecyclerView.State, | |
position: Int | |
) { | |
smoothScroller.targetPosition = position | |
startSmoothScroll(smoothScroller) | |
} | |
private class CenterSmoothScroller(context: Context) : LinearSmoothScroller(context) { | |
override fun calculateDtToFit( | |
viewStart: Int, | |
viewEnd: Int, | |
boxStart: Int, | |
boxEnd: Int, | |
snapPreference: Int | |
): Int { | |
return boxStart + (boxEnd - boxStart) / 2 - (viewStart + (viewEnd - viewStart) / 2) | |
} | |
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float { | |
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi | |
} | |
override fun calculateTimeForScrolling(dx: Int): Int { | |
return super.calculateTimeForScrolling(dx) | |
.coerceAtLeast(MIN_SCROLLING_TIME_MS) | |
} | |
} | |
companion object { | |
private const val MILLISECONDS_PER_INCH = 100f // default is 25f (bigger = slower) | |
private const val MIN_SCROLLING_TIME_MS = 200 | |
} | |
} | |
// GetFavoriteItemsUseCase.kt | |
class GetFavoriteItemsUseCase( | |
coroutineDispatcher: CoroutineDispatcher, | |
private val getUserUseCase: GetUserUseCase, | |
) : CoroutineUseCase<GetFavoriteItemsUseCase.Params, List<FavoriteItem>>(coroutineDispatcher) { | |
override suspend fun execute(parameters: Params): List<FavoriteItem> { | |
val (sectionId, isUserUSM) = parameters | |
val user = getUserUseCase(Unit).successOrThrow() | |
val hasFavorites = user.user.hasA360Favorites | |
val currentSection = when { | |
sectionId != -1 -> sectionId | |
isUserUSM && !hasFavorites -> FavoriteSection.TOP_LISTS.id | |
else -> FavoriteSection.FAVORITES.id | |
} | |
val sections = FavoriteSection.values().toMutableList() | |
if (!isUserUSM) sections.remove(FavoriteSection.TOP_LISTS) | |
return sections.mapIndexed { index, favoriteSection -> | |
FavoriteItem( | |
type = favoriteSection, | |
backgroundRes = when (index) { | |
0 -> R.drawable.background_favorite_start | |
sections.lastIndex -> R.drawable.background_favorite_end | |
else -> R.drawable.background_favorite_default | |
}, | |
selected = favoriteSection.id == currentSection, | |
) | |
} | |
} | |
data class Params( | |
val sectionId: Int, | |
val isUserUSM: Boolean, | |
) | |
} | |
// FavoriteItem.kt | |
data class FavoriteItem( | |
val type: FavoriteSection, | |
@DrawableRes val backgroundRes: Int = R.drawable.background_favorite_default, | |
val selected: Boolean = false, | |
) | |
// | |
// item_favorite.xml | |
<?xml version="1.0" encoding="utf-8"?> | |
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
android:layout_width="wrap_content" | |
android:layout_height="@dimen/favorite_item_height"> | |
<View | |
android:id="@+id/selector" | |
android:layout_width="0dp" | |
android:layout_height="0dp" | |
android:layout_margin="@dimen/margin_2" | |
android:background="@drawable/background_favorite_selected" | |
android:elevation="2dp" | |
app:layout_constraintBottom_toBottomOf="parent" | |
app:layout_constraintEnd_toEndOf="parent" | |
app:layout_constraintStart_toStartOf="parent" | |
app:layout_constraintTop_toTopOf="parent" /> | |
<TextView | |
android:id="@+id/tvTitle" | |
style="@style/TextAppearance.TextSemiBold" | |
android:layout_width="wrap_content" | |
android:layout_height="0dp" | |
android:layout_margin="@dimen/margin_2" | |
android:elevation="2dp" | |
android:gravity="center" | |
android:includeFontPadding="false" | |
android:paddingHorizontal="@dimen/padding_16" | |
android:textColor="@color/black" | |
android:textSize="@dimen/textSize_14" | |
app:layout_constraintBottom_toBottomOf="parent" | |
app:layout_constraintEnd_toEndOf="parent" | |
app:layout_constraintStart_toStartOf="parent" | |
app:layout_constraintTop_toTopOf="parent" /> | |
</androidx.constraintlayout.widget.ConstraintLayout> | |
// Selected | |
<?xml version="1.0" encoding="utf-8"?> | |
<shape xmlns:android="http://schemas.android.com/apk/res/android" | |
android:shape="rectangle"> | |
<solid android:color="@color/colorWhite" /> | |
<corners android:radius="@dimen/selector_shapeRadius" /> | |
</shape> | |
// Default | |
<?xml version="1.0" encoding="utf-8"?> | |
<shape xmlns:android="http://schemas.android.com/apk/res/android" | |
android:shape="rectangle"> | |
<solid android:color="@color/bgFavoriteItem" /> | |
</shape> | |
// End | |
<?xml version="1.0" encoding="utf-8"?> | |
<shape xmlns:android="http://schemas.android.com/apk/res/android" | |
android:shape="rectangle"> | |
<solid android:color="@color/bgFavoriteItem" /> | |
<corners | |
android:bottomRightRadius="@dimen/selector_shapeRadius" | |
android:topRightRadius="@dimen/selector_shapeRadius" /> | |
</shape> | |
// Start | |
<?xml version="1.0" encoding="utf-8"?> | |
<shape xmlns:android="http://schemas.android.com/apk/res/android" | |
android:shape="rectangle"> | |
<solid android:color="@color/bgFavoriteItem" /> | |
<corners | |
android:bottomLeftRadius="@dimen/selector_shapeRadius" | |
android:topLeftRadius="@dimen/selector_shapeRadius" /> | |
</shape> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment