From 623bd577b36cd150071ffc650fd4271511add35b Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 13:49:52 +0900 Subject: [PATCH 01/17] =?UTF-8?q?fix:=20ProfileSmallKeywordChip=20?= =?UTF-8?q?=ED=8C=A8=EB=94=A9=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/profile/component/ProfileKeywordChip.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordChip.kt b/app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordChip.kt index 70233d44..89dae204 100644 --- a/app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordChip.kt +++ b/app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordChip.kt @@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.widthIn import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -50,11 +49,10 @@ fun ProfileKeywordChip( private fun ProfileSmallKeywordChip(keyword: String) { Box( Modifier - .widthIn(min = 64.dp) .draw9Patch(LocalContext.current, R.drawable.bg_tag_gray) .padding( vertical = 8.dp, - horizontal = 7.dp, + horizontal = 16.dp, ), ) { Text( From 9980028cf105b90cb32d83d41f5144dadee49716 Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 14:16:50 +0900 Subject: [PATCH 02/17] =?UTF-8?q?feat:=20=ED=83=80=EC=9D=B8=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EB=92=A4=EB=A1=9C=EA=B0=80=EA=B8=B0=20?= =?UTF-8?q?=ED=97=A4=EB=8D=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/profile/ProfileScreen.kt | 124 ++++++++++-------- .../profile/component/ProfileTopSection.kt | 2 +- .../profile/navigation/ProfileNavigation.kt | 3 + 3 files changed, 72 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt index e6360afe..a1eb0a3d 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt @@ -1,6 +1,7 @@ package com.flint.presentation.profile import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -27,6 +28,7 @@ import com.flint.core.designsystem.component.bottomsheet.OttListBottomSheet import com.flint.core.designsystem.component.indicator.FlintLoadingIndicator import com.flint.core.designsystem.component.listView.CollectionSection import com.flint.core.designsystem.component.listView.SavedContentsSection +import com.flint.core.designsystem.component.topappbar.FlintBackTopAppbar import com.flint.core.designsystem.theme.FlintTheme import com.flint.core.designsystem.theme.FlintTheme.colors import com.flint.core.navigation.model.CollectionListRouteType @@ -40,6 +42,7 @@ import com.flint.presentation.profile.uistate.ProfileUiState @Composable fun ProfileRoute( paddingValues: PaddingValues, + navigateUp: () -> Unit, navigateToCollectionList: (routeType: CollectionListRouteType, userId: String?) -> Unit, navigateToSavedContentList: () -> Unit, // TODO: 스프린트에서 구현 navigateToCollectionDetail: (collectionId: String) -> Unit, @@ -76,6 +79,7 @@ fun ProfileRoute( ProfileScreen( modifier = Modifier.padding(paddingValues), uiState = state.data, + onBackClick = navigateUp, onCollectionItemClick = navigateToCollectionDetail, onContentItemClick = { contentId -> viewModel.getOttListPerContent(contentId) @@ -115,6 +119,7 @@ private fun ProfileScreen( uiState: ProfileUiState, modifier: Modifier = Modifier, onRefreshClick: () -> Unit = {}, + onBackClick: () -> Unit = {}, onCollectionItemClick: (collectionId: String) -> Unit, onContentItemClick: (contentId: String) -> Unit = {}, // TODO: 바텀시트 띄우기 onContentMoreClick: () -> Unit = {}, @@ -123,75 +128,82 @@ private fun ProfileScreen( ) { val userName = uiState.profile.nickname - LazyColumn( - overscrollEffect = null, - contentPadding = PaddingValues(bottom = 70.dp), - modifier = - modifier - .background(colors.background) - .fillMaxSize(), + Box( + modifier = modifier + .background(colors.background) + .fillMaxSize(), ) { - item { - with(uiState.profile) { - ProfileTopSection( - userName = nickname, - profileUrl = profileImageUrl.orEmpty(), - isFliner = isFliner, - ) + LazyColumn( + overscrollEffect = null, + contentPadding = PaddingValues(bottom = 70.dp), + ) { + item { + with(uiState.profile) { + ProfileTopSection( + userName = nickname, + profileUrl = profileImageUrl.orEmpty(), + isFliner = isFliner, + ) + } } - } - item { - Spacer(Modifier.height(20.dp)) + item { + Spacer(Modifier.height(20.dp)) - ProfileKeywordSection( - nickname = uiState.profile.nickname, - keywordList = uiState.keywords, - onRefreshClick = onRefreshClick, - modifier = Modifier.fillMaxWidth(), - ) - } + ProfileKeywordSection( + nickname = uiState.profile.nickname, + keywordList = uiState.keywords, + onRefreshClick = onRefreshClick, + modifier = Modifier.fillMaxWidth(), + ) + } - item { - if (uiState.createCollections.collections.isNotEmpty()) { - Spacer(Modifier.height(48.dp)) + item { + if (uiState.createCollections.collections.isNotEmpty()) { + Spacer(Modifier.height(48.dp)) + + CollectionSection( + title = "${userName}님의 컬렉션", + description = "${userName}님이 생성한 컬렉션이에요", + onItemClick = onCollectionItemClick, + isAllVisible = true, + onAllClick = onCreatedCollectionMoreClick, + collectionListModel = uiState.createCollections, + ) + } + } - CollectionSection( - title = "${userName}님의 컬렉션", - description = "${userName}님이 생성한 컬렉션이에요", - onItemClick = onCollectionItemClick, - isAllVisible = true, - onAllClick = onCreatedCollectionMoreClick, - collectionListModel = uiState.createCollections, - ) + item { + if (uiState.savedCollections.collections.isNotEmpty()) { + Spacer(Modifier.height(48.dp)) + + CollectionSection( + title = "저장한 컬렉션", + description = "${userName}님이 저장한 컬렉션이에요", + onItemClick = onCollectionItemClick, + isAllVisible = true, + onAllClick = onSavedCollectionMoreClick, + collectionListModel = uiState.savedCollections, + ) + } } - } - item { - if (uiState.savedCollections.collections.isNotEmpty()) { + item { Spacer(Modifier.height(48.dp)) - CollectionSection( - title = "저장한 컬렉션", - description = "${userName}님이 저장한 컬렉션이에요", - onItemClick = onCollectionItemClick, - isAllVisible = true, - onAllClick = onSavedCollectionMoreClick, - collectionListModel = uiState.savedCollections, + SavedContentsSection( + title = "저장한 작품", + description = "${userName}님이 저장한 작품이에요", + contentModelList = uiState.savedContents, + onItemClick = onContentItemClick, + isAllVisible = false, + onAllClick = {}, ) } } - - item { - Spacer(Modifier.height(48.dp)) - - SavedContentsSection( - title = "저장한 작품", - description = "${userName}님이 저장한 작품이에요", - contentModelList = uiState.savedContents, - onItemClick = onContentItemClick, - isAllVisible = false, - onAllClick = {}, + if (uiState.userId != null) { + FlintBackTopAppbar( + onClick = onBackClick, ) } } diff --git a/app/src/main/java/com/flint/presentation/profile/component/ProfileTopSection.kt b/app/src/main/java/com/flint/presentation/profile/component/ProfileTopSection.kt index b1d3e5df..cdf3d092 100644 --- a/app/src/main/java/com/flint/presentation/profile/component/ProfileTopSection.kt +++ b/app/src/main/java/com/flint/presentation/profile/component/ProfileTopSection.kt @@ -38,7 +38,7 @@ fun ProfileTopSection( modifier = modifier .fillMaxWidth() - .height(260.dp) + .height(306.dp) .paint( painter = painterResource(id = R.drawable.img_collection_bg2), contentScale = ContentScale.FillBounds, diff --git a/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt b/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt index 5ac4914e..de8a3fa6 100644 --- a/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt +++ b/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt @@ -32,6 +32,7 @@ fun NavGraphBuilder.myProfileNavGraph( composable { ProfileRoute( paddingValues = paddingValues, + navigateUp = {}, navigateToCollectionList = navigateToCollectionList, navigateToSavedContentList = navigateToSavedContentList, navigateToCollectionDetail = navigateToCollectionDetail, @@ -41,6 +42,7 @@ fun NavGraphBuilder.myProfileNavGraph( fun NavGraphBuilder.profileNavGraph( paddingValues: PaddingValues, + navigateUp: () -> Unit, navigateToCollectionList: (routeType: CollectionListRouteType, userId: String?) -> Unit, navigateToSavedContentList: () -> Unit, navigateToCollectionDetail: (collectionId: String) -> Unit, @@ -48,6 +50,7 @@ fun NavGraphBuilder.profileNavGraph( composable { ProfileRoute( paddingValues = paddingValues, + navigateUp = navigateUp, navigateToCollectionList = navigateToCollectionList, navigateToSavedContentList = navigateToSavedContentList, navigateToCollectionDetail = navigateToCollectionDetail, From d5901f500b461a020e6c382af5ab7011bf197aec Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 14:24:09 +0900 Subject: [PATCH 03/17] =?UTF-8?q?feat:=20ProfileScreen=20=ED=94=84?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/profile/ProfileScreen.kt | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt index a1eb0a3d..bcc8a082 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt @@ -20,6 +20,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -32,7 +34,11 @@ import com.flint.core.designsystem.component.topappbar.FlintBackTopAppbar import com.flint.core.designsystem.theme.FlintTheme import com.flint.core.designsystem.theme.FlintTheme.colors import com.flint.core.navigation.model.CollectionListRouteType +import com.flint.domain.model.collection.CollectionListModel +import com.flint.domain.model.content.BookmarkedContentListModel import com.flint.domain.model.ott.OttListModel +import com.flint.domain.model.user.KeywordListModel +import com.flint.domain.model.user.UserProfileResponseModel import com.flint.presentation.profile.component.ProfileKeywordSection import com.flint.presentation.profile.component.ProfileTopSection import com.flint.presentation.profile.sideeffect.ProfileSideEffect @@ -211,13 +217,48 @@ private fun ProfileScreen( @Preview(showBackground = true) @Composable -private fun ProfileScreenPreview() { +private fun ProfileScreenPreview( + @PreviewParameter(ProfileUiStatePreviewParameterProvider::class) uiState: ProfileUiState, +) { FlintTheme { ProfileScreen( - uiState = ProfileUiState.Fake, + uiState = uiState, onCollectionItemClick = {}, onCreatedCollectionMoreClick = {}, onSavedCollectionMoreClick = {} ) } } + +private class ProfileUiStatePreviewParameterProvider : PreviewParameterProvider { + override val values: Sequence = sequenceOf( + // 내 프로필 + ProfileUiState( + userId = null, + profile = UserProfileResponseModel( + id = "", + nickname = "닉네임", + profileImageUrl = "", + isFliner = false, + ), + keywords = KeywordListModel.FakeList1, + createCollections = CollectionListModel.FakeList, + savedCollections = CollectionListModel.FakeList, + savedContents = BookmarkedContentListModel.FakeList, + ), + // 다른 사용자 프로필 + ProfileUiState( + userId = "1", + profile = UserProfileResponseModel( + id = "", + nickname = "닉네임", + profileImageUrl = "", + isFliner = true, + ), + keywords = KeywordListModel.FakeList3, + createCollections = CollectionListModel(), + savedCollections = CollectionListModel(), + savedContents = BookmarkedContentListModel.FakeList, + ), + ) +} From 0ad85ed60bf2ab82c34ed255c2e39b58e9212c67 Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 14:45:30 +0900 Subject: [PATCH 04/17] =?UTF-8?q?style:=20=EB=A1=9C=EB=94=A9=20=EC=9D=B8?= =?UTF-8?q?=EB=94=94=EC=BC=80=EC=9D=B4=ED=84=B0=20=EC=83=89=EC=83=81=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/indicator/FlintLoadingIndicator.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/flint/core/designsystem/component/indicator/FlintLoadingIndicator.kt b/app/src/main/java/com/flint/core/designsystem/component/indicator/FlintLoadingIndicator.kt index 3a72d5f8..b3081dca 100644 --- a/app/src/main/java/com/flint/core/designsystem/component/indicator/FlintLoadingIndicator.kt +++ b/app/src/main/java/com/flint/core/designsystem/component/indicator/FlintLoadingIndicator.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import com.flint.core.designsystem.theme.FlintTheme @Composable fun FlintLoadingIndicator() { @@ -18,6 +19,8 @@ fun FlintLoadingIndicator() { .background(Color.Transparent), contentAlignment = Alignment.Center, ) { - CircularProgressIndicator() + CircularProgressIndicator( + color = FlintTheme.colors.primary400 + ) } } From 8ee50c38dde77c81b4aaa3a9547d0bddbd0decfd Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 14:47:21 +0900 Subject: [PATCH 05/17] =?UTF-8?q?fix:=20profileNavGraph=20navigateUp=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/flint/presentation/main/MainNavHost.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/flint/presentation/main/MainNavHost.kt b/app/src/main/java/com/flint/presentation/main/MainNavHost.kt index c83ff4bd..84a0dfb3 100644 --- a/app/src/main/java/com/flint/presentation/main/MainNavHost.kt +++ b/app/src/main/java/com/flint/presentation/main/MainNavHost.kt @@ -100,6 +100,7 @@ fun MainNavHost( profileNavGraph( paddingValues = paddingValues, + navigateUp = navigator::navigateUp, navigateToCollectionList = navigator::navigateToCollectionList, navigateToSavedContentList = navigator::navigateToSavedContent, navigateToCollectionDetail = navigator::navigateToCollectionDetail, From 2a97ae30dcee6f613d8d3017430ff712d91317de Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 15:00:21 +0900 Subject: [PATCH 06/17] =?UTF-8?q?refactor:=20=ED=94=84=EB=A1=9C=ED=95=84?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=20=ED=94=84=EB=A1=9C=ED=95=84=20=EB=B0=8F?= =?UTF-8?q?=20=EC=9E=91=ED=92=88/=EC=BB=AC=EB=A0=89=EC=85=98=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EB=B9=84=EB=8F=99=EA=B8=B0=20=EB=A1=9C?= =?UTF-8?q?=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/profile/ProfileViewModel.kt | 31 ++++++------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt b/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt index 91324516..5f0d3507 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt @@ -34,7 +34,7 @@ class ProfileViewModel @Inject constructor( val userId = savedStateHandle.toRoute().userId private val _uiState = MutableStateFlow>( - UiState.Empty + UiState.Loading ) val uiState: StateFlow> = _uiState.asStateFlow() @@ -50,24 +50,6 @@ class ProfileViewModel @Inject constructor( val keywordsDeferred = async { userRepository.getUserKeywords(userId = userId).getOrDefault(KeywordListModel()) } - - ProfileUiState( - userId = userId, - profile = profileDeferred.await(), - keywords = keywordsDeferred.await() - ) - }.onSuccess { combinedState -> - _uiState.update { UiState.Success(combinedState) } - getSectionInfo() - } - } - } - - fun getSectionInfo() { - viewModelScope.launch { - val currentState = (_uiState.value as? UiState.Success)?.data ?: return@launch - - suspendRunCatching { val createdCollectionsDeferred = async { userRepository.getUserCreatedCollections(userId = userId).getOrThrow() } @@ -78,13 +60,18 @@ class ProfileViewModel @Inject constructor( userRepository.getUserBookmarkedContents(userId = userId).getOrThrow() } - currentState.copy( + ProfileUiState( + userId = userId, + profile = profileDeferred.await(), + keywords = keywordsDeferred.await(), createCollections = createdCollectionsDeferred.await(), savedCollections = bookmarkedCollectionsDeferred.await(), savedContents = savedContentListDeferred.await() ) - }.onSuccess { updatedState -> - _uiState.update { UiState.Success(updatedState) } + }.onSuccess { combinedState -> + _uiState.update { UiState.Success(combinedState) } + }.onFailure { + _uiState.update { UiState.Failure } } } } From b2c9154e3a3bb6335fc831b5f8176ddb569366ca Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 15:52:01 +0900 Subject: [PATCH 07/17] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=ED=83=88?= =?UTF-8?q?=ED=87=B4=20=EC=9D=B4=EC=8A=A4=ED=84=B0=EC=97=90=EA=B7=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/flint/data/api/AuthApi.kt | 5 +++ .../dto/auth/response/WithdrawResponseDto.kt | 12 +++++++ .../flint/domain/repository/AuthRepository.kt | 6 ++++ .../flint/presentation/main/MainNavHost.kt | 2 ++ .../flint/presentation/main/MainNavigator.kt | 5 +++ .../presentation/profile/ProfileScreen.kt | 9 +++++- .../presentation/profile/ProfileViewModel.kt | 12 +++++++ .../profile/component/ProfileTopSection.kt | 31 ++++++++++++++++++- .../profile/navigation/ProfileNavigation.kt | 4 +++ .../profile/sideeffect/ProfileSideEffect.kt | 3 +- .../splash/navigation/SplashNavigation.kt | 6 ++++ 11 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/flint/data/dto/auth/response/WithdrawResponseDto.kt diff --git a/app/src/main/java/com/flint/data/api/AuthApi.kt b/app/src/main/java/com/flint/data/api/AuthApi.kt index 09647b24..14db04d7 100644 --- a/app/src/main/java/com/flint/data/api/AuthApi.kt +++ b/app/src/main/java/com/flint/data/api/AuthApi.kt @@ -4,8 +4,10 @@ import com.flint.data.dto.auth.request.SignupRequestDto import com.flint.data.dto.auth.request.SocialVerifyRequestDto import com.flint.data.dto.auth.response.SignupResponseDto import com.flint.data.dto.auth.response.SocialVerifyResponseDto +import com.flint.data.dto.auth.response.WithdrawResponseDto import com.flint.data.dto.base.BaseResponse import retrofit2.http.Body +import retrofit2.http.DELETE import retrofit2.http.POST interface AuthApi { @@ -18,4 +20,7 @@ interface AuthApi { suspend fun socialVerify( @Body requestDto: SocialVerifyRequestDto, ): BaseResponse + + @DELETE("/api/v1/auth/withdraw") + suspend fun withdraw(): WithdrawResponseDto } diff --git a/app/src/main/java/com/flint/data/dto/auth/response/WithdrawResponseDto.kt b/app/src/main/java/com/flint/data/dto/auth/response/WithdrawResponseDto.kt new file mode 100644 index 00000000..f072762c --- /dev/null +++ b/app/src/main/java/com/flint/data/dto/auth/response/WithdrawResponseDto.kt @@ -0,0 +1,12 @@ +package com.flint.data.dto.auth.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class WithdrawResponseDto( + @SerialName("status") + val status: Int, + @SerialName("message") + val message: String, +) diff --git a/app/src/main/java/com/flint/domain/repository/AuthRepository.kt b/app/src/main/java/com/flint/domain/repository/AuthRepository.kt index 484f24d5..fe7cd318 100644 --- a/app/src/main/java/com/flint/domain/repository/AuthRepository.kt +++ b/app/src/main/java/com/flint/domain/repository/AuthRepository.kt @@ -38,4 +38,10 @@ class AuthRepository @Inject constructor( result } + suspend fun withdraw(): Result = + suspendRunCatching { + api.withdraw() + preferencesManager.removeString(ACCESS_TOKEN) + preferencesManager.clearAll() + } } \ No newline at end of file diff --git a/app/src/main/java/com/flint/presentation/main/MainNavHost.kt b/app/src/main/java/com/flint/presentation/main/MainNavHost.kt index 84a0dfb3..d51e9d45 100644 --- a/app/src/main/java/com/flint/presentation/main/MainNavHost.kt +++ b/app/src/main/java/com/flint/presentation/main/MainNavHost.kt @@ -96,6 +96,7 @@ fun MainNavHost( navigateToCollectionList = navigator::navigateToCollectionList, navigateToSavedContentList = navigator::navigateToSavedContent, navigateToCollectionDetail = navigator::navigateToCollectionDetail, + navigateToSplash = navigator::navigateToSplash, ) profileNavGraph( @@ -104,6 +105,7 @@ fun MainNavHost( navigateToCollectionList = navigator::navigateToCollectionList, navigateToSavedContentList = navigator::navigateToSavedContent, navigateToCollectionDetail = navigator::navigateToCollectionDetail, + navigateToSplash = navigator::navigateToSplash, ) } } diff --git a/app/src/main/java/com/flint/presentation/main/MainNavigator.kt b/app/src/main/java/com/flint/presentation/main/MainNavigator.kt index 57d6cf88..d4dc14bb 100644 --- a/app/src/main/java/com/flint/presentation/main/MainNavigator.kt +++ b/app/src/main/java/com/flint/presentation/main/MainNavigator.kt @@ -22,6 +22,7 @@ import com.flint.presentation.onboarding.navigation.navigateToOnboarding import com.flint.presentation.profile.navigation.navigateToMyProfile import com.flint.presentation.profile.navigation.navigateToProfile import com.flint.presentation.savedcontent.navigation.navigateToSavedContentList +import com.flint.presentation.splash.navigation.navigateToSplash import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -158,6 +159,10 @@ class MainNavigator( fun navigateUp() { navController.navigateUp() } + + fun navigateToSplash() { + navController.navigateToSplash(clearStackNavOptions) + } } @Composable diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt index bcc8a082..51ab7221 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt @@ -52,6 +52,7 @@ fun ProfileRoute( navigateToCollectionList: (routeType: CollectionListRouteType, userId: String?) -> Unit, navigateToSavedContentList: () -> Unit, // TODO: 스프린트에서 구현 navigateToCollectionDetail: (collectionId: String) -> Unit, + navigateToSplash: () -> Unit, viewModel: ProfileViewModel = hiltViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -72,6 +73,9 @@ fun ProfileRoute( ottListModel = sideEffect.ottListModel showOttListBottomSheet = true } + is ProfileSideEffect.WithdrawSuccess -> { + navigateToSplash() + } } } } @@ -102,6 +106,7 @@ fun ProfileRoute( state.data.userId ) }, + onEasterEggWithdraw = viewModel::easterEggWithdraw, ) } @@ -130,7 +135,8 @@ private fun ProfileScreen( onContentItemClick: (contentId: String) -> Unit = {}, // TODO: 바텀시트 띄우기 onContentMoreClick: () -> Unit = {}, onCreatedCollectionMoreClick: () -> Unit, - onSavedCollectionMoreClick: () -> Unit + onSavedCollectionMoreClick: () -> Unit, + onEasterEggWithdraw: () -> Unit = {}, ) { val userName = uiState.profile.nickname @@ -149,6 +155,7 @@ private fun ProfileScreen( userName = nickname, profileUrl = profileImageUrl.orEmpty(), isFliner = isFliner, + onEasterEggWithdraw = onEasterEggWithdraw, ) } } diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt b/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt index 5f0d3507..364deeec 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt @@ -8,6 +8,7 @@ import com.flint.core.common.util.UiState import com.flint.core.common.util.suspendRunCatching import com.flint.core.navigation.Route import com.flint.domain.model.user.KeywordListModel +import com.flint.domain.repository.AuthRepository import com.flint.domain.repository.ContentRepository import com.flint.domain.repository.UserRepository import com.flint.presentation.profile.sideeffect.ProfileSideEffect @@ -27,6 +28,7 @@ import javax.inject.Inject @HiltViewModel class ProfileViewModel @Inject constructor( savedStateHandle: SavedStateHandle, + private val authRepository: AuthRepository, private val userRepository: UserRepository, private val contentRepository: ContentRepository ) : ViewModel() { @@ -85,4 +87,14 @@ class ProfileViewModel @Inject constructor( Timber.e(it) } } + + fun easterEggWithdraw() = viewModelScope.launch { + authRepository.withdraw() + .onSuccess { + _sideEffect.emit(ProfileSideEffect.WithdrawSuccess) + } + .onFailure { + Timber.e(it) + } + } } diff --git a/app/src/main/java/com/flint/presentation/profile/component/ProfileTopSection.kt b/app/src/main/java/com/flint/presentation/profile/component/ProfileTopSection.kt index cdf3d092..4310abc5 100644 --- a/app/src/main/java/com/flint/presentation/profile/component/ProfileTopSection.kt +++ b/app/src/main/java/com/flint/presentation/profile/component/ProfileTopSection.kt @@ -13,6 +13,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableLongStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.paint @@ -23,16 +28,24 @@ import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.flint.R +import com.flint.core.common.extension.noRippleClickable import com.flint.core.designsystem.component.image.ProfileImage import com.flint.core.designsystem.theme.FlintTheme +private const val EASTER_EGG_CLICK_COUNT = 5 +private const val EASTER_EGG_CLICK_TIMEOUT = 3000L + @Composable fun ProfileTopSection( userName: String, profileUrl: String, isFliner: Boolean, modifier: Modifier = Modifier, + onEasterEggWithdraw: () -> Unit = {}, ) { + var clickCount by remember { mutableIntStateOf(0) } + var lastClickTime by remember { mutableLongStateOf(0L) } + Column { Box( modifier = @@ -83,7 +96,23 @@ fun ProfileTopSection( Modifier .offset(x = 13.dp, y = (-42).dp) .align(Alignment.BottomStart) - .size(128.dp), + .size(128.dp) + .noRippleClickable( + onClick = { + val currentTime = System.currentTimeMillis() + if (currentTime - lastClickTime > EASTER_EGG_CLICK_TIMEOUT) { + clickCount = 1 + } else { + clickCount++ + } + lastClickTime = currentTime + + if (clickCount >= EASTER_EGG_CLICK_COUNT) { + clickCount = 0 + onEasterEggWithdraw() + } + } + ) ) } } diff --git a/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt b/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt index de8a3fa6..4fb530ef 100644 --- a/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt +++ b/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt @@ -28,6 +28,7 @@ fun NavGraphBuilder.myProfileNavGraph( navigateToCollectionList: (routeType: CollectionListRouteType, userId: String?) -> Unit, navigateToSavedContentList: () -> Unit, navigateToCollectionDetail: (collectionId: String) -> Unit, + navigateToSplash: () -> Unit, ) { composable { ProfileRoute( @@ -36,6 +37,7 @@ fun NavGraphBuilder.myProfileNavGraph( navigateToCollectionList = navigateToCollectionList, navigateToSavedContentList = navigateToSavedContentList, navigateToCollectionDetail = navigateToCollectionDetail, + navigateToSplash = navigateToSplash, ) } } @@ -46,6 +48,7 @@ fun NavGraphBuilder.profileNavGraph( navigateToCollectionList: (routeType: CollectionListRouteType, userId: String?) -> Unit, navigateToSavedContentList: () -> Unit, navigateToCollectionDetail: (collectionId: String) -> Unit, + navigateToSplash: () -> Unit, ) { composable { ProfileRoute( @@ -54,6 +57,7 @@ fun NavGraphBuilder.profileNavGraph( navigateToCollectionList = navigateToCollectionList, navigateToSavedContentList = navigateToSavedContentList, navigateToCollectionDetail = navigateToCollectionDetail, + navigateToSplash = navigateToSplash, ) } } diff --git a/app/src/main/java/com/flint/presentation/profile/sideeffect/ProfileSideEffect.kt b/app/src/main/java/com/flint/presentation/profile/sideeffect/ProfileSideEffect.kt index 57d59e44..c24d6331 100644 --- a/app/src/main/java/com/flint/presentation/profile/sideeffect/ProfileSideEffect.kt +++ b/app/src/main/java/com/flint/presentation/profile/sideeffect/ProfileSideEffect.kt @@ -2,6 +2,7 @@ package com.flint.presentation.profile.sideeffect import com.flint.domain.model.ott.OttListModel -interface ProfileSideEffect { +sealed interface ProfileSideEffect { data class ShowOttListBottomSheet(val ottListModel: OttListModel) : ProfileSideEffect + data object WithdrawSuccess : ProfileSideEffect } diff --git a/app/src/main/java/com/flint/presentation/splash/navigation/SplashNavigation.kt b/app/src/main/java/com/flint/presentation/splash/navigation/SplashNavigation.kt index 137f0a21..2d0e135c 100644 --- a/app/src/main/java/com/flint/presentation/splash/navigation/SplashNavigation.kt +++ b/app/src/main/java/com/flint/presentation/splash/navigation/SplashNavigation.kt @@ -1,11 +1,17 @@ package com.flint.presentation.splash.navigation import androidx.compose.foundation.layout.PaddingValues +import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.flint.core.navigation.Route import com.flint.presentation.splash.SplashRoute +fun NavController.navigateToSplash(navOptions: NavOptions? = null) { + navigate(Route.Splash, navOptions) +} + fun NavGraphBuilder.splashNavGraph( paddingValues: PaddingValues, navigateToLogin: () -> Unit, From 808f8ea310a9aabbb413d14c31752dad80b1f6e4 Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 15:59:56 +0900 Subject: [PATCH 08/17] =?UTF-8?q?refactor:=20=ED=9A=8C=EC=9B=90=ED=83=88?= =?UTF-8?q?=ED=87=B4=20=ED=9B=84=20=EC=95=B1=20=EC=9E=AC=EC=8B=9C=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/flint/presentation/MainActivity.kt | 2 +- .../main/java/com/flint/presentation/main/MainNavigator.kt | 5 ----- .../java/com/flint/presentation/profile/ProfileScreen.kt | 6 ++++-- .../presentation/profile/navigation/ProfileNavigation.kt | 4 ---- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/flint/presentation/MainActivity.kt b/app/src/main/java/com/flint/presentation/MainActivity.kt index 19012314..ef41cb7e 100644 --- a/app/src/main/java/com/flint/presentation/MainActivity.kt +++ b/app/src/main/java/com/flint/presentation/MainActivity.kt @@ -62,7 +62,7 @@ class MainActivity : ComponentActivity() { } } - private fun restartApplication() { + fun restartApplication() { val packageManager: PackageManager = this.packageManager val intent = packageManager.getLaunchIntentForPackage(this.packageName) val componentName = intent!!.component diff --git a/app/src/main/java/com/flint/presentation/main/MainNavigator.kt b/app/src/main/java/com/flint/presentation/main/MainNavigator.kt index d4dc14bb..57d6cf88 100644 --- a/app/src/main/java/com/flint/presentation/main/MainNavigator.kt +++ b/app/src/main/java/com/flint/presentation/main/MainNavigator.kt @@ -22,7 +22,6 @@ import com.flint.presentation.onboarding.navigation.navigateToOnboarding import com.flint.presentation.profile.navigation.navigateToMyProfile import com.flint.presentation.profile.navigation.navigateToProfile import com.flint.presentation.savedcontent.navigation.navigateToSavedContentList -import com.flint.presentation.splash.navigation.navigateToSplash import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -159,10 +158,6 @@ class MainNavigator( fun navigateUp() { navController.navigateUp() } - - fun navigateToSplash() { - navController.navigateToSplash(clearStackNavOptions) - } } @Composable diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt index 51ab7221..6af9f1b6 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -39,6 +40,7 @@ import com.flint.domain.model.content.BookmarkedContentListModel import com.flint.domain.model.ott.OttListModel import com.flint.domain.model.user.KeywordListModel import com.flint.domain.model.user.UserProfileResponseModel +import com.flint.presentation.MainActivity import com.flint.presentation.profile.component.ProfileKeywordSection import com.flint.presentation.profile.component.ProfileTopSection import com.flint.presentation.profile.sideeffect.ProfileSideEffect @@ -52,11 +54,11 @@ fun ProfileRoute( navigateToCollectionList: (routeType: CollectionListRouteType, userId: String?) -> Unit, navigateToSavedContentList: () -> Unit, // TODO: 스프린트에서 구현 navigateToCollectionDetail: (collectionId: String) -> Unit, - navigateToSplash: () -> Unit, viewModel: ProfileViewModel = hiltViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() val uriHandler = LocalUriHandler.current + val context = LocalContext.current var showOttListBottomSheet by remember { mutableStateOf(false) } var ottListModel by remember { mutableStateOf(OttListModel()) } @@ -74,7 +76,7 @@ fun ProfileRoute( showOttListBottomSheet = true } is ProfileSideEffect.WithdrawSuccess -> { - navigateToSplash() + (context as? MainActivity)?.restartApplication() } } } diff --git a/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt b/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt index 4fb530ef..de8a3fa6 100644 --- a/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt +++ b/app/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.kt @@ -28,7 +28,6 @@ fun NavGraphBuilder.myProfileNavGraph( navigateToCollectionList: (routeType: CollectionListRouteType, userId: String?) -> Unit, navigateToSavedContentList: () -> Unit, navigateToCollectionDetail: (collectionId: String) -> Unit, - navigateToSplash: () -> Unit, ) { composable { ProfileRoute( @@ -37,7 +36,6 @@ fun NavGraphBuilder.myProfileNavGraph( navigateToCollectionList = navigateToCollectionList, navigateToSavedContentList = navigateToSavedContentList, navigateToCollectionDetail = navigateToCollectionDetail, - navigateToSplash = navigateToSplash, ) } } @@ -48,7 +46,6 @@ fun NavGraphBuilder.profileNavGraph( navigateToCollectionList: (routeType: CollectionListRouteType, userId: String?) -> Unit, navigateToSavedContentList: () -> Unit, navigateToCollectionDetail: (collectionId: String) -> Unit, - navigateToSplash: () -> Unit, ) { composable { ProfileRoute( @@ -57,7 +54,6 @@ fun NavGraphBuilder.profileNavGraph( navigateToCollectionList = navigateToCollectionList, navigateToSavedContentList = navigateToSavedContentList, navigateToCollectionDetail = navigateToCollectionDetail, - navigateToSplash = navigateToSplash, ) } } From 75afa248e0f53d1a399460d2eabbb71be0c0df0f Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 16:05:42 +0900 Subject: [PATCH 09/17] =?UTF-8?q?refactor:=20ContextExt=EB=A5=BC=20?= =?UTF-8?q?=ED=86=B5=ED=95=9C=20=EC=95=B1=20=EC=9E=AC=EC=8B=9C=EC=9E=91=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/flint/core/common/extension/ContextExt.kt | 14 ++++++++++++++ .../com/flint/presentation/main/MainNavHost.kt | 2 -- .../flint/presentation/profile/ProfileScreen.kt | 3 ++- 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/flint/core/common/extension/ContextExt.kt diff --git a/app/src/main/java/com/flint/core/common/extension/ContextExt.kt b/app/src/main/java/com/flint/core/common/extension/ContextExt.kt new file mode 100644 index 00000000..766513f2 --- /dev/null +++ b/app/src/main/java/com/flint/core/common/extension/ContextExt.kt @@ -0,0 +1,14 @@ +package com.flint.core.common.extension + +import android.app.Activity +import android.content.Context +import android.content.ContextWrapper + +fun Context.findActivity(): Activity { + var context = this + while (context is ContextWrapper) { + if (context is Activity) return context + context = context.baseContext + } + throw IllegalStateException("no activity") +} diff --git a/app/src/main/java/com/flint/presentation/main/MainNavHost.kt b/app/src/main/java/com/flint/presentation/main/MainNavHost.kt index d51e9d45..84a0dfb3 100644 --- a/app/src/main/java/com/flint/presentation/main/MainNavHost.kt +++ b/app/src/main/java/com/flint/presentation/main/MainNavHost.kt @@ -96,7 +96,6 @@ fun MainNavHost( navigateToCollectionList = navigator::navigateToCollectionList, navigateToSavedContentList = navigator::navigateToSavedContent, navigateToCollectionDetail = navigator::navigateToCollectionDetail, - navigateToSplash = navigator::navigateToSplash, ) profileNavGraph( @@ -105,7 +104,6 @@ fun MainNavHost( navigateToCollectionList = navigator::navigateToCollectionList, navigateToSavedContentList = navigator::navigateToSavedContent, navigateToCollectionDetail = navigator::navigateToCollectionDetail, - navigateToSplash = navigator::navigateToSplash, ) } } diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt index 6af9f1b6..111fd4e7 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.flint.core.common.extension.findActivity import com.flint.core.common.util.UiState import com.flint.core.designsystem.component.bottomsheet.OttListBottomSheet import com.flint.core.designsystem.component.indicator.FlintLoadingIndicator @@ -76,7 +77,7 @@ fun ProfileRoute( showOttListBottomSheet = true } is ProfileSideEffect.WithdrawSuccess -> { - (context as? MainActivity)?.restartApplication() + (context.findActivity() as? MainActivity)?.restartApplication() } } } From 2ad8a607765174e80c823a6aaff5ba6a3beff403 Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 17:08:24 +0900 Subject: [PATCH 10/17] =?UTF-8?q?refactor:=20=ED=94=84=EB=A1=9C=ED=95=84?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=20ProfileTopSection=20=EB=A1=9C=EB=94=A9?= =?UTF-8?q?=20=EB=B2=94=EC=9C=84=EC=97=90=EC=84=9C=20=EC=A0=9C=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../indicator/FlintLoadingIndicator.kt | 6 +- .../presentation/profile/ProfileScreen.kt | 185 ++++++++++-------- .../presentation/profile/ProfileViewModel.kt | 36 ++-- .../profile/uistate/ProfileUiState.kt | 39 ++-- 4 files changed, 151 insertions(+), 115 deletions(-) diff --git a/app/src/main/java/com/flint/core/designsystem/component/indicator/FlintLoadingIndicator.kt b/app/src/main/java/com/flint/core/designsystem/component/indicator/FlintLoadingIndicator.kt index b3081dca..d3fdb69f 100644 --- a/app/src/main/java/com/flint/core/designsystem/component/indicator/FlintLoadingIndicator.kt +++ b/app/src/main/java/com/flint/core/designsystem/component/indicator/FlintLoadingIndicator.kt @@ -11,10 +11,12 @@ import androidx.compose.ui.graphics.Color import com.flint.core.designsystem.theme.FlintTheme @Composable -fun FlintLoadingIndicator() { +fun FlintLoadingIndicator( + modifier: Modifier = Modifier +) { Box( modifier = - Modifier + modifier .fillMaxSize() .background(Color.Transparent), contentAlignment = Alignment.Center, diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt index 111fd4e7..18ea59a5 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.ui.Alignment import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn @@ -14,11 +15,15 @@ import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -33,6 +38,7 @@ import com.flint.core.designsystem.component.indicator.FlintLoadingIndicator import com.flint.core.designsystem.component.listView.CollectionSection import com.flint.core.designsystem.component.listView.SavedContentsSection import com.flint.core.designsystem.component.topappbar.FlintBackTopAppbar +import com.flint.core.designsystem.theme.Colors import com.flint.core.designsystem.theme.FlintTheme import com.flint.core.designsystem.theme.FlintTheme.colors import com.flint.core.navigation.model.CollectionListRouteType @@ -45,6 +51,7 @@ import com.flint.presentation.MainActivity import com.flint.presentation.profile.component.ProfileKeywordSection import com.flint.presentation.profile.component.ProfileTopSection import com.flint.presentation.profile.sideeffect.ProfileSideEffect +import com.flint.presentation.profile.uistate.ProfileSectionData import com.flint.presentation.profile.uistate.ProfileUiState @OptIn(ExperimentalMaterial3Api::class) @@ -83,38 +90,28 @@ fun ProfileRoute( } } - when (val state = uiState) { - is UiState.Loading -> { - FlintLoadingIndicator() - } - - is UiState.Success -> { - ProfileScreen( - modifier = Modifier.padding(paddingValues), - uiState = state.data, - onBackClick = navigateUp, - onCollectionItemClick = navigateToCollectionDetail, - onContentItemClick = { contentId -> - viewModel.getOttListPerContent(contentId) - }, - onCreatedCollectionMoreClick = { - navigateToCollectionList( - CollectionListRouteType.CREATED, - state.data.userId - ) - }, - onSavedCollectionMoreClick = { - navigateToCollectionList( - CollectionListRouteType.SAVED, - state.data.userId - ) - }, - onEasterEggWithdraw = viewModel::easterEggWithdraw, + ProfileScreen( + modifier = Modifier.padding(paddingValues), + uiState = uiState, + onBackClick = navigateUp, + onCollectionItemClick = navigateToCollectionDetail, + onContentItemClick = { contentId -> + viewModel.getOttListPerContent(contentId) + }, + onCreatedCollectionMoreClick = { + navigateToCollectionList( + CollectionListRouteType.CREATED, + uiState.userId ) - } - - else -> {} - } + }, + onSavedCollectionMoreClick = { + navigateToCollectionList( + CollectionListRouteType.SAVED, + uiState.userId + ) + }, + onEasterEggWithdraw = viewModel::easterEggWithdraw, + ) if (showOttListBottomSheet) { OttListBottomSheet( @@ -135,7 +132,7 @@ private fun ProfileScreen( onRefreshClick: () -> Unit = {}, onBackClick: () -> Unit = {}, onCollectionItemClick: (collectionId: String) -> Unit, - onContentItemClick: (contentId: String) -> Unit = {}, // TODO: 바텀시트 띄우기 + onContentItemClick: (contentId: String) -> Unit = {}, onContentMoreClick: () -> Unit = {}, onCreatedCollectionMoreClick: () -> Unit, onSavedCollectionMoreClick: () -> Unit, @@ -163,58 +160,57 @@ private fun ProfileScreen( } } - item { - Spacer(Modifier.height(20.dp)) + when (val sectionData = uiState.sectionData) { + is UiState.Loading -> { + item { + FlintLoadingIndicator( + modifier = Modifier.fillParentMaxHeight(), + ) + } + } - ProfileKeywordSection( - nickname = uiState.profile.nickname, - keywordList = uiState.keywords, - onRefreshClick = onRefreshClick, - modifier = Modifier.fillMaxWidth(), - ) - } + is UiState.Success -> { + item { + Spacer(Modifier.height(20.dp)) - item { - if (uiState.createCollections.collections.isNotEmpty()) { - Spacer(Modifier.height(48.dp)) + ProfileKeywordSection( + nickname = uiState.profile.nickname, + keywordList = sectionData.data.keywords, + onRefreshClick = onRefreshClick, + modifier = Modifier.fillMaxWidth(), + ) + } - CollectionSection( - title = "${userName}님의 컬렉션", - description = "${userName}님이 생성한 컬렉션이에요", - onItemClick = onCollectionItemClick, - isAllVisible = true, - onAllClick = onCreatedCollectionMoreClick, - collectionListModel = uiState.createCollections, - ) - } - } + item { + if (sectionData.data.savedCollections.collections.isNotEmpty()) { + Spacer(Modifier.height(48.dp)) - item { - if (uiState.savedCollections.collections.isNotEmpty()) { - Spacer(Modifier.height(48.dp)) + CollectionSection( + title = "저장한 컬렉션", + description = "${userName}님이 저장한 컬렉션이에요", + onItemClick = onCollectionItemClick, + isAllVisible = true, + onAllClick = onSavedCollectionMoreClick, + collectionListModel = sectionData.data.savedCollections, + ) + } + } - CollectionSection( - title = "저장한 컬렉션", - description = "${userName}님이 저장한 컬렉션이에요", - onItemClick = onCollectionItemClick, - isAllVisible = true, - onAllClick = onSavedCollectionMoreClick, - collectionListModel = uiState.savedCollections, - ) - } - } + item { + Spacer(Modifier.height(48.dp)) - item { - Spacer(Modifier.height(48.dp)) + SavedContentsSection( + title = "저장한 작품", + description = "${userName}님이 저장한 작품이에요", + contentModelList = sectionData.data.savedContents, + onItemClick = onContentItemClick, + isAllVisible = false, + onAllClick = {}, + ) + } + } - SavedContentsSection( - title = "저장한 작품", - description = "${userName}님이 저장한 작품이에요", - contentModelList = uiState.savedContents, - onItemClick = onContentItemClick, - isAllVisible = false, - onAllClick = {}, - ) + else -> {} } } if (uiState.userId != null) { @@ -242,6 +238,17 @@ private fun ProfileScreenPreview( private class ProfileUiStatePreviewParameterProvider : PreviewParameterProvider { override val values: Sequence = sequenceOf( + // 로딩 상태 + ProfileUiState( + userId = null, + profile = UserProfileResponseModel( + id = "", + nickname = "닉네임", + profileImageUrl = "", + isFliner = false, + ), + sectionData = UiState.Loading + ), // 내 프로필 ProfileUiState( userId = null, @@ -251,10 +258,14 @@ private class ProfileUiStatePreviewParameterProvider : PreviewParameterProvider< profileImageUrl = "", isFliner = false, ), - keywords = KeywordListModel.FakeList1, - createCollections = CollectionListModel.FakeList, - savedCollections = CollectionListModel.FakeList, - savedContents = BookmarkedContentListModel.FakeList, + sectionData = UiState.Success( + ProfileSectionData( + keywords = KeywordListModel.FakeList1, + createCollections = CollectionListModel.FakeList, + savedCollections = CollectionListModel.FakeList, + savedContents = BookmarkedContentListModel.FakeList, + ) + ), ), // 다른 사용자 프로필 ProfileUiState( @@ -265,10 +276,14 @@ private class ProfileUiStatePreviewParameterProvider : PreviewParameterProvider< profileImageUrl = "", isFliner = true, ), - keywords = KeywordListModel.FakeList3, - createCollections = CollectionListModel(), - savedCollections = CollectionListModel(), - savedContents = BookmarkedContentListModel.FakeList, + sectionData = UiState.Success( + ProfileSectionData( + keywords = KeywordListModel.FakeList3, + createCollections = CollectionListModel(), + savedCollections = CollectionListModel(), + savedContents = BookmarkedContentListModel.FakeList, + ) + ), ), ) } diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt b/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt index 364deeec..04603045 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt @@ -12,6 +12,7 @@ import com.flint.domain.repository.AuthRepository import com.flint.domain.repository.ContentRepository import com.flint.domain.repository.UserRepository import com.flint.presentation.profile.sideeffect.ProfileSideEffect +import com.flint.presentation.profile.uistate.ProfileSectionData import com.flint.presentation.profile.uistate.ProfileUiState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.async @@ -35,20 +36,30 @@ class ProfileViewModel @Inject constructor( val userId = savedStateHandle.toRoute().userId - private val _uiState = MutableStateFlow>( - UiState.Loading - ) - val uiState: StateFlow> = _uiState.asStateFlow() + private val _uiState = MutableStateFlow(ProfileUiState(userId = userId)) + val uiState: StateFlow = _uiState.asStateFlow() private val _sideEffect = MutableSharedFlow() val sideEffect = _sideEffect.asSharedFlow() fun getProfile() { viewModelScope.launch { - suspendRunCatching { - val profileDeferred = async { - userRepository.getUserProfile(userId = userId).getOrThrow() + userRepository.getUserProfile(userId = userId) + .onSuccess { profile -> + _uiState.update { it.copy(profile = profile) } + loadSectionData() + } + .onFailure { + Timber.e(it) } + } + } + + private fun loadSectionData() { + viewModelScope.launch { + _uiState.update { it.copy(sectionData = UiState.Loading) } + + suspendRunCatching { val keywordsDeferred = async { userRepository.getUserKeywords(userId = userId).getOrDefault(KeywordListModel()) } @@ -62,18 +73,17 @@ class ProfileViewModel @Inject constructor( userRepository.getUserBookmarkedContents(userId = userId).getOrThrow() } - ProfileUiState( - userId = userId, - profile = profileDeferred.await(), + ProfileSectionData( keywords = keywordsDeferred.await(), createCollections = createdCollectionsDeferred.await(), savedCollections = bookmarkedCollectionsDeferred.await(), savedContents = savedContentListDeferred.await() ) - }.onSuccess { combinedState -> - _uiState.update { UiState.Success(combinedState) } + }.onSuccess { sectionData -> + _uiState.update { it.copy(sectionData = UiState.Success(sectionData)) } }.onFailure { - _uiState.update { UiState.Failure } + _uiState.update { it.copy(sectionData = UiState.Failure) } + Timber.e(it) } } } diff --git a/app/src/main/java/com/flint/presentation/profile/uistate/ProfileUiState.kt b/app/src/main/java/com/flint/presentation/profile/uistate/ProfileUiState.kt index cb73d200..41534097 100644 --- a/app/src/main/java/com/flint/presentation/profile/uistate/ProfileUiState.kt +++ b/app/src/main/java/com/flint/presentation/profile/uistate/ProfileUiState.kt @@ -1,6 +1,7 @@ package com.flint.presentation.profile.uistate import androidx.compose.runtime.Immutable +import com.flint.core.common.util.UiState import com.flint.domain.model.collection.CollectionListModel import com.flint.domain.model.content.BookmarkedContentListModel import com.flint.domain.model.user.KeywordListModel @@ -9,28 +10,36 @@ import com.flint.domain.model.user.UserProfileResponseModel @Immutable data class ProfileUiState( val userId: String? = null, - val keywords: KeywordListModel, - val profile: UserProfileResponseModel, - val savedContents: BookmarkedContentListModel = BookmarkedContentListModel(), - val createCollections: CollectionListModel = CollectionListModel(), - val savedCollections: CollectionListModel = CollectionListModel(), + val profile: UserProfileResponseModel = UserProfileResponseModel.Empty, + val sectionData: UiState = UiState.Loading, ) { companion object { val Empty = ProfileUiState( - keywords = KeywordListModel(), - profile = UserProfileResponseModel.Companion.Empty, - createCollections = CollectionListModel.FakeList, - savedCollections = CollectionListModel.FakeList, - savedContents = BookmarkedContentListModel.FakeList, + profile = UserProfileResponseModel.Empty, + sectionData = UiState.Loading, ) val Fake = ProfileUiState( - keywords = KeywordListModel.FakeList1, - profile = UserProfileResponseModel.Companion.Fake, - createCollections = CollectionListModel.FakeList, - savedCollections = CollectionListModel.FakeList, - savedContents = BookmarkedContentListModel.FakeList, + profile = UserProfileResponseModel.Fake, + sectionData = UiState.Success(ProfileSectionData.Fake), ) } +} + +@Immutable +data class ProfileSectionData( + val keywords: KeywordListModel = KeywordListModel(), + val createCollections: CollectionListModel = CollectionListModel(), + val savedCollections: CollectionListModel = CollectionListModel(), + val savedContents: BookmarkedContentListModel = BookmarkedContentListModel(), +) { + companion object { + val Fake = ProfileSectionData( + keywords = KeywordListModel.FakeList1, + createCollections = CollectionListModel.FakeList, + savedCollections = CollectionListModel.FakeList, + savedContents = BookmarkedContentListModel.FakeList, + ) + } } \ No newline at end of file From 872635df55fd7b9f6d9b135a17ff45f2cb618c28 Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 17:17:30 +0900 Subject: [PATCH 11/17] =?UTF-8?q?refactor:=20=ED=94=84=EB=A1=9C=ED=95=84?= =?UTF-8?q?=20=EB=A1=9C=EB=94=A9=EB=B0=94=20=EC=9C=84=EC=B9=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/profile/ProfileScreen.kt | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt index 18ea59a5..707fe0a9 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt @@ -139,6 +139,9 @@ private fun ProfileScreen( onEasterEggWithdraw: () -> Unit = {}, ) { val userName = uiState.profile.nickname + var topHeightPx by remember { mutableIntStateOf(0) } + val density = LocalDensity.current + val topHeightDp = with(density) { topHeightPx.toDp() } Box( modifier = modifier @@ -150,13 +153,19 @@ private fun ProfileScreen( contentPadding = PaddingValues(bottom = 70.dp), ) { item { - with(uiState.profile) { - ProfileTopSection( - userName = nickname, - profileUrl = profileImageUrl.orEmpty(), - isFliner = isFliner, - onEasterEggWithdraw = onEasterEggWithdraw, - ) + Box( + modifier = Modifier.onGloballyPositioned { coordinates -> + topHeightPx = coordinates.size.height + } + ) { + with(uiState.profile) { + ProfileTopSection( + userName = nickname, + profileUrl = profileImageUrl.orEmpty(), + isFliner = isFliner, + onEasterEggWithdraw = onEasterEggWithdraw, + ) + } } } @@ -164,7 +173,9 @@ private fun ProfileScreen( is UiState.Loading -> { item { FlintLoadingIndicator( - modifier = Modifier.fillParentMaxHeight(), + modifier = Modifier + .fillMaxSize() + .padding(top = topHeightDp / 2) ) } } From 398e1e412a96733cdd9b7f8f1844ded91ae97d25 Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 17:20:13 +0900 Subject: [PATCH 12/17] =?UTF-8?q?style:=20=EB=94=94=EC=9E=90=EC=9D=B8=20QA?= =?UTF-8?q?=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../collectionlist/component/CollectionFileItem.kt | 4 +++- .../presentation/profile/component/ProfileKeywordSection.kt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/flint/presentation/collectionlist/component/CollectionFileItem.kt b/app/src/main/java/com/flint/presentation/collectionlist/component/CollectionFileItem.kt index b8dd41e8..d823d1d4 100644 --- a/app/src/main/java/com/flint/presentation/collectionlist/component/CollectionFileItem.kt +++ b/app/src/main/java/com/flint/presentation/collectionlist/component/CollectionFileItem.kt @@ -61,7 +61,9 @@ fun CollectionFileItem( Column( verticalArrangement = Arrangement.spacedBy(4.dp), - modifier = Modifier.width(154.dp), + modifier = Modifier + .width(154.dp) + .padding(horizontal = 8.dp), ) { Text( text = collection.title, diff --git a/app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordSection.kt b/app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordSection.kt index bf83953f..6ba4d528 100644 --- a/app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordSection.kt +++ b/app/src/main/java/com/flint/presentation/profile/component/ProfileKeywordSection.kt @@ -56,7 +56,7 @@ fun ProfileKeywordSection( ) Spacer(Modifier.height(4.dp)) Text( - text = "${nickname}님이 관심있어하는 키워드에요", + text = "${nickname}님이 관심있어하는 키워드예요", style = FlintTheme.typography.body2R14, color = FlintTheme.colors.gray100, ) From 48dc5e467ddd51fb6c52f490ee8d962a49b18bc7 Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 17:30:59 +0900 Subject: [PATCH 13/17] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=ED=83=88?= =?UTF-8?q?=ED=87=B4=20=ED=94=8C=EB=9E=98=EA=B7=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/flint/presentation/profile/ProfileScreen.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt index 707fe0a9..2c9eca88 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt @@ -163,7 +163,11 @@ private fun ProfileScreen( userName = nickname, profileUrl = profileImageUrl.orEmpty(), isFliner = isFliner, - onEasterEggWithdraw = onEasterEggWithdraw, + onEasterEggWithdraw = { + if (uiState.userId == null) { + onEasterEggWithdraw() + } + }, ) } } @@ -239,6 +243,7 @@ private fun ProfileScreenPreview( ) { FlintTheme { ProfileScreen( + modifier = Modifier.fillMaxSize(), uiState = uiState, onCollectionItemClick = {}, onCreatedCollectionMoreClick = {}, From 4489afbc6c6200c358fd18664008d2342e6d8385 Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 17:51:58 +0900 Subject: [PATCH 14/17] =?UTF-8?q?fix:=20=EC=BD=94=EB=93=9C=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=82=B4=EC=9A=A9=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/flint/domain/repository/AuthRepository.kt | 1 - .../java/com/flint/presentation/profile/ProfileScreen.kt | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/flint/domain/repository/AuthRepository.kt b/app/src/main/java/com/flint/domain/repository/AuthRepository.kt index fe7cd318..773b0b86 100644 --- a/app/src/main/java/com/flint/domain/repository/AuthRepository.kt +++ b/app/src/main/java/com/flint/domain/repository/AuthRepository.kt @@ -41,7 +41,6 @@ class AuthRepository @Inject constructor( suspend fun withdraw(): Result = suspendRunCatching { api.withdraw() - preferencesManager.removeString(ACCESS_TOKEN) preferencesManager.clearAll() } } \ No newline at end of file diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt index 2c9eca88..6a34c739 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt @@ -84,7 +84,12 @@ fun ProfileRoute( showOttListBottomSheet = true } is ProfileSideEffect.WithdrawSuccess -> { - (context.findActivity() as? MainActivity)?.restartApplication() + val activity = context.findActivity() as? MainActivity + if (activity != null) { + activity.restartApplication() + } else { + //TODO: Fallback: 앱 재시작이 불가능할 경우, 다른 처리 로직을 여기에 작성 + } } } } From 86d85572551c9599ac2a411b093193fa76746f12 Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 18:09:00 +0900 Subject: [PATCH 15/17] =?UTF-8?q?fix:=20Ott=20=EB=B0=94=ED=85=80=EC=8B=9C?= =?UTF-8?q?=ED=8A=B8=20=ED=91=9C=EC=8B=9C,=20CollectionInputTextField=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/textfield/CollectionInputTextField.kt | 4 +++- .../main/java/com/flint/presentation/profile/ProfileScreen.kt | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/flint/core/designsystem/component/textfield/CollectionInputTextField.kt b/app/src/main/java/com/flint/core/designsystem/component/textfield/CollectionInputTextField.kt index 3ed3a42c..dd71d34d 100644 --- a/app/src/main/java/com/flint/core/designsystem/component/textfield/CollectionInputTextField.kt +++ b/app/src/main/java/com/flint/core/designsystem/component/textfield/CollectionInputTextField.kt @@ -2,6 +2,7 @@ package com.flint.core.designsystem.component.textfield import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -49,7 +50,8 @@ fun CollectionInputTextField( maxLines = maxLines, keyboardOptions = keyboardOptions, keyboardActions = keyboardActions, - modifier = modifier, + paddingValues = PaddingValues(horizontal = 12.dp, vertical = 10.dp), + modifier = modifier.heightIn(min = 40.dp), ) if (!isShowLengthTitle) return diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt index 6a34c739..6f9baed6 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt @@ -81,7 +81,9 @@ fun ProfileRoute( when (sideEffect) { is ProfileSideEffect.ShowOttListBottomSheet -> { ottListModel = sideEffect.ottListModel - showOttListBottomSheet = true + if (ottListModel.otts.isNotEmpty()) { + showOttListBottomSheet = true + } } is ProfileSideEffect.WithdrawSuccess -> { val activity = context.findActivity() as? MainActivity From 94b10847b425097c14714550879159a5494874e5 Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 18:30:58 +0900 Subject: [PATCH 16/17] =?UTF-8?q?fix:=20=EC=83=9D=EC=84=B1=20=EC=BB=AC?= =?UTF-8?q?=EB=A0=89=EC=85=98=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flint/presentation/profile/ProfileScreen.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt index 6f9baed6..f9b0f971 100644 --- a/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt +++ b/app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt @@ -203,6 +203,21 @@ private fun ProfileScreen( ) } + item { + if (sectionData.data.createCollections.collections.isNotEmpty()) { + Spacer(Modifier.height(48.dp)) + + CollectionSection( + title = "생성한 컬렉션", + description = "${userName}님이 생성한 컬렉션이에요", + onItemClick = onCollectionItemClick, + isAllVisible = true, + onAllClick = onCreatedCollectionMoreClick, + collectionListModel = sectionData.data.createCollections, + ) + } + } + item { if (sectionData.data.savedCollections.collections.isNotEmpty()) { Spacer(Modifier.height(48.dp)) From d5ad75def223bf41bad2e7c6aaefb0155285fe52 Mon Sep 17 00:00:00 2001 From: Nahyun Kim Date: Fri, 23 Jan 2026 18:58:21 +0900 Subject: [PATCH 17/17] =?UTF-8?q?fix:=20BasicTextField=20=ED=85=8D?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=ED=8F=AC=EC=BB=A4=EC=8B=B1=20=EC=98=81?= =?UTF-8?q?=EC=97=AD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../textfield/FlintBasicTextField.kt | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/flint/core/designsystem/component/textfield/FlintBasicTextField.kt b/app/src/main/java/com/flint/core/designsystem/component/textfield/FlintBasicTextField.kt index e09ab2f9..a3ebcfb7 100644 --- a/app/src/main/java/com/flint/core/designsystem/component/textfield/FlintBasicTextField.kt +++ b/app/src/main/java/com/flint/core/designsystem/component/textfield/FlintBasicTextField.kt @@ -2,6 +2,7 @@ package com.flint.core.designsystem.component.textfield import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -24,6 +25,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.text.TextStyle @@ -54,6 +57,7 @@ fun FlintBasicTextField( trailingContent: @Composable () -> Unit = {}, ) { val interactionSource: MutableInteractionSource = remember { MutableInteractionSource() } + val focusRequester = remember { FocusRequester() } Box( modifier = @@ -64,10 +68,18 @@ fun FlintBasicTextField( width = 1.dp, color = borderColor, shape = RoundedCornerShape(radius), - ), + ) + .clickable( + interactionSource = interactionSource, + indication = null, + ) { + focusRequester.requestFocus() + }, ) { BasicTextField( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .fillMaxSize() + .focusRequester(focusRequester), value = value, textStyle = textStyle.copy(color = FlintTheme.colors.white), onValueChange = { @@ -84,8 +96,7 @@ fun FlintBasicTextField( cursorBrush = SolidColor(FlintTheme.colors.gray300), decorationBox = { innerTextField -> Row( - modifier = - Modifier + modifier = Modifier .fillMaxSize() .padding(paddingValues), horizontalArrangement = Arrangement.SpaceBetween, @@ -121,7 +132,9 @@ private fun BasicTextFieldPreview() { var text by remember { mutableStateOf("") } FlintBasicTextField( - modifier = Modifier.fillMaxWidth().height(40.dp), + modifier = Modifier + .fillMaxWidth() + .height(40.dp), placeholder = "PlaceHolder", value = text, onValueChange = { text = it },