Skip to content

Instantly share code, notes, and snippets.

@Aldikitta
Last active September 6, 2023 06:40
Show Gist options
  • Save Aldikitta/1daece80397b70acbb682b692d6037ec to your computer and use it in GitHub Desktop.
Save Aldikitta/1daece80397b70acbb682b692d6037ec to your computer and use it in GitHub Desktop.
//RESOURCE CLASS
package com.kreditplus.sally.core.utils.network
import com.google.gson.Gson
import com.google.gson.JsonParser
import com.google.gson.annotations.SerializedName
import com.kreditplus.sally.core.base.dto.KreditPlusBaseResponseDto
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart
import org.json.JSONException
import org.json.JSONObject
import retrofit2.HttpException
import java.io.IOException
const val CLIENT_ERROR = "Terjadi kesalahan, mohon periksa masukan anda"
const val SERVER_ERROR = "Terjadi kesalahan pada Server, coba lagi nanti"
const val NETWORK_ERROR = "Koneksi internet bermasalah, coba lagi nanti"
const val HTTP_UNKNOWN_ERROR = "HTTP Error tidak diketahui (exc: 4xx/5xx)"
const val UNKNOWN_ERROR = "Error tidak diketahui"
sealed interface KreditPlusResponse<out T> {
data class Success<T>(val data: T) : KreditPlusResponse<T>
data class Error<T>(
val exception: AppException,
val errorCode: String? = null,
val responseBodyError: String? = null,
val error: ErrorResponse? = null
) :
KreditPlusResponse<T>
data class Loading(val status: Boolean) : KreditPlusResponse<Nothing>
}
open class AppException(
message: String? = null,
cause: Throwable? = null,
val responseBodyError: String? = null,
) : Throwable(message, cause)
class NetworkException(message: String? = null, cause: Throwable? = null) :
AppException(message, cause)
class ServerException(
message: String? = null,
cause: Throwable? = null,
responseBodyError: String? = null
) :
AppException(message, cause, responseBodyError)
class ClientException(
message: String? = null,
cause: Throwable? = null,
responseBodyError: String? = null
) :
AppException(message, cause, responseBodyError)
class UnknownException(
message: String? = null,
cause: Throwable? = null,
responseBodyError: String? = null
) :
AppException(message, cause, responseBodyError)
suspend fun <T> asSuspendKreditPlusResponse(apiCall: suspend () -> T, loadingState: (Boolean) -> Unit): KreditPlusResponse<T> {
return try {
loadingState(true)
val response = apiCall.invoke()
KreditPlusResponse.Success(response)
} catch (error: Throwable) {
val exception = when (error) {
is HttpException -> {
val errorBody = error.response()?.errorBody()?.string()
when (error.code()) {
in 400..499 -> {
ClientException(
message = "${CLIENT_ERROR}: ${error.code()}",
cause = error,
responseBodyError = errorBody
)
}
in 500..599 -> ServerException(
message = "${SERVER_ERROR}: ${error.code()}",
cause = error,
responseBodyError = errorBody
)
else -> UnknownException(
message = "${HTTP_UNKNOWN_ERROR}: ${error.code()}",
cause = error,
responseBodyError = errorBody
)
}
}
is IOException -> NetworkException(
message = NETWORK_ERROR,
cause = error
)
else -> AppException(
message = UNKNOWN_ERROR,
cause = error
)
}
val errorCode = when (error) {
is HttpException -> {
when (error.code()) {
in 400..499 -> {
"#ER${error.code()}"
}
in 500..599 -> {
"#ER${error.code()}"
}
else -> {
"#ER${error.code()}"
}
}
}
else -> {
"Outside: 4xx/5xx"
}
}
val errorResponse = Gson().fromJson(exception.responseBodyError, ErrorResponse::class.java)
KreditPlusResponse.Error(exception, errorCode, exception.responseBodyError, errorResponse)
} finally {
loadingState(false)
}
}
fun <T> Flow<T>.asFlowKreditPlusResponse(): Flow<KreditPlusResponse<T>> {
return this
.map<T, KreditPlusResponse<T>> {
KreditPlusResponse.Success(it)
}
.onStart { emit(KreditPlusResponse.Loading(true)) }
.onCompletion { emit(KreditPlusResponse.Loading(false)) }
.catch { error ->
val exception = when (error) {
is HttpException -> {
val errorBody = error.response()?.errorBody()?.string()
when (error.code()) {
in 400..499 -> {
ClientException(
message = "${CLIENT_ERROR}: ${error.code()}",
cause = error,
responseBodyError = errorBody
)
}
in 500..599 -> {
ServerException(
message = "${SERVER_ERROR}: ${error.code()}",
cause = error,
responseBodyError = errorBody
)
}
else -> {
UnknownException(
message = "${HTTP_UNKNOWN_ERROR}: ${error.code()}",
cause = error,
responseBodyError = errorBody
)
}
}
}
is IOException -> NetworkException(
message = NETWORK_ERROR,
cause = error
)
else -> AppException(
message = UNKNOWN_ERROR,
cause = error
)
}
val errorCode = when (error) {
is HttpException -> {
when (error.code()) {
in 400..499 -> {
"#ER${error.code()}"
}
in 500..599 -> {
"#ER${error.code()}"
}
else -> {
"#ER${error.code()}"
}
}
}
else -> {
"Outside: 4xx/5xx"
}
}
val errorResponse = Gson().fromJson(exception.responseBodyError, ErrorResponse::class.java)
emit(KreditPlusResponse.Error(exception, errorCode, exception.responseBodyError, errorResponse))
}
}
// This code is use to handle exception error in paging
fun asPagingKreditPlusResponse(cause: Throwable?): LoadStateError {
val error = LoadStateError()
when (cause) {
is IOException -> {
error.errorMessage = cause.message
}
is HttpException -> {
error.errorCode = cause.code()
error.errorMessage = cause.message
error.responseBodyError = cause.response()?.errorBody()?.string()
error.errorMessageStatic = "${HTTP_UNKNOWN_ERROR}: ${cause.code()}"
when (error.errorCode) {
in 400..499 -> {
error.errorMessageStatic = "${CLIENT_ERROR}: ${cause.code()}"
}
in 500..599 -> {
error.errorMessageStatic = "${SERVER_ERROR}: ${cause.code()}"
}
else -> {
error.errorMessageStatic = "${HTTP_UNKNOWN_ERROR}: ${cause.code()}"
}
}
}
else -> {
error.errorMessage = cause?.message
}
}
return error
}
data class LoadStateError(
var errorCode: Int? = null,
var errorMessage: String? = null,
var responseBodyError: String? = null,
var errorMessageStatic: String? = null
)
fun asResponseErrorResponse(
responseBodyError: String?,
statusFieldName: String = "status",
validationArrayName: String = "validation",
fieldFieldName: String = "field",
messageFieldName: String = "message",
statusType: String = "Error validation"
): Map<String, String> {
val errorMap = mutableMapOf<String, String>()
responseBodyError?.let {
try {
val json = JSONObject(responseBodyError)
if (json.has(statusFieldName) && json.getString(statusFieldName) == statusType) {
val validationArray = json.getJSONArray(validationArrayName)
for (i in 0 until validationArray.length()) {
val validationObj = validationArray.getJSONObject(i)
val field = validationObj.getString(fieldFieldName)
val message = validationObj.getString(messageFieldName)
errorMap[field] = message
}
} else {
val validationArray = json.getJSONArray(validationArrayName)
for (i in 0 until validationArray.length()) {
val validationObj = validationArray.getJSONObject(i)
val field = validationObj.getString(fieldFieldName)
val message = validationObj.getString(messageFieldName)
errorMap[field] = message
}
}
} catch (e: JSONException) {
// Handle JSON parsing error if needed
}
}
return errorMap
}
data class ErrorResponse(
@SerializedName("code")
val code: Int?,
@SerializedName("data")
val data: Any?,
@SerializedName("message")
val message: String?,
@SerializedName("request_id")
val requestId: String?,
@SerializedName("timestamp")
val timestamp: String?
)
// SUSPEND FUNCTION
// API SERVICE
@GET("agent-visit/{id}")
suspend fun getDetailAgentVisitWithFullResponse(
@Header("Authorization") token: String,
@Path(value = "id", encoded = true) id: Int
): BaseResponse<GetAgentDetailResponse>
// DATA SOURCE
suspend fun getDetailAgentVisitFullResponse(
token: String,
id: Int
): SallyResponseResource<BaseResponse<GetAgentDetailResponse>> {
return asSallyResponseResourceSuspend {
Log.d("MYTAG", "SUSPEND")
agentVisitService.getDetailAgentVisitWithFullResponse(
token = token,
id = id
)
}
}
// REPOSITORY
override suspend fun getDetailAgentVisitWithFullResponse(id: Int):
SallyResponseResource<BaseResponse<GetAgentDetailResponse>> {
return agentVisitDataSource.getDetailAgentVisitFullResponse(
token = "",
id = id
)
}
// USE CASE
override suspend fun getDetailAgentVisitWithFullResponse(id: Int):
SallyResponseResource<BaseResponse<GetAgentDetailResponse>> {
return iAgentVisitRepository.getDetailAgentVisitWithFullResponse(id)
}
// VIEWMODEL
sealed interface VisitingDetailUiState {
object Loading : VisitingDetailUiState
data class Error(val error: String) : VisitingDetailUiState
data class Success(
val agentVisitingDetail: GetAgentDetailResponse? = null
) : VisitingDetailUiState
}
sealed interface DraftDetailUiEvent {
data class ShowErrorMessage(
val staticError: String?,
val dynamicError: String?,
val errorCode: String?,
val responseBodyError: String?
) : DraftDetailUiEvent
}
private val _errorEventFlow = MutableSharedFlow<DraftDetailUiEvent>(replay = 1)
val errorEventFlow = _errorEventFlow.asSharedFlow()
private val _uiStateDetail =
MutableStateFlow<VisitingDetailUiState>(VisitingDetailUiState.Loading)
val uiStateDetail = _uiStateDetail.asStateFlow()
fun getAgentVisitDetailFullResponse() {
val visitId = savedStateHandle.get<Int>("visitId")
viewModelScope.launch {
val visitDetail = visitId?.let { useCase.getDetailAgentVisitWithFullResponse(id = it) }
when (visitDetail) {
is SallyResponseResource.Loading -> {
Log.d("MYTAG", "LOADING")
_uiStateDetail.value = VisitingDetailUiState.Loading
}
is SallyResponseResource.Success -> {
Log.d("MYTAG", "SUCCESS")
_uiStateDetail.value = VisitingDetailUiState.Success(visitDetail.data.data)
}
is SallyResponseResource.Error -> {
Log.d("MYTAG", "ERROR")
Log.d("MYTAG", "ERROR 1 ${visitDetail.responseBodyError}")
Log.d("MYTAG", "ERROR 2 ${visitDetail.exception.responseBodyError}")
val validationError =
asResponseErrorResponse(responseBodyError = visitDetail.exception.responseBodyError)
validationError.forEach { (field, message) ->
Log.d(
"MYTAG",
"createAgentProspect: ERROR ${"Field: $field, Message: $message"}"
)
}
_eventFlow.emit(
VisitingUiEvent.ShowErrorMessageStatic(
staticError = visitDetail.exception.message,
dynamicError = visitDetail.exception.cause?.message.toString(),
errorCode = visitDetail.errorCode,
responseBodyError = visitDetail.exception.responseBodyError
)
)
_uiStateDetail.value =
VisitingDetailUiState.Error(error = visitDetail.exception.toString())
}
else -> {
AnalyticsUtils.analytic(
Constant.EVENT_FAILURE,
"Exception in getAgentVisit Detail"
)
}
}
}
}
// FRAGMENT
override fun onViewCreated() {
viewModel.getAgentVisitDetailFullResponse()
observeVisitDetail()
}
private fun observeVisitDetail() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiStateDetail.collect { visitingUiState ->
when (visitingUiState) {
is VisitingDetailUiState.Success -> {
Log.d("MYTAG", "SUCCESS FRAGMENT")
// HANDLE SUCCESS EVENT
}
is VisitingDetailUiState.Error -> {
Log.d("MYTAG", "ERROR FRAGMENT")
viewModel.eventFlow.collectLatest {
when (it) {
is VisitingUiEvent.ShowErrorMessageStatic -> {
Timber.tag("MYTAG")
.d("observeVisitDetail: %s", it.staticError)
Timber.tag("MYTAG")
.d("observeVisitDetail: %s", it.dynamicError)
Timber.tag("MYTAG")
.d("observeVisitDetail: %s", it.errorCode)
Timber.tag("MYTAG")
.d("observeVisitDetail: %s", it.responseBodyError)
}
}
}
}
is VisitingDetailUiState.Loading -> {
// HANDLE LOADING EVENT
Log.d("MYTAG", "LOADING FRAGMENT")
}
}
}
}
}
}
// FLOW FUNCTION
// API SERVICE
@GET("agent-visit/{id}")
suspend fun getDetailAgentVisitWithFullResponse(
@Header("Authorization") token: String,
@Path(value = "id", encoded = true) id: Int
): BaseResponse<GetAgentDetailResponse>
// DATA SOURCE
fun getDetailAgentVisitFullResponseFlow(
token: String,
id: Int
): Flow<BaseResponse<GetAgentDetailResponse>> {
return flow {
while (true) {
Log.d("MYTAG", "FLOW")
val getDetailAgent = agentVisitService.getDetailAgentVisitWithFullResponse(
token = token,
id = id
)
emit(getDetailAgent)
delay(5000L)
}
}
}
// REPOSITORY
override fun getDetailAgentVisitFullResponseFlow(id: Int):
Flow<SallyResponseResource<BaseResponse<GetAgentDetailResponse>>> {
return agentVisitDataSource.getDetailAgentVisitFullResponseFlow(
token = "Bearer ${getAccountInfo().token}",
id = id
).asSallyResponseResourceFlow()
}
// USE CASE
override fun getDetailAgentVisitFullResponseFlow(id: Int):
Flow<SallyResponseResource<BaseResponse<GetAgentDetailResponse>>> {
return iAgentVisitRepository.getDetailAgentVisitFullResponseFlow(id)
}
// VIEWMODEL
sealed interface VisitingDetailUiState {
object Loading : VisitingDetailUiState
data class Error(val error: String) : VisitingDetailUiState
data class Success(
val agentVisitingDetail: GetAgentDetailResponse? = null
) : VisitingDetailUiState
}
private val _uiStateDetail =
MutableStateFlow<VisitingDetailUiState>(VisitingDetailUiState.Loading)
val uiStateDetail = _uiStateDetail.asStateFlow()
// if viewmodelScope
fun getAgentVisitDetailFullResponseFlow() {
val visitId = savedStateHandle.get<Int>("visitId")
viewModelScope.launch {
if (visitId != null) {
useCase.getDetailAgentVisitFullResponseFlow(id = visitId)
.collectLatest { visitDetail ->
when (visitDetail) {
is SallyResponseResource.Loading -> {
Log.d("MYTAG", "LOADING")
_uiStateDetail.value = VisitingDetailUiState.Loading
}
is SallyResponseResource.Success -> {
Log.d("MYTAG", "SUCCESS")
_uiStateDetail.value =
VisitingDetailUiState.Success(visitDetail.data.data)
}
is SallyResponseResource.Error -> {
Log.d("MYTAG", "ERROR")
_eventFlow.emit(
VisitingUiEvent.ShowErrorMessageStatic(
staticError = visitDetail.exception.message,
dynamicError = visitDetail.exception.cause?.message.toString(),
errorCode = visitDetail.errorCode,
responseBodyError = visitDetail.exception.responseBodyError
)
)
_uiStateDetail.value =
VisitingDetailUiState.Error(error = visitDetail.exception.toString())
}
}
}
}
}
}
// if StateIn
val agentDetail: StateFlow<VisitingDetailUiState>? =
visitId?.let {
useCase.getDetailAgentVisitFullResponseFlow(id = it).map { visitDetail ->
Log.d("MYTAG", ": got exec")
when (visitDetail) {
is SallyResponseResource.Loading -> {
Log.d("MYTAG", "LOADING")
VisitingDetailUiState.Loading
}
is SallyResponseResource.Success -> {
Log.d("MYTAG", "SUCCESS")
VisitingDetailUiState.Success(visitDetail.data.data)
}
is SallyResponseResource.Error -> {
Log.d("MYTAG", "ERROR")
_eventFlow.emit(
VisitingUiEvent.ShowErrorMessageStatic(
staticError = visitDetail.exception.message,
dynamicError = visitDetail.exception.cause?.message.toString(),
errorCode = visitDetail.errorCode,
responseBodyError = visitDetail.exception.responseBodyError
)
)
VisitingDetailUiState.Error(error = visitDetail.exception.toString())
}
}
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
VisitingDetailUiState.Loading
)
}
// FRAGMENT
override fun onViewCreated() {
if (stateIn) {
observeVisitDetailStateIn()
} else {
viewModel.getAgentVisitDetailFullResponseFlow()
observeVisitDetailBasis()
}
}
private fun observeVisitDetailBasic() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiStateDetail.collect { visitingUiState ->
when (visitingUiState) {
is VisitingDetailUiState.Success -> {
Log.d("MYTAG", "SUCCESS FRAGMENT")
// HANDLE SUCCESS EVENT
}
is VisitingDetailUiState.Error -> {
Log.d("MYTAG", "ERROR FRAGMENT")
viewModel.eventFlow.collectLatest {
when (it) {
is VisitingUiEvent.ShowErrorMessageStatic -> {
Timber.tag("MYTAG")
.d("observeVisitDetail: %s", it.staticError)
Timber.tag("MYTAG")
.d("observeVisitDetail: %s", it.dynamicError)
Timber.tag("MYTAG")
.d("observeVisitDetail: %s", it.errorCode)
Timber.tag("MYTAG")
.d("observeVisitDetail: %s", it.responseBodyError)
}
}
}
}
is VisitingDetailUiState.Loading -> {
// HANDLE LOADING EVENT
Log.d("MYTAG", "LOADING FRAGMENT")
}
}
}
}
}
}
private fun observeVisitDetailStateIn() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiStateDetail.collect { visitingUiState ->
when (visitingUiState) {
is VisitingDetailUiState.Success -> {
// HANDLE SUCCESS EVENT
}
is VisitingDetailUiState.Error -> {
viewModel.eventFlow.collectLatest {
when (it) {
is VisitingUiEvent.ShowErrorMessageStatic -> {
Timber.tag("MYTAG").d("observeVisitDetail: %s", it.staticError)
Timber.tag("MYTAG").d("observeVisitDetail: %s", it.dynamicError)
Timber.tag("MYTAG").d("observeVisitDetail: %s", it.errorCode)
Timber.tag("MYTAG").d("observeVisitDetail: %s", it.responseBodyError)
}
}
}
}
is VisitingDetailUiState.Loading -> {
// HANDLE LOADING EVENT
}
}
}
}
}
}
// PAGING
// API SERVICE
@GET("agent-visit")
suspend fun getListAgentVisitFullResponse(
@Header("Authorization") token: String,
@QueryMap body: MutableMap<String, Any>,
): BaseResponse<List<GetAgentVisitResponse>>
// DATA SOURCE
suspend fun getListAgentVisitFullResponse(
token: String,
body: GetAgentVisitRequest,
): BaseResponse<List<GetAgentVisitResponse>> {
return agentVisitService.getListAgentVisitFullResponse(
token = token,
body = convertDataClassToMap(body)
)
}
// PAGING SOURCE
class AgentVisitListPagingDataSource(
private val agentVisitDataSource: AgentVisitDataSource,
private val getAgentVisitRequest: GetAgentVisitRequest,
private val token: String
) : PagingSource<Int, GetAgentVisitResponse>() {
override fun getRefreshKey(state: PagingState<Int, GetAgentVisitResponse>): Int? {
Log.d("MYTAG", "paging source call: ")
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, GetAgentVisitResponse> {
Log.d("MYTAG", "paging source load: ")
return try {
Log.d("MYTAG", "paging source load: success")
val nextPageNumber = params.key ?: 1
val pageSize = params.loadSize
val bodyWithSkip = getAgentVisitRequest.copy(skip = (nextPageNumber - 1) * pageSize)
val getListResponse = agentVisitDataSource.getListAgentVisitFullResponse(
token = token,
body = bodyWithSkip
)
val data = getListResponse.data ?: emptyList()
val nextKey = if (data.isEmpty()) {
null
} else {
nextPageNumber + 1
}
LoadResult.Page(
data = data,
prevKey = if (nextPageNumber == 1) null else nextPageNumber - 1,
nextKey = nextKey
)
} catch (e: IOException) {
print("Error: ${e.message}")
Log.d("MYTAG", "paging source error IOexcetpion: ")
LoadResult.Error(e)
} catch (e: Exception) {
println("${e.message}")
Log.d("MYTAG", "paging source error excetpion: $e")
LoadResult.Error(e)
} catch (e: HttpException) {
println("${e.message}")
Log.d("MYTAG", "paging source error excetpion: $e")
LoadResult.Error(e)
}
}
}
// REPOSITORY
override fun getListAgentVisitWithFullResponse(body: GetAgentVisitRequest):
Flow<PagingData<GetAgentVisitResponse>> =
Pager(
config = PagingConfig(
pageSize = 20,
prefetchDistance = 10,
),
pagingSourceFactory = {
AgentVisitListPagingDataSource(
agentVisitDataSource = agentVisitDataSource,
token = "",
getAgentVisitRequest = body
)
}
).flow
// USE CASE
override fun getListAgentVisitWithFullResponse(body: GetAgentVisitRequest):
Flow<PagingData<GetAgentVisitResponse>> {
return iAgentVisitRepository.getListAgentVisitWithFullResponse(
body = body
)
}
// VIEWMODEL
data class ListAgentVisit(
val agentList: Flow<PagingData<GetAgentVisitResponse>>,
) {
companion object {
val default: ListAgentVisit = ListAgentVisit(
agentList = emptyFlow(),
)
}
}
data class FilterAgentState(
val search: String,
val prospectConsument: String,
val agentProfessionCode: String,
val startDate: String,
val endDate: String
) {
companion object {
val default: FilterAgentState = FilterAgentState(
search = "",
prospectConsument = "",
agentProfessionCode = "",
startDate = "",
endDate = ""
)
}
}
private val filterAgentState = MutableStateFlow(FilterAgentState.default)
val getListAgent: StateFlow<ListAgentVisit> = filterAgentState.flatMapLatest { filterState ->
flow {
val agentList = useCase.getListAgentVisitWithFullResponse(
body = GetAgentVisitRequest(
branchCode = useCase.getAccountInfo().branchCode,
moId = useCase.getAccountInfo().employeeId,
skip = 1,
search = filterState.search,
prospectConsument = filterState.prospectConsument,
agentProfessionCode = filterState.agentProfessionCode,
startDate = filterState.startDate,
endDate = filterState.endDate
)
).cachedIn(viewModelScope)
emit(ListAgentVisit(agentList = agentList))
}
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
ListAgentVisit.default
)
fun updateFilterState(
search: String? = null,
prospectConsument: String? = null,
agentProfessionCode: String? = null,
startDate: String? = null,
endDate: String? = null
) {
val currentFilter = filterAgentState.value
val updatedFilter = currentFilter.copy(
search = search ?: currentFilter.search,
prospectConsument = prospectConsument ?: currentFilter.prospectConsument,
agentProfessionCode = agentProfessionCode ?: currentFilter.agentProfessionCode,
startDate = startDate ?: currentFilter.startDate,
endDate = endDate ?: currentFilter.endDate
)
filterAgentState.value = updatedFilter
}
fun resetFilterState() {
filterAgentState.value = FilterAgentState.default
}
// FRAGMENT
override fun onViewCreated() {
setupRecyclerView()
setupList()
}
// example using filter state
viewModel.search.value = query
viewModel.updateFilterState(
search = query
)
private fun setupRecyclerView() {
Log.d("MYTAG", "paging initial fragment")
val navController = findNavController()
agentVisitAdapter = AgentVisitAdapter(
viewModel = viewModel,
navController = navController
)
binding.lstAgentVisiting.adapter = agentVisitAdapter
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.getListAgent.collectLatest {
Log.d("MYTAG", "paging fragment:")
it.agentList.collectLatest { paging ->
agentVisitAdapter.submitData(paging)
}
}
}
}
}
private fun setupList() {
val navController = findNavController()
agentVisitAdapter = AgentVisitAdapter(
viewModel = viewModel,
navController = navController
)
binding.lstAgentVisiting.apply {
layoutManager = LinearLayoutManager(context)
adapter = agentVisitAdapter.withLoadStateHeaderAndFooter(
header = PagingLoadStateAdapter { agentVisitAdapter.retry() },
footer = PagingLoadStateAdapter { agentVisitAdapter.retry() }
)
setHasFixedSize(true)
viewLifecycleOwner.lifecycleScope.launch {
agentVisitAdapter.loadStateFlow.collectLatest { loadState ->
when (loadState.refresh) {
is LoadState.Loading -> {
binding.lytShimmerAgent.root.visible(isVisible = loadState.refresh is LoadState.Loading)
binding.chipsFilterShimmer.root.visible(isVisible = loadState.refresh is LoadState.Loading)
}
is LoadState.Error -> {
val error = (loadState.refresh as LoadState.Error).error
val loadStateError: LoadStateError = handleLoadStatePagingError(cause = error)
val errorCode: Int? = loadStateError.errorCode
val errorMessage: String? = loadStateError.errorMessage
val responseBodyError: String? = loadStateError.responseBodyError
val errorMessageStatic: String? = loadStateError.errorMessageStatic
Log.d("MYTAG", "setupList: $errorCode")
Log.d("MYTAG", "setupList: $errorMessage")
Log.d("MYTAG", "setupList: $responseBodyError")
Log.d("MYTAG", "setupList: $errorMessageStatic")
}
is LoadState.NotLoading -> {
binding.lstAgentVisiting.isVisible = true
}
}
// if (loadState.source.append.endOfPaginationReached && agentVisitAdapter.itemCount != 0)
// requireContext().toast(context.getString(com.kreditplus.sally.core.R.string.data_pagination_loaded))
// with(binding) {
// lytShimmerAgent.root.visible(loadState.refresh is LoadState.Loading && agentVisitAdapter.itemCount == 0)
// chipsFilterShimmer.root.visible(loadState.refresh is LoadState.Loading && agentVisitAdapter.itemCount == 0)
// lstAgentVisiting.isVisible = agentVisitAdapter.itemCount > 0
// lytEmptyAgent.root.visible(loadState.refresh is LoadState.NotLoading && agentVisitAdapter.itemCount == 0)
// if (agentVisitAdapter.itemCount == 0) {
// with(binding.lytEmptyAgent) {
// lblTitleEmpty.text =
// getString(R.string.empty_state_title_agent)
// lblMessageEmpty.text =
// getString(R.string.empty_state_label_agent)
// }
// }
// val errorState = when (loadState.refresh) {
// is LoadState.Error -> {
// loadState.refresh as LoadState.Error
// }
//
// else -> null
// }
// errorState?.let { errorStates ->
// if (agentVisitAdapter.itemCount == 0) {
// binding.lytEmptyAgent.apply {
// if (!errorStates.error.message.isNullOrEmpty()) {
// lblTitleEmpty.text =
// getString(R.string.error_state_title_agent)
// lblMessageEmpty.text = errorStates.error.message
// requireContext().toast(errorStates.error.message.orEmpty())
// }
// }
// }
// }
// if (loadState.refresh is LoadState.Loading) lstAgentVisiting.scrollToPosition(
// 0
// )
// }
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment