FavoriteViewModel.kt

package com.gyleedev.githubsearch.feature.favorite

import android.os.Build
import androidx.annotation.RequiresExtension
import androidx.lifecycle.viewModelScope
import androidx.paging.cachedIn
import com.gyleedev.githubsearch.domain.model.FilterStatus
import com.gyleedev.githubsearch.domain.model.UserModel
import com.gyleedev.githubsearch.domain.usecase.GetFavoritesUseCase
import com.gyleedev.githubsearch.domain.usecase.UpdateFavoriteStatusUseCase
import com.gyleedev.ui.BaseViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject

/*
필터, 소트 종류가 많아지면 uiState 사용 고려
지금은 보일러 플레이트가 늘 뿐
1. update filterState
2. favorite 리스트 가져오는거
 */
@HiltViewModel
class FavoriteViewModel @Inject constructor(
    private val updateFavoriteUseCase: UpdateFavoriteStatusUseCase,
    private val getFavoritesUseCase: GetFavoritesUseCase,
) : BaseViewModel() {
    private val filterState = MutableStateFlow(FilterStatus.ALL)
    private val showFavoriteDialog = MutableStateFlow(false)
    private val showFilterDialog = MutableStateFlow(false)

    private val focusedUser = MutableStateFlow<UserModel?>(null)

    val uiState = combine(filterState, showFavoriteDialog, showFilterDialog) { filterState, showFavorite, showFilter ->
        FavoriteUiState.Success(
            favoriteDialogState = showFavorite,
            filterDialogState = showFilter,
            filterState = filterState,
        )
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5_000),
        initialValue = FavoriteUiState.Loading,
    )

    @OptIn(ExperimentalCoroutinesApi::class)
    val items =
        filterState
            .flatMapLatest {
                getFavoritesUseCase(it)
            }.cachedIn(viewModelScope)

    @RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
    fun updateFilter(status: FilterStatus) {
        viewModelScope.launch(exceptionHandler) {
            filterState.emit(status)
        }
    }

    @RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
    fun showFavoriteDialog(user: UserModel) {
        viewModelScope.launch(exceptionHandler) {
            focusedUser.emit(user)
            updateShowFavoriteDialog()
        }
    }

    @RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
    fun updateFavoriteStatus() {
        viewModelScope.launch(exceptionHandler) {
            focusedUser.value?.let {
                updateFavoriteUseCase(it)
            }
            focusedUser.emit(null)
            updateShowFavoriteDialog()
        }
    }

    @RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
    fun updateShowFavoriteDialog() {
        viewModelScope.launch(exceptionHandler) {
            showFavoriteDialog.emit(!showFavoriteDialog.value)
        }
    }

    @RequiresExtension(extension = Build.VERSION_CODES.S, version = 7)
    fun updateShowFilterDialog() {
        viewModelScope.launch(exceptionHandler) {
            showFilterDialog.emit(!showFilterDialog.value)
        }
    }
}