Skip to content

Commit

Permalink
add itemList Fragment, ViewModel
Browse files Browse the repository at this point in the history
  • Loading branch information
quanda-0562 committed Jul 17, 2023
1 parent 052e1e7 commit 579e646
Show file tree
Hide file tree
Showing 16 changed files with 398 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ fun HomeScreen(
navController: NavController,
viewModel: PopularMovieViewModel = hiltViewModel()
) {
val movieList by viewModel.itemList.collectAsState(listOf())
val refreshing by viewModel.isRefreshing.collectAsState(false)
val pullRefreshState = rememberPullRefreshState(refreshing, { viewModel.doRefresh() })
val itemListUiState by viewModel.itemListUiState.collectAsState()
val pullRefreshState =
rememberPullRefreshState(itemListUiState.isRefreshing, { viewModel.doRefresh() })
val scrollState = rememberLazyGridState()
val endOfListReached by remember {
derivedStateOf {
Expand All @@ -65,7 +65,7 @@ fun HomeScreen(
state = scrollState,
) {
items(
items = movieList,
items = itemListUiState.items,
key = { movie: Movie -> movie.id },
itemContent = { movie ->
ItemMovie(
Expand All @@ -79,7 +79,7 @@ fun HomeScreen(
}

PullRefreshIndicator(
refreshing = refreshing,
refreshing = itemListUiState.isRefreshing,
state = pullRefreshState,
modifier = Modifier.align(Alignment.TopCenter)
)
Expand Down
40 changes: 18 additions & 22 deletions app/src/main/java/com/example/moviedb/ui/base/BaseActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,8 @@ abstract class BaseActivity<ViewBinding : ViewDataBinding, ViewModel : BaseViewM
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collectLatest { uiState ->
when (uiState) {
is UiState.Loading -> {
handleLoading(isLoading = true)
}

is UiState.Error -> {
handleLoading(isLoading = false)
handleError(uiState.errorType)
}

else -> {
handleLoading(isLoading = false)
}
}
handleLoading(uiState.isLoading)
handleError(errorType = uiState.errorType)
}
}
}
Expand All @@ -68,10 +56,11 @@ abstract class BaseActivity<ViewBinding : ViewDataBinding, ViewModel : BaseViewM
* override this if not use loading dialog (example progress bar)
*/
protected open fun handleLoading(isLoading: Boolean) {
if (isLoading) showLoadingDialog() else dismissLLoadingDialog()
if (isLoading) showLoadingDialog()
else dismissLLoadingDialog()
}

protected fun handleError(errorType: ErrorType) {
protected fun handleError(errorType: ErrorType?) {
when (errorType) {
ErrorType.NoInternetConnection -> {
handleErrorMessage(getString(R.string.no_internet_connection))
Expand All @@ -96,16 +85,23 @@ abstract class BaseActivity<ViewBinding : ViewDataBinding, ViewModel : BaseViewM
is ErrorType.UnknownError -> {
handleErrorMessage(getString(R.string.unknown_error))
}

else -> {
dismissShowingDialog()
}
}
}

protected open fun handleErrorMessage(message: String?) {
if (message.isNullOrBlank()) return
dismissLLoadingDialog()
showDialog(
message = message,
firstText = getString(R.string.ok)
)
if (message.isNullOrBlank().not()) {
showDialog(
message = message,
firstText = getString(R.string.ok),
dismissListener = {
viewModel.hideError()
}
)
}
}

override fun onStart() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,8 @@ abstract class BaseBottomSheetDialogFragment<ViewBinding : ViewDataBinding, View
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collectLatest { uiState ->
when (uiState) {
is UiState.Loading -> {
handleLoading(isLoading = true)
}

is UiState.Error -> {
handleLoading(isLoading = false)
handleError(uiState.errorType)
}

else -> {
handleLoading(isLoading = false)
}
}
handleLoading(uiState.isLoading)
handleError(errorType = uiState.errorType)
}
}
}
Expand All @@ -84,7 +72,7 @@ abstract class BaseBottomSheetDialogFragment<ViewBinding : ViewDataBinding, View
else baseActivity.dismissLLoadingDialog()
}

protected fun handleError(errorType: ErrorType) {
protected fun handleError(errorType: ErrorType?) {
when (errorType) {
ErrorType.NoInternetConnection -> {
handleErrorMessage(getString(R.string.no_internet_connection))
Expand All @@ -109,16 +97,23 @@ abstract class BaseBottomSheetDialogFragment<ViewBinding : ViewDataBinding, View
is ErrorType.UnknownError -> {
handleErrorMessage(getString(R.string.unknown_error))
}

else -> {
baseActivity.dismissShowingDialog()
}
}
}

protected open fun handleErrorMessage(message: String?) {
if (message.isNullOrBlank()) return
baseActivity.dismissLLoadingDialog()
baseActivity.showDialog(
message = message,
firstText = getString(R.string.ok)
)
if (message.isNullOrBlank().not()) {
baseActivity.showDialog(
message = message,
firstText = getString(R.string.ok),
dismissListener = {
viewModel.hideError()
}
)
}
}

override fun onStart() {
Expand Down
37 changes: 16 additions & 21 deletions app/src/main/java/com/example/moviedb/ui/base/BaseDialogFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,8 @@ abstract class BaseDialogFragment<ViewBinding : ViewDataBinding, ViewModel : Bas
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collectLatest { uiState ->
when (uiState) {
is UiState.Loading -> {
handleLoading(isLoading = true)
}

is UiState.Error -> {
handleLoading(isLoading = false)
handleError(uiState.errorType)
}

else -> {
handleLoading(isLoading = false)
}
}
handleLoading(uiState.isLoading)
handleError(errorType = uiState.errorType)
}
}
}
Expand All @@ -83,7 +71,7 @@ abstract class BaseDialogFragment<ViewBinding : ViewDataBinding, ViewModel : Bas
else baseActivity.dismissLLoadingDialog()
}

protected fun handleError(errorType: ErrorType) {
protected fun handleError(errorType: ErrorType?) {
when (errorType) {
ErrorType.NoInternetConnection -> {
handleErrorMessage(getString(R.string.no_internet_connection))
Expand All @@ -108,16 +96,23 @@ abstract class BaseDialogFragment<ViewBinding : ViewDataBinding, ViewModel : Bas
is ErrorType.UnknownError -> {
handleErrorMessage(getString(R.string.unknown_error))
}

else -> {
baseActivity.dismissShowingDialog()
}
}
}

protected open fun handleErrorMessage(message: String?) {
if (message.isNullOrBlank()) return
baseActivity.dismissLLoadingDialog()
baseActivity.showDialog(
message = message,
firstText = getString(R.string.ok)
)
if (message.isNullOrBlank().not()) {
baseActivity.showDialog(
message = message,
firstText = getString(R.string.ok),
dismissListener = {
viewModel.hideError()
}
)
}
}

override fun onStart() {
Expand Down
37 changes: 16 additions & 21 deletions app/src/main/java/com/example/moviedb/ui/base/BaseFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,8 @@ abstract class BaseFragment<ViewBinding : ViewDataBinding, ViewModel : BaseViewM
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collectLatest { uiState ->
when (uiState) {
is UiState.Loading -> {
handleLoading(isLoading = true)
}

is UiState.Error -> {
handleLoading(isLoading = false)
handleError(uiState.errorType)
}

else -> {
handleLoading(isLoading = false)
}
}
handleLoading(uiState.isLoading)
handleError(errorType = uiState.errorType)
}
}
}
Expand All @@ -84,7 +72,7 @@ abstract class BaseFragment<ViewBinding : ViewDataBinding, ViewModel : BaseViewM
else baseActivity.dismissLLoadingDialog()
}

protected fun handleError(errorType: ErrorType) {
protected fun handleError(errorType: ErrorType?) {
when (errorType) {
ErrorType.NoInternetConnection -> {
handleErrorMessage(getString(R.string.no_internet_connection))
Expand All @@ -109,16 +97,23 @@ abstract class BaseFragment<ViewBinding : ViewDataBinding, ViewModel : BaseViewM
is ErrorType.UnknownError -> {
handleErrorMessage(getString(R.string.unknown_error))
}

else -> {
baseActivity.dismissShowingDialog()
}
}
}

protected open fun handleErrorMessage(message: String?) {
if (message.isNullOrBlank()) return
baseActivity.dismissLLoadingDialog()
baseActivity.showDialog(
message = message,
firstText = getString(R.string.ok)
)
if (message.isNullOrBlank().not()) {
baseActivity.showDialog(
message = message,
firstText = getString(R.string.ok),
dismissListener = {
viewModel.hideError()
}
)
}
}

override fun onStart() {
Expand Down
41 changes: 29 additions & 12 deletions app/src/main/java/com/example/moviedb/ui/base/BaseViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.example.moviedb.data.remote.toBaseException
import com.example.moviedb.data.repository.UserRepository
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import java.net.ConnectException
Expand All @@ -15,7 +17,8 @@ import java.net.UnknownHostException
import javax.inject.Inject

open class BaseViewModel : ViewModel() {
val uiState = MutableStateFlow<UiState>(UiState.Success)
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState

@Inject
lateinit var userRepo: UserRepository
Expand All @@ -30,15 +33,11 @@ open class BaseViewModel : ViewModel() {
}
protected val viewModelScopeExceptionHandler by lazy { viewModelScope + exceptionHandler }

fun showSuccess() {
uiState.value = UiState.Success
}

/**
* handle throwable when load fail
*/
protected open suspend fun onError(throwable: Throwable) {
val errorType: ErrorType = when (throwable) {
protected fun toErrorType(throwable: Throwable): ErrorType {
return when (throwable) {
// case no internet connection
is UnknownHostException -> {
ErrorType.NoInternetConnection
Expand Down Expand Up @@ -70,16 +69,34 @@ open class BaseViewModel : ViewModel() {
}
}
}
uiState.value = UiState.Error(errorType)
}

fun showError(throwable: Throwable) {
uiState.value = UiState.Error(ErrorType.UnknownError(throwable))
protected open fun onError(throwable: Throwable) {
_uiState.update {
it.copy(
isLoading = false,
errorType = toErrorType(throwable)
)
}
}

open fun hideError() {
_uiState.update {
it.copy(errorType = null)
}
}

fun showLoading() {
uiState.value = UiState.Loading
_uiState.update {
it.copy(isLoading = true, errorType = null)
}
}

fun hideLoading() {
_uiState.update {
it.copy(isLoading = false)
}
}

fun isLoading() = uiState.value == UiState.Loading
fun isLoading() = uiState.value.isLoading
}
9 changes: 4 additions & 5 deletions app/src/main/java/com/example/moviedb/ui/base/UiState.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package com.example.moviedb.ui.base

sealed class UiState {
object Success : UiState()
object Loading : UiState()
class Error(val errorType: ErrorType) : UiState()
}
data class UiState(
val isLoading: Boolean = false,
val errorType: ErrorType? = null
)

sealed class ErrorType {
object NoInternetConnection : ErrorType()
Expand Down
Loading

0 comments on commit 579e646

Please sign in to comment.