From 708fa3f85bc5c1770a9e1ab49d3d425e79d10de4 Mon Sep 17 00:00:00 2001 From: Naeun Kim <102296721+Nico1eKim@users.noreply.github.com> Date: Tue, 2 Sep 2025 16:04:14 +0900 Subject: [PATCH 1/9] =?UTF-8?q?[chore]:=20=ED=95=84=EC=9A=94=20=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EB=8D=94=EB=AF=B8=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20(#125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/group/room/mock/GroupRoomChatData.kt | 57 ------------------- 1 file changed, 57 deletions(-) delete mode 100644 app/src/main/java/com/texthip/thip/ui/group/room/mock/GroupRoomChatData.kt diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/mock/GroupRoomChatData.kt b/app/src/main/java/com/texthip/thip/ui/group/room/mock/GroupRoomChatData.kt deleted file mode 100644 index 84b22e23..00000000 --- a/app/src/main/java/com/texthip/thip/ui/group/room/mock/GroupRoomChatData.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.texthip.thip.ui.group.room.mock - -import androidx.compose.ui.graphics.painter.Painter - -data class GroupRoomChatData( - val profileImage: Painter?, - val nickname: String, - val date: String, - val content: String, - val isMine: Boolean -) - -val mockMessages = listOf( - GroupRoomChatData( - null, - "user.01", - "2024.04.29", - "공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다.", - isMine = true - ), - GroupRoomChatData( - null, - "user.01", - "2024.04.28", - "공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다.", - isMine = true - ), - GroupRoomChatData(null, "user.01", "2024.04.30", "공백 포함 글자 입력입니다.", isMine = false), - GroupRoomChatData( - null, - "user.01", - "2024.04.30", - "공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다.", - isMine = true - ), - GroupRoomChatData( - null, - "user.01", - "2024.04.30", - "공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다.", - isMine = false - ), - GroupRoomChatData( - null, - "user.01", - "2024.04.27", - "공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다.", - isMine = true - ), - GroupRoomChatData( - null, - "user.01", - "2024.04.27", - "공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다. 공백 포함 글자 입력입니다.", - isMine = true - ), -).sortedByDescending { it.date } \ No newline at end of file From e91b17502afd598a540c7c4d6daf5a8a2266cd1a Mon Sep 17 00:00:00 2001 From: Naeun Kim <102296721+Nico1eKim@users.noreply.github.com> Date: Tue, 2 Sep 2025 16:06:39 +0900 Subject: [PATCH 2/9] =?UTF-8?q?[feat]:=20=EC=98=A4=EB=8A=98=EC=9D=98=20?= =?UTF-8?q?=ED=95=9C=EB=A7=88=EB=94=94=20=EC=82=AD=EC=A0=9C=20data=20layer?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20(#125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rooms/response/RoomsDeleteDailyGreetingResponse.kt | 8 ++++++++ .../texthip/thip/data/repository/RoomsRepository.kt | 10 ++++++++++ .../java/com/texthip/thip/data/service/RoomsService.kt | 7 +++++++ 3 files changed, 25 insertions(+) create mode 100644 app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsDeleteDailyGreetingResponse.kt diff --git a/app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsDeleteDailyGreetingResponse.kt b/app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsDeleteDailyGreetingResponse.kt new file mode 100644 index 00000000..0eb5a2ba --- /dev/null +++ b/app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomsDeleteDailyGreetingResponse.kt @@ -0,0 +1,8 @@ +package com.texthip.thip.data.model.rooms.response + +import kotlinx.serialization.Serializable + +@Serializable +data class RoomsDeleteDailyGreetingResponse ( + val roomId: Int, +) \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/data/repository/RoomsRepository.kt b/app/src/main/java/com/texthip/thip/data/repository/RoomsRepository.kt index 4618c660..2d6f6faa 100644 --- a/app/src/main/java/com/texthip/thip/data/repository/RoomsRepository.kt +++ b/app/src/main/java/com/texthip/thip/data/repository/RoomsRepository.kt @@ -289,6 +289,16 @@ class RoomsRepository @Inject constructor( ).handleBaseResponse().getOrThrow() } + suspend fun deleteRoomsDailyGreeting( + roomId: Int, + attendanceCheckId: Int + ) = runCatching { + roomsService.deleteRoomsDailyGreeting( + roomId = roomId, + attendanceCheckId = attendanceCheckId + ).handleBaseResponse().getOrThrow() + } + suspend fun getRoomsRecordsPin( roomId: Int, recordId: Int diff --git a/app/src/main/java/com/texthip/thip/data/service/RoomsService.kt b/app/src/main/java/com/texthip/thip/data/service/RoomsService.kt index b7365b58..ea8313d6 100644 --- a/app/src/main/java/com/texthip/thip/data/service/RoomsService.kt +++ b/app/src/main/java/com/texthip/thip/data/service/RoomsService.kt @@ -21,6 +21,7 @@ import com.texthip.thip.data.model.rooms.response.RoomsBookPageResponse import com.texthip.thip.data.model.rooms.response.RoomsCreateDailyGreetingResponse import com.texthip.thip.data.model.rooms.response.RoomsCreateVoteResponse import com.texthip.thip.data.model.rooms.response.RoomsDailyGreetingResponse +import com.texthip.thip.data.model.rooms.response.RoomsDeleteDailyGreetingResponse import com.texthip.thip.data.model.rooms.response.RoomsDeleteRecordResponse import com.texthip.thip.data.model.rooms.response.RoomsDeleteVoteResponse import com.texthip.thip.data.model.rooms.response.RoomsPlayingResponse @@ -178,6 +179,12 @@ interface RoomsService { @Body request: RoomsCreateDailyGreetingRequest ): BaseResponse + @DELETE("rooms/{roomId}/daily-greeting/{attendanceCheckId}") + suspend fun deleteRoomsDailyGreeting( + @Path("roomId") roomId: Int, + @Path("attendanceCheckId") attendanceCheckId: Int + ): BaseResponse + @GET("rooms/{roomId}/records/{recordId}/pin") suspend fun getRoomsRecordsPin( @Path("roomId") roomId: Int, From 9802257b668250aebf54573a55646f334b282f39 Mon Sep 17 00:00:00 2001 From: Naeun Kim <102296721+Nico1eKim@users.noreply.github.com> Date: Tue, 2 Sep 2025 16:06:49 +0900 Subject: [PATCH 3/9] =?UTF-8?q?[feat]:=20=EC=98=A4=EB=8A=98=EC=9D=98=20?= =?UTF-8?q?=ED=95=9C=EB=A7=88=EB=94=94=20=EC=82=AD=EC=A0=9C=20api=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0=20=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1=20?= =?UTF-8?q?(#125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/group/room/screen/GroupRoomChatScreen.kt | 11 +++++++++-- .../room/viewmodel/GroupRoomChatViewModel.kt | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt index f366f0ad..6e701d7c 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt @@ -1,5 +1,6 @@ package com.texthip.thip.ui.group.room.screen +import android.widget.Toast import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween import androidx.compose.animation.slideInVertically @@ -28,6 +29,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -60,6 +62,7 @@ fun GroupRoomChatScreen( ) { var inputText by remember { mutableStateOf("") } val uiState by viewModel.uiState.collectAsState() + val context = LocalContext.current var activeToast by remember { mutableStateOf(null) } @@ -69,7 +72,9 @@ fun GroupRoomChatScreen( is GroupRoomChatEvent.ShowToast -> { activeToast = event.type } - + is GroupRoomChatEvent.ShowErrorToast -> { + Toast.makeText(context, event.message, Toast.LENGTH_SHORT).show() + } else -> Unit } } @@ -298,7 +303,9 @@ fun GroupRoomChatContent( text = stringResource(R.string.delete), color = colors.Red, onClick = { - // TODO: 삭제 처리 + selectedMessage?.let { message -> + onEvent(GroupRoomChatEvent.DeleteGreeting(message.attendanceCheckId)) + } isBottomSheetVisible = false } ) diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomChatViewModel.kt b/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomChatViewModel.kt index f8858cea..91757209 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomChatViewModel.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomChatViewModel.kt @@ -31,6 +31,7 @@ sealed interface GroupRoomChatEvent { data object LoadMore : GroupRoomChatEvent data class ShowToast(val type: ToastType) : GroupRoomChatEvent data class ShowErrorToast(val message: String) : GroupRoomChatEvent + data class DeleteGreeting(val attendanceCheckId: Int) : GroupRoomChatEvent } @HiltViewModel @@ -55,10 +56,24 @@ class GroupRoomChatViewModel @Inject constructor( fun onEvent(event: GroupRoomChatEvent) { when (event) { is GroupRoomChatEvent.LoadMore -> fetchDailyGreetings() + is GroupRoomChatEvent.DeleteGreeting -> deleteDailyGreeting(event.attendanceCheckId) else -> Unit } } + private fun deleteDailyGreeting(attendanceCheckId: Int) { + viewModelScope.launch { + roomsRepository.deleteRoomsDailyGreeting( + roomId = roomId, + attendanceCheckId = attendanceCheckId + ).onSuccess { + fetchDailyGreetings(isRefresh = true) + }.onFailure { throwable -> + _eventFlow.emit(GroupRoomChatEvent.ShowErrorToast(throwable.message ?: "삭제에 실패했습니다.")) + } + } + } + private fun fetchDailyGreetings(isRefresh: Boolean = false) { val currentState = _uiState.value if (currentState.isLoading || currentState.isLoadingMore || (currentState.isLastPage && !isRefresh)) return From 65b7e587ad3ff6e76875e6b88a42f95968fece3a Mon Sep 17 00:00:00 2001 From: Naeun Kim <102296721+Nico1eKim@users.noreply.github.com> Date: Wed, 3 Sep 2025 20:54:53 +0900 Subject: [PATCH 4/9] =?UTF-8?q?[chore]:=20string=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thip/ui/group/myroom/component/GroupMySectionHeader.kt | 2 +- app/src/main/res/values/strings.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupMySectionHeader.kt b/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupMySectionHeader.kt index 2148e1f1..1b35730d 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupMySectionHeader.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/myroom/component/GroupMySectionHeader.kt @@ -28,7 +28,7 @@ fun GroupMySectionHeader(onClick: (() -> Unit)? = null) { verticalAlignment = Alignment.CenterVertically ) { Text( - text = stringResource(R.string.my_group), + text = stringResource(R.string.my_group_room), style = typography.title_b700_s20_h24, color = colors.White ) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 24c043da..599cfa10 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -155,7 +155,6 @@ "모집" "장르" 마감 임박한 독서 모임방 - 내 모임방 %1$s명 참여 "%1$s님의 진행도 " From 4affaf870d8703594940967063e44a095d3584e5 Mon Sep 17 00:00:00 2001 From: Naeun Kim <102296721+Nico1eKim@users.noreply.github.com> Date: Wed, 3 Sep 2025 20:55:25 +0900 Subject: [PATCH 5/9] =?UTF-8?q?[feat]:=20=EB=B0=A9=20=EB=82=98=EA=B0=80?= =?UTF-8?q?=EA=B8=B0=20data=20layer=20=EC=83=9D=EC=84=B1=20(#125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/texthip/thip/data/repository/RoomsRepository.kt | 8 ++++++++ .../java/com/texthip/thip/data/service/RoomsService.kt | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/app/src/main/java/com/texthip/thip/data/repository/RoomsRepository.kt b/app/src/main/java/com/texthip/thip/data/repository/RoomsRepository.kt index 2d6f6faa..e31f725b 100644 --- a/app/src/main/java/com/texthip/thip/data/repository/RoomsRepository.kt +++ b/app/src/main/java/com/texthip/thip/data/repository/RoomsRepository.kt @@ -308,4 +308,12 @@ class RoomsRepository @Inject constructor( recordId = recordId ).handleBaseResponse().getOrThrow() } + + suspend fun leaveRoom( + roomId: Int, + ) = runCatching { + roomsService.leaveRoom( + roomId = roomId, + ).handleBaseResponse().getOrThrow() + } } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/data/service/RoomsService.kt b/app/src/main/java/com/texthip/thip/data/service/RoomsService.kt index ea8313d6..e34a9aa8 100644 --- a/app/src/main/java/com/texthip/thip/data/service/RoomsService.kt +++ b/app/src/main/java/com/texthip/thip/data/service/RoomsService.kt @@ -190,4 +190,9 @@ interface RoomsService { @Path("roomId") roomId: Int, @Path("recordId") recordId: Int ): BaseResponse + + @DELETE("rooms/{roomId}/leave") + suspend fun leaveRoom( + @Path("roomId") roomId: Int + ): BaseResponse } \ No newline at end of file From 6654dbd01c305d1ef8ac9e9aaf1852e5294e7e8f Mon Sep 17 00:00:00 2001 From: Naeun Kim <102296721+Nico1eKim@users.noreply.github.com> Date: Thu, 4 Sep 2025 00:35:31 +0900 Subject: [PATCH 6/9] =?UTF-8?q?[feat]:=20=EB=B0=A9=20=EB=82=98=EA=B0=80?= =?UTF-8?q?=EA=B8=B0=20api=20=EC=97=B0=EA=B2=B0=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20(#125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/group/room/screen/GroupRoomScreen.kt | 75 ++++++++++++++++++- .../room/viewmodel/GroupRoomViewModel.kt | 28 ++++++- app/src/main/res/values/strings.xml | 3 + 3 files changed, 102 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt index d11949e8..bbeb0d64 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomScreen.kt @@ -1,5 +1,9 @@ package com.texthip.thip.ui.group.room.screen +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -28,6 +32,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.compose.AsyncImage @@ -36,15 +41,20 @@ import com.texthip.thip.data.model.rooms.response.CurrentVote import com.texthip.thip.data.model.rooms.response.RoomsPlayingResponse import com.texthip.thip.ui.common.bottomsheet.MenuBottomSheet import com.texthip.thip.ui.common.modal.DialogPopup +import com.texthip.thip.ui.common.modal.ToastWithDate import com.texthip.thip.ui.common.topappbar.GradationTopAppBar import com.texthip.thip.ui.group.room.component.GroupRoomBody import com.texthip.thip.ui.group.room.component.GroupRoomHeader import com.texthip.thip.ui.group.room.mock.MenuBottomSheetItem +import com.texthip.thip.ui.group.room.viewmodel.GroupRoomEvent +import com.texthip.thip.ui.group.room.viewmodel.GroupRoomToastType import com.texthip.thip.ui.group.room.viewmodel.GroupRoomUiState import com.texthip.thip.ui.group.room.viewmodel.GroupRoomViewModel import com.texthip.thip.ui.theme.ThipTheme import com.texthip.thip.ui.theme.ThipTheme.colors import com.texthip.thip.utils.type.GenreBackgroundImage +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.collectLatest @Composable fun GroupRoomScreen( @@ -57,12 +67,23 @@ fun GroupRoomScreen( viewModel: GroupRoomViewModel = hiltViewModel() ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + var activeToast by remember { mutableStateOf(null) } // 화면이 처음 그려질 때 데이터 로딩 실행 LaunchedEffect(key1 = Unit) { viewModel.fetchRoomsPlaying(roomId) } + LaunchedEffect(key1 = viewModel.eventFlow) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is GroupRoomEvent.ShowToast -> { + activeToast = event.type + } + } + } + } + // UI 상태에 따라 다른 화면을 보여줌 when (val state = uiState) { is GroupRoomUiState.Loading -> { @@ -79,7 +100,10 @@ fun GroupRoomScreen( onNavigateToMates = onNavigateToMates, onNavigateToChat = onNavigateToChat, onNavigateToNote = onNavigateToNote, - onNavigateToBookDetail = onNavigateToBookDetail + onNavigateToBookDetail = onNavigateToBookDetail, + onLeaveRoomConfirm = { viewModel.leaveRoom(roomId) }, + activeToast = activeToast, + onDismissToast = { activeToast = null } ) } @@ -100,6 +124,9 @@ fun GroupRoomContent( onNavigateToChat: () -> Unit = {}, onNavigateToNote: (page: Int?, isOverview: Boolean?) -> Unit = { _, _ -> }, onNavigateToBookDetail: (isbn: String) -> Unit = {}, + onLeaveRoomConfirm: () -> Unit = {}, + activeToast: GroupRoomToastType?, + onDismissToast: () -> Unit = {} ) { val scrollState = rememberScrollState() @@ -204,6 +231,47 @@ fun GroupRoomContent( isRightIconVisible = true, onRightClick = { isBottomSheetVisible = true }, ) + + AnimatedVisibility( + visible = activeToast != null, + enter = slideInVertically( + initialOffsetY = { -it }, + animationSpec = tween(durationMillis = 2000) + ), + exit = slideOutVertically( + targetOffsetY = { -it }, + animationSpec = tween(durationMillis = 2000) + ), + modifier = Modifier + .align(Alignment.TopCenter) + .padding(horizontal = 20.dp, vertical = 16.dp) + .zIndex(3f) + ) { + LaunchedEffect(activeToast) { + if (activeToast != null) { + delay(3000L) + if (activeToast == GroupRoomToastType.LEAVE_ROOM_SUCCESS) { + onBackClick() + } + onDismissToast() + } + } + + when (activeToast) { + GroupRoomToastType.LEAVE_ROOM_SUCCESS -> { + ToastWithDate(message = stringResource(R.string.leave_room_toast)) + } + + GroupRoomToastType.ACTION_FAILURE -> { + ToastWithDate( + message = stringResource(R.string.leave_room_fail_toast), + color = colors.Red + ) + } + + null -> {} + } + } } if (isBottomSheetVisible) { @@ -248,7 +316,7 @@ fun GroupRoomContent( title = stringResource(R.string.leave_room_modal_title), description = stringResource(R.string.leave_room_modal_content), onConfirm = { - // 방 나가기 로직 + onLeaveRoomConfirm() isLeaveDialogVisible = false }, onCancel = { @@ -304,7 +372,8 @@ private fun GroupRoomScreenPreview() { userPercentage = 5, currentVotes = emptyList() ), - onBackClick = {} + onBackClick = {}, + activeToast = null ) } } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomViewModel.kt b/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomViewModel.kt index 3fa2d3b3..2d1b2bcf 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomViewModel.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomViewModel.kt @@ -1,11 +1,13 @@ package com.texthip.thip.ui.group.room.viewmodel -import com.texthip.thip.data.model.rooms.response.RoomsPlayingResponse import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.texthip.thip.data.model.rooms.response.RoomsPlayingResponse import com.texthip.thip.data.repository.RoomsRepository import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import javax.inject.Inject @@ -16,6 +18,15 @@ sealed interface GroupRoomUiState { data class Error(val message: String) : GroupRoomUiState // 실패 } +enum class GroupRoomToastType { + LEAVE_ROOM_SUCCESS, + ACTION_FAILURE // 방 나가기/삭제 등 실패 시 공통으로 사용 +} + +sealed interface GroupRoomEvent { + data class ShowToast(val type: GroupRoomToastType) : GroupRoomEvent +} + @HiltViewModel class GroupRoomViewModel @Inject constructor( private val roomsRepository: RoomsRepository @@ -23,6 +34,9 @@ class GroupRoomViewModel @Inject constructor( private val _uiState = MutableStateFlow(GroupRoomUiState.Loading) val uiState = _uiState.asStateFlow() + private val _eventFlow = MutableSharedFlow() + val eventFlow = _eventFlow.asSharedFlow() + fun fetchRoomsPlaying(roomId: Int) { // ViewModel의 생명주기와 연결된 코루틴 스코프에서 실행 viewModelScope.launch { @@ -41,4 +55,16 @@ class GroupRoomViewModel @Inject constructor( } } } + + fun leaveRoom(roomId: Int) { + viewModelScope.launch { + roomsRepository.leaveRoom(roomId = roomId) + .onSuccess { + _eventFlow.emit(GroupRoomEvent.ShowToast(GroupRoomToastType.LEAVE_ROOM_SUCCESS)) + } + .onFailure { throwable -> + _eventFlow.emit(GroupRoomEvent.ShowToast(GroupRoomToastType.ACTION_FAILURE)) + } + } + } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 599cfa10..8fea16af 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -169,6 +169,8 @@ %1$s 저 현재 페이지 %d % + 모임 나가기를 완료했어요. + 모임 나가기를 실패했어요. 소개글 @@ -194,6 +196,7 @@ 아직 대화가 없어요 첫번째 한마디를 남겨보세요! 오늘의 한마디는 하루에 다섯번까지 작성할 수 있어요 + 오늘의 한마디 삭제를 완료했어요. %d. %s From 081b865df577c31f08d504afe2e4ca77797b3829 Mon Sep 17 00:00:00 2001 From: Naeun Kim <102296721+Nico1eKim@users.noreply.github.com> Date: Thu, 4 Sep 2025 00:35:56 +0900 Subject: [PATCH 7/9] =?UTF-8?q?[refactor]:=20=EC=98=A4=EB=8A=98=EC=9D=98?= =?UTF-8?q?=20=ED=95=9C=EB=A7=88=EB=94=94=20=EC=82=AD=EC=A0=9C=20=EC=8B=9C?= =?UTF-8?q?=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EB=9C=A8=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=20(#125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../group/room/screen/GroupRoomChatScreen.kt | 53 +++++++------------ .../room/viewmodel/GroupRoomChatViewModel.kt | 4 +- 2 files changed, 22 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt index 6e701d7c..0cb18056 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt @@ -80,6 +80,13 @@ fun GroupRoomChatScreen( } } + LaunchedEffect(activeToast) { + if (activeToast != null) { + delay(3000) + activeToast = null + } + } + GroupRoomChatContent( uiState = uiState, onEvent = viewModel::onEvent, @@ -91,7 +98,6 @@ fun GroupRoomChatScreen( }, onNavigateBack = onBackClick, activeToast = activeToast, - onDismissToast = { activeToast = null } ) } @@ -104,7 +110,6 @@ fun GroupRoomChatContent( onSendClick: () -> Unit, onNavigateBack: () -> Unit, activeToast: ToastType?, - onDismissToast: () -> Unit ) { var isBottomSheetVisible by remember { mutableStateOf(false) } var selectedMessage by remember { mutableStateOf(null) } @@ -247,11 +252,11 @@ fun GroupRoomChatContent( AnimatedVisibility( visible = activeToast != null, enter = slideInVertically( - initialOffsetY = { -it }, // 위에서 아래로 + initialOffsetY = { -it }, animationSpec = tween(durationMillis = 2000) ), exit = slideOutVertically( - targetOffsetY = { -it }, // 위로 사라짐 + targetOffsetY = { -it }, animationSpec = tween(durationMillis = 2000) ), modifier = Modifier @@ -259,39 +264,20 @@ fun GroupRoomChatContent( .padding(horizontal = 20.dp, vertical = 16.dp) .zIndex(3f) ) { - LaunchedEffect(activeToast) { - if (activeToast != null) { - delay(3000L) - onDismissToast() + when (activeToast) { + ToastType.DAILY_GREETING_LIMIT -> { + ToastWithDate(color = colors.Red) } - } - AnimatedVisibility( - visible = activeToast != null, - enter = slideInVertically( - initialOffsetY = { -it }, - animationSpec = tween(durationMillis = 2000) - ), - exit = slideOutVertically( - targetOffsetY = { -it }, - animationSpec = tween(durationMillis = 2000) - ), - modifier = Modifier - .align(Alignment.TopCenter) - .padding(horizontal = 20.dp, vertical = 16.dp) - .zIndex(3f) - ) { - when (activeToast) { - ToastType.DAILY_GREETING_LIMIT -> { - ToastWithDate(color = colors.Red) - } - - ToastType.FIRST_WRITE -> { - ToastWithDate() - } + ToastType.FIRST_WRITE -> { + ToastWithDate() + } - null -> {} + ToastType.DELETE_GREETING_SUCCESS -> { + ToastWithDate(message = stringResource(R.string.group_room_chat_delete_success)) } + + null -> {} } } } @@ -360,7 +346,6 @@ private fun GroupRoomChatScreenPreview() { onSendClick = {}, onNavigateBack = {}, activeToast = null, - onDismissToast = {} ) } } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomChatViewModel.kt b/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomChatViewModel.kt index 91757209..6df70275 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomChatViewModel.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/room/viewmodel/GroupRoomChatViewModel.kt @@ -24,7 +24,8 @@ data class GroupRoomChatUiState( enum class ToastType { DAILY_GREETING_LIMIT, - FIRST_WRITE + FIRST_WRITE, + DELETE_GREETING_SUCCESS } sealed interface GroupRoomChatEvent { @@ -67,6 +68,7 @@ class GroupRoomChatViewModel @Inject constructor( roomId = roomId, attendanceCheckId = attendanceCheckId ).onSuccess { + _eventFlow.emit(GroupRoomChatEvent.ShowToast(ToastType.DELETE_GREETING_SUCCESS)) fetchDailyGreetings(isRefresh = true) }.onFailure { throwable -> _eventFlow.emit(GroupRoomChatEvent.ShowErrorToast(throwable.message ?: "삭제에 실패했습니다.")) From 4c94e994d8785fdf45b2824b27d07bc0965f8a5f Mon Sep 17 00:00:00 2001 From: Naeun Kim <102296721+Nico1eKim@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:12:58 +0900 Subject: [PATCH 8/9] =?UTF-8?q?[refactor]:=20=EB=B0=A9=20=EB=82=98?= =?UTF-8?q?=EA=B0=94=EC=9D=84=20=EB=95=8C=20=EB=82=B4=20=EB=AA=A8=EC=9E=84?= =?UTF-8?q?=EB=B0=A9=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=8B=A4=EC=8B=9C=20?= =?UTF-8?q?fetch=ED=95=98=EA=B2=8C=20=EC=88=98=EC=A0=95=20(#125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/texthip/thip/ui/group/myroom/screen/GroupMyScreen.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/texthip/thip/ui/group/myroom/screen/GroupMyScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/myroom/screen/GroupMyScreen.kt index 617328d0..26022136 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/myroom/screen/GroupMyScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/myroom/screen/GroupMyScreen.kt @@ -48,6 +48,10 @@ fun GroupMyScreen( ) { val uiState by viewModel.uiState.collectAsState() + LaunchedEffect(key1 = Unit) { + viewModel.refreshData() + } + GroupMyContent( uiState = uiState, onCardClick = onCardClick, From 140f7fbdf1a74de2c86130dab74be997b77bda76 Mon Sep 17 00:00:00 2001 From: Naeun Kim <102296721+Nico1eKim@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:23:49 +0900 Subject: [PATCH 9/9] =?UTF-8?q?[refactor]:=20=EC=98=A4=EB=8A=98=EC=9D=98?= =?UTF-8?q?=20=ED=95=9C=EB=A7=88=EB=94=94=20toast=20=EC=82=AC=EB=9D=BC?= =?UTF-8?q?=EC=A7=88=EB=95=8C=20=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EC=95=88=EB=90=98=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20(#125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thip/ui/feed/screen/FeedCommentScreen.kt | 2 - .../group/room/screen/GroupRoomChatScreen.kt | 66 ++++++++++++------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt index c14322f8..d2a682e5 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt @@ -41,7 +41,6 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource @@ -204,7 +203,6 @@ private fun FeedCommentContent( var showDeleteDialog by remember { mutableStateOf(false) } var showToast by remember { mutableStateOf(false) } var toastMessage by remember { mutableStateOf("") } - val context = LocalContext.current LaunchedEffect(showToast) { if (showToast) { diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt index 0cb18056..bca30a8c 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomChatScreen.kt @@ -29,6 +29,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -64,13 +65,34 @@ fun GroupRoomChatScreen( val uiState by viewModel.uiState.collectAsState() val context = LocalContext.current - var activeToast by remember { mutableStateOf(null) } + var showToast by remember { mutableStateOf(false) } + var toastMessage by remember { mutableStateOf("") } + val colorWhite = colors.White + val colorRed = colors.Red + var toastColor by remember { mutableStateOf(colorWhite) } + + val dailyGreetingLimitMessage = stringResource(R.string.group_room_chat_max) + val deleteSuccessMessage = stringResource(R.string.group_room_chat_delete_success) LaunchedEffect(key1 = Unit) { viewModel.eventFlow.collectLatest { event -> when (event) { is GroupRoomChatEvent.ShowToast -> { - activeToast = event.type + when (event.type) { + ToastType.DAILY_GREETING_LIMIT -> { + toastMessage = dailyGreetingLimitMessage + toastColor = colorRed + } + ToastType.FIRST_WRITE -> { + toastMessage = dailyGreetingLimitMessage + toastColor = colorWhite + } + ToastType.DELETE_GREETING_SUCCESS -> { + toastMessage = deleteSuccessMessage + toastColor = colorWhite + } + } + showToast = true } is GroupRoomChatEvent.ShowErrorToast -> { Toast.makeText(context, event.message, Toast.LENGTH_SHORT).show() @@ -80,10 +102,10 @@ fun GroupRoomChatScreen( } } - LaunchedEffect(activeToast) { - if (activeToast != null) { + LaunchedEffect(showToast) { + if (showToast) { delay(3000) - activeToast = null + showToast = false } } @@ -97,7 +119,9 @@ fun GroupRoomChatScreen( inputText = "" }, onNavigateBack = onBackClick, - activeToast = activeToast, + showToast = showToast, + toastMessage = toastMessage, + toastColor = toastColor ) } @@ -109,7 +133,9 @@ fun GroupRoomChatContent( onInputTextChanged: (String) -> Unit, onSendClick: () -> Unit, onNavigateBack: () -> Unit, - activeToast: ToastType?, + showToast: Boolean, + toastMessage: String, + toastColor: Color, ) { var isBottomSheetVisible by remember { mutableStateOf(false) } var selectedMessage by remember { mutableStateOf(null) } @@ -250,7 +276,8 @@ fun GroupRoomChatContent( } AnimatedVisibility( - visible = activeToast != null, + // visible 조건을 showToast로 변경 + visible = showToast, enter = slideInVertically( initialOffsetY = { -it }, animationSpec = tween(durationMillis = 2000) @@ -264,21 +291,10 @@ fun GroupRoomChatContent( .padding(horizontal = 20.dp, vertical = 16.dp) .zIndex(3f) ) { - when (activeToast) { - ToastType.DAILY_GREETING_LIMIT -> { - ToastWithDate(color = colors.Red) - } - - ToastType.FIRST_WRITE -> { - ToastWithDate() - } - - ToastType.DELETE_GREETING_SUCCESS -> { - ToastWithDate(message = stringResource(R.string.group_room_chat_delete_success)) - } - - null -> {} - } + ToastWithDate( + message = toastMessage, + color = toastColor + ) } } @@ -345,7 +361,9 @@ private fun GroupRoomChatScreenPreview() { onInputTextChanged = { newText -> inputText = newText }, onSendClick = {}, onNavigateBack = {}, - activeToast = null, + showToast = false, + toastMessage = "", + toastColor = colors.White ) } } \ No newline at end of file