From 6716df4e403af7108f470772ec5c8bd6d588075d Mon Sep 17 00:00:00 2001 From: easyhz Date: Fri, 19 Jul 2024 23:49:56 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20organization=20flow=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80=20#20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/values/strings.xml | 1 + .../component/creation/CategoryView.kt | 80 +++++++++++++++++++ .../contract/creation/CreationIntent.kt | 3 +- .../contract/creation/CreationState.kt | 28 ++++++- .../creation/OrganizationCreationScreen.kt | 12 ++- .../creation/OrganizationCreationViewModel.kt | 15 ++-- .../organization/util/creation/Category.kt | 14 ++++ 7 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 feature/organization/src/main/java/com/easyhz/noffice/feature/organization/component/creation/CategoryView.kt create mode 100644 feature/organization/src/main/java/com/easyhz/noffice/feature/organization/util/creation/Category.kt diff --git a/core/design-system/src/main/res/values/strings.xml b/core/design-system/src/main/res/values/strings.xml index 9990c8b7..e9f3d67b 100644 --- a/core/design-system/src/main/res/values/strings.xml +++ b/core/design-system/src/main/res/values/strings.xml @@ -63,4 +63,5 @@ 그룹 만들기 그룹 이름이 무엇인가요? 이름을 입력해 주세요. + 그룹의 카테고리를 모두 선택해 주세요 \ No newline at end of file diff --git a/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/component/creation/CategoryView.kt b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/component/creation/CategoryView.kt new file mode 100644 index 00000000..3454705a --- /dev/null +++ b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/component/creation/CategoryView.kt @@ -0,0 +1,80 @@ +package com.easyhz.noffice.feature.organization.component.creation + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.itemsIndexed +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.easyhz.noffice.core.design_system.R +import com.easyhz.noffice.core.design_system.component.button.CheckButton +import com.easyhz.noffice.core.design_system.component.button.CheckButtonDefaults +import com.easyhz.noffice.core.design_system.component.button.MediumButton +import com.easyhz.noffice.core.design_system.theme.Green100 +import com.easyhz.noffice.core.design_system.theme.Green700 +import com.easyhz.noffice.core.design_system.theme.Grey50 +import com.easyhz.noffice.core.design_system.theme.Grey600 +import com.easyhz.noffice.feature.organization.contract.creation.CreationIntent +import com.easyhz.noffice.feature.organization.screen.creation.OrganizationCreationViewModel + +@Composable +internal fun CategoryView( + modifier: Modifier = Modifier, + viewModel: OrganizationCreationViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + Column( + modifier = modifier + ) { + CommonHeader( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp, horizontal = 8.dp), + title = stringResource(id = R.string.organization_creation_category_title) + ) + LazyVerticalGrid( + modifier = Modifier.weight(1f).padding(top = 8.dp), + columns = GridCells.Fixed(2), + verticalArrangement = Arrangement.spacedBy(10.dp), + horizontalArrangement = Arrangement.spacedBy(7.dp) + ) { + itemsIndexed(uiState.category) { index, item -> + CheckButton( + modifier = Modifier.weight(1f), + textAlign = TextAlign.Center, + text = item.title, + isComplete = item.isSelected, + color = CheckButtonDefaults( + completeContainerColor = Green100, + completeContentColor = Green700, + completeIconColor = null, + incompleteContainerColor = Grey50, + incompleteContentColor = Grey600, + incompleteIconColor = null + ) + ) { + viewModel.postIntent(CreationIntent.ClickCategoryItem(index)) + } + } + } + MediumButton( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 16.dp), + text = stringResource(id = R.string.sign_up_button), + enabled = uiState.enabledStepButton[uiState.step.currentStep] ?: false + ) { + viewModel.postIntent(CreationIntent.ClickNextButton) + } + } +} \ No newline at end of file diff --git a/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/contract/creation/CreationIntent.kt b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/contract/creation/CreationIntent.kt index 0a85e0c7..67c8a174 100644 --- a/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/contract/creation/CreationIntent.kt +++ b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/contract/creation/CreationIntent.kt @@ -6,7 +6,8 @@ import com.easyhz.noffice.core.common.base.UiIntent sealed class CreationIntent: UiIntent() { data object ClickBackButton: CreationIntent() data object ClickNextButton: CreationIntent() - data class ChangeGroupNameTextValue(val text: TextFieldValue): CreationIntent() + data class ChangeGroupNameTextValue(val text: String): CreationIntent() data object ClearGroupName: CreationIntent() data object ClearFocus: CreationIntent() + data class ClickCategoryItem(val selectedIndex: Int): CreationIntent() } \ No newline at end of file diff --git a/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/contract/creation/CreationState.kt b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/contract/creation/CreationState.kt index ca0fbcbd..50b2a902 100644 --- a/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/contract/creation/CreationState.kt +++ b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/contract/creation/CreationState.kt @@ -1,23 +1,27 @@ package com.easyhz.noffice.feature.organization.contract.creation -import androidx.compose.ui.text.input.TextFieldValue import com.easyhz.noffice.core.common.base.UiState +import com.easyhz.noffice.core.common.extension.toEnumMap import com.easyhz.noffice.core.common.util.Step import com.easyhz.noffice.core.common.util.toEnabledStepButton +import com.easyhz.noffice.feature.organization.util.creation.Category import com.easyhz.noffice.feature.organization.util.creation.CreationStep +import com.easyhz.noffice.feature.organization.util.creation.toState import java.util.EnumMap data class CreationState( val step: Step, val enabledStepButton: EnumMap, - val groupName: TextFieldValue + val groupName: String, + val category: List ): UiState() { companion object { const val GROUP_NAME_MAX = 10 fun init() = CreationState( step = Step(currentStep = CreationStep.GROUP_NAME, previousStep = null), enabledStepButton = CreationStep.entries.toEnabledStepButton(), - groupName = TextFieldValue("") + groupName = "", + category = Category.toState() ) } @@ -28,4 +32,20 @@ data class CreationState( ), ) -} \ No newline at end of file + fun CreationState.updateCategoryItem(selectedIndex: Int): CreationState { + val updatedCategory = category.mapIndexed { index, categoryState -> + categoryState.copy(isSelected = categoryState.isSelected.xor(index == selectedIndex)) + } + return copy( + category = updatedCategory, + enabledStepButton = enabledStepButton.toMutableMap().apply { + this[step.currentStep] = updatedCategory.any { it.isSelected } + }.toEnumMap() + ) + } +} + +data class CategoryState( + val title: String, + val isSelected: Boolean +) \ No newline at end of file diff --git a/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/screen/creation/OrganizationCreationScreen.kt b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/screen/creation/OrganizationCreationScreen.kt index faeb810e..51f4253b 100644 --- a/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/screen/creation/OrganizationCreationScreen.kt +++ b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/screen/creation/OrganizationCreationScreen.kt @@ -1,5 +1,6 @@ package com.easyhz.noffice.feature.organization.screen.creation +import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContent import androidx.compose.animation.SizeTransform import androidx.compose.animation.fadeIn @@ -22,13 +23,14 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.easyhz.noffice.core.common.util.collectInSideEffectWithLifecycle import com.easyhz.noffice.core.design_system.R import com.easyhz.noffice.core.design_system.component.scaffold.NofficeBasicScaffold -import com.easyhz.noffice.core.design_system.component.scaffold.NofficeScaffold import com.easyhz.noffice.core.design_system.component.topBar.DetailTopBar import com.easyhz.noffice.core.design_system.extension.screenHorizonPadding import com.easyhz.noffice.core.design_system.theme.Grey400 import com.easyhz.noffice.core.design_system.theme.White import com.easyhz.noffice.core.design_system.util.topBar.DetailTopBarMenu +import com.easyhz.noffice.feature.organization.component.creation.CategoryView import com.easyhz.noffice.feature.organization.component.creation.GroupNameView +import com.easyhz.noffice.feature.organization.contract.creation.CreationIntent import com.easyhz.noffice.feature.organization.contract.creation.CreationSideEffect import com.easyhz.noffice.feature.organization.util.creation.CreationStep @@ -40,6 +42,10 @@ fun OrganizationCreationScreen( val uiState by viewModel.uiState.collectAsStateWithLifecycle() val focusManager = LocalFocusManager.current + BackHandler(onBack = { + viewModel.postIntent(CreationIntent.ClickBackButton) + }) + NofficeBasicScaffold( modifier = modifier, containerColor = White, @@ -54,7 +60,7 @@ fun OrganizationCreationScreen( tint = Grey400 ) }, - onClick = { } + onClick = { viewModel.postIntent(CreationIntent.ClickBackButton) } ) ) } @@ -76,7 +82,7 @@ fun OrganizationCreationScreen( ) { targetScreen -> when(targetScreen) { CreationStep.GROUP_NAME -> { GroupNameView(modifier = Modifier.screenHorizonPadding()) } - CreationStep.CATEGORY -> { } + CreationStep.CATEGORY -> { CategoryView(modifier = Modifier.screenHorizonPadding()) } CreationStep.IMAGE -> { } CreationStep.END_DATE -> { } CreationStep.PROMOTION -> { } diff --git a/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/screen/creation/OrganizationCreationViewModel.kt b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/screen/creation/OrganizationCreationViewModel.kt index b3c549b1..06bda81c 100644 --- a/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/screen/creation/OrganizationCreationViewModel.kt +++ b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/screen/creation/OrganizationCreationViewModel.kt @@ -1,6 +1,5 @@ package com.easyhz.noffice.feature.organization.screen.creation -import androidx.compose.ui.text.input.TextFieldValue import com.easyhz.noffice.core.common.base.BaseViewModel import com.easyhz.noffice.core.common.util.updateStepButton import com.easyhz.noffice.feature.organization.contract.creation.CreationIntent @@ -23,6 +22,7 @@ class OrganizationCreationViewModel @Inject constructor( is CreationIntent.ChangeGroupNameTextValue -> { onChangeGroupNameTextValue(intent.text) } is CreationIntent.ClearGroupName -> { onClearGroupName() } is CreationIntent.ClearFocus -> { onClearFocus() } + is CreationIntent.ClickCategoryItem -> { onClickCategoryItem(intent.selectedIndex) } } } @@ -35,14 +35,15 @@ class OrganizationCreationViewModel @Inject constructor( private fun onClickNextButton() { currentState.step.currentStep.nextStep()?.let { nextStep -> reduce { updateStep(currentStep = nextStep) } + postSideEffect { CreationSideEffect.ClearFocus } } ?: run { /* TODO NEXT */ } } - private fun onChangeGroupNameTextValue(newText: TextFieldValue) { - if (newText.text.length > GROUP_NAME_MAX) return - val isEnabledButton = newText.text.isNotBlank() + private fun onChangeGroupNameTextValue(newText: String) { + if (newText.length > GROUP_NAME_MAX) return + val isEnabledButton = newText.isNotBlank() reduce { copy( groupName = newText, @@ -55,10 +56,14 @@ class OrganizationCreationViewModel @Inject constructor( } private fun onClearGroupName() { - reduce { copy(groupName = TextFieldValue("")) } + reduce { copy(groupName = "") } } private fun onClearFocus() { postSideEffect { CreationSideEffect.ClearFocus } } + + private fun onClickCategoryItem(selectedIndex: Int) { + reduce { updateCategoryItem(selectedIndex) } + } } \ No newline at end of file diff --git a/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/util/creation/Category.kt b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/util/creation/Category.kt new file mode 100644 index 00000000..c55a5ad9 --- /dev/null +++ b/feature/organization/src/main/java/com/easyhz/noffice/feature/organization/util/creation/Category.kt @@ -0,0 +1,14 @@ +package com.easyhz.noffice.feature.organization.util.creation + +import com.easyhz.noffice.feature.organization.contract.creation.CategoryState + +//enum class Category { +//} + +val Category = listOf("IT 계열", "문화 생활", "어학", "예술", "음악 · 공연", "스터디 · 연구", "스포츠", "창업", "종교", "마케팅 · 홍보", "자연과학", "기타") + +fun List.toState(): List = map { + CategoryState( + it, false + ) +} \ No newline at end of file