From 5951676f0079f58c5c76da8d31c55cb592ad6bd1 Mon Sep 17 00:00:00 2001 From: CraZyLegenD Date: Sat, 19 Dec 2020 12:45:32 +0100 Subject: [PATCH] feat: recycler generator with one view holder refactor: removed image decoder for coroutines --- .../crazylegend/coroutines/ImageDecoder.kt | 33 ----------- .../AbstractViewBindingAdapter.kt | 18 ------ .../AbstractViewBindingHolderAdapter.kt | 55 +++++++++++++++++++ .../recyclerview/RecyclerViewExtensions.kt | 17 ++++++ .../RecyclerViewWithHolderGenerator.kt | 51 +++++++++++++++++ .../com/crazylegend/retrofit/RetrofitUtils.kt | 1 + 6 files changed, 124 insertions(+), 51 deletions(-) delete mode 100644 coroutines/src/main/java/com/crazylegend/coroutines/ImageDecoder.kt create mode 100644 recyclerview/src/main/java/com/crazylegend/recyclerview/AbstractViewBindingHolderAdapter.kt create mode 100644 recyclerview/src/main/java/com/crazylegend/recyclerview/RecyclerViewWithHolderGenerator.kt diff --git a/coroutines/src/main/java/com/crazylegend/coroutines/ImageDecoder.kt b/coroutines/src/main/java/com/crazylegend/coroutines/ImageDecoder.kt deleted file mode 100644 index b5716596f..000000000 --- a/coroutines/src/main/java/com/crazylegend/coroutines/ImageDecoder.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.crazylegend.coroutines - -import android.graphics.ImageDecoder -import kotlinx.coroutines.CoroutineScope - -/** - * Created by crazy on 9/1/20 to long live and prosper ! - */ - - -suspend inline fun ImageDecoder.decodeImageOnIO(crossinline transform: ImageDecoder.() -> Unit) = - withIOContext { - transform(this@decodeImageOnIO) - } - - -suspend inline fun ImageDecoder.decodeImageOnDefault(crossinline transform: ImageDecoder.() -> Unit) = - withDefaultContext { - transform(this@decodeImageOnDefault) - } - - -inline fun ImageDecoder.decodeImageIO(scope: CoroutineScope, crossinline transform: ImageDecoder.() -> Unit) = - scope.io { - transform(this@decodeImageIO) - } - - -inline fun ImageDecoder.decodeImageOnDefault(scope: CoroutineScope, crossinline transform: ImageDecoder.() -> Unit) = - scope.default { - transform(this@decodeImageOnDefault) - } - diff --git a/recyclerview/src/main/java/com/crazylegend/recyclerview/AbstractViewBindingAdapter.kt b/recyclerview/src/main/java/com/crazylegend/recyclerview/AbstractViewBindingAdapter.kt index f748eacb5..f60a5ae29 100644 --- a/recyclerview/src/main/java/com/crazylegend/recyclerview/AbstractViewBindingAdapter.kt +++ b/recyclerview/src/main/java/com/crazylegend/recyclerview/AbstractViewBindingAdapter.kt @@ -1,7 +1,6 @@ package com.crazylegend.recyclerview import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView @@ -52,23 +51,6 @@ abstract class AbstractViewBindingAdapter Unit) { - setOnClickListener(object : View.OnClickListener { - var lastTime = 0L - override fun onClick(v: View) { - val now = System.currentTimeMillis() - if (now - lastTime > coolDown) { - action(v) - lastTime = now - } - } - }) - } - - @Suppress("UNCHECKED_CAST") private fun setViewHolder(binding: ViewBinding): VH = viewHolder(binding as VB) } \ No newline at end of file diff --git a/recyclerview/src/main/java/com/crazylegend/recyclerview/AbstractViewBindingHolderAdapter.kt b/recyclerview/src/main/java/com/crazylegend/recyclerview/AbstractViewBindingHolderAdapter.kt new file mode 100644 index 000000000..979dd6102 --- /dev/null +++ b/recyclerview/src/main/java/com/crazylegend/recyclerview/AbstractViewBindingHolderAdapter.kt @@ -0,0 +1,55 @@ +package com.crazylegend.recyclerview + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import androidx.viewbinding.ViewBinding +import com.crazylegend.recyclerview.clickListeners.forItemClickListener + + +/** + * Created by crazy on 4/5/20 to long live and prosper ! + * Takes leverage of not providing that damn layout res id + * + * USAGE: + * class TestViewBindingAdapter : AbstractViewBindingAdapter( +::TestViewHolderShimmer, CustomizableCardViewBinding::inflate +) + * + */ +abstract class AbstractViewBindingHolderAdapter( + private val bindingInflater: (LayoutInflater, ViewGroup, Boolean) -> VB, + areItemsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null }, + areContentsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null } +) : + ListAdapter>(GenericDiffUtil(areItemsTheSameCallback, areContentsTheSameCallback)) { + + var forItemClickListener: forItemClickListener? = null + var onLongClickListener: forItemClickListener? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractViewHolder { + val binding = bindingInflater.invoke(LayoutInflater.from(parent.context), parent, false) + val holder = AbstractViewHolder(binding) + + holder.itemView.setOnClickListenerCooldown { + if (holder.adapterPosition != RecyclerView.NO_POSITION) + forItemClickListener?.forItem(holder.adapterPosition, getItem(holder.adapterPosition), it) + } + holder.itemView.setOnLongClickListener { + if (holder.adapterPosition != RecyclerView.NO_POSITION) + onLongClickListener?.forItem(holder.adapterPosition, getItem(holder.adapterPosition), it) + true + } + return holder + } + + override fun onBindViewHolder(holder: AbstractViewHolder, position: Int) { + val item = getItem(holder.adapterPosition) + bindItems(item, position, itemCount, holder.binding) + } + + abstract fun bindItems(item: T, position: Int, itemCount: Int, binding: VB) + + class AbstractViewHolder(val binding: VB) : RecyclerView.ViewHolder(binding.root) +} \ No newline at end of file diff --git a/recyclerview/src/main/java/com/crazylegend/recyclerview/RecyclerViewExtensions.kt b/recyclerview/src/main/java/com/crazylegend/recyclerview/RecyclerViewExtensions.kt index d28f9a7e8..75db80178 100644 --- a/recyclerview/src/main/java/com/crazylegend/recyclerview/RecyclerViewExtensions.kt +++ b/recyclerview/src/main/java/com/crazylegend/recyclerview/RecyclerViewExtensions.kt @@ -663,4 +663,21 @@ fun RecyclerView.smoothSnapToPosition(position: Int, performClick: Boolean = tru } smoothScroller.targetPosition = position layoutManager?.startSmoothScroll(smoothScroller) +} + + +/** + * Sets an on click listener for a view, but ensures the action cannot be triggered more often than [coolDown] milliseconds. + */ +internal inline fun View.setOnClickListenerCooldown(coolDown: Long = 1000L, crossinline action: (view: View) -> Unit) { + setOnClickListener(object : View.OnClickListener { + var lastTime = 0L + override fun onClick(v: View) { + val now = System.currentTimeMillis() + if (now - lastTime > coolDown) { + action(v) + lastTime = now + } + } + }) } \ No newline at end of file diff --git a/recyclerview/src/main/java/com/crazylegend/recyclerview/RecyclerViewWithHolderGenerator.kt b/recyclerview/src/main/java/com/crazylegend/recyclerview/RecyclerViewWithHolderGenerator.kt new file mode 100644 index 000000000..7d93ce52a --- /dev/null +++ b/recyclerview/src/main/java/com/crazylegend/recyclerview/RecyclerViewWithHolderGenerator.kt @@ -0,0 +1,51 @@ +package com.crazylegend.recyclerview + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import androidx.viewbinding.ViewBinding + + +/** + * Created by crazy on 3/9/20 to long live and prosper ! + */ + + +inline fun generateRecyclerWithHolder( + noinline bindingInflater: (LayoutInflater, ViewGroup, Boolean) -> VB, + noinline areItemsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null }, + noinline areContentsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null }, + crossinline binder: (item: T, position: Int, itemCount: Int, binding: VB) -> Unit): AbstractViewBindingHolderAdapter { + + return object : AbstractViewBindingHolderAdapter(bindingInflater, areItemsTheSameCallback, areContentsTheSameCallback) { + override fun bindItems(item: T, position: Int, itemCount: Int, binding: VB) { + binder(item, position, itemCount, binding) + } + } +} + +inline fun RecyclerView.generateVerticalAdapterWithHolder( + noinline bindingInflater: (LayoutInflater, ViewGroup, Boolean) -> VB, + noinline areItemsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null }, + noinline areContentsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null }, + crossinline binder: (item: T, position: Int, itemCount: Int, binding: VB) -> Unit, + hasFixedSize: Boolean = false, reverseLayout: Boolean = false): AbstractViewBindingHolderAdapter { + + val adapter = generateRecyclerWithHolder(bindingInflater, areItemsTheSameCallback, areContentsTheSameCallback, binder) + initRecyclerViewAdapter(adapter, RecyclerView.VERTICAL, hasFixedSize, reverseLayout) + return adapter +} + +inline fun RecyclerView.generateHorizontalAdapterWithHolder( + noinline bindingInflater: (LayoutInflater, ViewGroup, Boolean) -> VB, + noinline areItemsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null }, + noinline areContentsTheSameCallback: (old: T, new: T) -> Boolean? = { _, _ -> null }, + crossinline binder: (item: T, position: Int, itemCount: Int, binding: VB) -> Unit, + hasFixedSize: Boolean = false, reverseLayout: Boolean = false): AbstractViewBindingHolderAdapter { + + val adapter = generateRecyclerWithHolder(bindingInflater, areItemsTheSameCallback, areContentsTheSameCallback, binder) + initRecyclerViewAdapter(adapter, RecyclerView.HORIZONTAL, hasFixedSize, reverseLayout) + return adapter +} + + diff --git a/retrofit/src/main/java/com/crazylegend/retrofit/RetrofitUtils.kt b/retrofit/src/main/java/com/crazylegend/retrofit/RetrofitUtils.kt index 4477d16de..6c251b438 100644 --- a/retrofit/src/main/java/com/crazylegend/retrofit/RetrofitUtils.kt +++ b/retrofit/src/main/java/com/crazylegend/retrofit/RetrofitUtils.kt @@ -143,6 +143,7 @@ fun ArrayMap.addImageByteStringsToRetrofit(byteList: List