Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -51,13 +52,14 @@ 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

@Composable
fun OnboardingContentRoute(
paddingValues: PaddingValues,
navigateToOnboardingOtt: () -> Unit,
navigateToOnboardingDone: () -> Unit,
navigateUp: () -> Unit,
viewModel: OnboardingViewModel = hiltViewModel(),
) {
Expand All @@ -72,12 +74,13 @@ fun OnboardingContentRoute(
nickname = profileUiState.nickname,
contentUiState = contentUiState,
onBackClick = navigateUp,
onNextClick = navigateToOnboardingOtt,
onNextClick = navigateToOnboardingDone,
onSearchKeywordChanged = viewModel::updateSearchKeyword,
onSearchAction = viewModel::searchContents,
onClearAction = viewModel::loadInitialContents,
onContentClick = viewModel::toggleContentSelection,
onRemoveContent = viewModel::toggleContentSelection,
onGenreClick = viewModel::selectGenre,
modifier = Modifier.padding(paddingValues),
)
}
Expand All @@ -93,6 +96,7 @@ fun OnboardingContentScreen(
onClearAction: () -> Unit,
onContentClick: (SearchContentItemModel) -> Unit,
onRemoveContent: (SearchContentItemModel) -> Unit,
onGenreClick: (String) -> Unit,
modifier: Modifier = Modifier,
) {
val keyboardController = LocalSoftwareKeyboardController.current
Expand Down Expand Up @@ -148,13 +152,34 @@ 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)
.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),
verticalAlignment = Alignment.CenterVertically,
) {
items(OnboardingContentUiState.GENRES) { genre ->
val isSelected = genre in contentUiState.selectedGenres
FlintGenreChip(
text = genre,
isSelected = isSelected,
onClick = { onGenreClick(genre) },
)
}
}

FlintSearchTextField(
placeholder = "작품 이름",
Expand Down Expand Up @@ -183,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(
Expand Down Expand Up @@ -305,6 +342,7 @@ private fun OnboardingContentScreenListPreview() {
onClearAction = {},
onContentClick = {},
onRemoveContent = {},
onGenreClick = {},
)
}
}
Expand All @@ -329,6 +367,39 @@ private fun OnboardingContentScreenEmptyPreview() {
onClearAction = {},
onContentClick = {},
onRemoveContent = {},
onGenreClick = {},
)
}
}

@Preview(showBackground = true, name = "장르 칩 인터랙티브")
@Composable
private fun OnboardingContentScreenGenreInteractivePreview() {
var selectedGenres by remember { mutableStateOf(setOf<String>()) }

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
}
},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,16 @@ data class OnboardingContentUiState(
val searchResults: UiState<ImmutableList<SearchContentItemModel>> = UiState.Empty,
val selectedContents: ImmutableList<SearchContentItemModel> = persistentListOf(),
val isSearching: Boolean = false,
val selectedGenres: ImmutableList<String> = 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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ 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)
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

private fun getSearchContentList(keyword: String?) {
viewModelScope.launch {
_contentUiState.update { it.copy(searchResults = UiState.Loading) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ fun NavGraphBuilder.onBoardingNavGraph(
OnboardingContentRoute(
paddingValues = paddingValues,
navigateUp = navController::navigateUp,
navigateToOnboardingOtt = navController::navigateToOnboardingOtt,
navigateToOnboardingDone = navController::navigateToOnboardingDone,
viewModel = sharedViewModel,
)
}
Expand Down
Loading