From 633557a386b500871aac2e1fbf7919dc7e98fdbe Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 12:52:08 +0900 Subject: [PATCH 01/17] =?UTF-8?q?[refactor]:=20LogotopAppbar=20=EC=9A=B0?= =?UTF-8?q?=EC=B8=A1=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thip/ui/common/topappbar/LogoTopAppBar.kt | 2 +- app/src/main/res/drawable/ic_notice_no.xml | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/ic_notice_no.xml diff --git a/app/src/main/java/com/texthip/thip/ui/common/topappbar/LogoTopAppBar.kt b/app/src/main/java/com/texthip/thip/ui/common/topappbar/LogoTopAppBar.kt index 411fb48b..14fcd678 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/topappbar/LogoTopAppBar.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/topappbar/LogoTopAppBar.kt @@ -32,7 +32,7 @@ fun LogoTopAppBar( val rightIcon = if (hasNotification) { painterResource(R.drawable.ic_notice_yes) } else { - painterResource(R.drawable.ic_notice) + painterResource(R.drawable.ic_notice_no) } Box( diff --git a/app/src/main/res/drawable/ic_notice_no.xml b/app/src/main/res/drawable/ic_notice_no.xml new file mode 100644 index 00000000..b1f88d20 --- /dev/null +++ b/app/src/main/res/drawable/ic_notice_no.xml @@ -0,0 +1,19 @@ + + + + From 8e5cee444b8021d64a4994fd2e55325a56d49bb2 Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 13:06:50 +0900 Subject: [PATCH 02/17] =?UTF-8?q?[refactor]:=20=EC=B1=85=20=EC=9E=90?= =?UTF-8?q?=EC=84=B8=ED=9E=88=EB=B3=B4=EA=B8=B0=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EC=9A=B0=EC=B8=A1=20=EB=B2=84=ED=8A=BC=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EB=B0=8F=20gradient=20=EC=88=98=EC=A0=95=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/common/topappbar/GradationTopAppBar.kt | 51 +++++++++++++++---- .../search/screen/SearchBookDetailScreen.kt | 39 +++----------- 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/common/topappbar/GradationTopAppBar.kt b/app/src/main/java/com/texthip/thip/ui/common/topappbar/GradationTopAppBar.kt index 1fbec027..12e038ad 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/topappbar/GradationTopAppBar.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/topappbar/GradationTopAppBar.kt @@ -1,5 +1,6 @@ package com.texthip.thip.ui.common.topappbar +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -9,6 +10,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush @@ -20,14 +26,39 @@ import androidx.compose.ui.unit.dp import com.texthip.thip.R import com.texthip.thip.ui.common.view.CountingBar import com.texthip.thip.ui.theme.ThipTheme.colors +import kotlinx.coroutines.delay @Composable fun GradationTopAppBar( isImageVisible: Boolean = false, count: Int = 0, + autoHideCount: Boolean? = null, + countDisplayDurationMs: Long = 5000L, onLeftClick: () -> Unit, - onRightClick: () -> Unit, + onRightClick: () -> Unit = {}, ) { + var isCountVisible by remember { mutableStateOf(isImageVisible) } + + // autoHideCount가 null이 아닐 때만 자동 숨김 로직 실행 + LaunchedEffect(autoHideCount, count) { + when (autoHideCount) { + true -> { + if (count > 0) { + isCountVisible = true + delay(countDisplayDurationMs) + isCountVisible = false + } + } + false -> { + isCountVisible = true + } + null -> { + // 기존 동작 유지: isImageVisible 파라미터 사용 + isCountVisible = isImageVisible + } + } + } + val bgColor = Brush.verticalGradient( colors = listOf( colors.Black, @@ -54,15 +85,17 @@ fun GradationTopAppBar( ) } - if (isImageVisible) { - CountingBar( - modifier = Modifier - .align(Alignment.Center), - content = stringResource(R.string.reading_user_num, count) - ) + Column { + AnimatedVisibility( + visible = isCountVisible && count > 0 + ) { + CountingBar( + content = stringResource(R.string.reading_user_num, count) + ) + } } - IconButton( + /*IconButton( onClick = onRightClick, modifier = Modifier.align(Alignment.CenterEnd) ) { @@ -71,7 +104,7 @@ fun GradationTopAppBar( contentDescription = "More Options", tint = Color.Unspecified ) - } + }*/ } } diff --git a/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt b/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt index 2ea2b17e..37463a13 100644 --- a/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt @@ -1,6 +1,5 @@ package com.texthip.thip.ui.search.screen -import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable @@ -51,7 +50,6 @@ import com.texthip.thip.R import com.texthip.thip.data.model.book.response.BookDetailResponse import com.texthip.thip.ui.common.buttons.ActionMediumButton import com.texthip.thip.ui.common.modal.InfoPopup -import com.texthip.thip.ui.common.topappbar.DefaultTopAppBar import com.texthip.thip.ui.common.topappbar.GradationTopAppBar import com.texthip.thip.ui.mypage.component.SavedFeedCard import com.texthip.thip.ui.search.component.SearchFilterButton @@ -62,7 +60,6 @@ import com.texthip.thip.ui.theme.ThipTheme import com.texthip.thip.ui.theme.ThipTheme.colors import com.texthip.thip.ui.theme.ThipTheme.typography import com.texthip.thip.utils.color.hexToColor -import kotlinx.coroutines.delay @Composable @@ -91,7 +88,6 @@ fun SearchBookDetailScreen( bookDetail = uiState.bookDetail, uiState = uiState, onLeftClick = onLeftClick, - onRightClick = onRightClick, onRecruitingGroupClick = onRecruitingGroupClick, onWriteFeedClick = onWriteFeedClick, onFeedClick = onFeedClick, @@ -117,7 +113,6 @@ private fun SearchBookDetailScreenContent( bookDetail: BookDetailResponse? = null, uiState: BookDetailUiState? = null, onLeftClick: () -> Unit = {}, - onRightClick: () -> Unit = {}, onRecruitingGroupClick: () -> Unit = {}, onWriteFeedClick: () -> Unit = {}, onFeedClick: (Int) -> Unit = {}, @@ -125,7 +120,6 @@ private fun SearchBookDetailScreenContent( onSortChange: (String) -> Unit = {}, onLoadMore: () -> Unit = {} ) { - var isAlarmVisible by remember { mutableStateOf(true) } var isIntroductionPopupVisible by remember { mutableStateOf(false) } var isBookmarked by remember { mutableStateOf(bookDetail?.isSaved ?: false) } var isFilterDropdownVisible by remember { mutableStateOf(false) } @@ -158,14 +152,6 @@ private fun SearchBookDetailScreenContent( } } - // 알림 5초간 노출 - LaunchedEffect(bookDetail) { - if (bookDetail != null) { - isAlarmVisible = true - delay(5000) - isAlarmVisible = false - } - } // 북마크 상태 동기화 LaunchedEffect(bookDetail?.isSaved) { @@ -488,24 +474,13 @@ private fun SearchBookDetailScreenContent( } // TopAppBar 오버레이 (고정) - Column { - AnimatedVisibility(visible = isAlarmVisible) { - GradationTopAppBar( - isImageVisible = true, - count = bookDetail.readCount, - onLeftClick = onLeftClick, - onRightClick = {} - ) - } - AnimatedVisibility(visible = !isAlarmVisible) { - DefaultTopAppBar( - isRightIconVisible = true, - isTitleVisible = false, - onLeftClick = onLeftClick, - onRightClick = onRightClick - ) - } - } + GradationTopAppBar( + count = bookDetail.readCount, + autoHideCount = true, + countDisplayDurationMs = 5000L, + onLeftClick = onLeftClick, + onRightClick = {} + ) if (isIntroductionPopupVisible) { Box( From a0bb368ac74b722474685f7fa90ce0ab073f466b Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 13:16:10 +0900 Subject: [PATCH 03/17] =?UTF-8?q?[refactor]:=20=EC=B1=85=20=EC=9E=90?= =?UTF-8?q?=EC=84=B8=ED=9E=88=EB=B3=B4=EA=B8=B0=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=ED=94=BC=EB=93=9C=20=EC=9E=91=EC=84=B1=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=EC=9C=BC=EB=A1=9C=20=EB=84=A4=EB=B9=84?= =?UTF-8?q?=EA=B2=8C=EC=9D=B4=EC=85=98=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thip/ui/navigator/navigations/FeedNavigation.kt | 13 +++++++++++++ .../ui/navigator/navigations/SearchNavigation.kt | 10 ++++++++-- .../thip/ui/search/screen/SearchBookDetailScreen.kt | 6 +++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt b/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt index 906166ca..4bc9a51c 100644 --- a/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt +++ b/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt @@ -96,6 +96,19 @@ fun NavGraphBuilder.feedNavigation(navController: NavHostController, navigateBac bookImageUrl = route.bookImageUrl, recordContent = route.recordContent ) + } else if (route.isbn != null && + route.bookTitle != null && + route.bookAuthor != null + ) { + // 새 글 작성 모드: 책 정보만 있는 경우 (책 상세 페이지에서 온 경우) + viewModel.selectBook( + com.texthip.thip.ui.group.makeroom.mock.BookData( + title = route.bookTitle, + imageUrl = route.bookImageUrl ?: "", + author = route.bookAuthor, + isbn = route.isbn + ) + ) } } diff --git a/app/src/main/java/com/texthip/thip/ui/navigator/navigations/SearchNavigation.kt b/app/src/main/java/com/texthip/thip/ui/navigator/navigations/SearchNavigation.kt index d1e08ad5..809dc468 100644 --- a/app/src/main/java/com/texthip/thip/ui/navigator/navigations/SearchNavigation.kt +++ b/app/src/main/java/com/texthip/thip/ui/navigator/navigations/SearchNavigation.kt @@ -7,6 +7,7 @@ import androidx.navigation.toRoute import com.texthip.thip.ui.navigator.extensions.navigateToBookDetail import com.texthip.thip.ui.navigator.extensions.navigateToBookGroup import com.texthip.thip.ui.navigator.extensions.navigateToFeedComment +import com.texthip.thip.ui.navigator.extensions.navigateToFeedWrite import com.texthip.thip.ui.navigator.extensions.navigateToGroupMakeRoomWithBook import com.texthip.thip.ui.navigator.extensions.navigateToGroupRecruit import com.texthip.thip.ui.navigator.extensions.navigateToRegisterBook @@ -43,8 +44,13 @@ fun NavGraphBuilder.searchNavigation(navController: NavHostController) { onRecruitingGroupClick = { navController.navigateToBookGroup(isbn) }, - onWriteFeedClick = { - // TODO: 피드 작성 화면으로 이동 + onWriteFeedClick = { bookDetail -> + navController.navigateToFeedWrite( + isbn = bookDetail.isbn, + bookTitle = bookDetail.title, + bookAuthor = bookDetail.authorName, + bookImageUrl = bookDetail.imageUrl + ) }, onFeedClick = { feedId -> navController.navigateToFeedComment(feedId) diff --git a/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt b/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt index 37463a13..664daa8b 100644 --- a/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt @@ -69,7 +69,7 @@ fun SearchBookDetailScreen( onLeftClick: () -> Unit = {}, onRightClick: () -> Unit = {}, onRecruitingGroupClick: () -> Unit = {}, - onWriteFeedClick: () -> Unit = {}, + onWriteFeedClick: (BookDetailResponse) -> Unit = {}, onFeedClick: (Int) -> Unit = {}, onBookmarkClick: (String, Boolean) -> Unit = { _, _ -> }, viewModel: BookDetailViewModel = hiltViewModel() @@ -114,7 +114,7 @@ private fun SearchBookDetailScreenContent( uiState: BookDetailUiState? = null, onLeftClick: () -> Unit = {}, onRecruitingGroupClick: () -> Unit = {}, - onWriteFeedClick: () -> Unit = {}, + onWriteFeedClick: (BookDetailResponse) -> Unit = {}, onFeedClick: (Int) -> Unit = {}, onBookmarkClick: (String, Boolean) -> Unit = { _, _ -> }, onSortChange: (String) -> Unit = {}, @@ -316,7 +316,7 @@ private fun SearchBookDetailScreenContent( hasRightIcon = true, hasRightPlusIcon = true, modifier = Modifier.weight(1f), - onClick = onWriteFeedClick + onClick = { onWriteFeedClick(bookDetail) } ) Box( modifier = Modifier From ce25137454603959f07bda6650fcdc7286bfb4af Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 13:32:21 +0900 Subject: [PATCH 04/17] =?UTF-8?q?[refactor]:=20=EB=AA=A8=EC=9E=84=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=ED=99=94=EB=A9=B4=20=EC=9E=A5=EB=A5=B4=20?= =?UTF-8?q?=EC=99=BC=EC=AA=BD=20=EC=A0=95=EB=A0=AC=20=EB=B0=8F=20=EB=8B=A4?= =?UTF-8?q?=EC=A4=91=20=EC=84=A0=ED=83=9D=20=EA=B0=80=EB=8A=A5=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20=EC=88=98=EC=A0=95=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/texthip/thip/ui/common/buttons/GenreChipRow.kt | 5 +++-- .../com/texthip/thip/ui/common/buttons/SubGenreChipRow.kt | 5 +++-- .../com/texthip/thip/ui/feed/screen/FeedWriteScreen.kt | 8 +++++--- .../texthip/thip/ui/feed/viewmodel/FeedWriteUiState.kt | 2 +- .../texthip/thip/ui/feed/viewmodel/FeedWriteViewModel.kt | 3 +-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/GenreChipRow.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/GenreChipRow.kt index 364cac9f..9619852b 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/buttons/GenreChipRow.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/GenreChipRow.kt @@ -18,11 +18,12 @@ fun GenreChipRow( modifier: Modifier = Modifier.width(4.dp), genres: List, selectedIndex: Int, - onSelect: (Int) -> Unit + onSelect: (Int) -> Unit, + horizontalArrangement: Arrangement.Horizontal = Arrangement.Center ) { Row( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center + horizontalArrangement = horizontalArrangement ) { genres.forEachIndexed { idx, genre -> OptionChipButton( diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/SubGenreChipRow.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/SubGenreChipRow.kt index 383e5f61..c29255df 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/buttons/SubGenreChipRow.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/SubGenreChipRow.kt @@ -16,11 +16,12 @@ import com.texthip.thip.ui.theme.ThipTheme fun SubGenreChipGrid( subGenres: List, selectedGenres: List, - onGenreToggle: (String) -> Unit + onGenreToggle: (String) -> Unit, + horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally ) { FlowRow( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally), + horizontalArrangement = Arrangement.spacedBy(8.dp, horizontalAlignment), verticalArrangement = Arrangement.spacedBy(8.dp) ) { subGenres.forEach { genre -> diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedWriteScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedWriteScreen.kt index 2f485e1b..1a98d1a7 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedWriteScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedWriteScreen.kt @@ -304,10 +304,11 @@ fun FeedWriteContent( ) Spacer(modifier = Modifier.padding(top = 12.dp)) GenreChipRow( - modifier = Modifier.width(18.dp), + modifier = Modifier.width(8.dp), genres = uiState.categories.map { it.category }, selectedIndex = uiState.selectedCategoryIndex, - onSelect = onSelectCategory + onSelect = onSelectCategory, + horizontalArrangement = Arrangement.Start ) Spacer(modifier = Modifier.height(12.dp)) if (uiState.selectedCategoryIndex != -1) { @@ -316,7 +317,8 @@ fun FeedWriteContent( SubGenreChipGrid( subGenres = uiState.availableTags, selectedGenres = uiState.selectedTags, - onGenreToggle = onToggleTag + onGenreToggle = onToggleTag, + horizontalAlignment = Alignment.Start ) Row( modifier = Modifier.fillMaxWidth(), diff --git a/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedWriteUiState.kt b/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedWriteUiState.kt index 65780274..11dbfd18 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedWriteUiState.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedWriteUiState.kt @@ -56,7 +56,7 @@ data class FeedWriteUiState( get() = if (selectedCategoryIndex >= 0 && selectedCategoryIndex < categories.size) { categories[selectedCategoryIndex].tagList } else { - emptyList() + categories.flatMap { it.tagList }.distinct() } // 현재 선택된 카테고리 이름 diff --git a/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedWriteViewModel.kt b/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedWriteViewModel.kt index fa262004..add28b85 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedWriteViewModel.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedWriteViewModel.kt @@ -325,8 +325,7 @@ class FeedWriteViewModel @Inject constructor( fun selectCategory(index: Int) { updateState { it.copy( - selectedCategoryIndex = index, - selectedTags = emptyList() // 카테고리 변경 시 태그 초기화 + selectedCategoryIndex = index ) } } From 616608a8f9f33895deb20c51064917f9196ec0d2 Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 13:44:51 +0900 Subject: [PATCH 05/17] =?UTF-8?q?[refactor]:=20=EB=AA=A8=EC=9E=84=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=ED=99=94=EB=A9=B4=20=EB=B9=84=EC=9C=A8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EB=82=B4=EC=9D=BC=EB=B6=80?= =?UTF-8?q?=ED=84=B0=20=EC=84=A0=ED=83=9D=20=EA=B0=80=EB=8A=A5=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20=EC=88=98=EC=A0=95=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../makeroom/component/GroupDatePicker.kt | 6 +++--- .../component/GroupRoomDurationPicker.kt | 21 +++++++++---------- .../makeroom/screen/GroupMakeRoomScreen.kt | 5 +++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupDatePicker.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupDatePicker.kt index b933856d..1b478a5c 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupDatePicker.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupDatePicker.kt @@ -49,9 +49,7 @@ fun GroupDatePicker( } Row( - modifier = modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween + verticalAlignment = Alignment.CenterVertically ) { Row( verticalAlignment = Alignment.CenterVertically @@ -72,6 +70,7 @@ fun GroupDatePicker( ) Spacer(modifier = Modifier.width(2.dp)) Text( + modifier = Modifier.padding(end = 8.dp), text = stringResource(R.string.group_year), style = typography.info_r400_s12, color = colors.White @@ -97,6 +96,7 @@ fun GroupDatePicker( ) Spacer(modifier = Modifier.width(2.dp)) Text( + modifier = Modifier.padding(end = 8.dp), text = stringResource(R.string.group_month), style = typography.info_r400_s12, color = colors.White diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt index c36d5f4b..4527ecfc 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt @@ -33,18 +33,19 @@ fun GroupRoomDurationPicker( onDateRangeSelected: (LocalDate, LocalDate) -> Unit = { _, _ -> } ) { val today = LocalDate.now() + val tomorrow = today.plusDays(1) val maxDate = today.plusMonths(12) var isInitialized by rememberSaveable { mutableStateOf(false) } - var startDate by rememberSaveable { mutableStateOf(today) } - var endDate by rememberSaveable { mutableStateOf(today.plusDays(1)) } + var startDate by rememberSaveable { mutableStateOf(tomorrow) } + var endDate by rememberSaveable { mutableStateOf(tomorrow.plusDays(1)) } var isPickerTouched by rememberSaveable { mutableStateOf(false) } - // 첫 시작 시에만 모든 날짜를 오늘 기준으로 초기화 + // 첫 시작 시에만 모든 날짜를 내일 기준으로 초기화 LaunchedEffect(Unit) { if (!isInitialized) { - startDate = today - endDate = today.plusDays(1) + startDate = tomorrow + endDate = tomorrow.plusDays(1) isInitialized = true } } @@ -63,7 +64,7 @@ fun GroupRoomDurationPicker( // 날짜 유효성 검사 및 자동 조정 LaunchedEffect(startDate) { val adjustedStartDate = when { - startDate.isBefore(today) -> today + startDate.isBefore(tomorrow) -> tomorrow startDate.isAfter(maxDate) -> maxDate else -> startDate } @@ -107,14 +108,13 @@ fun GroupRoomDurationPicker( // 시작 날짜 Picker GroupDatePicker( selectedDate = startDate, - minDate = today, + minDate = tomorrow, maxDate = maxDate, onDateSelected = { newDate -> startDate = newDate }, modifier = Modifier .weight(1f) - .fillMaxWidth() .pointerInput(Unit) { detectTapGestures( onPress = { isPickerTouched = true } @@ -127,20 +127,19 @@ fun GroupRoomDurationPicker( text = "~", style = typography.info_r400_s12, color = colors.White, - modifier = Modifier.padding(horizontal = 10.dp) + modifier = Modifier.padding(horizontal = 4.dp) ) // 끝 날짜 Picker GroupDatePicker( selectedDate = endDate, - minDate = today, + minDate = tomorrow, maxDate = maxDate, onDateSelected = { newDate -> endDate = newDate }, modifier = Modifier .weight(1f) - .fillMaxWidth() .pointerInput(Unit) { detectTapGestures( onPress = { isPickerTouched = true } diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/screen/GroupMakeRoomScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/screen/GroupMakeRoomScreen.kt index 54964d1c..f4fff79a 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/screen/GroupMakeRoomScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/screen/GroupMakeRoomScreen.kt @@ -146,10 +146,11 @@ fun GroupMakeRoomContent( ) Spacer(modifier = Modifier.padding(top = 12.dp)) GenreChipRow( - modifier = Modifier.width(18.dp), + modifier = Modifier.width(12.dp), genres = uiState.genres.toDisplayStrings(), selectedIndex = uiState.selectedGenreIndex, - onSelect = onSelectGenre + onSelect = onSelectGenre, + horizontalArrangement = Arrangement.Start ) Spacer(modifier = Modifier.height(12.dp)) From ba47bd9b9d274766e302251cd97f81d9a7e0f479 Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 13:57:50 +0900 Subject: [PATCH 06/17] =?UTF-8?q?[refactor]:=20=ED=94=BC=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=ED=9B=84=20=EC=83=88=EB=A1=9C=20=EA=B3=A0?= =?UTF-8?q?=EC=B9=A8=20=EB=B0=8F=20=ED=94=BC=EB=93=9C=20=EC=83=81=EB=8B=A8?= =?UTF-8?q?=20=EC=95=8C=EB=A6=BC=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=84=A4?= =?UTF-8?q?=EB=B9=84=EA=B2=8C=EC=9D=B4=EC=85=98=20=EA=B5=AC=ED=98=84=20(#1?= =?UTF-8?q?02)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../texthip/thip/ui/feed/screen/FeedScreen.kt | 18 +++++++++++++++++- .../thip/ui/feed/viewmodel/FeedViewModel.kt | 1 + .../ui/navigator/navigations/FeedNavigation.kt | 11 +++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt index e1ee0d57..d23fbda3 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt @@ -68,8 +68,11 @@ fun FeedScreen( onNavigateToFeedComment: (Int) -> Unit = {}, onNavigateToBookDetail: (String) -> Unit = {}, onNavigateToUserProfile: (userId: Long) -> Unit = {}, + onNavigateToNotification: () -> Unit = {}, resultFeedId: Int? = null, + refreshFeed: Boolean? = null, onResultConsumed: () -> Unit = {}, + onRefreshConsumed: () -> Unit = {}, feedViewModel: FeedViewModel = hiltViewModel(), ) { val feedUiState by feedViewModel.uiState.collectAsState() @@ -122,6 +125,19 @@ fun FeedScreen( if (showProgressBar) { showProgressBar = false } + + // 애니메이션이 완전히 끝난 후 새로고침 실행 + feedViewModel.refreshData() + } + } + } + + LaunchedEffect(refreshFeed) { + if (refreshFeed == true) { + onRefreshConsumed() + // resultFeedId가 있을 때는 애니메이션 후에 새로고침하므로 여기서는 실행하지 않음 + if (resultFeedId == null) { + feedViewModel.refreshData() } } } @@ -152,7 +168,7 @@ fun FeedScreen( leftIcon = painterResource(R.drawable.ic_plusfriend), hasNotification = false, onLeftClick = {}, - onRightClick = {}, + onRightClick = onNavigateToNotification, ) Spacer(modifier = Modifier.height(32.dp)) HeaderMenuBarTab( diff --git a/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt b/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt index 0e7d0d1d..c7bf48b5 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt @@ -263,6 +263,7 @@ class FeedViewModel @Inject constructor( } fun refreshData() { + loadAllFeeds() fetchRecentWriters() } diff --git a/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt b/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt index 4bc9a51c..188b0562 100644 --- a/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt +++ b/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt @@ -12,6 +12,7 @@ import com.texthip.thip.ui.feed.screen.FeedScreen import com.texthip.thip.ui.feed.screen.FeedWriteScreen import com.texthip.thip.ui.feed.screen.MySubscriptionScreen import com.texthip.thip.ui.feed.viewmodel.FeedWriteViewModel +import com.texthip.thip.ui.navigator.extensions.navigateToAlarm import com.texthip.thip.ui.navigator.extensions.navigateToBookDetail import com.texthip.thip.ui.navigator.extensions.navigateToFeedComment import com.texthip.thip.ui.navigator.extensions.navigateToFeedWrite @@ -24,12 +25,17 @@ import com.texthip.thip.ui.navigator.routes.MainTabRoutes fun NavGraphBuilder.feedNavigation(navController: NavHostController, navigateBack: () -> Unit) { composable { backStackEntry -> val resultFeedId = backStackEntry.savedStateHandle.get("feedId") + val refreshFeed = backStackEntry.savedStateHandle.get("refreshFeed") FeedScreen( resultFeedId = resultFeedId, + refreshFeed = refreshFeed, onResultConsumed = { backStackEntry.savedStateHandle.remove("feedId") }, + onRefreshConsumed = { + backStackEntry.savedStateHandle.remove("refreshFeed") + }, onNavigateToMySubscription = { navController.navigateToMySubscription() }, @@ -44,6 +50,9 @@ fun NavGraphBuilder.feedNavigation(navController: NavHostController, navigateBac }, onNavigateToUserProfile = { userId -> navController.navigateToUserProfile(userId) + }, + onNavigateToNotification = { + navController.navigateToAlarm() } ) } @@ -119,6 +128,8 @@ fun NavGraphBuilder.feedNavigation(navController: NavHostController, navigateBac // 피드 생성 성공 시 결과를 저장하고 피드 목록으로 돌아가기 navController.getBackStackEntry(MainTabRoutes.Feed) .savedStateHandle["feedId"] = feedId + navController.getBackStackEntry(MainTabRoutes.Feed) + .savedStateHandle["refreshFeed"] = true navController.popBackStack(MainTabRoutes.Feed, inclusive = false) } ) From ef4b7e92521eb1ee18905beca9049160d8a261ff Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 14:01:23 +0900 Subject: [PATCH 07/17] =?UTF-8?q?[refactor]:=20=ED=94=BC=EB=93=9C=20?= =?UTF-8?q?=EC=9E=90=EC=84=B8=ED=9E=88=EB=B3=B4=EA=B8=B0=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/texthip/thip/ui/feed/screen/FeedCommentScreen.kt | 5 ++++- .../texthip/thip/ui/navigator/navigations/FeedNavigation.kt | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) 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 ab0e5498..2c4cd837 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 @@ -68,6 +68,7 @@ fun FeedCommentScreen( onNavigateBack: () -> Unit = {}, onNavigateToFeedEdit: (Int) -> Unit = {}, onNavigateToUserProfile: (userId: Long) -> Unit = {}, + onNavigateToBookDetail: (String) -> Unit = {}, feedDetailViewModel: FeedDetailViewModel = hiltViewModel(), commentsViewModel: CommentsViewModel = hiltViewModel() ) { @@ -189,7 +190,9 @@ fun FeedCommentScreen( ActionBookButton( bookTitle = feedDetail.bookTitle, bookAuthor = feedDetail.bookAuthor, - onClick = {} + onClick = { + onNavigateToBookDetail(feedDetail.isbn) + } ) } Text( diff --git a/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt b/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt index 188b0562..13986830 100644 --- a/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt +++ b/app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt @@ -157,6 +157,9 @@ fun NavGraphBuilder.feedNavigation(navController: NavHostController, navigateBac }, onNavigateToUserProfile = { userId -> navController.navigateToUserProfile(userId) + }, + onNavigateToBookDetail = { isbn -> + navController.navigateToBookDetail(isbn) } ) } From 98c5953fc3bf409b344101731ee865d09f9e3fe6 Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 14:21:07 +0900 Subject: [PATCH 08/17] =?UTF-8?q?[refactor]:=20=EC=83=81=EB=8B=B9=20?= =?UTF-8?q?=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EB=A9=94=EC=84=B8=EC=A7=80=20?= =?UTF-8?q?=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=EB=B0=8F=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=ED=86=B5=EC=9D=BC=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thip/ui/feed/screen/FeedCommentScreen.kt | 26 ++++++++++---- .../feed/screen/MySubscriptionListScreen.kt | 36 ++++++++++++------- .../group/room/screen/GroupRoomChatScreen.kt | 32 ++++++++++++----- .../room/screen/GroupRoomRecruitScreen.kt | 26 ++++++++++---- .../thip/ui/group/screen/GroupScreen.kt | 26 ++++++++++---- .../screen/MypageNotificationEditScreen.kt | 31 ++++++++++------ 6 files changed, 128 insertions(+), 49 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 2c4cd837..2313ca57 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 @@ -1,5 +1,9 @@ package com.texthip.thip.ui.feed.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.clickable import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Arrangement @@ -343,13 +347,23 @@ fun FeedCommentScreen( } // 신고 완료 토스트 - if (showToast) { + AnimatedVisibility( + visible = showToast, + 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(2f) + ) { ToastWithDate( - message = "게시글 신고를 완료했어요.", - modifier = Modifier - .align(Alignment.TopCenter) - .padding(horizontal = 20.dp, vertical = 16.dp) - .zIndex(2f) + message = "게시글 신고를 완료했어요." ) } } diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/MySubscriptionListScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/MySubscriptionListScreen.kt index 6bbbdbe7..932b3165 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/MySubscriptionListScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/MySubscriptionListScreen.kt @@ -1,5 +1,9 @@ package com.texthip.thip.ui.feed.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.clickable import androidx.compose.foundation.layout.Box @@ -103,19 +107,25 @@ fun MySubscriptionContent( } Box(modifier = Modifier.fillMaxSize()) { - if (uiState.showToast) { - Box( - modifier = Modifier - .fillMaxWidth() - .zIndex(1f) - .align(Alignment.TopCenter) - .padding(horizontal = 15.dp, vertical = 15.dp), - ) { - ToastWithDate( - message = uiState.toastMessage, - modifier = Modifier.fillMaxWidth() - ) - } + AnimatedVisibility( + visible = uiState.showToast, + enter = slideInVertically( + initialOffsetY = { -it }, + animationSpec = tween(durationMillis = 2000) + ), + exit = slideOutVertically( + targetOffsetY = { -it }, + animationSpec = tween(durationMillis = 2000) + ), + modifier = Modifier + .align(Alignment.TopCenter) + .padding(horizontal = 15.dp, vertical = 15.dp) + .zIndex(1f) + ) { + ToastWithDate( + message = uiState.toastMessage, + modifier = Modifier.fillMaxWidth() + ) } Column( 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 f31bc1eb..f366f0ad 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 @@ -261,16 +261,32 @@ fun GroupRoomChatContent( } } - 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 -> {} + null -> {} + } } } } diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt index d3154c0c..71167a83 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.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.Arrangement import androidx.compose.foundation.layout.Box @@ -461,13 +465,23 @@ fun GroupRoomRecruitContent( } // 토스트 팝업 - if (uiState.showToast && !uiState.shouldNavigateToGroupScreen) { + AnimatedVisibility( + visible = uiState.showToast && !uiState.shouldNavigateToGroupScreen, + 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(2f) + ) { ToastWithDate( - message = uiState.toastMessage, - modifier = Modifier - .align(Alignment.TopCenter) - .padding(horizontal = 20.dp, vertical = 16.dp) - .zIndex(2f) + message = uiState.toastMessage ) } diff --git a/app/src/main/java/com/texthip/thip/ui/group/screen/GroupScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/screen/GroupScreen.kt index 8ca4dac4..08d42777 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/screen/GroupScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/screen/GroupScreen.kt @@ -1,5 +1,9 @@ package com.texthip.thip.ui.group.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 @@ -165,13 +169,23 @@ fun GroupContent( ) // 토스트 팝업 - if (uiState.showToast) { + AnimatedVisibility( + visible = uiState.showToast, + 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(2f) + ) { ToastWithDate( - message = uiState.toastMessage, - modifier = Modifier - .align(Alignment.TopCenter) - .padding(horizontal = 20.dp, vertical = 16.dp) - .zIndex(2f) + message = uiState.toastMessage ) } } diff --git a/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageNotificationEditScreen.kt b/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageNotificationEditScreen.kt index 137f8cb6..10a75645 100644 --- a/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageNotificationEditScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageNotificationEditScreen.kt @@ -1,5 +1,9 @@ package com.texthip.thip.ui.mypage.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 @@ -40,20 +44,27 @@ fun NotificationScreen( LaunchedEffect(toastMessage) { if (toastMessage != null) { - delay(2000) + delay(3000) toastMessage = null } } Box(modifier = Modifier.fillMaxSize()) { - toastMessage?.let { message -> - Box( - modifier = Modifier - .fillMaxWidth() - .zIndex(1f) - .align(Alignment.TopCenter) - .padding(horizontal = 15.dp, vertical = 15.dp), - contentAlignment = Alignment.TopCenter - ) { + AnimatedVisibility( + visible = toastMessage != null, + enter = slideInVertically( + initialOffsetY = { -it }, + animationSpec = tween(durationMillis = 2000) + ), + exit = slideOutVertically( + targetOffsetY = { -it }, + animationSpec = tween(durationMillis = 2000) + ), + modifier = Modifier + .align(Alignment.TopCenter) + .padding(horizontal = 15.dp, vertical = 15.dp) + .zIndex(1f) + ) { + toastMessage?.let { message -> ToastWithDate( message = stringResource( if (message == "push_on") R.string.push_on else R.string.push_off From a7e7dd65c6c22b8ad0ce43a91131fda26106d5ed Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 14:28:18 +0900 Subject: [PATCH 09/17] =?UTF-8?q?[refactor]:=20=EB=B0=94=ED=85=80=20?= =?UTF-8?q?=EC=8B=9C=ED=8A=B8=20=ED=82=A4=EB=B3=B4=EB=93=9C=20=ED=8C=A8?= =?UTF-8?q?=EB=94=A9=20=EC=B6=94=EA=B0=80=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/texthip/thip/ui/common/bottomsheet/CustomBottomSheet.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/texthip/thip/ui/common/bottomsheet/CustomBottomSheet.kt b/app/src/main/java/com/texthip/thip/ui/common/bottomsheet/CustomBottomSheet.kt index ec81fc0e..3eedc1e2 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/bottomsheet/CustomBottomSheet.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/bottomsheet/CustomBottomSheet.kt @@ -34,6 +34,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import com.texthip.thip.ui.theme.ThipTheme import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.utils.rooms.advancedImePadding import kotlinx.coroutines.launch private const val BOTTOM_SHEET_HIDDEN_OFFSET = 300f @@ -93,6 +94,7 @@ fun CustomBottomSheet( modifier = Modifier .fillMaxWidth() .offset(y = (offsetY + animatableOffset.value).dp) + .advancedImePadding() .background( color = colors.DarkGrey, shape = RoundedCornerShape(topEnd = 12.dp, topStart = 12.dp) From ff4da7d0c8c2d728d35c0f384705a56aafa8ae2e Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 20:23:49 +0900 Subject: [PATCH 10/17] =?UTF-8?q?[refactor]:=20=EC=B1=85=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=ED=8C=A8=EB=94=A9=20=EC=88=98=EC=A0=95=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/texthip/thip/ui/search/component/SearchActiveField.kt | 1 + .../texthip/thip/ui/search/component/SearchBookFilteredResult.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/java/com/texthip/thip/ui/search/component/SearchActiveField.kt b/app/src/main/java/com/texthip/thip/ui/search/component/SearchActiveField.kt index b25d9c88..f8fad714 100644 --- a/app/src/main/java/com/texthip/thip/ui/search/component/SearchActiveField.kt +++ b/app/src/main/java/com/texthip/thip/ui/search/component/SearchActiveField.kt @@ -69,6 +69,7 @@ fun SearchActiveField( if (index < bookList.size - 1) { Spacer( modifier = Modifier + .padding(top = 12.dp) .fillMaxWidth() .height(1.dp) .background(colors.DarkGrey02) diff --git a/app/src/main/java/com/texthip/thip/ui/search/component/SearchBookFilteredResult.kt b/app/src/main/java/com/texthip/thip/ui/search/component/SearchBookFilteredResult.kt index b6775d63..9f0b3b9d 100644 --- a/app/src/main/java/com/texthip/thip/ui/search/component/SearchBookFilteredResult.kt +++ b/app/src/main/java/com/texthip/thip/ui/search/component/SearchBookFilteredResult.kt @@ -96,6 +96,7 @@ fun SearchBookFilteredResult( if (index < bookList.size - 1) { Spacer( modifier = Modifier + .padding(top = 12.dp) .fillMaxWidth() .height(1.dp) .background(colors.DarkGrey02) From 67d7cdc4fe666c5ed76ab16152254e1c207c7cae Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 20:28:40 +0900 Subject: [PATCH 11/17] =?UTF-8?q?[refactor]:=20=EB=AA=A8=EC=A7=91=EC=A4=91?= =?UTF-8?q?=EC=9D=B8=20=EB=AA=A8=EC=9E=84=EB=B0=A9=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EB=82=B4=EB=B6=80=20=EC=A0=95=EB=A0=AC=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thip/ui/group/room/screen/GroupRoomRecruitScreen.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt index 71167a83..5c4774bc 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt @@ -246,8 +246,7 @@ fun GroupRoomRecruitContent( Row( Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween + verticalAlignment = Alignment.CenterVertically ) { //모집 기간 Column { @@ -282,7 +281,7 @@ fun GroupRoomRecruitContent( //참여 인원 Column( verticalArrangement = Arrangement.Center, - modifier = Modifier.padding(end = 18.dp) + modifier = Modifier.padding(start = 90.dp) ) { Row( verticalAlignment = Alignment.CenterVertically @@ -300,7 +299,8 @@ fun GroupRoomRecruitContent( ) } Row( - modifier = Modifier.padding(top = 12.dp), + modifier = Modifier + .padding(top = 12.dp), verticalAlignment = Alignment.CenterVertically ) { Text( From 60ecacb5fa330b393c47b679ca7d2a7f2a78e177 Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 20:33:19 +0900 Subject: [PATCH 12/17] =?UTF-8?q?[refactor]:=20=EB=AA=A8=EC=A7=91=EC=A4=91?= =?UTF-8?q?=EC=9D=B8=20=EB=AA=A8=EC=9E=84=EB=B0=A9=20dto=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/rooms/response/RoomRecruitingResponse.kt | 2 +- .../ui/group/room/screen/GroupRoomRecruitScreen.kt | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomRecruitingResponse.kt b/app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomRecruitingResponse.kt index 5c016aa9..d34b247e 100644 --- a/app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomRecruitingResponse.kt +++ b/app/src/main/java/com/texthip/thip/data/model/rooms/response/RoomRecruitingResponse.kt @@ -31,7 +31,7 @@ data class RoomRecruitingResponse( @Serializable data class RecommendRoomResponse( @SerialName("roomId") val roomId: Int, - @SerialName("roomImageUrl") val roomImageUrl: String?, + @SerialName("bookImageUrl") val bookImageUrl: String?, @SerialName("roomName") val roomName: String, @SerialName("memberCount") val memberCount: Int, @SerialName("recruitCount") val recruitCount: Int, diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt index 5c4774bc..c93bab84 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomRecruitScreen.kt @@ -343,10 +343,7 @@ fun GroupRoomRecruitContent( ) Spacer(Modifier.width(4.dp)) Text( - text = detail.recruitEndDate.replace( - "뒤", - "남음" - ), + text = detail.recruitEndDate, style = typography.info_m500_s12, color = colors.NeonGreen ) @@ -406,7 +403,7 @@ fun GroupRoomRecruitContent( participants = rec.memberCount, maxParticipants = rec.recruitCount, endDate = rec.recruitEndDate, - imageUrl = rec.roomImageUrl, + imageUrl = rec.bookImageUrl, onClick = { onRecommendationClick(rec) } ) } @@ -543,7 +540,7 @@ fun GroupRoomRecruitScreenPreview() { recommendRooms = listOf( RecommendRoomResponse( roomId = 2, - roomImageUrl = "https://picsum.photos/300/400?rec1", + bookImageUrl = "https://picsum.photos/300/400?rec1", roomName = "📚 현대문학 깊이 탐구하기", memberCount = 12, recruitCount = 15, @@ -551,7 +548,7 @@ fun GroupRoomRecruitScreenPreview() { ), RecommendRoomResponse( roomId = 3, - roomImageUrl = "https://picsum.photos/300/400?rec2", + bookImageUrl = "https://picsum.photos/300/400?rec2", roomName = "✨ 철학 소설로 삶을 되돌아보기", memberCount = 8, recruitCount = 12, @@ -559,7 +556,7 @@ fun GroupRoomRecruitScreenPreview() { ), RecommendRoomResponse( roomId = 4, - roomImageUrl = "https://picsum.photos/300/400?rec3", + bookImageUrl = "https://picsum.photos/300/400?rec3", roomName = "🎭 인간 심리를 다룬 소설 읽기", memberCount = 15, recruitCount = 18, From 20222ef876c8117f2f99b583f6ed2a74e129f0c4 Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 20:44:48 +0900 Subject: [PATCH 13/17] =?UTF-8?q?[refactor]:=20=EB=AA=A8=EC=A7=91=EC=A4=91?= =?UTF-8?q?=EC=9D=B8=20=ED=99=94=EB=A9=B4=20=EB=B9=84=EC=9C=A8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search/screen/SearchBookDetailScreen.kt | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt b/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt index 664daa8b..293ce2c6 100644 --- a/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/search/screen/SearchBookDetailScreen.kt @@ -37,6 +37,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.positionInRoot +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -125,6 +126,12 @@ private fun SearchBookDetailScreenContent( var isFilterDropdownVisible by remember { mutableStateOf(false) } var filterButtonPosition by remember { mutableStateOf(IntOffset.Zero) } val density = LocalDensity.current + val configuration = LocalConfiguration.current + + // 화면 크기에 따른 최대 높이 설정 (태블릿 대응) + val maxImageHeight = remember(configuration.screenHeightDp) { + (configuration.screenHeightDp * 0.6f).dp.coerceAtMost(620.dp) + } val filterOptions = listOf( stringResource(R.string.sort_like), stringResource(R.string.sort_latest) @@ -214,7 +221,7 @@ private fun SearchBookDetailScreenContent( contentDescription = bookDetail.title, modifier = Modifier .fillMaxWidth() - .heightIn(min = 420.dp) + .heightIn(min = 420.dp, max = maxImageHeight) .blur(4.dp), contentScale = ContentScale.Crop, fallback = painterResource(R.drawable.img_book_cover_sample), @@ -227,9 +234,10 @@ private fun SearchBookDetailScreenContent( brush = Brush.verticalGradient( colors = listOf( Color.Transparent, - colors.Black.copy(alpha = 0.3f), - colors.Black.copy(alpha = 0.6f), - colors.Black.copy(alpha = 0.9f), + colors.Black.copy(alpha = 0.2f), + colors.Black.copy(alpha = 0.5f), + colors.Black.copy(alpha = 0.8f), + colors.Black.copy(alpha = 0.95f), colors.Black ), startY = 0f, @@ -386,6 +394,24 @@ private fun SearchBookDetailScreenContent( } } + // 피드 섹션 전환을 위한 추가 그라데이션 + item { + Box( + modifier = Modifier + .fillMaxWidth() + .height(30.dp) + .background( + brush = Brush.verticalGradient( + colors = listOf( + colors.Black, + colors.Black.copy(alpha = 0.95f), + colors.Black.copy(alpha = 0.9f) + ) + ) + ) + ) + } + // 피드 목록 (ViewModel에서 변환된 데이터 사용) val feedItems = uiState?.feedItems ?: emptyList() From b000d81bdb20bb568c16cb8d550a088f0c7b1383 Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 22:06:10 +0900 Subject: [PATCH 14/17] =?UTF-8?q?[refactor]:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=9E=85=EB=A0=A5=20=ED=99=94=EB=A9=B4=20=EC=BB=A4?= =?UTF-8?q?=EC=84=9C=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/common/forms/SingleDigitTextBox.kt | 55 ++++++++++--------- .../component/GroupRoomDurationPicker.kt | 1 - .../room/screen/GroupRoomUnlockScreen.kt | 30 +++++----- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/common/forms/SingleDigitTextBox.kt b/app/src/main/java/com/texthip/thip/ui/common/forms/SingleDigitTextBox.kt index 380fb8a6..2b618894 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/forms/SingleDigitTextBox.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/forms/SingleDigitTextBox.kt @@ -1,6 +1,5 @@ package com.texthip.thip.ui.common.forms -import android.view.KeyEvent import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box @@ -12,16 +11,16 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.input.key.KeyEventType -import androidx.compose.ui.input.key.onKeyEvent -import androidx.compose.ui.input.key.type +import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -39,6 +38,15 @@ fun SingleDigitBox( containerColor: Color = colors.darkGray01, borderColor: Color = Color.Transparent ) { + // TextFieldValue로 커서 위치 제어 + val textFieldValue = remember(value) { + val displayText = value.ifEmpty { "\u200B" } // Zero Width Space + TextFieldValue( + text = displayText, + selection = TextRange(displayText.length) // 커서를 맨 끝에 위치 + ) + } + val myStyle = typography.smalltitle_sb600_s18_h24.copy( lineHeight = 20.sp, textAlign = TextAlign.Center, @@ -53,37 +61,32 @@ fun SingleDigitBox( contentAlignment = Alignment.Center ) { BasicTextField( - value = value, - onValueChange = { input -> - val filtered = input.filter { it.isDigit() }.take(1) + value = textFieldValue, + onValueChange = { newValue -> + val cleaned = newValue.text.replace("\u200B", "") + val filtered = cleaned.filter { it.isDigit() }.take(1) + + // 백스페이스 감지: Zero Width Space가 지워졌을 때 + if (newValue.text.isEmpty() && value.isEmpty()) { + onBackspace?.invoke() + return@BasicTextField + } + onValueChange(filtered) }, - textStyle = myStyle, + textStyle = myStyle.copy( + color = if (value.isEmpty()) Color.Transparent else colors.White + ), singleLine = true, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword), - modifier = modifier - .background(containerColor, RoundedCornerShape(12.dp)) - .border(1.dp, borderColor, RoundedCornerShape(12.dp)) - .onKeyEvent { keyEvent -> - if (keyEvent.nativeKeyEvent.keyCode == KeyEvent.KEYCODE_DEL && - keyEvent.type == KeyEventType.KeyDown - ) { - if (value.isEmpty()) { - onBackspace?.invoke() - true - } else { - false - } - } else { - false - } - }, cursorBrush = SolidColor(colors.NeonGreen), decorationBox = { innerTextField -> Box( Modifier.fillMaxSize(), contentAlignment = Alignment.Center - ) { innerTextField() } + ) { + innerTextField() + } } ) } diff --git a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt index 4527ecfc..49d41c13 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/makeroom/component/GroupRoomDurationPicker.kt @@ -195,7 +195,6 @@ fun GroupRoomDurationPicker( fun MeetingDurationPickerPreview() { ThipTheme { GroupRoomDurationPicker { startDate, endDate -> - println("Selected date range: $startDate to $endDate") } } } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomUnlockScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomUnlockScreen.kt index 2db56fb5..066326ce 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomUnlockScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/room/screen/GroupRoomUnlockScreen.kt @@ -66,6 +66,7 @@ fun GroupRoomUnlockScreen( viewModel.resetPasswordState() onSuccessNavigation() } + false -> { showError = true delay(1000) // 사용자에게 에러 메시지를 보여줄 시간 @@ -74,7 +75,8 @@ fun GroupRoomUnlockScreen( focusRequesters[0].requestFocus() viewModel.resetPasswordState() // ViewModel 상태 초기화 } - null -> { } + + null -> {} } } @@ -85,7 +87,7 @@ fun GroupRoomUnlockScreen( focusRequesters[0].requestFocus() keyboardController?.show() } - + // 화면 종료 시 리소스 정리 DisposableEffect(Unit) { onDispose { @@ -94,10 +96,7 @@ fun GroupRoomUnlockScreen( } } - Box( - modifier = Modifier - .fillMaxSize() - ) { + Box(modifier = Modifier.fillMaxSize()) { Column( modifier = Modifier.fillMaxSize() ) { @@ -133,25 +132,24 @@ fun GroupRoomUnlockScreen( onValueChange = { input -> if (input.length <= 1 && input.all { it.isDigit() }) { val newPassword = password.copyOf() + val wasEmpty = password[index].isEmpty() newPassword[index] = input password = newPassword + // 숫자가 입력되면 다음 칸으로 이동 if (input.isNotEmpty() && index < 3) { focusRequesters[index + 1].requestFocus() + } else if (input.isEmpty() && !wasEmpty && index > 0) { + focusRequesters[index - 1].requestFocus() } + } }, onBackspace = { - val newPassword = password.copyOf() - if (password[index].isNotEmpty()) { - // 현재 박스에 값이 있으면 현재 박스 지우기 - newPassword[index] = "" - password = newPassword - } else if (index > 0) { - // 현재 박스가 비어있으면 이전 박스로 이동하면서 지우기 - newPassword[index - 1] = "" - password = newPassword - focusRequesters[index - 1].requestFocus() + // 빈 박스에서 백스페이스 → 이전 박스로 이동 + if (index > 0) { + val prevIndex = index - 1 + focusRequesters[prevIndex].requestFocus() } }, borderColor = if (showError) colors.Red else Color.Transparent, From 619cae4b499ce373afdcf4e55b8dc5fe674aac02 Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Tue, 19 Aug 2025 22:40:17 +0900 Subject: [PATCH 15/17] =?UTF-8?q?[refactor]:=20=ED=94=BC=EB=93=9C=20?= =?UTF-8?q?=EC=B1=85=20=EC=98=81=EC=97=AD=20=EB=B6=80=EB=B6=84=20"?= =?UTF-8?q?=EC=A0=80"=EA=B0=80=20=ED=95=AD=EC=83=81=20=EB=B3=B4=EC=9D=B4?= =?UTF-8?q?=EA=B2=8C=20=EC=88=98=EC=A0=95=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thip/ui/common/buttons/ActionBookButton.kt | 14 ++++++++++++-- .../thip/ui/mypage/component/BookContent.kt | 2 -- app/src/main/res/values/strings.xml | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBookButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBookButton.kt index f2bc6b1b..1a109d7e 100644 --- a/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBookButton.kt +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBookButton.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon import androidx.compose.material3.Text @@ -51,16 +52,25 @@ fun ActionBookButton( maxLines = 1 ) + // 저자명과 "저"를 분리 Text( - text = bookAuthor + stringResource(R.string.author), + text = bookAuthor, style = typography.info_r400_s12_h24, color = colors.Grey, - modifier = Modifier.width(100.dp), + modifier = Modifier + .widthIn(max = 80.dp) + .padding(start = 8.dp), textAlign = TextAlign.Right, overflow = TextOverflow.Ellipsis, maxLines = 1 ) + Text( + text = stringResource(R.string.author), + style = typography.info_r400_s12_h24, + color = colors.Grey, + ) + Icon( painter = painterResource(R.drawable.ic_chevron), contentDescription = null, diff --git a/app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt b/app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt index 17b63d74..16d4b6e7 100644 --- a/app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt +++ b/app/src/main/java/com/texthip/thip/ui/mypage/component/BookContent.kt @@ -2,13 +2,11 @@ package com.texthip.thip.ui.mypage.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3e20ec44..3ca5c34e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,7 +27,7 @@ 한한강한강한강한ㅇㅇㄴㄴㅁ강 - + " 저" 내 피드에 추가 아니오 From 80711ea8f92cf7caf0f17c4010e4cfcf9eb5af42 Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Wed, 20 Aug 2025 02:25:18 +0900 Subject: [PATCH 16/17] =?UTF-8?q?[refactor]:=20=EB=84=A4=EB=B9=84=EA=B2=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=8B=9C=20=EC=83=81=ED=83=9C=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../texthip/thip/ui/feed/screen/FeedScreen.kt | 29 +++++++++++++------ .../thip/ui/feed/viewmodel/FeedViewModel.kt | 17 +++++++++++ .../thip/ui/group/screen/GroupScreen.kt | 7 ++++- .../thip/ui/group/viewmodel/GroupViewModel.kt | 14 +++++++++ .../thip/ui/mypage/screen/MypageScreen.kt | 8 +++++ 5 files changed, 65 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt index d23fbda3..bfd92fc6 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt @@ -82,13 +82,19 @@ fun FeedScreen( val feedTabTitles = listOf(stringResource(R.string.feed), stringResource(R.string.my_feed)) - // 무한 스크롤 로직 - val listState = rememberLazyListState() + // 탭별로 별도의 스크롤 상태 관리 + val allFeedListState = rememberLazyListState() + val myFeedListState = rememberLazyListState() + val currentListState = when (feedUiState.selectedTabIndex) { + 0 -> allFeedListState + 1 -> myFeedListState + else -> allFeedListState + } // 무한 스크롤 로직 - val shouldLoadMore by remember(feedUiState.canLoadMoreCurrentTab, feedUiState.isLoadingMore) { + val shouldLoadMore by remember(feedUiState.canLoadMoreCurrentTab, feedUiState.isLoadingMore, feedUiState.selectedTabIndex) { derivedStateOf { - val layoutInfo = listState.layoutInfo + val layoutInfo = currentListState.layoutInfo val totalItems = layoutInfo.totalItemsCount val lastVisibleIndex = layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0 @@ -107,7 +113,15 @@ fun FeedScreen( } LaunchedEffect(Unit) { - feedViewModel.refreshData() + feedViewModel.resetToInitialState() + // 탭 전환 시 스크롤을 맨 위로 초기화 + allFeedListState.scrollToItem(0) + myFeedListState.scrollToItem(0) + } + + // 탭 변경 시 해당 탭의 스크롤을 최상단으로 부드럽게 이동 + LaunchedEffect(feedUiState.selectedTabIndex) { + currentListState.scrollToItem(0) } LaunchedEffect(resultFeedId) { @@ -125,8 +139,6 @@ fun FeedScreen( if (showProgressBar) { showProgressBar = false } - - // 애니메이션이 완전히 끝난 후 새로고침 실행 feedViewModel.refreshData() } } @@ -135,7 +147,6 @@ fun FeedScreen( LaunchedEffect(refreshFeed) { if (refreshFeed == true) { onRefreshConsumed() - // resultFeedId가 있을 때는 애니메이션 후에 새로고침하므로 여기서는 실행하지 않음 if (resultFeedId == null) { feedViewModel.refreshData() } @@ -179,7 +190,7 @@ fun FeedScreen( // 스크롤 영역 전체 LazyColumn( - state = listState, + state = currentListState, modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(12.dp) ) { diff --git a/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt b/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt index c7bf48b5..3d83db23 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt @@ -267,6 +267,23 @@ class FeedViewModel @Inject constructor( fetchRecentWriters() } + fun resetToInitialState() { + // 탭과 데이터를 모두 초기 상태로 리셋 + updateState { + it.copy( + selectedTabIndex = 0, + allFeeds = emptyList(), + myFeeds = emptyList(), + isLastPageAllFeeds = false, + isLastPageMyFeeds = false + ) + } + allFeedsNextCursor = null + myFeedsNextCursor = null + loadAllFeeds(isInitial = true) + fetchRecentWriters() + } + private fun fetchRecentWriters() { viewModelScope.launch { updateState { it.copy(isLoading = true) } diff --git a/app/src/main/java/com/texthip/thip/ui/group/screen/GroupScreen.kt b/app/src/main/java/com/texthip/thip/ui/group/screen/GroupScreen.kt index 08d42777..42de8590 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/screen/GroupScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/screen/GroupScreen.kt @@ -58,7 +58,7 @@ fun GroupScreen( ) { // 화면 재진입 시 데이터 새로고침 LaunchedEffect(Unit) { - viewModel.refreshDataOnScreenEnter() + viewModel.resetToInitialState() } val uiState by viewModel.uiState.collectAsState() @@ -95,6 +95,11 @@ fun GroupContent( onHideToast: () -> Unit = {} ) { val scrollState = rememberScrollState() + + // 탭 전환 시 스크롤을 맨 위로 초기화 + LaunchedEffect(Unit) { + scrollState.scrollTo(0) + } Box( modifier = Modifier.fillMaxSize() diff --git a/app/src/main/java/com/texthip/thip/ui/group/viewmodel/GroupViewModel.kt b/app/src/main/java/com/texthip/thip/ui/group/viewmodel/GroupViewModel.kt index 5615c50d..854ebc4b 100644 --- a/app/src/main/java/com/texthip/thip/ui/group/viewmodel/GroupViewModel.kt +++ b/app/src/main/java/com/texthip/thip/ui/group/viewmodel/GroupViewModel.kt @@ -206,4 +206,18 @@ class GroupViewModel @Inject constructor( refreshGroupData() } + fun resetToInitialState() { + // 장르 선택을 초기화하고 모든 데이터를 새로고침 + updateState { + it.copy( + selectedGenreIndex = 0, + roomMainList = it.roomMainList?.copy( + deadlineRoomList = emptyList(), + popularRoomList = emptyList() + ) + ) + } + refreshGroupData() + } + } \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageScreen.kt b/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageScreen.kt index c214883c..4bcc60be 100644 --- a/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/mypage/screen/MypageScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -85,6 +86,12 @@ fun MyPageContent( onDeleteAccount: () -> Unit ) { val context = LocalContext.current + val listState = rememberLazyListState() + + // 탭 전환 시 스크롤을 맨 위로 초기화 + LaunchedEffect(Unit) { + listState.scrollToItem(0) + } Box( Modifier @@ -102,6 +109,7 @@ fun MyPageContent( rightIcon = painterResource(R.drawable.ic_plus) ) LazyColumn( + state = listState, modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(0.dp) ) { From c82b8221a3ffe51cc87392820cac1719b0609fb4 Mon Sep 17 00:00:00 2001 From: rbqks529 Date: Wed, 20 Aug 2025 02:49:18 +0900 Subject: [PATCH 17/17] =?UTF-8?q?[refactor]:=20=ED=94=BC=EB=93=9C=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EB=B3=80=EA=B2=BD=EC=8B=9C=20indicator=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../texthip/thip/ui/feed/screen/FeedScreen.kt | 20 +++++++++--- .../thip/ui/feed/viewmodel/FeedViewModel.kt | 31 +++++++++++++------ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt index bfd92fc6..4264dc8b 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/screen/FeedScreen.kt @@ -114,9 +114,6 @@ fun FeedScreen( LaunchedEffect(Unit) { feedViewModel.resetToInitialState() - // 탭 전환 시 스크롤을 맨 위로 초기화 - allFeedListState.scrollToItem(0) - myFeedListState.scrollToItem(0) } // 탭 변경 시 해당 탭의 스크롤을 최상단으로 부드럽게 이동 @@ -169,8 +166,8 @@ fun FeedScreen( Box(modifier = Modifier.fillMaxSize()) { PullToRefreshBox( - isRefreshing = feedUiState.isRefreshing, - onRefresh = { feedViewModel.refreshCurrentTab() } + isRefreshing = feedUiState.isPullToRefreshing, + onRefresh = { feedViewModel.pullToRefresh() } ) { Column( modifier = Modifier.fillMaxSize() @@ -414,6 +411,19 @@ fun FeedScreen( icon = painterResource(id = R.drawable.ic_write), onClick = onNavigateToFeedWrite ) + + // 탭 전환 시 화면 가운데 로딩 인디케이터 + if (feedUiState.isRefreshing) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + color = colors.White, + modifier = Modifier.size(48.dp) + ) + } + } } } diff --git a/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt b/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt index 3d83db23..09190363 100644 --- a/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt +++ b/app/src/main/java/com/texthip/thip/ui/feed/viewmodel/FeedViewModel.kt @@ -21,7 +21,8 @@ data class FeedUiState( val recentWriters: List = emptyList(), val myFeedInfo: FeedMineInfoResponse? = null, val isLoading: Boolean = false, - val isRefreshing: Boolean = false, + val isRefreshing: Boolean = false, // 탭 전환용 로딩 + val isPullToRefreshing: Boolean = false, // Pull to refresh용 로딩 val isLoadingMore: Boolean = false, val isLastPageAllFeeds: Boolean = false, val isLastPageMyFeeds: Boolean = false, @@ -71,12 +72,16 @@ class FeedViewModel @Inject constructor( when (index) { 0 -> { - loadAllFeeds(isInitial = true) + // 항상 새로고침 (인디케이터 표시) + refreshCurrentTab() } 1 -> { - loadMyFeeds(isInitial = true) - fetchMyFeedInfo() + // 항상 새로고침 (인디케이터 표시) + refreshCurrentTab() + if (_uiState.value.myFeedInfo == null) { + fetchMyFeedInfo() + } } } } @@ -187,6 +192,18 @@ class FeedViewModel @Inject constructor( } } + fun pullToRefresh() { + viewModelScope.launch { + updateState { it.copy(isPullToRefreshing = true) } + + when (_uiState.value.selectedTabIndex) { + 0 -> refreshAllFeeds() + 1 -> refreshMyFeeds() + } + updateState { it.copy(isPullToRefreshing = false) } + } + } + private suspend fun refreshAllFeeds() { allFeedsNextCursor = null @@ -196,7 +213,6 @@ class FeedViewModel @Inject constructor( updateState { it.copy( allFeeds = response.feedList, - isRefreshing = false, isLastPageAllFeeds = response.isLast, error = null ) @@ -205,7 +221,6 @@ class FeedViewModel @Inject constructor( updateState { it.copy( allFeeds = emptyList(), - isRefreshing = false, isLastPageAllFeeds = true ) } @@ -213,7 +228,6 @@ class FeedViewModel @Inject constructor( }.onFailure { exception -> updateState { it.copy( - isRefreshing = false, error = exception.message ) } @@ -229,7 +243,6 @@ class FeedViewModel @Inject constructor( updateState { it.copy( myFeeds = response.feedList, - isRefreshing = false, isLastPageMyFeeds = response.isLast, error = null ) @@ -238,7 +251,6 @@ class FeedViewModel @Inject constructor( updateState { it.copy( myFeeds = emptyList(), - isRefreshing = false, isLastPageMyFeeds = true ) } @@ -246,7 +258,6 @@ class FeedViewModel @Inject constructor( }.onFailure { exception -> updateState { it.copy( - isRefreshing = false, error = exception.message ) }