-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FEAT/#14] 7주차 과제 구현 #15
base: develop
Are you sure you want to change the base?
Changes from all commits
5fedc56
2b47925
5889e71
6ec409c
b3118ee
7397c2e
98b232f
3b6de4f
0016a1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package org.sopt.and.core.viewmodel | ||
|
||
import androidx.lifecycle.ViewModel | ||
import androidx.lifecycle.viewModelScope | ||
import kotlinx.coroutines.flow.MutableSharedFlow | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.asSharedFlow | ||
import kotlinx.coroutines.flow.asStateFlow | ||
import kotlinx.coroutines.launch | ||
|
||
abstract class BaseViewModel<State : UiState, SideEffect : UiSideEffect, Event : UiEvent>( | ||
) : ViewModel() { | ||
|
||
/** | ||
* [createInitialState] is a function that creates the initial state of the state. | ||
* Its role is to force users to initialize UiState in child viewmodel | ||
*/ | ||
private val initialState: State by lazy { createInitialState() } | ||
abstract fun createInitialState(): State | ||
|
||
private val _uiState = MutableStateFlow<State>(initialState) | ||
val uiState = _uiState.asStateFlow() | ||
val currentState: State | ||
get() = uiState.value | ||
|
||
private val _event: MutableSharedFlow<Event> = MutableSharedFlow<Event>() | ||
val event = _event.asSharedFlow() | ||
|
||
private val _sideEffect: MutableSharedFlow<UiSideEffect> = MutableSharedFlow<UiSideEffect>() | ||
val sideEffect = _sideEffect.asSharedFlow() | ||
|
||
fun setState(reduce: State.() -> State) { | ||
_uiState.value = currentState.reduce() | ||
} | ||
|
||
/** | ||
* [setEvent] is used in UI to send out event which can change UI State | ||
* | ||
* It is set as `open`, making it possible for child viewmodel to override and customize this method | ||
*/ | ||
open fun setEvent(event: Event) { | ||
dispatchEvent(event) | ||
} | ||
|
||
/** | ||
* [dispatchEvent] is used to wrap event logins with coroutineScope | ||
* | ||
* By doing so, event logics can handle multiple emissions such as `SideEffect` | ||
*/ | ||
private fun dispatchEvent(event: Event) = viewModelScope.launch { | ||
handleEvent(event) | ||
} | ||
|
||
protected abstract suspend fun handleEvent(event: Event) | ||
|
||
fun setSideEffect(sideEffect: SideEffect) { | ||
viewModelScope.launch { | ||
_sideEffect.emit(sideEffect) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package org.sopt.and.core.viewmodel | ||
|
||
interface UiEvent |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package org.sopt.and.core.viewmodel | ||
|
||
interface UiSideEffect |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package org.sopt.and.core.viewmodel | ||
|
||
interface UiState |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,33 @@ | ||
package org.sopt.and.presentation.home | ||
|
||
import androidx.lifecycle.ViewModel | ||
import dagger.hilt.android.lifecycle.HiltViewModel | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.asStateFlow | ||
import kotlinx.coroutines.flow.update | ||
import org.sopt.and.core.viewmodel.BaseViewModel | ||
import org.sopt.and.domain.repository.RecommendationRepository | ||
import org.sopt.and.presentation.home.state.HomeUiState | ||
import org.sopt.and.presentation.home.contract.HomeUiEvent | ||
import org.sopt.and.presentation.home.contract.HomeUiState | ||
import javax.inject.Inject | ||
|
||
@HiltViewModel | ||
class HomeViewModel @Inject constructor( | ||
private val recommendationRepository: RecommendationRepository | ||
) : ViewModel() { | ||
private var _uiState = MutableStateFlow(HomeUiState()) | ||
val uiState = _uiState.asStateFlow() | ||
) : BaseViewModel<HomeUiState, Nothing, HomeUiEvent>() { | ||
override fun createInitialState(): HomeUiState = HomeUiState() | ||
|
||
init { | ||
initializeHomeState() | ||
override suspend fun handleEvent(event: HomeUiEvent) { | ||
when(event) { | ||
is HomeUiEvent.OnTabSelected -> { | ||
setState { copy(selectedTabIndex = event.index) } | ||
} | ||
} | ||
} | ||
|
||
private fun initializeHomeState() = _uiState.update { currentState -> | ||
currentState.copy( | ||
bannerImgList = recommendationRepository.getBannerImages(), | ||
recommendations = recommendationRepository.getRecommendations(), | ||
rankedSeries = recommendationRepository.getMostPopularSeries() | ||
) | ||
} | ||
|
||
fun updateSelectedTabIndex(index: Int) = _uiState.update { currentState -> | ||
currentState.copy(selectedTabIndex = index) | ||
fun initializeHomeState() { | ||
setState { | ||
copy( | ||
bannerImgList = recommendationRepository.getBannerImages(), | ||
recommendations = recommendationRepository.getRecommendations(), | ||
rankedSeries = recommendationRepository.getMostPopularSeries() | ||
) | ||
} | ||
Comment on lines
+25
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그 세미나할때 팟장지현이가
라고 했는데 이건 상관이 없을까요...?! 저도 잘 몰라서 물어봅니다...! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 상태를 변경하는 로직을 한 군데에서만 관리하기 위해서 setState에서만 상태 변경을 해주시는 것이 좋습니다! (자세한 내용은 세미나 자료 참고,,) |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.sopt.and.presentation.home.contract | ||
|
||
import org.sopt.and.core.viewmodel.UiEvent | ||
|
||
sealed class HomeUiEvent: UiEvent { | ||
data class OnTabSelected(val index: Int): HomeUiEvent() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,11 @@ | ||
package org.sopt.and.presentation.home.state | ||
package org.sopt.and.presentation.home.contract | ||
|
||
import org.sopt.and.core.viewmodel.UiState | ||
import org.sopt.and.domain.entity.HomeRecommendation | ||
|
||
data class HomeUiState( | ||
val selectedTabIndex: Int = 0, | ||
val bannerImgList: List<Int> = emptyList(), | ||
val recommendations: List<HomeRecommendation> = emptyList(), | ||
val rankedSeries: HomeRecommendation? = null | ||
) | ||
) : UiState |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
empty 처리 해주는 거 좋네요!!