Skip to content

Commit

Permalink
refactor/#4 : debounce, flatMapLatest 적용
Browse files Browse the repository at this point in the history
- 특정 시간 내의 이벤트 하나의 이벤트 처리
- 이벤트 처리 후 0.3초 간격을 두고 다음 이벤트 처리
  • Loading branch information
TaewoongR committed Jan 23, 2025
1 parent 4498aa5 commit a6e6254
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import com.boostcamp.mapisode.mygroup.sideeffect.GroupSideEffect
import com.boostcamp.mapisode.mygroup.sideeffect.rememberFlowWithLifecycle
import com.boostcamp.mapisode.mygroup.state.GroupState
import com.boostcamp.mapisode.mygroup.viewmodel.GroupViewModel
import timber.log.Timber
import com.boostcamp.mapisode.mygroup.R as S

@Composable
Expand Down Expand Up @@ -106,14 +105,14 @@ private fun <T> GroupScreen(

MapisodeScaffold(
modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectTapGestures(
onPress = {
focusManager.clearFocus()
},
)
},
.fillMaxSize()
.pointerInput(Unit) {
detectTapGestures(
onPress = {
focusManager.clearFocus()
},
)
},
isStatusBarPaddingExist = true,
topBar = {
TopAppBar(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ 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 >(
initialState: UI_STATE
): ViewModel() {
abstract class GroupBaseViewModel<UI_INTENT : UiIntent, UI_STATE : UiState, UI_EFFECT : SideEffect>(
initialState: UI_STATE,
) : ViewModel() {
private val _state = MutableStateFlow(initialState)
val state = _state.asStateFlow()

private val _intent = MutableSharedFlow<UI_INTENT>()

private val _effect = Channel<SideEffect>()
val effect = _effect.receiveAsFlow()

protected val currentState: UI_STATE
get() = _state.value

private val _intent = MutableSharedFlow<UI_INTENT>()

/**
* initialize the reducer with the intent argument
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ 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.UiIntent
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 @@ -30,34 +34,39 @@ class GroupCreationViewModel @Inject constructor(
) {
private val userId: ConcurrentHashMap<String, String> = ConcurrentHashMap()

@OptIn(FlowPreview::class)
override suspend fun reducer(intent: SharedFlow<GroupCreationIntent>) {
intent.collectLatest { uiIntent ->
when (uiIntent) {
GroupCreationIntent.Initialize -> {
initializeCreatingGroup()
}
intent.debounce(100L)
.flatMapLatest { value ->
flowOf(value).onEach { delay(300) }
}
.collectLatest { uiIntent ->
when (uiIntent) {
GroupCreationIntent.Initialize -> {
initializeCreatingGroup()
}

GroupCreationIntent.OnBackClick -> {
sendEffect { GroupCreationSideEffect.NavigateToGroupScreen }
}
GroupCreationIntent.OnBackClick -> {
sendEffect { GroupCreationSideEffect.NavigateToGroupScreen }
}

is GroupCreationIntent.OnGroupCreationClick -> {
checkGroupEdit(uiIntent.title, uiIntent.content, uiIntent.imageUrl)
}
is GroupCreationIntent.OnGroupCreationClick -> {
checkGroupEdit(uiIntent.title, uiIntent.content, uiIntent.imageUrl)
}

is GroupCreationIntent.OnPhotoPickerClick -> {
sendState { copy(isSelectingGroupImage = true) }
}
is GroupCreationIntent.OnPhotoPickerClick -> {
sendState { copy(isSelectingGroupImage = true) }
}

is GroupCreationIntent.OnGroupImageSelect -> {
imageApply(uiIntent.imageUrl)
}
is GroupCreationIntent.OnGroupImageSelect -> {
imageApply(uiIntent.imageUrl)
}

is GroupCreationIntent.OnBackToGroupCreation -> {
sendState { copy(isSelectingGroupImage = false) }
is GroupCreationIntent.OnBackToGroupCreation -> {
sendState { copy(isSelectingGroupImage = false) }
}
}
}
}
}

private fun initializeCreatingGroup() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ 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.UiIntent
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.toImmutableList
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 javax.inject.Inject

Expand All @@ -30,58 +34,64 @@ class GroupDetailViewModel @Inject constructor(
) : GroupBaseViewModel<GroupDetailIntent, GroupDetailState, GroupDetailSideEffect>(GroupDetailState()) {
private val groupId = mutableStateOf("")

@OptIn(FlowPreview::class)
override suspend fun reducer(intent: SharedFlow<GroupDetailIntent>) {
intent.collectLatest { uiIntent ->
when (uiIntent) {
is GroupDetailIntent.InitializeGroupDetail -> {
getGroupDetail(uiIntent.groupId)
}
intent
.debounce(100L)
.flatMapLatest { value ->
flowOf(value).onEach { delay(300) }
}
.collectLatest { uiIntent ->
when (uiIntent) {
is GroupDetailIntent.InitializeGroupDetail -> {
getGroupDetail(uiIntent.groupId)
}

is GroupDetailIntent.TryGetGroup -> {
tryGetGroup()
}
is GroupDetailIntent.TryGetGroup -> {
tryGetGroup()
}

is GroupDetailIntent.TryGetUserInfo -> {
setGroupMembersInfo()
}
is GroupDetailIntent.TryGetUserInfo -> {
setGroupMembersInfo()
}

is GroupDetailIntent.OnEditClick -> {
sendEffect { GroupDetailSideEffect.NavigateToGroupEditScreen(groupId.value) }
delay(100)
sendState { copy(isGroupLoading = true) }
}
is GroupDetailIntent.OnEditClick -> {
sendEffect { GroupDetailSideEffect.NavigateToGroupEditScreen(groupId.value) }
delay(100)
sendState { copy(isGroupLoading = true) }
}

is GroupDetailIntent.OnBackClick -> {
sendEffect { GroupDetailSideEffect.NavigateToGroupScreen }
}
is GroupDetailIntent.OnBackClick -> {
sendEffect { GroupDetailSideEffect.NavigateToGroupScreen }
}

is GroupDetailIntent.OnEpisodeClick -> {
sendEffect { GroupDetailSideEffect.NavigateToEpisode(uiIntent.episodeId) }
}
is GroupDetailIntent.OnEpisodeClick -> {
sendEffect { GroupDetailSideEffect.NavigateToEpisode(uiIntent.episodeId) }
}

is GroupDetailIntent.OnIssueCodeClick -> {
issueInvitationCode()
}
is GroupDetailIntent.OnIssueCodeClick -> {
issueInvitationCode()
}

is GroupDetailIntent.OnGroupOutClick -> {
sendEffect { GroupDetailSideEffect.WarnGroupOut }
}
is GroupDetailIntent.OnGroupOutClick -> {
sendEffect { GroupDetailSideEffect.WarnGroupOut }
}

is GroupDetailIntent.OnGroupOutConfirm -> {
sendEffect { GroupDetailSideEffect.RemoveDialog }
delay(100)
leaveGroup()
}
is GroupDetailIntent.OnGroupOutConfirm -> {
sendEffect { GroupDetailSideEffect.RemoveDialog }
delay(100)
leaveGroup()
}

is GroupDetailIntent.OnGroupOutCancel -> {
sendEffect { GroupDetailSideEffect.RemoveDialog }
}
is GroupDetailIntent.OnGroupOutCancel -> {
sendEffect { GroupDetailSideEffect.RemoveDialog }
}

is GroupDetailIntent.TryGetGroupEpisodes -> {
getGroupEpisodes()
is GroupDetailIntent.TryGetGroupEpisodes -> {
getGroupEpisodes()
}
}
}
}
}

private fun getGroupDetail(groupId: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,56 @@ 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.UiIntent
import dagger.hilt.android.lifecycle.HiltViewModel
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.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()) {

@OptIn(FlowPreview::class)
override suspend fun reducer(intent: SharedFlow<GroupEditIntent>) {
intent.collectLatest { uiIntent ->
when (uiIntent) {
is GroupEditIntent.Initialize -> {
initializeCreatingGroup(uiIntent.groupId)
}
intent.debounce(100L)
.flatMapLatest { value ->
flowOf(value).onEach { delay(300) }
}
.collect { uiIntent ->
when (uiIntent) {
is GroupEditIntent.Initialize -> {
initializeCreatingGroup(uiIntent.groupId)
}

is GroupEditIntent.OnBackClick -> {
sendEffect { GroupEditSideEffect.NavigateToGroupDetailScreen }
}
is GroupEditIntent.OnBackClick -> {
sendEffect { GroupEditSideEffect.NavigateToGroupDetailScreen }
}

is GroupEditIntent.OnGroupEditClick -> {
checkGroupEdit(uiIntent.title, uiIntent.content, uiIntent.imageUrl)
}
is GroupEditIntent.OnGroupEditClick -> {
checkGroupEdit(uiIntent.title, uiIntent.content, uiIntent.imageUrl)
}

GroupEditIntent.DenyPhotoPermission -> sendEffect {
GroupEditSideEffect.ShowToast(R.string.message_error_permission_denied)
}
GroupEditIntent.DenyPhotoPermission -> sendEffect {
GroupEditSideEffect.ShowToast(R.string.message_error_permission_denied)
}

is GroupEditIntent.OnGroupImageSelect -> {
imageApply(uiIntent.imageUrl)
}
is GroupEditIntent.OnGroupImageSelect -> {
imageApply(uiIntent.imageUrl)
}

GroupEditIntent.OnPhotoPickerClick -> {
sendState { copy(isSelectingGroupImage = true) }
}
GroupEditIntent.OnPhotoPickerClick -> {
sendState { copy(isSelectingGroupImage = true) }
}

GroupEditIntent.OnBackToGroupCreation -> sendState { copy(isSelectingGroupImage = false) }
GroupEditIntent.OnBackToGroupCreation -> sendState { copy(isSelectingGroupImage = false) }
}
}
}
}

private fun initializeCreatingGroup(groupId: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ 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.UiIntent
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

Expand All @@ -36,13 +40,16 @@ class GroupJoinViewModel @Inject constructor(
}
}

@OptIn(FlowPreview::class)
override suspend fun reducer(intent: SharedFlow<GroupJoinIntent>) {
viewModelScope.launch {
intent.collectLatest { intent ->

when (intent) {
intent.debounce(100L)
.flatMapLatest { value ->
flowOf(value).onEach { delay(300) }
}
.collectLatest { uiIntent ->
when (uiIntent) {
is GroupJoinIntent.TryGetGroup -> {
tryGetGroupByGroupId(intent.inviteCode)
tryGetGroupByGroupId(uiIntent.inviteCode)
}

is GroupJoinIntent.OnJoinClick -> {
Expand All @@ -54,7 +61,6 @@ class GroupJoinViewModel @Inject constructor(
}
}
}
}
}

private fun tryGetGroupByGroupId(inviteCodes: String) {
Expand Down
Loading

0 comments on commit a6e6254

Please sign in to comment.