From e1b45de0b824376fb0db19c9275cffbdc43b7cd1 Mon Sep 17 00:00:00 2001 From: ckals413 Date: Fri, 1 May 2026 00:54:30 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=EC=98=A8=EB=B3=B4=EB=94=A9=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EB=82=B4=20=EC=9E=A5=EB=A5=B4=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EC=B9=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../onboarding/OnboardingContentScreen.kt | 60 ++++++++++++++++--- .../onboarding/OnboardingUiState.kt | 14 +---- .../onboarding/OnboardingViewModel.kt | 14 +++++ 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt b/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt index 52478cb0..706a4d19 100644 --- a/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt +++ b/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt @@ -51,6 +51,7 @@ import com.flint.core.designsystem.component.view.FlintSearchEmptyView import com.flint.core.designsystem.theme.FlintTheme import com.flint.domain.model.search.SearchContentItemModel import com.flint.domain.model.search.SearchContentListModel +import com.flint.presentation.onboarding.component.FlintGenreChip import com.flint.presentation.onboarding.component.OnboardingContentItem import com.flint.presentation.onboarding.component.StepProgressBar @@ -78,6 +79,7 @@ fun OnboardingContentRoute( onClearAction = viewModel::loadInitialContents, onContentClick = viewModel::toggleContentSelection, onRemoveContent = viewModel::toggleContentSelection, + onGenreClick = viewModel::selectGenre, modifier = Modifier.padding(paddingValues), ) } @@ -93,6 +95,7 @@ fun OnboardingContentScreen( onClearAction: () -> Unit, onContentClick: (SearchContentItemModel) -> Unit, onRemoveContent: (SearchContentItemModel) -> Unit, + onGenreClick: (String) -> Unit, modifier: Modifier = Modifier, ) { val keyboardController = LocalSoftwareKeyboardController.current @@ -148,13 +151,22 @@ fun OnboardingContentScreen( .background(FlintTheme.colors.background) .padding(bottom = 16.dp) ) { - Text( - text = contentUiState.currentStepQuestion, - color = FlintTheme.colors.gray300, - style = FlintTheme.typography.body2R14, - ) - - Spacer(modifier = Modifier.height(24.dp)) + // 장르 칩 가로 스크롤 + LazyRow( + modifier = Modifier.height(48.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp), + contentPadding = PaddingValues(end = 4.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + items(OnboardingContentUiState.GENRES) { genre -> + val isSelected = genre in contentUiState.selectedGenres + FlintGenreChip( + text = genre, + isSelected = isSelected, + onClick = { onGenreClick(genre) }, + ) + } + } FlintSearchTextField( placeholder = "작품 이름", @@ -305,6 +317,7 @@ private fun OnboardingContentScreenListPreview() { onClearAction = {}, onContentClick = {}, onRemoveContent = {}, + onGenreClick = {}, ) } } @@ -329,6 +342,39 @@ private fun OnboardingContentScreenEmptyPreview() { onClearAction = {}, onContentClick = {}, onRemoveContent = {}, + onGenreClick = {}, + ) + } +} + +@Preview(showBackground = true, name = "장르 칩 인터랙티브") +@Composable +private fun OnboardingContentScreenGenreInteractivePreview() { + var selectedGenres by remember { mutableStateOf(setOf()) } + + FlintTheme { + OnboardingContentScreen( + nickname = "안비", + contentUiState = OnboardingContentUiState( + searchResults = UiState.Success(SearchContentListModel.FakeList), + selectedGenres = selectedGenres.toList().let { + kotlinx.collections.immutable.persistentListOf(*it.toTypedArray()) + }, + ), + onBackClick = {}, + onNextClick = {}, + onSearchKeywordChanged = {}, + onSearchAction = {}, + onClearAction = {}, + onContentClick = {}, + onRemoveContent = {}, + onGenreClick = { genre -> + selectedGenres = if (genre in selectedGenres) { + selectedGenres - genre + } else { + selectedGenres + genre + } + }, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/flint/presentation/onboarding/OnboardingUiState.kt b/app/src/main/java/com/flint/presentation/onboarding/OnboardingUiState.kt index b5a526d7..6dceb40d 100644 --- a/app/src/main/java/com/flint/presentation/onboarding/OnboardingUiState.kt +++ b/app/src/main/java/com/flint/presentation/onboarding/OnboardingUiState.kt @@ -48,24 +48,16 @@ data class OnboardingContentUiState( val searchResults: UiState> = UiState.Empty, val selectedContents: ImmutableList = persistentListOf(), val isSearching: Boolean = false, + val selectedGenres: ImmutableList = persistentListOf(), ) { companion object { const val REQUIRED_SELECTION_COUNT = 7 - private val STEP_QUESTIONS = listOf( - "이번 달 가장 재미있었던 작품은?", - "여러번 정주행 했던 작품은 무엇인가요?", - "좋아하는 인물이 등장하는 작품은 무엇인가요?", - "요즘 밥 먹으면서 자주 보는 작품은 무엇인가요?", - "\"이건 꼭 봐\"라고 말했던 작품은 무엇인가요?", - "계절마다 생각나는 작품은 무엇인가요?", - "어렸을 적 즐겨봤던 추억의 작품은 무엇인가요?" + val GENRES = listOf( + "액션", "로맨스", "SF", "드라마", "코미디", "호러" ) } - val currentStepQuestion: String - get() = STEP_QUESTIONS.getOrElse(selectedContents.size) { STEP_QUESTIONS.first() } - val canProceed: Boolean get() = selectedContents.size == REQUIRED_SELECTION_COUNT diff --git a/app/src/main/java/com/flint/presentation/onboarding/OnboardingViewModel.kt b/app/src/main/java/com/flint/presentation/onboarding/OnboardingViewModel.kt index fd6b48e1..ac61b2e6 100644 --- a/app/src/main/java/com/flint/presentation/onboarding/OnboardingViewModel.kt +++ b/app/src/main/java/com/flint/presentation/onboarding/OnboardingViewModel.kt @@ -111,6 +111,20 @@ class OnboardingViewModel getSearchContentList(keyword.ifEmpty { null }) } + fun selectGenre(genre: String) { + _contentUiState.update { currentState -> + val current = currentState.selectedGenres + val newSelectedGenres = if (genre in current) { + current.filterNot { it == genre }.toImmutableList() + } else { + (current + genre).toImmutableList() + } + currentState.copy(selectedGenres = newSelectedGenres) + } + val keyword = _contentUiState.value.searchKeyword + getSearchContentList(keyword.ifEmpty { null }) + } + private fun getSearchContentList(keyword: String?) { viewModelScope.launch { _contentUiState.update { it.copy(searchResults = UiState.Loading) } From 8999f3731f94602d47607936a81e7dddbdeb750f Mon Sep 17 00:00:00 2001 From: ckals413 Date: Sun, 3 May 2026 17:01:59 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=EC=98=A8=EB=B3=B4=EB=94=A9=20?= =?UTF-8?q?=EC=9E=A5=EB=A5=B4=20=EB=B0=8F=20=EC=84=A0=ED=83=9D=EB=90=9C=20?= =?UTF-8?q?=EC=9E=A5=EB=A5=B4=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=95=84=EC=9B=83=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../onboarding/OnboardingContentScreen.kt | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt b/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt index 706a4d19..4dbc9493 100644 --- a/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt +++ b/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.layout.layout import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.tooling.preview.Preview @@ -153,9 +154,21 @@ fun OnboardingContentScreen( ) { // 장르 칩 가로 스크롤 LazyRow( - modifier = Modifier.height(48.dp), + modifier = Modifier + .height(48.dp) + .layout { measurable, constraints -> + val sidePadding = 16.dp.roundToPx() + val placeable = measurable.measure( + constraints.copy( + maxWidth = constraints.maxWidth + sidePadding * 2, + ), + ) + layout(constraints.maxWidth, placeable.height) { + placeable.place(-sidePadding, 0) + } + }, + contentPadding = PaddingValues(start = 16.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), - contentPadding = PaddingValues(end = 4.dp), verticalAlignment = Alignment.CenterVertically, ) { items(OnboardingContentUiState.GENRES) { genre -> @@ -195,6 +208,18 @@ fun OnboardingContentScreen( Spacer(modifier = Modifier.height(16.dp)) LazyRow( state = lazyListState, + modifier = Modifier.layout { measurable, constraints -> + val sidePadding = 16.dp.roundToPx() + val placeable = measurable.measure( + constraints.copy( + maxWidth = constraints.maxWidth + sidePadding * 2, + ), + ) + layout(constraints.maxWidth, placeable.height) { + placeable.place(-sidePadding, 0) + } + }, + contentPadding = PaddingValues(start = 16.dp), horizontalArrangement = Arrangement.spacedBy(0.dp), ) { items( From 67b3c6dd5148e9c4476820caa7b457edac0fc85d Mon Sep 17 00:00:00 2001 From: ckals413 Date: Sun, 3 May 2026 17:13:35 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20=EC=98=A8=EB=B3=B4=EB=94=A9=20?= =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=ED=99=94=EB=A9=B4=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=99=84=EB=A3=8C=ED=99=94=EB=A9=B4=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flint/presentation/onboarding/OnboardingContentScreen.kt | 4 ++-- .../onboarding/navigation/OnboardingNavigation.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt b/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt index 4dbc9493..1dd7fe47 100644 --- a/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt +++ b/app/src/main/java/com/flint/presentation/onboarding/OnboardingContentScreen.kt @@ -59,7 +59,7 @@ import com.flint.presentation.onboarding.component.StepProgressBar @Composable fun OnboardingContentRoute( paddingValues: PaddingValues, - navigateToOnboardingOtt: () -> Unit, + navigateToOnboardingDone: () -> Unit, navigateUp: () -> Unit, viewModel: OnboardingViewModel = hiltViewModel(), ) { @@ -74,7 +74,7 @@ fun OnboardingContentRoute( nickname = profileUiState.nickname, contentUiState = contentUiState, onBackClick = navigateUp, - onNextClick = navigateToOnboardingOtt, + onNextClick = navigateToOnboardingDone, onSearchKeywordChanged = viewModel::updateSearchKeyword, onSearchAction = viewModel::searchContents, onClearAction = viewModel::loadInitialContents, diff --git a/app/src/main/java/com/flint/presentation/onboarding/navigation/OnboardingNavigation.kt b/app/src/main/java/com/flint/presentation/onboarding/navigation/OnboardingNavigation.kt index 721f4df4..5c2b75cc 100644 --- a/app/src/main/java/com/flint/presentation/onboarding/navigation/OnboardingNavigation.kt +++ b/app/src/main/java/com/flint/presentation/onboarding/navigation/OnboardingNavigation.kt @@ -59,7 +59,7 @@ fun NavGraphBuilder.onBoardingNavGraph( OnboardingContentRoute( paddingValues = paddingValues, navigateUp = navController::navigateUp, - navigateToOnboardingOtt = navController::navigateToOnboardingOtt, + navigateToOnboardingDone = navController::navigateToOnboardingDone, viewModel = sharedViewModel, ) } From 834e030831c389d8096a3c3c1c7ef2e77f99fff2 Mon Sep 17 00:00:00 2001 From: ckals413 Date: Mon, 4 May 2026 00:02:25 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20=EC=98=A8=EB=B3=B4=EB=94=A9=20?= =?UTF-8?q?=EC=9E=A5=EB=A5=B4=20=EC=84=A0=ED=83=9D=20=EC=8B=9C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EC=BD=98=ED=85=90=EC=B8=A0=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EA=B0=B1=EC=8B=A0=20=EB=A1=9C=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/flint/presentation/onboarding/OnboardingViewModel.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/flint/presentation/onboarding/OnboardingViewModel.kt b/app/src/main/java/com/flint/presentation/onboarding/OnboardingViewModel.kt index ac61b2e6..ed766513 100644 --- a/app/src/main/java/com/flint/presentation/onboarding/OnboardingViewModel.kt +++ b/app/src/main/java/com/flint/presentation/onboarding/OnboardingViewModel.kt @@ -121,8 +121,6 @@ class OnboardingViewModel } currentState.copy(selectedGenres = newSelectedGenres) } - val keyword = _contentUiState.value.searchKeyword - getSearchContentList(keyword.ifEmpty { null }) } private fun getSearchContentList(keyword: String?) {