Skip to content

Commit

Permalink
refactor/#16 : 업데이트 버전 BaseViewModel, Intent 동시 실행 방지 함수 core/ui 모듈에 선언
Browse files Browse the repository at this point in the history
  • Loading branch information
TaewoongR committed Feb 18, 2025
1 parent 1dc1470 commit 0d7874a
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.boostcamp.mapisode.ui.base

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlin.reflect.KClass

fun Flow<UiIntent>.retainFirstIfNavigating(vararg intents: KClass<out UiIntent>) = channelFlow {
var isFirst = true
collectLatest { value ->
if (isFirst) {
launch(Dispatchers.IO) {
isFirst = false
send(value)
if (intents.any { it.isInstance(value) }) {
delay(400)
}
isFirst = true
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.boostcamp.mapisode.mygroup.viewmodel
package com.boostcamp.mapisode.ui.base

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.boostcamp.mapisode.ui.base.SideEffect
import com.boostcamp.mapisode.ui.base.UiIntent
import com.boostcamp.mapisode.ui.base.UiState
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -15,7 +12,7 @@ import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

abstract class GroupBaseViewModel<UI_INTENT : UiIntent, UI_STATE : UiState, UI_EFFECT : SideEffect>(
abstract class RevisedBaseViewModel<UI_INTENT : UiIntent, UI_STATE : UiState, UI_EFFECT : SideEffect>(
initialState: UI_STATE,
) : ViewModel() {
private val _state = MutableStateFlow(initialState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,13 @@ import com.boostcamp.mapisode.mygroup.R
import com.boostcamp.mapisode.mygroup.intent.GroupCreationIntent
import com.boostcamp.mapisode.mygroup.sideeffect.GroupCreationSideEffect
import com.boostcamp.mapisode.mygroup.state.GroupCreationState
import com.boostcamp.mapisode.ui.base.RevisedBaseViewModel
import com.boostcamp.mapisode.ui.base.retainFirstIfNavigating
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import timber.log.Timber
import java.util.Date
Expand All @@ -29,18 +25,17 @@ import javax.inject.Inject
class GroupCreationViewModel @Inject constructor(
private val groupRepository: GroupRepository,
private val userPreferenceDataStore: UserPreferenceDataStore,
) : GroupBaseViewModel<GroupCreationIntent, GroupCreationState, GroupCreationSideEffect>(
) : RevisedBaseViewModel<GroupCreationIntent, GroupCreationState, GroupCreationSideEffect>(
GroupCreationState(),
) {
private val userId: ConcurrentHashMap<String, String> = ConcurrentHashMap()

@OptIn(FlowPreview::class)
override suspend fun reducer(intent: SharedFlow<GroupCreationIntent>) {
intent.debounce(100L)
.flatMapLatest { value ->
flowOf(value).onEach { delay(300) }
}
.collectLatest { uiIntent ->
intent.retainFirstIfNavigating(
GroupCreationIntent.OnGroupCreationClick::class,
GroupCreationIntent.OnGroupImageSelect::class,
)
.collect { uiIntent ->
when (uiIntent) {
GroupCreationIntent.Initialize -> {
initializeCreatingGroup()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@ import com.boostcamp.mapisode.mygroup.model.toGroupUiEpisodeModel
import com.boostcamp.mapisode.mygroup.model.toGroupUiModel
import com.boostcamp.mapisode.mygroup.sideeffect.GroupDetailSideEffect
import com.boostcamp.mapisode.mygroup.state.GroupDetailState
import com.boostcamp.mapisode.ui.base.RevisedBaseViewModel
import com.boostcamp.mapisode.ui.base.retainFirstIfNavigating
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import javax.inject.Inject
Expand All @@ -28,10 +26,15 @@ class GroupDetailViewModel @Inject constructor(
private val groupRepository: GroupRepository,
private val episodeRepository: EpisodeRepository,
private val userPreferenceDataStore: UserPreferenceDataStore,
) : GroupBaseViewModel<GroupDetailIntent, GroupDetailState, GroupDetailSideEffect>(GroupDetailState()) {
) : RevisedBaseViewModel<GroupDetailIntent, GroupDetailState, GroupDetailSideEffect>(
GroupDetailState(),
) {

override suspend fun reducer(intent: SharedFlow<GroupDetailIntent>) {
intent.retainFirstIfNavigating()
intent.retainFirstIfNavigating(
GroupDetailIntent.OnEditClick::class,
GroupDetailIntent.OnEpisodeClick::class,
)
.collect { uiIntent ->
when (uiIntent) {
is GroupDetailIntent.InitializeGroupDetail -> {
Expand Down Expand Up @@ -196,19 +199,3 @@ class GroupDetailViewModel @Inject constructor(
}
}
}

fun Flow<GroupDetailIntent>.retainFirstIfNavigating() = channelFlow {
var isFirst = true
collectLatest { value ->
if (isFirst) {
launch(Dispatchers.IO) {
isFirst = false
send(value)
if (value is GroupDetailIntent.OnEditClick || value is GroupDetailIntent.OnEpisodeClick) {
delay(300)
}
isFirst = true
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,25 @@ import com.boostcamp.mapisode.mygroup.intent.GroupEditIntent
import com.boostcamp.mapisode.mygroup.model.toGroupCreationModel
import com.boostcamp.mapisode.mygroup.sideeffect.GroupEditSideEffect
import com.boostcamp.mapisode.mygroup.state.GroupEditState
import com.boostcamp.mapisode.ui.base.RevisedBaseViewModel
import com.boostcamp.mapisode.ui.base.retainFirstIfNavigating
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class GroupEditViewModel @Inject constructor(private val groupRepository: GroupRepository) :
GroupBaseViewModel<GroupEditIntent, GroupEditState, GroupEditSideEffect>(GroupEditState()) {
RevisedBaseViewModel<GroupEditIntent, GroupEditState, GroupEditSideEffect>(GroupEditState()) {

@OptIn(FlowPreview::class)
override suspend fun reducer(intent: SharedFlow<GroupEditIntent>) {
intent.debounce(100L)
.flatMapLatest { value ->
flowOf(value).onEach { delay(300) }
}
intent.retainFirstIfNavigating(
GroupEditIntent.OnGroupEditClick::class,
GroupEditIntent.OnGroupImageSelect::class,
)
.collect { uiIntent ->
when (uiIntent) {
is GroupEditIntent.Initialize -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,20 @@ import com.boostcamp.mapisode.mygroup.intent.GroupJoinIntent
import com.boostcamp.mapisode.mygroup.model.toGroupCreationModel
import com.boostcamp.mapisode.mygroup.sideeffect.GroupJoinSideEffect
import com.boostcamp.mapisode.mygroup.state.GroupJoinState
import com.boostcamp.mapisode.ui.base.RevisedBaseViewModel
import com.boostcamp.mapisode.ui.base.retainFirstIfNavigating
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class GroupJoinViewModel @Inject constructor(
private val groupRepository: GroupRepository,
private val userPreferenceDataStore: UserPreferenceDataStore,
) : GroupBaseViewModel<GroupJoinIntent, GroupJoinState, GroupJoinSideEffect>(GroupJoinState()) {
) : RevisedBaseViewModel<GroupJoinIntent, GroupJoinState, GroupJoinSideEffect>(GroupJoinState()) {
private val myId: MutableStateFlow<String> = MutableStateFlow("")

init {
Expand All @@ -40,13 +36,12 @@ class GroupJoinViewModel @Inject constructor(
}
}

@OptIn(FlowPreview::class)
override suspend fun reducer(intent: SharedFlow<GroupJoinIntent>) {
intent.debounce(100L)
.flatMapLatest { value ->
flowOf(value).onEach { delay(300) }
}
.collectLatest { uiIntent ->
intent.retainFirstIfNavigating(
GroupJoinIntent.OnJoinClick::class,
GroupJoinIntent.OnBackClick::class,
)
.collect { uiIntent ->
when (uiIntent) {
is GroupJoinIntent.TryGetGroup -> {
tryGetGroupByGroupId(uiIntent.inviteCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@ import com.boostcamp.mapisode.mygroup.R
import com.boostcamp.mapisode.mygroup.intent.GroupIntent
import com.boostcamp.mapisode.mygroup.sideeffect.GroupSideEffect
import com.boostcamp.mapisode.mygroup.state.GroupState
import com.boostcamp.mapisode.ui.base.RevisedBaseViewModel
import com.boostcamp.mapisode.ui.base.retainFirstIfNavigating
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
Expand All @@ -25,14 +22,14 @@ import javax.inject.Inject
class GroupViewModel @Inject constructor(
private val groupRepository: GroupRepository,
private val userPreferenceDataStore: UserPreferenceDataStore,
) : GroupBaseViewModel<GroupIntent, GroupState, GroupSideEffect>(GroupState()) {
) : RevisedBaseViewModel<GroupIntent, GroupState, GroupSideEffect>(GroupState()) {

@OptIn(FlowPreview::class)
override suspend fun reducer(intent: SharedFlow<GroupIntent>) {
intent.debounce(100)
.flatMapLatest { value ->
flowOf(value).onEach { delay(300) }
}
intent.retainFirstIfNavigating(
GroupIntent.OnJoinClick::class,
GroupIntent.OnGroupCreateClick::class,
GroupIntent.OnGroupDetailClick::class,
)
.collect { uiIntent ->
when (uiIntent) {
GroupIntent.LoadGroups -> {
Expand Down

0 comments on commit 0d7874a

Please sign in to comment.