Skip to content

Commit

Permalink
Merge pull request #58 from sieunju/preview
Browse files Browse the repository at this point in the history
Preview
  • Loading branch information
sieunju authored Jun 30, 2024
2 parents f514492 + 5f7215d commit fb43b59
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 0 deletions.
16 changes: 16 additions & 0 deletions core/src/main/java/com/hmju/core/ui/adapter/ItemListAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ class ItemListAdapter : RecyclerView.Adapter<BaseViewHolder<*>>() {
}
}

/**
* PayLoad 방식의 BindViewHolder
*/
override fun onBindViewHolder(
holder: BaseViewHolder<*>,
pos: Int,
payloads: MutableList<Any>
) {
if (payloads.isEmpty()) {
this.onBindViewHolder(holder, pos)
} else if (payloads[0] is List<*>) {
@Suppress("UNCHECKED_CAST")
holder.onPayloadBindView(payloads[0] as List<Any>)
}
}

override fun getItemCount(): Int {
return dataList.size
}
Expand Down
16 changes: 16 additions & 0 deletions core/src/main/java/com/hmju/core/ui/adapter/ItemListAdapterV2.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,22 @@ class ItemListAdapterV2 : ListAdapter<BaseUiModel, BaseViewHolder<*>>(BaseDiffUt
}
}

/**
* PayLoad 방식의 BindViewHolder
*/
override fun onBindViewHolder(
holder: BaseViewHolder<*>,
pos: Int,
payloads: MutableList<Any>
) {
if (payloads.isEmpty()) {
this.onBindViewHolder(holder, pos)
} else if (payloads[0] is List<*>) {
@Suppress("UNCHECKED_CAST")
holder.onPayloadBindView(payloads[0] as List<Any>)
}
}

override fun getItemViewType(pos: Int): Int {
return if (currentList.size > pos) {
getItem(pos).layoutId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import android.view.View
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.text.HtmlCompat
import androidx.databinding.BindingAdapter
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.hmju.core.like_manager.LikeManager
import com.hmju.core.ui.adapter.ItemListAdapter
import com.hmju.core.ui.base.BaseUiModel
import com.hmju.core.ui.base.BaseViewModel
import com.hmju.core.ui.payloads.RvPayloadModel

/**
* Description :
Expand Down Expand Up @@ -61,4 +64,54 @@ object CommonBindingAdapter {
submitList(newList)
}
}

/**
* 원하는 ViewHolder에 업데이트 처리하고 싶을때 사용하는 함수
* 깜박거리는 이슈 대응하기 위함
* @param payloadModel 업데이트에 필요한 데이터 모델
*/
@JvmStatic
@BindingAdapter(
value = ["payloadModel"]
)
fun setItemListPayload(
rv: RecyclerView,
payloadModel: RvPayloadModel? = null
) {
if (payloadModel == null) return

val adapter = rv.adapter ?: return
if (!payloadModel.isValidate()) return

// 범위가 지정되어 있는 경우
if (payloadModel.isRangeValidate()) {
adapter.notifyItemRangeChanged(
payloadModel.firstPos,
payloadModel.lastPos.coerceAtMost(adapter.itemCount),
payloadModel.list
)
return
}

// 범위가 지정되어 있지 않으면 자동으로 처리
val layoutManager = rv.layoutManager
var firstPos = -1
var lastPos = -1
if (layoutManager is GridLayoutManager) {
firstPos = layoutManager.findFirstVisibleItemPosition()
lastPos = layoutManager.findLastVisibleItemPosition()
} else if (layoutManager is LinearLayoutManager) {
firstPos = layoutManager.findFirstVisibleItemPosition()
lastPos = layoutManager.findLastVisibleItemPosition()
}

if (firstPos != -1 && lastPos != -1) {
adapter.notifyItemRangeChanged(
firstPos,
lastPos,
payloadModel.list
)
}
}

}
52 changes: 52 additions & 0 deletions core/src/main/java/com/hmju/core/ui/payloads/RvPayloadModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.hmju.core.ui.payloads

import com.hmju.core.ui.base.BaseUiModel

/**
* Description : RecyclerView Payload Update 전용 데이터 모델
*
* Created by juhongmin on 2024. 6. 30.
*/
data class RvPayloadModel(
var firstPos: Int = -1,
var lastPos: Int = -1,
val list: MutableList<BaseUiModel> = mutableListOf()
) {

fun isValidate(): Boolean {
return list.isNotEmpty()
}

fun isRangeValidate(): Boolean {
return firstPos != -1 && lastPos != -1
}

/**
* 업데이트 리스트의 최소 / 최대 범위를 찾아서 업데이트할 정보를 셋팅하는 함수
* 단, 인자값으로 넣는 리스트는 data class 이거나, CurrentList 에 있는 데이터 그대로
* payloadList 에 추가만 하도록 해야함 [Collection.indexOf] 내부 로직 때문
* 성능 N X M
* LiveData 를 사용하는 경우 setValue 를 해줘야 합니다. AKA. notifyObserver
* @param list Current List
* @param payloadList Update List
*/
fun update(list: List<BaseUiModel>, payloadList: List<BaseUiModel>) {
if (list.isEmpty() || payloadList.isEmpty()) return
var firstPos = -1
var lastPos = 1
payloadList.forEach {
val findIndex = list.indexOf(it)
if (findIndex == -1) return@forEach
firstPos = if (firstPos == -1) {
findIndex
} else {
firstPos.coerceAtMost(findIndex)
}
lastPos = lastPos.coerceAtLeast(findIndex)
}
this.firstPos = firstPos
this.lastPos = lastPos.plus(1)
this.list.clear()
this.list.addAll(payloadList)
}
}
28 changes: 28 additions & 0 deletions core/src/main/java/com/hmju/core/ui/viewholders/BaseViewHolder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.databinding.ViewDataBinding
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import com.hmju.core.ui.base.ActivityViewModel
import com.hmju.core.ui.base.BaseUiModel
import com.hmju.core.ui.base.BaseViewModel
import com.hmju.core.ui.base.FragmentViewModel

Expand All @@ -29,6 +30,13 @@ abstract class BaseViewHolder<T : ViewDataBinding>(
@Throws(Exception::class)
abstract fun onBindView(item: Any)

/**
* 현재 보여지는 화면에서 업데이트 하고 싶을때 호출하는 함수
* 매개변수에 있는 데이터 모델을 현재 가지고 있는 데이터 모델과 같다면 업데이트 하도록 처리
* @param payloads 업데이트할 데이터 리스트
*/
open fun onPayloadBindView(payloads: List<Any>) {}

open fun onViewAttachedToWindow() {

}
Expand Down Expand Up @@ -66,4 +74,24 @@ abstract class BaseViewHolder<T : ViewDataBinding>(
binding.setVariable(variableId, viewModel.requestManager)
}
}

/**
* payloads 로 가져온 데이터 리스트에 현재 ViewHolder 에서 가지고 있는 데이터 모델과
* 같은 모델을 찾아서 리턴하는 함수
* 찾는 즉시 리턴하기 위해서 forEach 구문 사용 X
* @param payloads 업데이트할 데이터리스트
* @param block 비즈니스 로직
*/
protected inline fun <reified T : BaseUiModel> findPayloadModel(
payloads: List<Any>,
block: (T) -> Boolean
): T? {
for (item in payloads) {
if (item is T && block(item)) {
return item
}
}
return null
}

}
19 changes: 19 additions & 0 deletions core/src/main/java/com/hmju/core/util/ResourceManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.hmju.core.util

import android.content.res.Resources
import androidx.annotation.ColorRes
import androidx.annotation.StringRes

/**
* Description : Android Resource Manager
*
* Created by juhongmin on 6/22/24
*/
interface ResourceManager {
fun getRes(): Resources
fun getColor(@ColorRes color: Int): Int
fun getString(@StringRes resId: Int): CharSequence

fun getString(@StringRes resId: Int, vararg args: Any): CharSequence

}
34 changes: 34 additions & 0 deletions core/src/main/java/com/hmju/core/util/ResourceManagerImpl.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.hmju.core.util

import android.content.Context
import android.content.res.Resources
import androidx.annotation.ColorRes
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject

/**
* Description :
*
* Created by juhongmin on 6/22/24
*/
internal class ResourceManagerImpl @Inject constructor(
@ApplicationContext private val context: Context
) : ResourceManager {
override fun getRes(): Resources {
return context.resources
}

override fun getColor(@ColorRes color: Int): Int {
return ContextCompat.getColor(context, color)
}

override fun getString(@StringRes resId: Int): CharSequence {
return context.resources.getString(resId)
}

override fun getString(resId: Int, vararg args: Any): CharSequence {
return context.resources.getString(resId, args)
}
}
17 changes: 17 additions & 0 deletions core/src/main/java/com/hmju/core/util/UtilModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.hmju.core.util

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@InstallIn(SingletonComponent::class)
@Module
internal abstract class UtilModule {
@Singleton
@Binds
abstract fun bindResourceManager(
impl: ResourceManagerImpl
): ResourceManager
}

0 comments on commit fb43b59

Please sign in to comment.