From ff7fac7598bca4431a7eb138a042d6bbe371c453 Mon Sep 17 00:00:00 2001 From: TaewoongR Date: Wed, 4 Dec 2024 14:08:31 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix/#220=20:=20immutable=20state=20?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - core:model의 모델을 state로 사용 -> 화면 전용 immutable 모델 선언 및 state 사용 --- .../mapisode/mygroup/model/GroupUiModel.kt | 38 +++++++++++++++++++ .../mygroup/screen/GroupDetailScreen.kt | 2 +- .../mygroup/state/GroupDetailState.kt | 10 +++-- .../mygroup/viewmodel/GroupDetailViewModel.kt | 8 ++-- 4 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/model/GroupUiModel.kt diff --git a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/model/GroupUiModel.kt b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/model/GroupUiModel.kt new file mode 100644 index 00000000..06dff224 --- /dev/null +++ b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/model/GroupUiModel.kt @@ -0,0 +1,38 @@ +package com.boostcamp.mapisode.mygroup.model + +import androidx.compose.runtime.Immutable +import com.boostcamp.mapisode.model.GroupModel +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList +import java.util.Date + +@Immutable +data class GroupUiModel( + val id: String, + val adminUser: String, + val createdAt: Date, + val description: String, + val imageUrl: String, + val name: String, + val members: ImmutableList, +) { + fun toGroupModel(): GroupModel = GroupModel( + id = id, + adminUser = adminUser, + createdAt = createdAt, + description = description, + imageUrl = imageUrl, + name = name, + members = members.toList(), + ) +} + +fun GroupModel.toGroupUiModel(): GroupUiModel = GroupUiModel( + id = id, + adminUser = adminUser, + createdAt = createdAt, + description = description, + imageUrl = imageUrl, + name = name, + members = members.toImmutableList(), +) diff --git a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/screen/GroupDetailScreen.kt b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/screen/GroupDetailScreen.kt index ad8ff6fd..f54745bd 100644 --- a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/screen/GroupDetailScreen.kt +++ b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/screen/GroupDetailScreen.kt @@ -266,7 +266,7 @@ fun GroupDetailContent( 0 -> { if (uiState.group != null) { GroupDetailContent( - group = uiState.group, + group = uiState.group.toGroupModel(), members = uiState.membersInfo, onIssueCodeClick = onIssueCodeClick, onGroupOutClick = onGroupOutClick, diff --git a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/state/GroupDetailState.kt b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/state/GroupDetailState.kt index 8b699951..61f361ef 100644 --- a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/state/GroupDetailState.kt +++ b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/state/GroupDetailState.kt @@ -1,17 +1,19 @@ package com.boostcamp.mapisode.mygroup.state import androidx.compose.runtime.Immutable -import com.boostcamp.mapisode.model.GroupModel import com.boostcamp.mapisode.mygroup.model.GroupUiEpisodeModel import com.boostcamp.mapisode.mygroup.model.GroupUiMemberModel +import com.boostcamp.mapisode.mygroup.model.GroupUiModel import com.boostcamp.mapisode.ui.base.UiState +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf @Immutable data class GroupDetailState( val isGroupIdCaching: Boolean = true, val isGroupLoading: Boolean = false, val isGroupOwner: Boolean = false, - val group: GroupModel? = null, - val membersInfo: List = emptyList(), - val episodes: List = emptyList(), + val group: GroupUiModel? = null, + val membersInfo: ImmutableList = persistentListOf(), + val episodes: ImmutableList = persistentListOf(), ) : UiState diff --git a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/viewmodel/GroupDetailViewModel.kt b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/viewmodel/GroupDetailViewModel.kt index 44494b5e..134f90ef 100644 --- a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/viewmodel/GroupDetailViewModel.kt +++ b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/viewmodel/GroupDetailViewModel.kt @@ -9,10 +9,12 @@ import com.boostcamp.mapisode.mygroup.R import com.boostcamp.mapisode.mygroup.intent.GroupDetailIntent import com.boostcamp.mapisode.mygroup.model.GroupUiMemberModel 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.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.delay import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch @@ -97,7 +99,7 @@ class GroupDetailViewModel @Inject constructor( intent { copy( isGroupLoading = false, - group = group, + group = group.toGroupUiModel(), ) } if (group.adminUser == userPreferenceDataStore.getUserId().first()) { @@ -154,7 +156,7 @@ class GroupDetailViewModel @Inject constructor( intent { copy( - membersInfo = memberInfo, + membersInfo = memberInfo.toImmutableList(), ) } } @@ -186,7 +188,7 @@ class GroupDetailViewModel @Inject constructor( member.id == it.createdBy }?.name ?: "" it.toGroupUiEpisodeModel(name) - }, + }.toImmutableList(), ) } } catch (e: Exception) { From f7b9c354bbaffa1f7ef6cf10dcb500a43f9cf789 Mon Sep 17 00:00:00 2001 From: TaewoongR Date: Wed, 4 Dec 2024 14:14:00 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix/#220=20:=20=EC=B0=B8=EC=97=AC=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20state=20immutable=20=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - core:model의 모델을 state로 사용 -> 화면 전용 immutable 모델 선언 및 state 사용 - uiState 선언시 등호 대신 by 사용하여 State 내부 타입 바로 접근 --- .../mapisode/mygroup/screen/GroupJoinScreen.kt | 13 ++++++------- .../mapisode/mygroup/state/GroupJoinState.kt | 4 ++-- .../mygroup/viewmodel/GroupJoinViewModel.kt | 3 ++- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/screen/GroupJoinScreen.kt b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/screen/GroupJoinScreen.kt index 24ca8a07..11585cbe 100644 --- a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/screen/GroupJoinScreen.kt +++ b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/screen/GroupJoinScreen.kt @@ -17,7 +17,6 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.State import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable @@ -59,7 +58,7 @@ fun GroupJoinScreen( viewModel: GroupJoinViewModel = hiltViewModel(), ) { val context = LocalContext.current - val uiState = viewModel.uiState.collectAsStateWithLifecycle() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() val effect = rememberFlowWithLifecycle( flow = viewModel.sideEffect, initialValue = GroupJoinSideEffect.Idle, @@ -95,7 +94,7 @@ fun GroupJoinScreen( @Composable fun GroupJoinContent( - uiState: State, + uiState: GroupJoinState, onBackClick: () -> Unit, onGetGroup: (String) -> Unit, onJoinGroup: () -> Unit, @@ -193,13 +192,13 @@ fun GroupJoinContent( MapisodeDivider(direction = Direction.Horizontal, thickness = Thickness.Thin) Spacer(modifier = Modifier.padding(10.dp)) } - if (uiState.value.isGroupExist && uiState.value.group != null) { + if (uiState.isGroupExist && uiState.group != null) { item { - ConfirmJoinGroup(uiState.value.group!!) + ConfirmJoinGroup(uiState.group.toGroupModel()) Spacer(modifier = Modifier.padding(bottom = 70.dp)) } } - if (uiState.value.isGroupExist.not() || uiState.value.group == null) { + if (uiState.isGroupExist.not() || uiState.group == null) { item { MapisodeText( text = "존재하지 않는 그룹입니다.", @@ -208,7 +207,7 @@ fun GroupJoinContent( } } } - if (uiState.value.isGroupExist && uiState.value.group != null) { + if (uiState.isGroupExist && uiState.group != null) { Column( modifier = Modifier .fillMaxWidth() diff --git a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/state/GroupJoinState.kt b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/state/GroupJoinState.kt index b634870a..824d81f0 100644 --- a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/state/GroupJoinState.kt +++ b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/state/GroupJoinState.kt @@ -1,7 +1,7 @@ package com.boostcamp.mapisode.mygroup.state import androidx.compose.runtime.Immutable -import com.boostcamp.mapisode.model.GroupModel +import com.boostcamp.mapisode.mygroup.model.GroupCreationModel import com.boostcamp.mapisode.ui.base.UiState @Immutable @@ -9,5 +9,5 @@ data class GroupJoinState( val isGroupExist: Boolean = false, val isGroupLoading: Boolean = false, val isJoinedSuccess: Boolean = false, - val group: GroupModel? = null, + val group: GroupCreationModel? = null, ) : UiState diff --git a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/viewmodel/GroupJoinViewModel.kt b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/viewmodel/GroupJoinViewModel.kt index ffb5cf54..f301c3f3 100644 --- a/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/viewmodel/GroupJoinViewModel.kt +++ b/feature/mygroup/src/main/java/com/boostcamp/mapisode/mygroup/viewmodel/GroupJoinViewModel.kt @@ -5,6 +5,7 @@ import com.boostcamp.mapisode.datastore.UserPreferenceDataStore import com.boostcamp.mapisode.mygroup.GroupRepository import com.boostcamp.mapisode.mygroup.R 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.BaseViewModel @@ -54,7 +55,7 @@ class GroupJoinViewModel @Inject constructor( intent { copy(isGroupLoading = true) } try { val group = groupRepository.getGroupByInviteCodes(inviteCodes) - intent { copy(isGroupExist = true, group = group) } + intent { copy(isGroupExist = true, group = group.toGroupCreationModel()) } } catch (e: Exception) { intent { copy(isGroupExist = false) } postSideEffect(GroupJoinSideEffect.ShowToast(R.string.group_join_not_exist))