Last active
May 9, 2023 08:32
-
-
Save Morteza-QN/e59a3a05fab513152315f479cede1288 to your computer and use it in GitHub Desktop.
custom abstract class
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
import android.os.Bundle | |
import androidx.appcompat.app.AppCompatActivity | |
import androidx.viewbinding.ViewBinding | |
import dagger.hilt.android.AndroidEntryPoint | |
import kotlinx.coroutines.* | |
import javax.inject.Inject | |
@AndroidEntryPoint | |
abstract class BaseActivity<T : ViewBinding> : AppCompatActivity(), BaseView { | |
// SomeDependency with your own dependency | |
@Inject | |
lateinit var activity: AppCompatActivity | |
private var _binding: T? = null | |
protected val binding get() = _binding!! | |
private val job = SupervisorJob() | |
private val errorHandler = CoroutineExceptionHandler { _, exception -> | |
// handle errors here | |
} | |
val uiScope: CoroutineScope = CoroutineScope(Dispatchers.Main + job + errorHandler) | |
private val myActivityScope = CoroutineScope(Dispatchers.Main.immediate) | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
_binding = getViewBinding() | |
setContentView(binding.root) | |
initView() | |
} | |
abstract fun initView() | |
abstract fun getViewBinding(): T | |
override fun onDestroy() { | |
super.onDestroy() | |
job.cancel() | |
myActivityScope.cancel() | |
_binding = null | |
} | |
} |
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
import android.view.ViewGroup | |
import androidx.recyclerview.widget.DiffUtil | |
import androidx.recyclerview.widget.RecyclerView | |
import androidx.viewbinding.ViewBinding | |
abstract class BaseAdapter<T, VB : ViewBinding>( | |
private val itemClickListener: ((T) -> Unit)? = null | |
) : RecyclerView.Adapter<BaseAdapter<T, VB>.BaseViewHolder<VB>>() { | |
fun updateList(newList: List<T>) { | |
val diffResult = DiffUtil.calculateDiff(DiffUtilCallback(items, newList)) | |
items.clear() | |
items.addAll(newList) | |
diffResult.dispatchUpdatesTo(this) | |
} | |
protected val items = mutableListOf<T>() | |
protected abstract fun getViewHolder(binding: VB): BaseViewHolder<VB> | |
protected abstract fun createBinding(parent: ViewGroup, viewType: Int): VB | |
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<VB> { | |
val binding = createBinding(parent, viewType) | |
return getViewHolder(binding) | |
} | |
override fun getItemCount(): Int = items.size | |
override fun onBindViewHolder(holder: BaseViewHolder<VB>, position: Int) { | |
val item = items[position] | |
holder.bind(item) | |
itemClickListener?.let { clickListener -> | |
holder.itemView.setOnClickListener { | |
clickListener(item) | |
} | |
} | |
} | |
abstract inner class BaseViewHolder<VB : ViewBinding>(val binding: VB) : RecyclerView.ViewHolder(binding.root) { | |
abstract fun bind(item: T) | |
} | |
private class DiffUtilCallback<T>( | |
private val oldList: List<T>, | |
private val newList: List<T> | |
) : DiffUtil.Callback() { | |
override fun getOldListSize(): Int = oldList.size | |
override fun getNewListSize(): Int = newList.size | |
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { | |
return oldList[oldItemPosition] == newList[newItemPosition] | |
} | |
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { | |
return oldList[oldItemPosition] == newList[newItemPosition] | |
} | |
} | |
} |
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
import android.os.Bundle | |
import android.view.* | |
import androidx.fragment.app.Fragment | |
import androidx.viewbinding.ViewBinding | |
import com.devhoony.lottieproegressdialog.LottieProgressDialog | |
import ir.adorateb.adorax.common.network.Resource | |
import timber.log.Timber | |
typealias Inflate<R> = (LayoutInflater, ViewGroup?, Boolean) -> R | |
abstract class BaseFragment<Binding : ViewBinding>( | |
private val inflate: Inflate<Binding> | |
) : Fragment(), BaseView { | |
private var _binding: Binding? = null | |
protected val binding get() = _binding!! | |
private val dialogLoading: LottieProgressDialog by lazy { | |
LottieProgressDialog( | |
context = requireContext(), | |
isCancel = false, | |
dialogWidth = null, | |
dialogHeight = null, | |
animationViewWidth = null, | |
animationViewHeight = null, | |
fileName = LottieProgressDialog.SAMPLE_1, | |
title = null, | |
titleVisible = null | |
) | |
} | |
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { | |
_binding = inflate.invoke(inflater, container, false) | |
return binding.root | |
} | |
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | |
super.onViewCreated(view, savedInstanceState) | |
initView() | |
initObservers() | |
} | |
// handle changes to someLiveData | |
open fun initObservers() {} | |
// set up views and UI elements here | |
abstract fun initView() | |
protected fun <T> handleUIResult(resource: Resource<T>?) { | |
if (resource == null) return | |
when (resource) { | |
is Resource.Loading -> { | |
dialogLoading.show() | |
Timber.v(" >>> UI Result BaseFragment LOADING dialog show") | |
} | |
is Resource.Success -> { | |
dialogLoading.dismiss() | |
Timber.d(" >>> UI Result BaseFragment LOADING dismiss - SUCCESS") | |
} | |
is Resource.Error -> { | |
dialogLoading.dismiss() | |
Timber.e(" >>> UI Result BaseFragment LOADING dismiss - ERROR IS MSG=${resource.errorMessage} ") | |
} | |
is Resource.Failure -> { | |
dialogLoading.dismiss() | |
Timber.e(" >>> UI Result BaseFragment LOADING dismiss - FAILURE IS MSG=${(resource.message) ?: "failure"} ") | |
} | |
is Resource.NoInternet -> { | |
dialogLoading.dismiss() | |
Timber.i(" >>> UI Result BaseFragment LOADING dismiss - No Internet IS MSG=${resource.msg} ") | |
} | |
} | |
} | |
override fun onDestroyView() { | |
super.onDestroyView() | |
_binding = null | |
} | |
} |
Author
Morteza-QN
commented
May 9, 2023
private fun setUpSearch(){
binding.etSearchNews.addTextChangedListener{ editable->
job?.cancel()
job = MainScope().launch {
delay(500L)
}
editable?.let {
if (editable.toString().isNotEmpty()){
allNewsViewModel.doSearchForNews(editable.toString())
}
}
}
}
val scrollListener = object : RecyclerView.OnScrollListener(){
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
val visibleItemCount = layoutManager.childCount
val totalItemCount = layoutManager.itemCount
val isNoErrors = !isError
val isLoadingAndNotLastPage = !isLoading && !isLastPage
val isAtLastItem = firstVisibleItemPosition + visibleItemCount >= totalItemCount
val isNotAtBeginning = firstVisibleItemPosition >= 0
val isTotalMoreThanVisible = totalItemCount >= QUERY_PAGE_SIZE
val shouldPaginate = isNoErrors && isLoadingAndNotLastPage && isAtLastItem && isNotAtBeginning &&
isTotalMoreThanVisible && isScrolling
if(shouldPaginate) {
allNewsViewModel.doSearchForNews(binding.etSearchNews.text.toString())
isScrolling = false
}
}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if(newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
isScrolling = true
}
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment