From b5fd96eb4025d919dfe7868975883f9cd7d3fe9e Mon Sep 17 00:00:00 2001 From: jinukeu Date: Tue, 16 Jan 2024 22:19:32 +0900 Subject: [PATCH 01/14] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B6=80=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=EC=8B=9C=20=EA=B9=9C=EB=B9=A1=EC=9D=B4=EB=8A=94=20?= =?UTF-8?q?=ED=98=84=EC=83=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../received/search/LedgerSearchContract.kt | 1 + .../received/search/LedgerSearchScreen.kt | 44 ++++++++++++------- .../received/search/LedgerSearchViewModel.kt | 4 ++ 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchContract.kt b/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchContract.kt index fe257169..7645fad1 100644 --- a/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchContract.kt @@ -17,4 +17,5 @@ data class LedgerSearchState( sealed interface LedgerSearchSideEffect : SideEffect { data object PopBackStack : LedgerSearchSideEffect data class NavigateLedgerDetail(val ledger: Ledger) : LedgerSearchSideEffect + data object FocusClear : LedgerSearchSideEffect } diff --git a/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchScreen.kt b/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchScreen.kt index 17083f17..c4da8ab6 100644 --- a/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchScreen.kt @@ -11,9 +11,13 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -33,6 +37,7 @@ import com.susu.feature.received.R import kotlinx.collections.immutable.PersistentList import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.filter @OptIn(FlowPreview::class) @Composable @@ -42,10 +47,13 @@ fun LedgerSearchRoute( navigateLedgerDetail: (Ledger) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + val focusRequester = remember { FocusRequester() } + val focusManager = LocalFocusManager.current viewModel.sideEffect.collectWithLifecycle { sideEffect -> when (sideEffect) { LedgerSearchSideEffect.PopBackStack -> popBackStack() is LedgerSearchSideEffect.NavigateLedgerDetail -> navigateLedgerDetail(sideEffect.ledger) + LedgerSearchSideEffect.FocusClear -> focusManager.clearFocus() } } @@ -61,10 +69,13 @@ fun LedgerSearchRoute( LedgerSearchScreen( uiState = uiState, + focusRequester = focusRequester, onClickBackIcon = viewModel::popBackStack, onValueChangeSearchBar = viewModel::updateSearch, onClickSearchClearIcon = { viewModel.updateSearch("") }, onClickRecentSearchContainer = { search -> + viewModel.clearFocus() + viewModel.hideSearchResultEmpty() viewModel.updateSearch(search) viewModel.upsertLedgerRecentSearch(search) }, @@ -79,6 +90,7 @@ fun LedgerSearchRoute( @Composable fun LedgerSearchScreen( uiState: LedgerSearchState = LedgerSearchState(), + focusRequester: FocusRequester = remember { FocusRequester() }, onClickBackIcon: () -> Unit = {}, onClickSearchClearIcon: () -> Unit = {}, onValueChangeSearchBar: (String) -> Unit = {}, @@ -106,27 +118,27 @@ fun LedgerSearchScreen( ), ) { SusuSearchBar( + modifier = Modifier.focusRequester(focusRequester), value = uiState.searchKeyword, onValueChange = onValueChangeSearchBar, onClickClearIcon = onClickSearchClearIcon, placeholder = stringResource(R.string.ledger_search_screen_search_placeholder), ) - Crossfade(targetState = uiState.searchKeyword.isEmpty(), label = "SearchColumn") { showRecentSearch -> - if (showRecentSearch) { - RecentSearchColumn( - recentSearchList = uiState.recentSearchKeywordList, - onClickItem = onClickRecentSearchContainer, - onClickCloseIcon = onClickRecentSearchContainerCloseIcon, - ) - } else { - SearchResultColumn( - showSearchResultEmpty = uiState.showSearchResultEmpty, - ledgerList = uiState.ledgerList, - onClickItem = onClickSearchResultContainer, - ) - } + if (uiState.searchKeyword.isEmpty()) { + RecentSearchColumn( + recentSearchList = uiState.recentSearchKeywordList, + onClickItem = onClickRecentSearchContainer, + onClickCloseIcon = onClickRecentSearchContainerCloseIcon, + ) + } else { + SearchResultColumn( + showSearchResultEmpty = uiState.showSearchResultEmpty, + ledgerList = uiState.ledgerList, + onClickItem = onClickSearchResultContainer, + ) } + } } } @@ -137,7 +149,9 @@ private fun ResultEmptyColumn( title: String, ) { Column( - modifier = Modifier.fillMaxWidth().padding(top = 136.dp), + modifier = Modifier + .fillMaxWidth() + .padding(top = 136.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs), ) { diff --git a/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchViewModel.kt index 4f1372d3..2a19dbd2 100644 --- a/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchViewModel.kt @@ -41,6 +41,10 @@ class LedgerSearchViewModel @Inject constructor( .onFailure { } } + fun clearFocus() = postSideEffect(LedgerSearchSideEffect.FocusClear) + + fun hideSearchResultEmpty() = intent { copy(showSearchResultEmpty = false) } + fun updateSearch(search: String) = intent { copy(searchKeyword = search) } fun getLedgerList(search: String) = viewModelScope.launch { From bd97ed15adacc109e064a0a93235cfa137a4de7a Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 18 Jan 2024 00:14:19 +0900 Subject: [PATCH 02/14] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B6=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20Parent=20Screen=20=EB=8F=99=EC=9E=91=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../received/ledgeradd/LedgerAddContract.kt | 22 ++++++++++ .../received/ledgeradd/LedgerAddScreen.kt | 43 ++++++++++--------- .../received/ledgeradd/LedgerAddViewModel.kt | 32 ++++++++++++++ 3 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt new file mode 100644 index 00000000..24f617cb --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt @@ -0,0 +1,22 @@ +package com.susu.feature.received.ledgeradd + +import com.susu.core.model.Ledger +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf + +data class LedgerAddState( + val currentStep: LedgerAddStep = LedgerAddStep.CATEGORY, + val buttonEnabled: Boolean = false, +) : UiState + +enum class LedgerAddStep { + CATEGORY, + NAME, + DATE, +} + +sealed interface LedgerAddSideEffect : SideEffect { + data object PopBackStack : LedgerAddSideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt index 0902138a..f88935f3 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt @@ -1,5 +1,6 @@ package com.susu.feature.received.ledgeradd +import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -16,6 +17,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.susu.core.designsystem.component.appbar.SusuProgressAppBar import com.susu.core.designsystem.component.appbar.icon.BackIcon import com.susu.core.designsystem.component.button.FilledButtonColor @@ -23,42 +26,40 @@ import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.ui.R +import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec import com.susu.feature.received.ledgeradd.content.CategoryContent import com.susu.feature.received.ledgeradd.content.DateContent import com.susu.feature.received.ledgeradd.content.NameContent -enum class LedgerAddStep { - CATEGORY, - NAME, - DATE, -} + @Composable fun LedgerAddRoute( + viewModel: LedgerAddViewModel = hiltViewModel(), popBackStack: () -> Unit, ) { - var currentStep by remember { - mutableStateOf(LedgerAddStep.CATEGORY) + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + LedgerAddSideEffect.PopBackStack -> popBackStack() + } + } + + BackHandler { + viewModel.goToPrevStep() } LedgerAddScreen( - currentStep = currentStep, - onClickBack = popBackStack, - onClickNextButton = { - // TODO 임시 코드 입니다. - currentStep = when (currentStep) { - LedgerAddStep.CATEGORY -> LedgerAddStep.NAME - LedgerAddStep.NAME -> LedgerAddStep.DATE - LedgerAddStep.DATE -> LedgerAddStep.DATE - } - }, + uiState = uiState, + onClickBack = viewModel::goToPrevStep, + onClickNextButton = viewModel::goToNextStep, ) } @Composable fun LedgerAddScreen( - currentStep: LedgerAddStep = LedgerAddStep.CATEGORY, + uiState: LedgerAddState = LedgerAddState(), onClickBack: () -> Unit = {}, onClickNextButton: () -> Unit = {}, ) { @@ -73,12 +74,12 @@ fun LedgerAddScreen( BackIcon(onClickBack) }, entireStep = LedgerAddStep.entries.size, - currentStep = currentStep.ordinal + 1, + currentStep = uiState.currentStep.ordinal + 1, ) AnimatedContent( modifier = Modifier.weight(1f), - targetState = currentStep, + targetState = uiState.currentStep, label = "LedgerAddScreen", transitionSpec = { susuDefaultAnimatedContentTransitionSpec( @@ -101,6 +102,8 @@ fun LedgerAddScreen( color = FilledButtonColor.Black, style = MediumButtonStyle.height60, text = stringResource(id = R.string.word_save), + isClickable = uiState.buttonEnabled, + isActive = uiState.buttonEnabled, onClick = onClickNextButton, ) } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt new file mode 100644 index 00000000..8cff38b3 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt @@ -0,0 +1,32 @@ +package com.susu.feature.received.ledgeradd + +import androidx.lifecycle.viewModelScope +import com.susu.core.model.Ledger +import com.susu.core.ui.base.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toPersistentList +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class LedgerAddViewModel @Inject constructor( +) : BaseViewModel( + LedgerAddState(), +) { + fun goToPrevStep() { + when(currentState.currentStep) { + LedgerAddStep.CATEGORY -> postSideEffect(LedgerAddSideEffect.PopBackStack) + LedgerAddStep.NAME -> intent { copy(currentStep = LedgerAddStep.CATEGORY) } + LedgerAddStep.DATE -> intent { copy(currentStep = LedgerAddStep.NAME) } + } + } + + fun goToNextStep() { + when(currentState.currentStep) { + LedgerAddStep.CATEGORY -> intent { copy(currentStep = LedgerAddStep.NAME) } + LedgerAddStep.NAME -> intent { copy(currentStep = LedgerAddStep.DATE) } + LedgerAddStep.DATE -> { /* TODO 장부 추가 서버 연동 */ } + } + } + +} From 45a3604cea7ed8646e6c1136a91398da7f3f7b0a Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 18 Jan 2024 01:55:55 +0900 Subject: [PATCH 03/14] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B6=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EB=8F=99=EC=9E=91=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/button/BasicButton.kt | 2 + .../component/button/SusuGhostButton.kt | 2 + .../textfieldbutton/SusuTextFieldButton.kt | 4 +- core/ui/src/main/res/values/strings.xml | 1 + .../received/ledgeradd/LedgerAddScreen.kt | 55 ++++++++- .../received/ledgeradd/LedgerAddViewModel.kt | 1 + .../ledgeradd/category/CategoryContent.kt | 111 ++++++++++++++++++ .../ledgeradd/category/CategoryContract.kt | 21 ++++ .../ledgeradd/category/CategoryViewModel.kt | 61 ++++++++++ .../ledgeradd/content/CategoryContent.kt | 91 -------------- 10 files changed, 251 insertions(+), 98 deletions(-) create mode 100644 feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContent.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryViewModel.kt delete mode 100644 feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/CategoryContent.kt diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt index 749e9260..5cecee22 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt @@ -40,6 +40,7 @@ fun BasicButton( rightIcon: (@Composable () -> Unit)? = null, iconSpacing: Dp = 0.dp, isClickable: Boolean = true, + rippleEnabled: Boolean = true, onClick: () -> Unit = {}, ) { Box( @@ -52,6 +53,7 @@ fun BasicButton( shape = shape, ) .susuClickable( + rippleEnabled = rippleEnabled, rippleColor = rippleColor, runIf = isClickable, onClick = onClick, diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt index b9d2c682..b372b4a1 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt @@ -56,6 +56,7 @@ fun SusuGhostButton( rightIcon: (@Composable () -> Unit)? = null, isActive: Boolean = true, isClickable: Boolean = true, + rippleEnabled: Boolean = true, onClick: () -> Unit = {}, ) { val (paddingValues, iconSpacing, textStyle) = style() @@ -73,6 +74,7 @@ fun SusuGhostButton( padding = paddingValues, iconSpacing = iconSpacing, isClickable = isClickable, + rippleEnabled = rippleEnabled, onClick = onClick, ) } diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt index 6188e66d..fecf4144 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt @@ -75,6 +75,7 @@ fun SusuTextFieldFillMaxButton( onClickCloseIcon: () -> Unit = {}, onClickFilledButton: () -> Unit = {}, onClickButton: (isFocused: Boolean) -> Unit = {}, + focusRequester: FocusRequester = remember { FocusRequester() }, ) { val (backgroundColor, textColor) = with(color) { when { @@ -88,7 +89,8 @@ fun SusuTextFieldFillMaxButton( BasicTextField( modifier = modifier .fillMaxWidth() - .susuClickable { onClickButton(isFocused) }, + .susuClickable { onClickButton(isFocused) } + .focusRequester(focusRequester), value = text, onValueChange = onTextChange, enabled = isSaved.not() && isFocused, diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index a1bd3ed6..654e1dd2 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -28,4 +28,5 @@ 다음 완료 필터 적용하기 + 입력해주세요 diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt index f88935f3..3980723c 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt @@ -9,11 +9,11 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -25,18 +25,24 @@ import com.susu.core.designsystem.component.button.FilledButtonColor import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.model.Category import com.susu.core.ui.R import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec -import com.susu.feature.received.ledgeradd.content.CategoryContent +import com.susu.feature.received.Category.category.CategoryViewModel +import com.susu.feature.received.ledgeradd.category.CategoryContent +import com.susu.feature.received.ledgeradd.category.CategorySideEffect +import com.susu.feature.received.ledgeradd.category.CategoryState import com.susu.feature.received.ledgeradd.content.DateContent import com.susu.feature.received.ledgeradd.content.NameContent - +import kotlinx.coroutines.android.awaitFrame +import kotlinx.coroutines.launch @Composable fun LedgerAddRoute( viewModel: LedgerAddViewModel = hiltViewModel(), + categoryViewModel: CategoryViewModel = hiltViewModel(), popBackStack: () -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value @@ -46,6 +52,23 @@ fun LedgerAddRoute( } } + val categoryState = categoryViewModel.uiState.collectAsStateWithLifecycle().value + val focusRequester = remember { FocusRequester() } + val scope = rememberCoroutineScope() + categoryViewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is CategorySideEffect.UpdateParentButtonState -> TODO() + CategorySideEffect.FocusCustomCategory -> scope.launch { + awaitFrame() + focusRequester.requestFocus() + } + } + } + + LaunchedEffect(key1 = Unit) { + categoryViewModel.getCategoryConfig() + } + BackHandler { viewModel.goToPrevStep() } @@ -54,6 +77,12 @@ fun LedgerAddRoute( uiState = uiState, onClickBack = viewModel::goToPrevStep, onClickNextButton = viewModel::goToNextStep, + categoryState = categoryState, + focusRequester = focusRequester, + onClickCategoryButton = categoryViewModel::selectCategory, + onClickCustomCategoryButton = categoryViewModel::showCustomCategoryTextField, + onClickCustomCategoryTextFieldCloseIcon = categoryViewModel::hideCustomCategoryTextField, + onClickCustomCategoryTextField = categoryViewModel::selectCustomCategory, ) } @@ -62,6 +91,12 @@ fun LedgerAddScreen( uiState: LedgerAddState = LedgerAddState(), onClickBack: () -> Unit = {}, onClickNextButton: () -> Unit = {}, + categoryState: CategoryState = CategoryState(), + focusRequester: FocusRequester = remember { FocusRequester() }, + onClickCategoryButton: (Category) -> Unit = {}, + onClickCustomCategoryButton: () -> Unit = {}, + onClickCustomCategoryTextFieldCloseIcon: () -> Unit = {}, + onClickCustomCategoryTextField: () -> Unit = {}, ) { Box( modifier = Modifier @@ -88,7 +123,15 @@ fun LedgerAddScreen( }, ) { targetState -> when (targetState) { - LedgerAddStep.CATEGORY -> CategoryContent() + LedgerAddStep.CATEGORY -> CategoryContent( + uiState = categoryState, + focusRequester = focusRequester, + onClickCategoryButton = onClickCategoryButton, + onClickCustomCategoryButton = onClickCustomCategoryButton, + onClickCustomCategoryTextFieldCloseIcon = onClickCustomCategoryTextFieldCloseIcon, + onClickCustomCategoryTextField = onClickCustomCategoryTextField + ) + LedgerAddStep.NAME -> NameContent() LedgerAddStep.DATE -> DateContent() } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt index 8cff38b3..ff6db397 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt @@ -22,6 +22,7 @@ class LedgerAddViewModel @Inject constructor( } fun goToNextStep() { + intent { copy(buttonEnabled = false) } when(currentState.currentStep) { LedgerAddStep.CATEGORY -> intent { copy(currentStep = LedgerAddStep.NAME) } LedgerAddStep.NAME -> intent { copy(currentStep = LedgerAddStep.DATE) } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContent.kt new file mode 100644 index 00000000..2fd71438 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContent.kt @@ -0,0 +1,111 @@ +package com.susu.feature.received.ledgeradd.category + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.susu.core.designsystem.component.button.FilledButtonColor +import com.susu.core.designsystem.component.button.GhostButtonColor +import com.susu.core.designsystem.component.button.MediumButtonStyle +import com.susu.core.designsystem.component.button.SusuFilledButton +import com.susu.core.designsystem.component.button.SusuGhostButton +import com.susu.core.designsystem.component.textfieldbutton.SusuTextFieldFillMaxButton +import com.susu.core.designsystem.component.textfieldbutton.style.MediumTextFieldButtonStyle +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.model.Category +import com.susu.feature.received.R + +@Composable +fun CategoryContent( + uiState: CategoryState = CategoryState(), + focusRequester: FocusRequester = remember { FocusRequester() }, + onClickCategoryButton: (Category) -> Unit = {}, + onClickCustomCategoryButton: () -> Unit = {}, + onClickCustomCategoryTextFieldCloseIcon: () -> Unit = {}, + onClickCustomCategoryTextField: () -> Unit = {}, +) { + val scrollState = rememberScrollState() + + Column( + modifier = Modifier + .fillMaxSize() + .padding( + top = SusuTheme.spacing.spacing_xl, + start = SusuTheme.spacing.spacing_m, + end = SusuTheme.spacing.spacing_m, + ) + .verticalScroll(scrollState), + ) { + Text( + text = stringResource(R.string.select_category_screen_title), + style = SusuTheme.typography.title_m, + ) + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxl)) + + Column( + verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), + ) { + uiState.categoryConfig.forEach { category -> + if (category == uiState.selectedCategory) { + SusuFilledButton( + modifier = Modifier.fillMaxWidth(), + color = FilledButtonColor.Orange, + style = MediumButtonStyle.height60, + text = category.name, + ) + } else { + SusuGhostButton( + modifier = Modifier.fillMaxWidth(), + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + text = category.name, + rippleEnabled = false, + onClick = { onClickCategoryButton(category) } + ) + } + } + + if (uiState.showTextFieldButton) { + SusuTextFieldFillMaxButton( + focusRequester = focusRequester, + style = MediumTextFieldButtonStyle.height60, + isSaved = uiState.isSavedCustomCategory, + isFocused = uiState.customCategory == uiState.selectedCategory, + placeholder = stringResource(com.susu.core.ui.R.string.word_input_placeholder), + onClickCloseIcon = onClickCustomCategoryTextFieldCloseIcon, + onClickButton = { onClickCustomCategoryTextField() }, + ) + } else { + SusuGhostButton( + modifier = Modifier.fillMaxWidth(), + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + text = stringResource(com.susu.core.ui.R.string.word_input_yourself), + rippleEnabled = false, + onClick = onClickCustomCategoryButton, + ) + } + } + } +} + +@Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) +@Composable +fun CategoryContentPreview() { + SusuTheme { + CategoryContent() + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContract.kt new file mode 100644 index 00000000..75910078 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContract.kt @@ -0,0 +1,21 @@ +package com.susu.feature.received.ledgeradd.category + +import com.susu.core.model.Category +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import com.susu.feature.received.ledgeredit.LedgerEditSideEffect +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf + +data class CategoryState( + val selectedCategory: Category? = null, + val categoryConfig: PersistentList = persistentListOf(), + val customCategory: Category = Category(), + val showTextFieldButton: Boolean = false, + val isSavedCustomCategory: Boolean = false, +) : UiState + +sealed interface CategorySideEffect : SideEffect { + data object FocusCustomCategory : CategorySideEffect + data class UpdateParentButtonState(val enabled: Boolean) : CategorySideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryViewModel.kt new file mode 100644 index 00000000..020f9525 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryViewModel.kt @@ -0,0 +1,61 @@ +package com.susu.feature.received.Category.category + +import androidx.lifecycle.viewModelScope +import com.susu.core.model.Category +import com.susu.core.model.Ledger +import com.susu.core.ui.base.BaseViewModel +import com.susu.domain.usecase.categoryconfig.GetCategoryConfigUseCase +import com.susu.feature.received.ledgeradd.category.CategorySideEffect +import com.susu.feature.received.ledgeradd.category.CategoryState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toPersistentList +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class CategoryViewModel @Inject constructor( + private val getCategoryConfigUseCase: GetCategoryConfigUseCase, +) : BaseViewModel( + CategoryState(), +) { + val parentButtonEnabled = with(currentState) { + (selectedCategory == customCategory && !customCategory.customCategory.isNullOrEmpty()) || + selectedCategory != null + } + + fun getCategoryConfig() = viewModelScope.launch { + getCategoryConfigUseCase() + .onSuccess { + intent { + copy( + categoryConfig = it.dropLast(1).toPersistentList(), + customCategory = it.last(), + ) + } + } + .onFailure { } + } + + fun selectCategory(category: Category) = intent { copy(selectedCategory = category) } + + fun selectCustomCategory() = intent { + postSideEffect(CategorySideEffect.FocusCustomCategory) + copy(selectedCategory = customCategory) + } + + fun showCustomCategoryTextField() = intent { + copy( + showTextFieldButton = true, + selectedCategory = customCategory, + ) + } + + fun hideCustomCategoryTextField() = intent { + copy( + showTextFieldButton = false, + selectedCategory = null, + customCategory = customCategory.copy(customCategory = ""), + ) + } + +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/CategoryContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/CategoryContent.kt deleted file mode 100644 index 1fc7b0e1..00000000 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/CategoryContent.kt +++ /dev/null @@ -1,91 +0,0 @@ -package com.susu.feature.received.ledgeradd.content - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.susu.core.designsystem.component.button.GhostButtonColor -import com.susu.core.designsystem.component.button.MediumButtonStyle -import com.susu.core.designsystem.component.button.SusuGhostButton -import com.susu.core.designsystem.theme.SusuTheme -import com.susu.feature.received.R - -@Composable -fun CategoryContent() { - val scrollState = rememberScrollState() - - Column( - modifier = Modifier - .fillMaxSize() - .padding( - top = SusuTheme.spacing.spacing_xl, - start = SusuTheme.spacing.spacing_m, - end = SusuTheme.spacing.spacing_m, - ) - .verticalScroll(scrollState), - ) { - Text( - text = stringResource(R.string.select_category_screen_title), - style = SusuTheme.typography.title_m, - ) - - Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxl)) - - Column( - verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), - ) { - SusuGhostButton( - modifier = Modifier.fillMaxWidth(), - color = GhostButtonColor.Black, - style = MediumButtonStyle.height60, - text = "결혼식", - ) - - SusuGhostButton( - modifier = Modifier.fillMaxWidth(), - color = GhostButtonColor.Black, - style = MediumButtonStyle.height60, - text = "돌잔치", - ) - - SusuGhostButton( - modifier = Modifier.fillMaxWidth(), - color = GhostButtonColor.Black, - style = MediumButtonStyle.height60, - text = "장례식", - ) - - SusuGhostButton( - modifier = Modifier.fillMaxWidth(), - color = GhostButtonColor.Black, - style = MediumButtonStyle.height60, - text = "생일 기념일", - ) - - SusuGhostButton( - modifier = Modifier.fillMaxWidth(), - color = GhostButtonColor.Black, - style = MediumButtonStyle.height60, - text = stringResource(com.susu.core.ui.R.string.word_input_yourself), - ) - } - } -} - -@Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) -@Composable -fun CategoryContentPreview() { - SusuTheme { - CategoryContent() - } -} From 485e91b236cfa00e9c0a95c6fb5050c7d3934d2d Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 18 Jan 2024 09:54:06 +0900 Subject: [PATCH 04/14] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B6=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20=EB=8F=99=EC=9E=91=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../received/ledgeradd/LedgerAddScreen.kt | 16 ++++++++++-- .../received/ledgeradd/LedgerAddViewModel.kt | 10 +++++++ .../ledgeradd/category/CategoryContent.kt | 25 +++++++++++++++++- .../ledgeradd/category/CategoryContract.kt | 7 ++--- .../ledgeradd/category/CategoryViewModel.kt | 26 +++++++++++++++---- 5 files changed, 73 insertions(+), 11 deletions(-) diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt index 3980723c..7916cd92 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt @@ -57,7 +57,7 @@ fun LedgerAddRoute( val scope = rememberCoroutineScope() categoryViewModel.sideEffect.collectWithLifecycle { sideEffect -> when (sideEffect) { - is CategorySideEffect.UpdateParentButtonState -> TODO() + is CategorySideEffect.UpdateParentSelectedCategory -> viewModel.updateSelectedCategory(sideEffect.category) CategorySideEffect.FocusCustomCategory -> scope.launch { awaitFrame() focusRequester.requestFocus() @@ -83,6 +83,10 @@ fun LedgerAddRoute( onClickCustomCategoryButton = categoryViewModel::showCustomCategoryTextField, onClickCustomCategoryTextFieldCloseIcon = categoryViewModel::hideCustomCategoryTextField, onClickCustomCategoryTextField = categoryViewModel::selectCustomCategory, + onClickCustomCategoryTextFieldClearIcon = { categoryViewModel.updateCustomCategoryText("") }, + onTextChangeCustomCategoryTextField = categoryViewModel::updateCustomCategoryText, + onClickTextFieldInnerButton = categoryViewModel::toggleTextFieldSaved, + updateParentSelectedCategory = categoryViewModel::updateParentSelectedCategory, ) } @@ -97,6 +101,10 @@ fun LedgerAddScreen( onClickCustomCategoryButton: () -> Unit = {}, onClickCustomCategoryTextFieldCloseIcon: () -> Unit = {}, onClickCustomCategoryTextField: () -> Unit = {}, + onClickCustomCategoryTextFieldClearIcon: () -> Unit = {}, + onTextChangeCustomCategoryTextField: (String) -> Unit = {}, + onClickTextFieldInnerButton: () -> Unit = {}, + updateParentSelectedCategory: () -> Unit = {}, ) { Box( modifier = Modifier @@ -129,7 +137,11 @@ fun LedgerAddScreen( onClickCategoryButton = onClickCategoryButton, onClickCustomCategoryButton = onClickCustomCategoryButton, onClickCustomCategoryTextFieldCloseIcon = onClickCustomCategoryTextFieldCloseIcon, - onClickCustomCategoryTextField = onClickCustomCategoryTextField + onClickCustomCategoryTextField = onClickCustomCategoryTextField, + onClickCustomCategoryTextFieldClearIcon = onClickCustomCategoryTextFieldClearIcon, + onTextChangeCustomCategoryTextField = onTextChangeCustomCategoryTextField, + onClickTextFieldInnerButton = onClickTextFieldInnerButton, + updateParentSelectedCategory = updateParentSelectedCategory, ) LedgerAddStep.NAME -> NameContent() diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt index ff6db397..48da890a 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt @@ -1,6 +1,7 @@ package com.susu.feature.received.ledgeradd import androidx.lifecycle.viewModelScope +import com.susu.core.model.Category import com.susu.core.model.Ledger import com.susu.core.ui.base.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel @@ -13,6 +14,15 @@ class LedgerAddViewModel @Inject constructor( ) : BaseViewModel( LedgerAddState(), ) { + private var selectedCategory: Category? = null + + fun updateSelectedCategory(category: Category?) = intent { + selectedCategory = category + copy( + buttonEnabled = selectedCategory != null + ) + } + fun goToPrevStep() { when(currentState.currentStep) { LedgerAddStep.CATEGORY -> postSideEffect(LedgerAddSideEffect.PopBackStack) diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContent.kt index 2fd71438..c52e0f71 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContent.kt @@ -11,7 +11,9 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.res.stringResource @@ -22,10 +24,12 @@ import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.component.button.SusuGhostButton import com.susu.core.designsystem.component.textfieldbutton.SusuTextFieldFillMaxButton +import com.susu.core.designsystem.component.textfieldbutton.TextFieldButtonColor import com.susu.core.designsystem.component.textfieldbutton.style.MediumTextFieldButtonStyle import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.model.Category import com.susu.feature.received.R +import kotlinx.coroutines.flow.collect @Composable fun CategoryContent( @@ -35,7 +39,21 @@ fun CategoryContent( onClickCustomCategoryButton: () -> Unit = {}, onClickCustomCategoryTextFieldCloseIcon: () -> Unit = {}, onClickCustomCategoryTextField: () -> Unit = {}, + onClickCustomCategoryTextFieldClearIcon: () -> Unit = {}, + onTextChangeCustomCategoryTextField: (String) -> Unit = {}, + onClickTextFieldInnerButton: () -> Unit = {}, + updateParentSelectedCategory: () -> Unit = {}, ) { + LaunchedEffect( + key1 = uiState.selectedCategory, + key2 = uiState.isSavedCustomCategory, + ) { + snapshotFlow { uiState.selectedCategory } + .collect { + updateParentSelectedCategory() + } + } + val scrollState = rememberScrollState() Column( @@ -73,20 +91,25 @@ fun CategoryContent( style = MediumButtonStyle.height60, text = category.name, rippleEnabled = false, - onClick = { onClickCategoryButton(category) } + onClick = { onClickCategoryButton(category) }, ) } } if (uiState.showTextFieldButton) { SusuTextFieldFillMaxButton( + color = if (uiState.isCustomCategorySelected) TextFieldButtonColor.Orange else TextFieldButtonColor.Black, + text = uiState.customCategory.customCategory ?: "", + onTextChange = onTextChangeCustomCategoryTextField, focusRequester = focusRequester, style = MediumTextFieldButtonStyle.height60, isSaved = uiState.isSavedCustomCategory, isFocused = uiState.customCategory == uiState.selectedCategory, placeholder = stringResource(com.susu.core.ui.R.string.word_input_placeholder), onClickCloseIcon = onClickCustomCategoryTextFieldCloseIcon, + onClickClearIcon = onClickCustomCategoryTextFieldClearIcon, onClickButton = { onClickCustomCategoryTextField() }, + onClickFilledButton = onClickTextFieldInnerButton, ) } else { SusuGhostButton( diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContract.kt index 75910078..5bfb2623 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContract.kt @@ -3,7 +3,6 @@ package com.susu.feature.received.ledgeradd.category import com.susu.core.model.Category import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -import com.susu.feature.received.ledgeredit.LedgerEditSideEffect import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf @@ -13,9 +12,11 @@ data class CategoryState( val customCategory: Category = Category(), val showTextFieldButton: Boolean = false, val isSavedCustomCategory: Boolean = false, -) : UiState +) : UiState { + val isCustomCategorySelected = customCategory == selectedCategory +} sealed interface CategorySideEffect : SideEffect { data object FocusCustomCategory : CategorySideEffect - data class UpdateParentButtonState(val enabled: Boolean) : CategorySideEffect + data class UpdateParentSelectedCategory(val category: Category?) : CategorySideEffect } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryViewModel.kt index 020f9525..0f40f3f5 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryViewModel.kt @@ -18,10 +18,11 @@ class CategoryViewModel @Inject constructor( ) : BaseViewModel( CategoryState(), ) { - val parentButtonEnabled = with(currentState) { - (selectedCategory == customCategory && !customCategory.customCategory.isNullOrEmpty()) || - selectedCategory != null - } + private val parentSelectedCategory + get() = with(currentState) { + if (selectedCategory == customCategory && (customCategory.customCategory.isNullOrEmpty() || isSavedCustomCategory.not())) null + else selectedCategory + } fun getCategoryConfig() = viewModelScope.launch { getCategoryConfigUseCase() @@ -43,6 +44,13 @@ class CategoryViewModel @Inject constructor( copy(selectedCategory = customCategory) } + fun updateCustomCategoryText(text: String) = intent { + copy( + selectedCategory = customCategory.copy(customCategory = text), + customCategory = customCategory.copy(customCategory = text), + ) + } + fun showCustomCategoryTextField() = intent { copy( showTextFieldButton = true, @@ -52,10 +60,18 @@ class CategoryViewModel @Inject constructor( fun hideCustomCategoryTextField() = intent { copy( + isSavedCustomCategory = false, showTextFieldButton = false, - selectedCategory = null, + selectedCategory = if (isCustomCategorySelected) null else selectedCategory, customCategory = customCategory.copy(customCategory = ""), ) } + fun toggleTextFieldSaved() = intent { + copy( + isSavedCustomCategory = !isSavedCustomCategory, + ) + } + + fun updateParentSelectedCategory() = postSideEffect(CategorySideEffect.UpdateParentSelectedCategory(parentSelectedCategory)) } From 21c7eb2d9736a6835130fc7e7c0dd97adc899a68 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 18 Jan 2024 14:39:03 +0900 Subject: [PATCH 05/14] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B6=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=9D=B4=EB=A6=84=20=EC=9E=85=EB=A0=A5=20=EB=8F=99?= =?UTF-8?q?=EC=9E=91=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../received/ledgeradd/LedgerAddScreen.kt | 22 +++++++++++++++++-- .../received/ledgeradd/LedgerAddViewModel.kt | 17 ++++++++++---- .../{content => name}/NameContent.kt | 9 ++++++-- .../received/ledgeradd/name/NameContract.kt | 15 +++++++++++++ .../received/ledgeradd/name/NameViewModel.kt | 19 ++++++++++++++++ 5 files changed, 74 insertions(+), 8 deletions(-) rename feature/received/src/main/java/com/susu/feature/received/ledgeradd/{content => name}/NameContent.kt (85%) create mode 100644 feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameViewModel.kt diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt index 7916cd92..09a4a20a 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt @@ -34,7 +34,10 @@ import com.susu.feature.received.ledgeradd.category.CategoryContent import com.susu.feature.received.ledgeradd.category.CategorySideEffect import com.susu.feature.received.ledgeradd.category.CategoryState import com.susu.feature.received.ledgeradd.content.DateContent -import com.susu.feature.received.ledgeradd.content.NameContent +import com.susu.feature.received.ledgeradd.name.NameContent +import com.susu.feature.received.ledgeradd.name.NameSideEffect +import com.susu.feature.received.ledgeradd.name.NameState +import com.susu.feature.received.ledgeradd.name.NameViewModel import kotlinx.coroutines.android.awaitFrame import kotlinx.coroutines.launch @@ -43,6 +46,7 @@ import kotlinx.coroutines.launch fun LedgerAddRoute( viewModel: LedgerAddViewModel = hiltViewModel(), categoryViewModel: CategoryViewModel = hiltViewModel(), + nameViewModel: NameViewModel = hiltViewModel(), popBackStack: () -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value @@ -69,6 +73,13 @@ fun LedgerAddRoute( categoryViewModel.getCategoryConfig() } + val nameState = nameViewModel.uiState.collectAsStateWithLifecycle().value + nameViewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is NameSideEffect.UpdateParentName -> viewModel.updateName(sideEffect.name) + } + } + BackHandler { viewModel.goToPrevStep() } @@ -87,6 +98,8 @@ fun LedgerAddRoute( onTextChangeCustomCategoryTextField = categoryViewModel::updateCustomCategoryText, onClickTextFieldInnerButton = categoryViewModel::toggleTextFieldSaved, updateParentSelectedCategory = categoryViewModel::updateParentSelectedCategory, + nameState = nameState, + onTextChangeName = nameViewModel::updateName, ) } @@ -105,6 +118,8 @@ fun LedgerAddScreen( onTextChangeCustomCategoryTextField: (String) -> Unit = {}, onClickTextFieldInnerButton: () -> Unit = {}, updateParentSelectedCategory: () -> Unit = {}, + nameState: NameState = NameState(), + onTextChangeName: (String) -> Unit = {}, ) { Box( modifier = Modifier @@ -144,7 +159,10 @@ fun LedgerAddScreen( updateParentSelectedCategory = updateParentSelectedCategory, ) - LedgerAddStep.NAME -> NameContent() + LedgerAddStep.NAME -> NameContent( + uiState = nameState, + onTextChangeName = onTextChangeName, + ) LedgerAddStep.DATE -> DateContent() } } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt index 48da890a..82d3b228 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt @@ -15,16 +15,24 @@ class LedgerAddViewModel @Inject constructor( LedgerAddState(), ) { private var selectedCategory: Category? = null + private var name: String = "" fun updateSelectedCategory(category: Category?) = intent { selectedCategory = category copy( - buttonEnabled = selectedCategory != null + buttonEnabled = selectedCategory != null, + ) + } + + fun updateName(name: String) = intent { + this@LedgerAddViewModel.name = name + copy( + buttonEnabled = name.isNotEmpty(), ) } fun goToPrevStep() { - when(currentState.currentStep) { + when (currentState.currentStep) { LedgerAddStep.CATEGORY -> postSideEffect(LedgerAddSideEffect.PopBackStack) LedgerAddStep.NAME -> intent { copy(currentStep = LedgerAddStep.CATEGORY) } LedgerAddStep.DATE -> intent { copy(currentStep = LedgerAddStep.NAME) } @@ -33,10 +41,11 @@ class LedgerAddViewModel @Inject constructor( fun goToNextStep() { intent { copy(buttonEnabled = false) } - when(currentState.currentStep) { + when (currentState.currentStep) { LedgerAddStep.CATEGORY -> intent { copy(currentStep = LedgerAddStep.NAME) } LedgerAddStep.NAME -> intent { copy(currentStep = LedgerAddStep.DATE) } - LedgerAddStep.DATE -> { /* TODO 장부 추가 서버 연동 */ } + LedgerAddStep.DATE -> { /* TODO 장부 추가 서버 연동 */ + } } } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContent.kt similarity index 85% rename from feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/NameContent.kt rename to feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContent.kt index 9712b652..d2c8329c 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContent.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.ledgeradd.content +package com.susu.feature.received.ledgeradd.name import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -15,7 +15,10 @@ import com.susu.core.designsystem.theme.SusuTheme import com.susu.feature.received.R @Composable -fun NameContent() { +fun NameContent( + uiState: NameState = NameState(), + onTextChangeName: (String) -> Unit = {}, +) { Column( modifier = Modifier .fillMaxSize() @@ -33,6 +36,8 @@ fun NameContent() { Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_m)) SusuBasicTextField( + text = uiState.name, + onTextChange = onTextChangeName, placeholder = stringResource(R.string.input_name_screen_textfield_placeholder), ) } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContract.kt new file mode 100644 index 00000000..46382b00 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContract.kt @@ -0,0 +1,15 @@ +package com.susu.feature.received.ledgeradd.name + +import com.susu.core.model.Category +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf + +data class NameState( + val name: String = "", +) : UiState + +sealed interface NameSideEffect : SideEffect { + data class UpdateParentName(val name: String) : NameSideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameViewModel.kt new file mode 100644 index 00000000..0ba5054d --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameViewModel.kt @@ -0,0 +1,19 @@ +package com.susu.feature.received.ledgeradd.name + +import androidx.lifecycle.viewModelScope +import com.susu.core.ui.base.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toPersistentList +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class NameViewModel @Inject constructor( +) : BaseViewModel( + NameState(), +) { + fun updateName(name: String) = intent { + postSideEffect(NameSideEffect.UpdateParentName(name)) + copy(name = name) + } +} From 21c1cbea5edf16dfa54b2a467f9b14ff08e95601 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 18 Jan 2024 14:41:48 +0900 Subject: [PATCH 06/14] =?UTF-8?q?move:=20LedgerAddContent=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../received/ledgeradd/LedgerAddScreen.kt | 16 ++++++++-------- .../{ => content}/category/CategoryContent.kt | 2 +- .../{ => content}/category/CategoryContract.kt | 2 +- .../{ => content}/category/CategoryViewModel.kt | 4 ++-- .../ledgeradd/content/{ => date}/DateContent.kt | 4 ++-- .../{ => date}/component/SelectDateRow.kt | 2 +- .../ledgeradd/{ => content}/name/NameContent.kt | 2 +- .../ledgeradd/{ => content}/name/NameContract.kt | 2 +- .../{ => content}/name/NameViewModel.kt | 2 +- 9 files changed, 18 insertions(+), 18 deletions(-) rename feature/received/src/main/java/com/susu/feature/received/ledgeradd/{ => content}/category/CategoryContent.kt (98%) rename feature/received/src/main/java/com/susu/feature/received/ledgeradd/{ => content}/category/CategoryContract.kt (92%) rename feature/received/src/main/java/com/susu/feature/received/ledgeradd/{ => content}/category/CategoryViewModel.kt (94%) rename feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/{ => date}/DateContent.kt (93%) rename feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/{ => date}/component/SelectDateRow.kt (96%) rename feature/received/src/main/java/com/susu/feature/received/ledgeradd/{ => content}/name/NameContent.kt (96%) rename feature/received/src/main/java/com/susu/feature/received/ledgeradd/{ => content}/name/NameContract.kt (87%) rename feature/received/src/main/java/com/susu/feature/received/ledgeradd/{ => content}/name/NameViewModel.kt (90%) diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt index 09a4a20a..a5ee0434 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt @@ -30,14 +30,14 @@ import com.susu.core.ui.R import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec import com.susu.feature.received.Category.category.CategoryViewModel -import com.susu.feature.received.ledgeradd.category.CategoryContent -import com.susu.feature.received.ledgeradd.category.CategorySideEffect -import com.susu.feature.received.ledgeradd.category.CategoryState -import com.susu.feature.received.ledgeradd.content.DateContent -import com.susu.feature.received.ledgeradd.name.NameContent -import com.susu.feature.received.ledgeradd.name.NameSideEffect -import com.susu.feature.received.ledgeradd.name.NameState -import com.susu.feature.received.ledgeradd.name.NameViewModel +import com.susu.feature.received.ledgeradd.content.category.CategoryContent +import com.susu.feature.received.ledgeradd.content.category.CategorySideEffect +import com.susu.feature.received.ledgeradd.content.category.CategoryState +import com.susu.feature.received.ledgeradd.content.date.DateContent +import com.susu.feature.received.ledgeradd.content.name.NameContent +import com.susu.feature.received.ledgeradd.content.name.NameSideEffect +import com.susu.feature.received.ledgeradd.content.name.NameState +import com.susu.feature.received.ledgeradd.content.name.NameViewModel import kotlinx.coroutines.android.awaitFrame import kotlinx.coroutines.launch diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContent.kt similarity index 98% rename from feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContent.kt rename to feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContent.kt index c52e0f71..92af6616 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContent.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.ledgeradd.category +package com.susu.feature.received.ledgeradd.content.category import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContract.kt similarity index 92% rename from feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContract.kt rename to feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContract.kt index 5bfb2623..579f1e24 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContract.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.ledgeradd.category +package com.susu.feature.received.ledgeradd.content.category import com.susu.core.model.Category import com.susu.core.ui.base.SideEffect diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryViewModel.kt similarity index 94% rename from feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryViewModel.kt rename to feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryViewModel.kt index 0f40f3f5..fa2977df 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/category/CategoryViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryViewModel.kt @@ -5,8 +5,8 @@ import com.susu.core.model.Category import com.susu.core.model.Ledger import com.susu.core.ui.base.BaseViewModel import com.susu.domain.usecase.categoryconfig.GetCategoryConfigUseCase -import com.susu.feature.received.ledgeradd.category.CategorySideEffect -import com.susu.feature.received.ledgeradd.category.CategoryState +import com.susu.feature.received.ledgeradd.content.category.CategorySideEffect +import com.susu.feature.received.ledgeradd.content.category.CategoryState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.launch diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/DateContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt similarity index 93% rename from feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/DateContent.kt rename to feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt index 8d999704..1e286756 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/DateContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.ledgeradd.content +package com.susu.feature.received.ledgeradd.content.date import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -15,7 +15,7 @@ import androidx.compose.ui.unit.dp import com.susu.core.designsystem.component.bottomsheet.datepicker.SusuDatePickerBottomSheet import com.susu.core.designsystem.theme.SusuTheme import com.susu.feature.received.R -import com.susu.feature.received.ledgeradd.content.component.SelectDateRow +import com.susu.feature.received.ledgeradd.content.date.component.SelectDateRow @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/component/SelectDateRow.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/component/SelectDateRow.kt similarity index 96% rename from feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/component/SelectDateRow.kt rename to feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/component/SelectDateRow.kt index 0bf71509..0ffd54cf 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/component/SelectDateRow.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/component/SelectDateRow.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.ledgeradd.content.component +package com.susu.feature.received.ledgeradd.content.date.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt similarity index 96% rename from feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContent.kt rename to feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt index d2c8329c..a5751baa 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.ledgeradd.name +package com.susu.feature.received.ledgeradd.content.name import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContract.kt similarity index 87% rename from feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContract.kt rename to feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContract.kt index 46382b00..6a24d541 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContract.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.ledgeradd.name +package com.susu.feature.received.ledgeradd.content.name import com.susu.core.model.Category import com.susu.core.ui.base.SideEffect diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameViewModel.kt similarity index 90% rename from feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameViewModel.kt rename to feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameViewModel.kt index 0ba5054d..6fa527cf 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/name/NameViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameViewModel.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.ledgeradd.name +package com.susu.feature.received.ledgeradd.content.name import androidx.lifecycle.viewModelScope import com.susu.core.ui.base.BaseViewModel From 93d0e93b6f197e067961941569436a35725a33d0 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 18 Jan 2024 14:45:19 +0900 Subject: [PATCH 07/14] =?UTF-8?q?feat:=20SusuLimitDatePickerBottomSheet=20?= =?UTF-8?q?->=20initialCriteria=20Year,=20Month,=20Day=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datepicker/SusuDatePickerBottomSheet.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt index 5d9293bd..ebe6fcb8 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt @@ -114,9 +114,9 @@ fun SusuDatePickerBottomSheet( @OptIn(ExperimentalMaterial3Api::class) @Composable fun SusuLimitDatePickerBottomSheet( - criteriaYear: Int, - criteriaMonth: Int, - criteriaDay: Int, + initialCriteriaYear: Int? = null, + initialCriteriaMonth: Int? = null, + initialCriteriaDay: Int? = null, initialYear: Int? = null, initialMonth: Int? = null, initialDay: Int? = null, @@ -130,6 +130,12 @@ fun SusuLimitDatePickerBottomSheet( onDismissRequest: (Int, Int, Int) -> Unit = { _, _, _ -> }, onItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, ) { + val (criteriaYear, criteriaMonth, criteriaDay) = listOf( + initialCriteriaYear ?: 2030, + initialCriteriaMonth ?: 12, + initialCriteriaDay ?: 31, + ) + var selectedYear by remember { mutableIntStateOf( when { @@ -348,9 +354,9 @@ private fun getLastDayInMonth(year: Int, month: Int): Int { fun SusuLimitDatePickerBottomSheetPreview() { SusuTheme { SusuLimitDatePickerBottomSheet( - criteriaYear = 2024, - criteriaMonth = 2, - criteriaDay = 16, + initialCriteriaYear = 2024, + initialCriteriaMonth = 2, + initialCriteriaDay = 16, initialYear = 2024, initialMonth = 2, initialDay = 20, From d289aa49fb43da2e51b61958ceca887820810bf3 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 18 Jan 2024 16:09:30 +0900 Subject: [PATCH 08/14] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B6=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=82=A0=EC=A7=9C=20=EC=84=A0=ED=83=9D=20=EB=8F=99?= =?UTF-8?q?=EC=9E=91=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datepicker/SusuDatePickerBottomSheet.kt | 1 + .../main/java/com/susu/core/ui/util/Date.kt | 13 +++- .../received/ledgeradd/LedgerAddScreen.kt | 45 ++++++++++- .../received/ledgeradd/LedgerAddViewModel.kt | 7 +- .../ledgeradd/content/date/DateContent.kt | 74 +++++++++++++++++-- .../ledgeradd/content/date/DateContract.kt | 25 +++++++ .../ledgeradd/content/date/DateViewModel.kt | 40 ++++++++++ .../content/date/component/SelectDateRow.kt | 7 ++ .../ledgeradd/content/name/NameContent.kt | 5 ++ .../received/ledgeredit/LedgerEditScreen.kt | 12 +-- .../received/src/main/res/values/strings.xml | 1 + 11 files changed, 211 insertions(+), 19 deletions(-) create mode 100644 feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt index ebe6fcb8..4ffee172 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt @@ -279,6 +279,7 @@ fun SusuLimitDatePickerBottomSheet( ) } else { selectedDay = criteriaDay + onItemSelected(selectedYear, selectedMonth, selectedDay) Box( modifier = Modifier .width(100.dp) diff --git a/core/ui/src/main/java/com/susu/core/ui/util/Date.kt b/core/ui/src/main/java/com/susu/core/ui/util/Date.kt index 7a4b2ce2..a8a4febf 100644 --- a/core/ui/src/main/java/com/susu/core/ui/util/Date.kt +++ b/core/ui/src/main/java/com/susu/core/ui/util/Date.kt @@ -1,12 +1,23 @@ package com.susu.core.ui.util +import java.time.DateTimeException +import java.time.LocalDate import java.time.LocalDateTime +import java.time.Month +import java.time.YearMonth import java.time.format.DateTimeFormatter -val currentDate = LocalDateTime.now() +val currentDate: LocalDateTime = LocalDateTime.now() +val minDate: LocalDateTime = LocalDateTime.of(1930, 1, 1, 0, 0) @Suppress("detekt:FunctionNaming") fun LocalDateTime.to_yyyy_dot_MM_dot_dd(): String { val formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd") return this.format(formatter) } + +fun getSafeLocalDateTime(year: Int, month: Int, day: Int): LocalDateTime = try { + LocalDateTime.of(year, month, day, 0, 0) +} catch (e: DateTimeException) { + LocalDateTime.of(year, month, 1, 0, 0) +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt index a5ee0434..2b66771a 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt @@ -34,6 +34,8 @@ import com.susu.feature.received.ledgeradd.content.category.CategoryContent import com.susu.feature.received.ledgeradd.content.category.CategorySideEffect import com.susu.feature.received.ledgeradd.content.category.CategoryState import com.susu.feature.received.ledgeradd.content.date.DateContent +import com.susu.feature.received.ledgeradd.content.date.DateState +import com.susu.feature.received.ledgeradd.content.date.DateViewModel import com.susu.feature.received.ledgeradd.content.name.NameContent import com.susu.feature.received.ledgeradd.content.name.NameSideEffect import com.susu.feature.received.ledgeradd.content.name.NameState @@ -47,6 +49,7 @@ fun LedgerAddRoute( viewModel: LedgerAddViewModel = hiltViewModel(), categoryViewModel: CategoryViewModel = hiltViewModel(), nameViewModel: NameViewModel = hiltViewModel(), + dateViewModel: DateViewModel = hiltViewModel(), popBackStack: () -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value @@ -61,7 +64,13 @@ fun LedgerAddRoute( val scope = rememberCoroutineScope() categoryViewModel.sideEffect.collectWithLifecycle { sideEffect -> when (sideEffect) { - is CategorySideEffect.UpdateParentSelectedCategory -> viewModel.updateSelectedCategory(sideEffect.category) + is CategorySideEffect.UpdateParentSelectedCategory -> { + viewModel.updateSelectedCategory(sideEffect.category) + dateViewModel.updateNameAndCategory( + name = null, + categoryName = sideEffect.category?.customCategory ?: sideEffect.category?.name + ) + } CategorySideEffect.FocusCustomCategory -> scope.launch { awaitFrame() focusRequester.requestFocus() @@ -76,10 +85,18 @@ fun LedgerAddRoute( val nameState = nameViewModel.uiState.collectAsStateWithLifecycle().value nameViewModel.sideEffect.collectWithLifecycle { sideEffect -> when (sideEffect) { - is NameSideEffect.UpdateParentName -> viewModel.updateName(sideEffect.name) + is NameSideEffect.UpdateParentName -> { + viewModel.updateName(sideEffect.name) + dateViewModel.updateNameAndCategory( + name = sideEffect.name, + categoryName = null, + ) + } } } + val dateState = dateViewModel.uiState.collectAsStateWithLifecycle().value + BackHandler { viewModel.goToPrevStep() } @@ -100,6 +117,13 @@ fun LedgerAddRoute( updateParentSelectedCategory = categoryViewModel::updateParentSelectedCategory, nameState = nameState, onTextChangeName = nameViewModel::updateName, + dateState = dateState, + onStartDateItemSelected = dateViewModel::updateStartDate, + onClickStartDateText = dateViewModel::showStartDateBottomSheet, + onDismissStartDateBottomSheet = dateViewModel::hideStartDateBottomSheet, + onEndDateItemSelected = dateViewModel::updateEndDate, + onClickEndDateText = dateViewModel::showEndDateBottomSheet, + onDismissEndDateBottomSheet = dateViewModel::hideEndDateBottomSheet, ) } @@ -120,6 +144,13 @@ fun LedgerAddScreen( updateParentSelectedCategory: () -> Unit = {}, nameState: NameState = NameState(), onTextChangeName: (String) -> Unit = {}, + dateState: DateState = DateState(), + onStartDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, + onClickStartDateText: () -> Unit = {}, + onDismissStartDateBottomSheet: () -> Unit = {}, + onEndDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, + onClickEndDateText: () -> Unit = {}, + onDismissEndDateBottomSheet: () -> Unit = {}, ) { Box( modifier = Modifier @@ -163,7 +194,15 @@ fun LedgerAddScreen( uiState = nameState, onTextChangeName = onTextChangeName, ) - LedgerAddStep.DATE -> DateContent() + LedgerAddStep.DATE -> DateContent( + uiState = dateState, + onStartDateItemSelected = onStartDateItemSelected, + onClickStartDateText = onClickStartDateText, + onDismissStartDateBottomSheet = onDismissStartDateBottomSheet, + onEndDateItemSelected = onEndDateItemSelected, + onClickEndDateText = onClickEndDateText, + onDismissEndDateBottomSheet = onDismissEndDateBottomSheet, + ) } } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt index 82d3b228..63ec1aa1 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt @@ -7,6 +7,7 @@ import com.susu.core.ui.base.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.launch +import java.time.LocalDateTime import javax.inject.Inject @HiltViewModel @@ -16,6 +17,8 @@ class LedgerAddViewModel @Inject constructor( ) { private var selectedCategory: Category? = null private var name: String = "" + private var startAt: LocalDateTime? = null + private var endAt: LocalDateTime? = null fun updateSelectedCategory(category: Category?) = intent { selectedCategory = category @@ -40,12 +43,10 @@ class LedgerAddViewModel @Inject constructor( } fun goToNextStep() { - intent { copy(buttonEnabled = false) } when (currentState.currentStep) { LedgerAddStep.CATEGORY -> intent { copy(currentStep = LedgerAddStep.NAME) } LedgerAddStep.NAME -> intent { copy(currentStep = LedgerAddStep.DATE) } - LedgerAddStep.DATE -> { /* TODO 장부 추가 서버 연동 */ - } + LedgerAddStep.DATE -> { /* TODO 장부 추가 서버 연동 */ } } } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt index 1e286756..b6c7a9f7 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt @@ -8,18 +8,41 @@ import androidx.compose.foundation.layout.size import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.susu.core.designsystem.component.bottomsheet.datepicker.SusuDatePickerBottomSheet +import com.susu.core.designsystem.component.bottomsheet.datepicker.SusuLimitDatePickerBottomSheet +import com.susu.core.designsystem.theme.Gray60 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.util.AnnotatedText +import com.susu.core.ui.util.currentDate +import com.susu.core.ui.util.minDate import com.susu.feature.received.R import com.susu.feature.received.ledgeradd.content.date.component.SelectDateRow @OptIn(ExperimentalMaterial3Api::class) @Composable -fun DateContent() { +fun DateContent( + uiState: DateState = DateState(), + onStartDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, + onClickStartDateText: () -> Unit = {}, + onDismissStartDateBottomSheet: () -> Unit = {}, + onEndDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, + onClickEndDateText: () -> Unit = {}, + onDismissEndDateBottomSheet: () -> Unit = {}, +) { + LaunchedEffect(key1 = Unit) { + uiState.startAt?.run { + onStartDateItemSelected(year, monthValue, dayOfMonth) + } + + uiState.endAt?.run { + onEndDateItemSelected(year, monthValue, dayOfMonth) + } + } Column( modifier = Modifier .fillMaxSize() @@ -29,26 +52,65 @@ fun DateContent() { end = SusuTheme.spacing.spacing_m, ), ) { - // TODO Annotated Text 사용 - Text( - text = "고모부의 장례식은 언제인가요", - style = SusuTheme.typography.title_m, + AnnotatedText( + originalText = stringResource(R.string.date_content_title, uiState.name, uiState.categoryName), + originalTextStyle = SusuTheme.typography.title_m, + targetTextList = listOf(uiState.name, uiState.categoryName), + spanStyle = SusuTheme.typography.title_m.copy( + color = Gray60, + ).toSpanStyle(), ) Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_m)) SelectDateRow( + year = uiState.startAt?.year, + month = uiState.startAt?.monthValue, + day = uiState.startAt?.dayOfMonth, suffix = stringResource(R.string.ledger_add_screen_from), + onClick = onClickStartDateText, ) Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxs)) SelectDateRow( + year = uiState.endAt?.year, + month = uiState.endAt?.monthValue, + day = uiState.endAt?.dayOfMonth, suffix = stringResource(R.string.ledger_add_screen_until), + onClick = onClickEndDateText, ) } - SusuDatePickerBottomSheet(maximumContainerHeight = 346.dp) + if (uiState.showStartDateBottomSheet) { + SusuLimitDatePickerBottomSheet( + initialYear = uiState.startAt?.year ?: currentDate.year, + initialMonth = uiState.startAt?.monthValue ?: currentDate.monthValue, + initialDay = uiState.startAt?.dayOfMonth ?: currentDate.dayOfMonth, + initialCriteriaYear = uiState.endAt?.year, + initialCriteriaMonth = uiState.endAt?.monthValue, + initialCriteriaDay = uiState.endAt?.dayOfMonth, + afterDate = false, + maximumContainerHeight = 346.dp, + onDismissRequest = { _, _, _ -> onDismissStartDateBottomSheet() }, + onItemSelected = onStartDateItemSelected, + ) + } + + if (uiState.showEndDateBottomSheet) { + SusuLimitDatePickerBottomSheet( + initialYear = uiState.endAt?.year ?: currentDate.year, + initialMonth = uiState.endAt?.monthValue ?: currentDate.monthValue, + initialDay = uiState.endAt?.dayOfMonth ?: currentDate.dayOfMonth, + initialCriteriaYear = uiState.startAt?.year ?: minDate.year, + initialCriteriaMonth = uiState.startAt?.monthValue ?: minDate.monthValue, + initialCriteriaDay = uiState.startAt?.dayOfMonth ?: minDate.dayOfMonth, + afterDate = true, + maximumContainerHeight = 346.dp, + onDismissRequest = { _, _, _ -> onDismissEndDateBottomSheet() }, + onItemSelected = onEndDateItemSelected, + ) + } } @Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContract.kt new file mode 100644 index 00000000..7b83e0bd --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContract.kt @@ -0,0 +1,25 @@ +package com.susu.feature.received.ledgeradd.content.date + +import com.susu.core.model.Category +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf +import java.time.LocalDateTime + +data class DateState( + val name: String = "", + val categoryName: String = "", + val showEndAt: Boolean = true, + val startAt: LocalDateTime? = null, + val endAt: LocalDateTime? = null, + val showStartDateBottomSheet: Boolean = false, + val showEndDateBottomSheet: Boolean = false, +) : UiState + +sealed interface DateSideEffect : SideEffect { + data class UpdateParentDate( + val startAt: LocalDateTime?, + val endAt: LocalDateTime? = null, + ) : DateSideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt new file mode 100644 index 00000000..5bdb1fe9 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt @@ -0,0 +1,40 @@ +package com.susu.feature.received.ledgeradd.content.date + +import com.susu.core.ui.base.BaseViewModel +import com.susu.core.ui.util.getSafeLocalDateTime +import dagger.hilt.android.lifecycle.HiltViewModel +import java.time.LocalDate +import java.time.LocalDateTime +import javax.inject.Inject + +@HiltViewModel +class DateViewModel @Inject constructor( +) : BaseViewModel( + DateState(), +) { + fun updateNameAndCategory(name: String?, categoryName: String?) = intent { + copy( + name = name ?: this.name, + categoryName = categoryName ?: this.categoryName, + ) + } + + fun updateStartDate(year: Int, month: Int, day: Int) { + intent { + copy( + startAt = LocalDateTime.of(year, month, day, 0, 0), + ) + } + } + + fun updateEndDate(year: Int, month: Int, day: Int) = intent { + copy( + endAt = getSafeLocalDateTime(year, month, day), + ) + } + + fun showStartDateBottomSheet() = intent { copy(showStartDateBottomSheet = true) } + fun hideStartDateBottomSheet() = intent { copy(showStartDateBottomSheet = false) } + fun showEndDateBottomSheet() = intent { copy(showEndDateBottomSheet = true) } + fun hideEndDateBottomSheet() = intent { copy(showEndDateBottomSheet = false) } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/component/SelectDateRow.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/component/SelectDateRow.kt index 0ffd54cf..be01a579 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/component/SelectDateRow.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/component/SelectDateRow.kt @@ -5,10 +5,12 @@ import androidx.compose.foundation.layout.Row import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.susu.core.designsystem.theme.Gray30 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.susuClickable import com.susu.core.ui.util.AnnotatedText import com.susu.feature.received.R import java.time.LocalDateTime @@ -21,8 +23,13 @@ fun SelectDateRow( month: Int? = null, day: Int? = null, suffix: String? = null, + onClick: () -> Unit = {}, ) { Row( + modifier = Modifier.susuClickable( + rippleEnabled = false, + onClick = onClick, + ), horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), verticalAlignment = Alignment.Bottom, ) { diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt index a5751baa..01775166 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt @@ -7,6 +7,7 @@ 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.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -19,6 +20,10 @@ fun NameContent( uiState: NameState = NameState(), onTextChangeName: (String) -> Unit = {}, ) { + LaunchedEffect(key1 = Unit) { + onTextChangeName(uiState.name) + } + Column( modifier = Modifier .fillMaxSize() diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeredit/LedgerEditScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeredit/LedgerEditScreen.kt index fca24d9a..9aa852fd 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeredit/LedgerEditScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeredit/LedgerEditScreen.kt @@ -251,9 +251,9 @@ fun LedgerEditScreen( initialYear = uiState.startYear, initialMonth = uiState.startMonth, initialDay = uiState.startDay, - criteriaYear = uiState.endYear, - criteriaMonth = uiState.endMonth, - criteriaDay = uiState.endDay, + initialCriteriaYear = uiState.endYear, + initialCriteriaMonth = uiState.endMonth, + initialCriteriaDay = uiState.endDay, afterDate = false, maximumContainerHeight = 346.dp, onDismissRequest = { _, _, _ -> onDismissStartDateBottomSheet() }, @@ -266,9 +266,9 @@ fun LedgerEditScreen( initialYear = uiState.endYear, initialMonth = uiState.endMonth, initialDay = uiState.endDay, - criteriaYear = uiState.startYear, - criteriaMonth = uiState.startMonth, - criteriaDay = uiState.startDay, + initialCriteriaYear = uiState.startYear, + initialCriteriaMonth = uiState.startMonth, + initialCriteriaDay = uiState.startDay, afterDate = true, maximumContainerHeight = 346.dp, onDismissRequest = { _, _, _ -> onDismissEndDateBottomSheet() }, diff --git a/feature/received/src/main/res/values/strings.xml b/feature/received/src/main/res/values/strings.xml index f9cee99c..8eb6d841 100644 --- a/feature/received/src/main/res/values/strings.xml +++ b/feature/received/src/main/res/values/strings.xml @@ -28,4 +28,5 @@ 장부를 삭제할까요? 삭제한 장부와 봉투는 다시 복구할 수 없어요 장부가 삭제되었어요 + %s의 %s는 언제인가요 From a4daf57b698798ba2e1c057345210468e1f17638 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 18 Jan 2024 16:26:45 +0900 Subject: [PATCH 09/14] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B6=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=82=A0=EC=A7=9C=20=EC=84=A0=ED=83=9D=20=EB=8F=99?= =?UTF-8?q?=EC=9E=91=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../received/ledgeradd/LedgerAddScreen.kt | 14 ++++++++++++- .../received/ledgeradd/LedgerAddViewModel.kt | 11 +++++++++- .../ledgeradd/content/date/DateContent.kt | 9 ++------- .../ledgeradd/content/date/DateViewModel.kt | 20 ++++++++++++------- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt index 2b66771a..59a99249 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt @@ -34,6 +34,7 @@ import com.susu.feature.received.ledgeradd.content.category.CategoryContent import com.susu.feature.received.ledgeradd.content.category.CategorySideEffect import com.susu.feature.received.ledgeradd.content.category.CategoryState import com.susu.feature.received.ledgeradd.content.date.DateContent +import com.susu.feature.received.ledgeradd.content.date.DateSideEffect import com.susu.feature.received.ledgeradd.content.date.DateState import com.susu.feature.received.ledgeradd.content.date.DateViewModel import com.susu.feature.received.ledgeradd.content.name.NameContent @@ -68,9 +69,10 @@ fun LedgerAddRoute( viewModel.updateSelectedCategory(sideEffect.category) dateViewModel.updateNameAndCategory( name = null, - categoryName = sideEffect.category?.customCategory ?: sideEffect.category?.name + categoryName = sideEffect.category?.customCategory ?: sideEffect.category?.name, ) } + CategorySideEffect.FocusCustomCategory -> scope.launch { awaitFrame() focusRequester.requestFocus() @@ -96,6 +98,12 @@ fun LedgerAddRoute( } val dateState = dateViewModel.uiState.collectAsStateWithLifecycle().value + dateViewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is DateSideEffect.UpdateParentDate -> viewModel.updateDate(sideEffect.startAt, sideEffect.endAt) + } + + } BackHandler { viewModel.goToPrevStep() @@ -124,6 +132,7 @@ fun LedgerAddRoute( onEndDateItemSelected = dateViewModel::updateEndDate, onClickEndDateText = dateViewModel::showEndDateBottomSheet, onDismissEndDateBottomSheet = dateViewModel::hideEndDateBottomSheet, + updateParentDate = dateViewModel::updateParentDate, ) } @@ -151,6 +160,7 @@ fun LedgerAddScreen( onEndDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, onClickEndDateText: () -> Unit = {}, onDismissEndDateBottomSheet: () -> Unit = {}, + updateParentDate: () -> Unit = {}, ) { Box( modifier = Modifier @@ -194,6 +204,7 @@ fun LedgerAddScreen( uiState = nameState, onTextChangeName = onTextChangeName, ) + LedgerAddStep.DATE -> DateContent( uiState = dateState, onStartDateItemSelected = onStartDateItemSelected, @@ -202,6 +213,7 @@ fun LedgerAddScreen( onEndDateItemSelected = onEndDateItemSelected, onClickEndDateText = onClickEndDateText, onDismissEndDateBottomSheet = onDismissEndDateBottomSheet, + updateParentDate = updateParentDate, ) } } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt index 63ec1aa1..92bddd05 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt @@ -7,6 +7,7 @@ import com.susu.core.ui.base.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.launch +import timber.log.Timber import java.time.LocalDateTime import javax.inject.Inject @@ -34,6 +35,14 @@ class LedgerAddViewModel @Inject constructor( ) } + fun updateDate(startAt: LocalDateTime?, endAt: LocalDateTime?) = intent { + this@LedgerAddViewModel.startAt = startAt + this@LedgerAddViewModel.endAt = endAt + copy( + buttonEnabled = startAt != null && endAt != null + ) + } + fun goToPrevStep() { when (currentState.currentStep) { LedgerAddStep.CATEGORY -> postSideEffect(LedgerAddSideEffect.PopBackStack) @@ -46,7 +55,7 @@ class LedgerAddViewModel @Inject constructor( when (currentState.currentStep) { LedgerAddStep.CATEGORY -> intent { copy(currentStep = LedgerAddStep.NAME) } LedgerAddStep.NAME -> intent { copy(currentStep = LedgerAddStep.DATE) } - LedgerAddStep.DATE -> { /* TODO 장부 추가 서버 연동 */ } + LedgerAddStep.DATE -> { Timber.tag("LedgerAddViewModel").d("$name $selectedCategory $startAt $endAt") } } } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt index b6c7a9f7..9ccbda66 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt @@ -33,15 +33,10 @@ fun DateContent( onEndDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, onClickEndDateText: () -> Unit = {}, onDismissEndDateBottomSheet: () -> Unit = {}, + updateParentDate: () -> Unit = {}, ) { LaunchedEffect(key1 = Unit) { - uiState.startAt?.run { - onStartDateItemSelected(year, monthValue, dayOfMonth) - } - - uiState.endAt?.run { - onEndDateItemSelected(year, monthValue, dayOfMonth) - } + updateParentDate() } Column( modifier = Modifier diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt index 5bdb1fe9..6c8dc110 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt @@ -19,20 +19,26 @@ class DateViewModel @Inject constructor( ) } - fun updateStartDate(year: Int, month: Int, day: Int) { - intent { - copy( - startAt = LocalDateTime.of(year, month, day, 0, 0), - ) - } + fun updateStartDate(year: Int, month: Int, day: Int) = intent { + val toUpdateStartAt = LocalDateTime.of(year, month, day, 0, 0) + postSideEffect(DateSideEffect.UpdateParentDate(toUpdateStartAt, endAt)) + copy( + startAt = toUpdateStartAt, + ) } fun updateEndDate(year: Int, month: Int, day: Int) = intent { + val toUpdateEndAt = getSafeLocalDateTime(year, month, day) + postSideEffect(DateSideEffect.UpdateParentDate(startAt, toUpdateEndAt)) copy( - endAt = getSafeLocalDateTime(year, month, day), + endAt = toUpdateEndAt, ) } + fun updateParentDate() = with(currentState) { + postSideEffect(DateSideEffect.UpdateParentDate(startAt, endAt)) + } + fun showStartDateBottomSheet() = intent { copy(showStartDateBottomSheet = true) } fun hideStartDateBottomSheet() = intent { copy(showStartDateBottomSheet = false) } fun showEndDateBottomSheet() = intent { copy(showEndDateBottomSheet = true) } From c045e6033b0f6184515479475db0eb6be669f48d Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 18 Jan 2024 16:34:26 +0900 Subject: [PATCH 10/14] =?UTF-8?q?feat:=20CreateLedgerUseCase=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/data/repository/LedgerRepositoryImpl.kt | 4 ++++ .../java/com/susu/data/remote/api/LedgerService.kt | 6 ++++++ .../com/susu/domain/repository/LedgerRepository.kt | 4 ++++ .../domain/usecase/ledger/CreateLedgerUseCase.kt | 14 ++++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 domain/src/main/java/com/susu/domain/usecase/ledger/CreateLedgerUseCase.kt diff --git a/data/src/main/java/com/susu/data/data/repository/LedgerRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/LedgerRepositoryImpl.kt index 92aeae34..dc305d70 100644 --- a/data/src/main/java/com/susu/data/data/repository/LedgerRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/LedgerRepositoryImpl.kt @@ -28,6 +28,10 @@ class LedgerRepositoryImpl @Inject constructor( sort = sort, ).getOrThrow().toModel() + override suspend fun createLedger(ledger: Ledger): Ledger = ledgerService.createLedger( + ledgerRequest = ledger.toData(), + ).getOrThrow().toModel() + override suspend fun editLedger(ledger: Ledger): Ledger = ledgerService.editLedger( id = ledger.id, ledgerRequest = ledger.toData(), diff --git a/data/src/main/java/com/susu/data/remote/api/LedgerService.kt b/data/src/main/java/com/susu/data/remote/api/LedgerService.kt index ae30275d..0876a37c 100644 --- a/data/src/main/java/com/susu/data/remote/api/LedgerService.kt +++ b/data/src/main/java/com/susu/data/remote/api/LedgerService.kt @@ -9,6 +9,7 @@ import retrofit2.http.Body import retrofit2.http.DELETE import retrofit2.http.GET import retrofit2.http.PATCH +import retrofit2.http.POST import retrofit2.http.Path import retrofit2.http.Query @@ -29,6 +30,11 @@ interface LedgerService { @Body ledgerRequest: LedgerRequest, ): ApiResult + @POST("ledgers") + suspend fun createLedger( + @Body ledgerRequest: LedgerRequest, + ): ApiResult + @DELETE("ledgers") suspend fun deleteLedgerList(@Query("ids") idList: List): ApiResult } diff --git a/domain/src/main/java/com/susu/domain/repository/LedgerRepository.kt b/domain/src/main/java/com/susu/domain/repository/LedgerRepository.kt index d98b0d7c..99444615 100644 --- a/domain/src/main/java/com/susu/domain/repository/LedgerRepository.kt +++ b/domain/src/main/java/com/susu/domain/repository/LedgerRepository.kt @@ -13,6 +13,10 @@ interface LedgerRepository { sort: String?, ): List + suspend fun createLedger( + ledger: Ledger, + ): Ledger + suspend fun editLedger( ledger: Ledger, ): Ledger diff --git a/domain/src/main/java/com/susu/domain/usecase/ledger/CreateLedgerUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/ledger/CreateLedgerUseCase.kt new file mode 100644 index 00000000..ff9fff39 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/ledger/CreateLedgerUseCase.kt @@ -0,0 +1,14 @@ +package com.susu.domain.usecase.ledger + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.core.model.Ledger +import com.susu.domain.repository.LedgerRepository +import javax.inject.Inject + +class CreateLedgerUseCase @Inject constructor( + private val ledgerRepository: LedgerRepository, +) { + suspend operator fun invoke(ledger: Ledger) = runCatchingIgnoreCancelled { + ledgerRepository.createLedger(ledger) + } +} From 290efa4684b92c4fef9622f2bca3288ddbe2d3da Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 18 Jan 2024 17:14:06 +0900 Subject: [PATCH 11/14] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B6=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=84=9C=EB=B2=84=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../received/ledgeradd/LedgerAddContract.kt | 5 ++++ .../received/ledgeradd/LedgerAddScreen.kt | 9 +++++++ .../received/ledgeradd/LedgerAddViewModel.kt | 26 +++++++++++++++++-- .../received/navigation/ReceivedNavigation.kt | 2 ++ .../received/received/ReceivedScreen.kt | 1 + .../received/received/ReceivedViewModel.kt | 16 ++++++++++++ 6 files changed, 57 insertions(+), 2 deletions(-) diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt index 24f617cb..e68da22a 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt @@ -3,12 +3,14 @@ package com.susu.feature.received.ledgeradd import com.susu.core.model.Ledger import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState +import com.susu.feature.received.ledgerdetail.LedgerDetailSideEffect import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf data class LedgerAddState( val currentStep: LedgerAddStep = LedgerAddStep.CATEGORY, val buttonEnabled: Boolean = false, + val isLoading: Boolean = false, ) : UiState enum class LedgerAddStep { @@ -19,4 +21,7 @@ enum class LedgerAddStep { sealed interface LedgerAddSideEffect : SideEffect { data object PopBackStack : LedgerAddSideEffect + data class PopBackStackWithLedger(val ledger: String) : LedgerAddSideEffect + data class HandleException(val throwable: Throwable, val retry: () -> Unit) : LedgerAddSideEffect + } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt index 59a99249..0e5b3d6b 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt @@ -24,6 +24,7 @@ import com.susu.core.designsystem.component.appbar.icon.BackIcon import com.susu.core.designsystem.component.button.FilledButtonColor import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton +import com.susu.core.designsystem.component.screen.LoadingScreen import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.model.Category import com.susu.core.ui.R @@ -52,11 +53,15 @@ fun LedgerAddRoute( nameViewModel: NameViewModel = hiltViewModel(), dateViewModel: DateViewModel = hiltViewModel(), popBackStack: () -> Unit, + popBackStackWithLedger: (String) -> Unit, + handleException: (Throwable, () -> Unit) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value viewModel.sideEffect.collectWithLifecycle { sideEffect -> when (sideEffect) { LedgerAddSideEffect.PopBackStack -> popBackStack() + is LedgerAddSideEffect.HandleException -> handleException(sideEffect.throwable, sideEffect.retry) + is LedgerAddSideEffect.PopBackStackWithLedger -> popBackStackWithLedger(sideEffect.ledger) } } @@ -232,6 +237,10 @@ fun LedgerAddScreen( ) } } + + if (uiState.isLoading) { + LoadingScreen() + } } @Preview diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt index 92bddd05..2c6dd21f 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt @@ -4,15 +4,20 @@ import androidx.lifecycle.viewModelScope import com.susu.core.model.Category import com.susu.core.model.Ledger import com.susu.core.ui.base.BaseViewModel +import com.susu.core.ui.extension.encodeToUri +import com.susu.domain.usecase.ledger.CreateLedgerUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.launch +import kotlinx.datetime.toKotlinLocalDateTime +import kotlinx.serialization.json.Json import timber.log.Timber import java.time.LocalDateTime import javax.inject.Inject @HiltViewModel class LedgerAddViewModel @Inject constructor( + private val createLedgerUseCase: CreateLedgerUseCase, ) : BaseViewModel( LedgerAddState(), ) { @@ -39,7 +44,7 @@ class LedgerAddViewModel @Inject constructor( this@LedgerAddViewModel.startAt = startAt this@LedgerAddViewModel.endAt = endAt copy( - buttonEnabled = startAt != null && endAt != null + buttonEnabled = startAt != null && endAt != null, ) } @@ -55,8 +60,25 @@ class LedgerAddViewModel @Inject constructor( when (currentState.currentStep) { LedgerAddStep.CATEGORY -> intent { copy(currentStep = LedgerAddStep.NAME) } LedgerAddStep.NAME -> intent { copy(currentStep = LedgerAddStep.DATE) } - LedgerAddStep.DATE -> { Timber.tag("LedgerAddViewModel").d("$name $selectedCategory $startAt $endAt") } + LedgerAddStep.DATE -> createLedger() } } + private fun createLedger() = viewModelScope.launch { + intent { copy(isLoading = true) } + createLedgerUseCase( + ledger = Ledger( + title = name, + startAt = startAt!!.toKotlinLocalDateTime(), + endAt = endAt!!.toKotlinLocalDateTime(), + category = selectedCategory!!, + ), + ).onSuccess { ledger -> + postSideEffect(LedgerAddSideEffect.PopBackStackWithLedger(Json.encodeToUri(ledger))) + }.onFailure { + postSideEffect(LedgerAddSideEffect.HandleException(it, ::createLedger)) + } + intent { copy(isLoading = false) } + } + } diff --git a/feature/received/src/main/java/com/susu/feature/received/navigation/ReceivedNavigation.kt b/feature/received/src/main/java/com/susu/feature/received/navigation/ReceivedNavigation.kt index 91efea55..c4b10693 100644 --- a/feature/received/src/main/java/com/susu/feature/received/navigation/ReceivedNavigation.kt +++ b/feature/received/src/main/java/com/susu/feature/received/navigation/ReceivedNavigation.kt @@ -117,6 +117,8 @@ fun NavGraphBuilder.receivedNavGraph( ) { LedgerAddRoute( popBackStack = popBackStack, + popBackStackWithLedger = popBackStackWithLedger, + handleException = handleException, ) } } diff --git a/feature/received/src/main/java/com/susu/feature/received/received/ReceivedScreen.kt b/feature/received/src/main/java/com/susu/feature/received/received/ReceivedScreen.kt index 91a39a6e..3b5215fe 100644 --- a/feature/received/src/main/java/com/susu/feature/received/received/ReceivedScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/received/ReceivedScreen.kt @@ -71,6 +71,7 @@ fun ReceivedRoute( } LaunchedEffect(key1 = Unit) { + viewModel.addLedgerIfNeed(ledger = ledger) viewModel.updateLedgerIfNeed(ledger = ledger, toDeleteLedgerId = toDeleteLedgerId) } diff --git a/feature/received/src/main/java/com/susu/feature/received/received/ReceivedViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/received/ReceivedViewModel.kt index 6d7d25d5..8df23c9d 100644 --- a/feature/received/src/main/java/com/susu/feature/received/received/ReceivedViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/received/ReceivedViewModel.kt @@ -53,6 +53,22 @@ class ReceivedViewModel @Inject constructor( intent { copy(ledgerList = newList) } } + fun addLedgerIfNeed(ledger: String?) { + val toAddLedger = ledger?.let { + Json.decodeFromUri(ledger) + } ?: return + + if (toAddLedger in currentState.ledgerList) return + + intent { + copy( + ledgerList = currentState + .ledgerList + .add(0, toAddLedger), + ) + } + } + fun showAlignBottomSheet() = intent { copy(showAlignBottomSheet = true) } fun hideAlignBottomSheet() = intent { copy(showAlignBottomSheet = false) } fun navigateLedgerDetail(ledger: Ledger) = postSideEffect(ReceivedEffect.NavigateLedgerDetail(ledger)) From ca2e11c1815931cbde973cf051eb832afe077d68 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sun, 21 Jan 2024 10:27:06 +0900 Subject: [PATCH 12/14] chore: ktlint, detekt --- core/ui/src/main/java/com/susu/core/ui/util/Date.kt | 5 ++--- .../susu/feature/received/ledgeradd/LedgerAddContract.kt | 5 ----- .../susu/feature/received/ledgeradd/LedgerAddScreen.kt | 2 -- .../susu/feature/received/ledgeradd/LedgerAddViewModel.kt | 3 --- .../ledgeradd/content/category/CategoryViewModel.kt | 8 +++++--- .../received/ledgeradd/content/date/DateContent.kt | 2 -- .../received/ledgeradd/content/date/DateContract.kt | 3 --- .../received/ledgeradd/content/date/DateViewModel.kt | 4 +--- .../received/ledgeradd/content/name/NameContract.kt | 3 --- .../received/ledgeradd/content/name/NameViewModel.kt | 6 +----- .../susu/feature/received/search/LedgerSearchScreen.kt | 3 --- 11 files changed, 9 insertions(+), 35 deletions(-) diff --git a/core/ui/src/main/java/com/susu/core/ui/util/Date.kt b/core/ui/src/main/java/com/susu/core/ui/util/Date.kt index a8a4febf..eaafddaf 100644 --- a/core/ui/src/main/java/com/susu/core/ui/util/Date.kt +++ b/core/ui/src/main/java/com/susu/core/ui/util/Date.kt @@ -1,10 +1,8 @@ package com.susu.core.ui.util +import android.util.Log import java.time.DateTimeException -import java.time.LocalDate import java.time.LocalDateTime -import java.time.Month -import java.time.YearMonth import java.time.format.DateTimeFormatter val currentDate: LocalDateTime = LocalDateTime.now() @@ -19,5 +17,6 @@ fun LocalDateTime.to_yyyy_dot_MM_dot_dd(): String { fun getSafeLocalDateTime(year: Int, month: Int, day: Int): LocalDateTime = try { LocalDateTime.of(year, month, day, 0, 0) } catch (e: DateTimeException) { + Log.e("DateTimeError", "Invalid date provided: $year-$month-$day", e) LocalDateTime.of(year, month, 1, 0, 0) } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt index e68da22a..c2866a36 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddContract.kt @@ -1,11 +1,7 @@ package com.susu.feature.received.ledgeradd -import com.susu.core.model.Ledger import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -import com.susu.feature.received.ledgerdetail.LedgerDetailSideEffect -import kotlinx.collections.immutable.PersistentList -import kotlinx.collections.immutable.persistentListOf data class LedgerAddState( val currentStep: LedgerAddStep = LedgerAddStep.CATEGORY, @@ -23,5 +19,4 @@ sealed interface LedgerAddSideEffect : SideEffect { data object PopBackStack : LedgerAddSideEffect data class PopBackStackWithLedger(val ledger: String) : LedgerAddSideEffect data class HandleException(val throwable: Throwable, val retry: () -> Unit) : LedgerAddSideEffect - } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt index 0e5b3d6b..2910b1e1 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt @@ -45,7 +45,6 @@ import com.susu.feature.received.ledgeradd.content.name.NameViewModel import kotlinx.coroutines.android.awaitFrame import kotlinx.coroutines.launch - @Composable fun LedgerAddRoute( viewModel: LedgerAddViewModel = hiltViewModel(), @@ -107,7 +106,6 @@ fun LedgerAddRoute( when (sideEffect) { is DateSideEffect.UpdateParentDate -> viewModel.updateDate(sideEffect.startAt, sideEffect.endAt) } - } BackHandler { diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt index 2c6dd21f..3e795b65 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt @@ -7,11 +7,9 @@ import com.susu.core.ui.base.BaseViewModel import com.susu.core.ui.extension.encodeToUri import com.susu.domain.usecase.ledger.CreateLedgerUseCase import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.launch import kotlinx.datetime.toKotlinLocalDateTime import kotlinx.serialization.json.Json -import timber.log.Timber import java.time.LocalDateTime import javax.inject.Inject @@ -80,5 +78,4 @@ class LedgerAddViewModel @Inject constructor( } intent { copy(isLoading = false) } } - } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryViewModel.kt index fa2977df..fa45f756 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryViewModel.kt @@ -2,7 +2,6 @@ package com.susu.feature.received.Category.category import androidx.lifecycle.viewModelScope import com.susu.core.model.Category -import com.susu.core.model.Ledger import com.susu.core.ui.base.BaseViewModel import com.susu.domain.usecase.categoryconfig.GetCategoryConfigUseCase import com.susu.feature.received.ledgeradd.content.category.CategorySideEffect @@ -20,8 +19,11 @@ class CategoryViewModel @Inject constructor( ) { private val parentSelectedCategory get() = with(currentState) { - if (selectedCategory == customCategory && (customCategory.customCategory.isNullOrEmpty() || isSavedCustomCategory.not())) null - else selectedCategory + if (selectedCategory == customCategory && (customCategory.customCategory.isNullOrEmpty() || isSavedCustomCategory.not())) { + null + } else { + selectedCategory + } } fun getCategoryConfig() = viewModelScope.launch { diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt index 9ccbda66..1de34115 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt @@ -6,14 +6,12 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.susu.core.designsystem.component.bottomsheet.datepicker.SusuDatePickerBottomSheet import com.susu.core.designsystem.component.bottomsheet.datepicker.SusuLimitDatePickerBottomSheet import com.susu.core.designsystem.theme.Gray60 import com.susu.core.designsystem.theme.SusuTheme diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContract.kt index 7b83e0bd..6385f37d 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContract.kt @@ -1,10 +1,7 @@ package com.susu.feature.received.ledgeradd.content.date -import com.susu.core.model.Category import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -import kotlinx.collections.immutable.PersistentList -import kotlinx.collections.immutable.persistentListOf import java.time.LocalDateTime data class DateState( diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt index 6c8dc110..0724095b 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt @@ -3,13 +3,11 @@ package com.susu.feature.received.ledgeradd.content.date import com.susu.core.ui.base.BaseViewModel import com.susu.core.ui.util.getSafeLocalDateTime import dagger.hilt.android.lifecycle.HiltViewModel -import java.time.LocalDate import java.time.LocalDateTime import javax.inject.Inject @HiltViewModel -class DateViewModel @Inject constructor( -) : BaseViewModel( +class DateViewModel @Inject constructor() : BaseViewModel( DateState(), ) { fun updateNameAndCategory(name: String?, categoryName: String?) = intent { diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContract.kt index 6a24d541..09bb6ca4 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContract.kt @@ -1,10 +1,7 @@ package com.susu.feature.received.ledgeradd.content.name -import com.susu.core.model.Category import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -import kotlinx.collections.immutable.PersistentList -import kotlinx.collections.immutable.persistentListOf data class NameState( val name: String = "", diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameViewModel.kt index 6fa527cf..ab9fb5a9 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameViewModel.kt @@ -1,15 +1,11 @@ package com.susu.feature.received.ledgeradd.content.name -import androidx.lifecycle.viewModelScope import com.susu.core.ui.base.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.collections.immutable.toPersistentList -import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel -class NameViewModel @Inject constructor( -) : BaseViewModel( +class NameViewModel @Inject constructor() : BaseViewModel( NameState(), ) { fun updateName(name: String) = intent { diff --git a/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchScreen.kt b/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchScreen.kt index c4da8ab6..7e2619e3 100644 --- a/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/search/LedgerSearchScreen.kt @@ -1,6 +1,5 @@ package com.susu.feature.received.search -import androidx.compose.animation.Crossfade import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -37,7 +36,6 @@ import com.susu.feature.received.R import kotlinx.collections.immutable.PersistentList import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce -import kotlinx.coroutines.flow.filter @OptIn(FlowPreview::class) @Composable @@ -138,7 +136,6 @@ fun LedgerSearchScreen( onClickItem = onClickSearchResultContainer, ) } - } } } From 2ae42b14480f9a5f5a99d57ade4cc900a35ec3ca Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sun, 21 Jan 2024 17:53:35 +0900 Subject: [PATCH 13/14] =?UTF-8?q?refactor:=20=EC=9E=A5=EB=B6=80=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=84=A4=EA=B3=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../received/ledgeradd/LedgerAddScreen.kt | 156 ++++-------------- .../received/ledgeradd/LedgerAddViewModel.kt | 6 +- .../content/category/CategoryContent.kt | 71 ++++++-- .../content/category/CategoryViewModel.kt | 10 +- .../ledgeradd/content/date/DateContent.kt | 41 ++++- .../ledgeradd/content/date/DateViewModel.kt | 6 +- .../ledgeradd/content/name/NameContent.kt | 27 +++ 7 files changed, 171 insertions(+), 146 deletions(-) diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt index 2910b1e1..61f261ec 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddScreen.kt @@ -9,11 +9,11 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -30,27 +30,14 @@ import com.susu.core.model.Category import com.susu.core.ui.R import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec -import com.susu.feature.received.Category.category.CategoryViewModel -import com.susu.feature.received.ledgeradd.content.category.CategoryContent -import com.susu.feature.received.ledgeradd.content.category.CategorySideEffect -import com.susu.feature.received.ledgeradd.content.category.CategoryState -import com.susu.feature.received.ledgeradd.content.date.DateContent -import com.susu.feature.received.ledgeradd.content.date.DateSideEffect -import com.susu.feature.received.ledgeradd.content.date.DateState -import com.susu.feature.received.ledgeradd.content.date.DateViewModel -import com.susu.feature.received.ledgeradd.content.name.NameContent -import com.susu.feature.received.ledgeradd.content.name.NameSideEffect -import com.susu.feature.received.ledgeradd.content.name.NameState -import com.susu.feature.received.ledgeradd.content.name.NameViewModel -import kotlinx.coroutines.android.awaitFrame -import kotlinx.coroutines.launch +import com.susu.feature.received.ledgeradd.content.category.CategoryContentRoute +import com.susu.feature.received.ledgeradd.content.date.DateContentRoute +import com.susu.feature.received.ledgeradd.content.name.NameContentRoute +import java.time.LocalDateTime @Composable fun LedgerAddRoute( viewModel: LedgerAddViewModel = hiltViewModel(), - categoryViewModel: CategoryViewModel = hiltViewModel(), - nameViewModel: NameViewModel = hiltViewModel(), - dateViewModel: DateViewModel = hiltViewModel(), popBackStack: () -> Unit, popBackStackWithLedger: (String) -> Unit, handleException: (Throwable, () -> Unit) -> Unit, @@ -64,48 +51,12 @@ fun LedgerAddRoute( } } - val categoryState = categoryViewModel.uiState.collectAsStateWithLifecycle().value - val focusRequester = remember { FocusRequester() } - val scope = rememberCoroutineScope() - categoryViewModel.sideEffect.collectWithLifecycle { sideEffect -> - when (sideEffect) { - is CategorySideEffect.UpdateParentSelectedCategory -> { - viewModel.updateSelectedCategory(sideEffect.category) - dateViewModel.updateNameAndCategory( - name = null, - categoryName = sideEffect.category?.customCategory ?: sideEffect.category?.name, - ) - } - - CategorySideEffect.FocusCustomCategory -> scope.launch { - awaitFrame() - focusRequester.requestFocus() - } - } - } - - LaunchedEffect(key1 = Unit) { - categoryViewModel.getCategoryConfig() + var dateContentCategoryName: String by remember { + mutableStateOf("") } - val nameState = nameViewModel.uiState.collectAsStateWithLifecycle().value - nameViewModel.sideEffect.collectWithLifecycle { sideEffect -> - when (sideEffect) { - is NameSideEffect.UpdateParentName -> { - viewModel.updateName(sideEffect.name) - dateViewModel.updateNameAndCategory( - name = sideEffect.name, - categoryName = null, - ) - } - } - } - - val dateState = dateViewModel.uiState.collectAsStateWithLifecycle().value - dateViewModel.sideEffect.collectWithLifecycle { sideEffect -> - when (sideEffect) { - is DateSideEffect.UpdateParentDate -> viewModel.updateDate(sideEffect.startAt, sideEffect.endAt) - } + var dateContentName: String by remember { + mutableStateOf("") } BackHandler { @@ -116,26 +67,19 @@ fun LedgerAddRoute( uiState = uiState, onClickBack = viewModel::goToPrevStep, onClickNextButton = viewModel::goToNextStep, - categoryState = categoryState, - focusRequester = focusRequester, - onClickCategoryButton = categoryViewModel::selectCategory, - onClickCustomCategoryButton = categoryViewModel::showCustomCategoryTextField, - onClickCustomCategoryTextFieldCloseIcon = categoryViewModel::hideCustomCategoryTextField, - onClickCustomCategoryTextField = categoryViewModel::selectCustomCategory, - onClickCustomCategoryTextFieldClearIcon = { categoryViewModel.updateCustomCategoryText("") }, - onTextChangeCustomCategoryTextField = categoryViewModel::updateCustomCategoryText, - onClickTextFieldInnerButton = categoryViewModel::toggleTextFieldSaved, - updateParentSelectedCategory = categoryViewModel::updateParentSelectedCategory, - nameState = nameState, - onTextChangeName = nameViewModel::updateName, - dateState = dateState, - onStartDateItemSelected = dateViewModel::updateStartDate, - onClickStartDateText = dateViewModel::showStartDateBottomSheet, - onDismissStartDateBottomSheet = dateViewModel::hideStartDateBottomSheet, - onEndDateItemSelected = dateViewModel::updateEndDate, - onClickEndDateText = dateViewModel::showEndDateBottomSheet, - onDismissEndDateBottomSheet = dateViewModel::hideEndDateBottomSheet, - updateParentDate = dateViewModel::updateParentDate, + updateParentSelectedCategory = { category -> + viewModel.updateSelectedCategory(category) + dateContentCategoryName = category?.customCategory ?: category?.name ?: "" + }, + updateParentName = { name -> + viewModel.updateName(name) + dateContentName = name + }, + dateContentName = dateContentName, + dateContentCategoryName = dateContentCategoryName, + updateParentDate = { startAt, endAt -> + viewModel.updateDate(startAt, endAt) + }, ) } @@ -144,26 +88,11 @@ fun LedgerAddScreen( uiState: LedgerAddState = LedgerAddState(), onClickBack: () -> Unit = {}, onClickNextButton: () -> Unit = {}, - categoryState: CategoryState = CategoryState(), - focusRequester: FocusRequester = remember { FocusRequester() }, - onClickCategoryButton: (Category) -> Unit = {}, - onClickCustomCategoryButton: () -> Unit = {}, - onClickCustomCategoryTextFieldCloseIcon: () -> Unit = {}, - onClickCustomCategoryTextField: () -> Unit = {}, - onClickCustomCategoryTextFieldClearIcon: () -> Unit = {}, - onTextChangeCustomCategoryTextField: (String) -> Unit = {}, - onClickTextFieldInnerButton: () -> Unit = {}, - updateParentSelectedCategory: () -> Unit = {}, - nameState: NameState = NameState(), - onTextChangeName: (String) -> Unit = {}, - dateState: DateState = DateState(), - onStartDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, - onClickStartDateText: () -> Unit = {}, - onDismissStartDateBottomSheet: () -> Unit = {}, - onEndDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, - onClickEndDateText: () -> Unit = {}, - onDismissEndDateBottomSheet: () -> Unit = {}, - updateParentDate: () -> Unit = {}, + updateParentSelectedCategory: (Category?) -> Unit = {}, + updateParentName: (String) -> Unit = {}, + dateContentCategoryName: String = "", + dateContentName: String = "", + updateParentDate: (LocalDateTime?, LocalDateTime?) -> Unit = { _, _ -> }, ) { Box( modifier = Modifier @@ -190,32 +119,17 @@ fun LedgerAddScreen( }, ) { targetState -> when (targetState) { - LedgerAddStep.CATEGORY -> CategoryContent( - uiState = categoryState, - focusRequester = focusRequester, - onClickCategoryButton = onClickCategoryButton, - onClickCustomCategoryButton = onClickCustomCategoryButton, - onClickCustomCategoryTextFieldCloseIcon = onClickCustomCategoryTextFieldCloseIcon, - onClickCustomCategoryTextField = onClickCustomCategoryTextField, - onClickCustomCategoryTextFieldClearIcon = onClickCustomCategoryTextFieldClearIcon, - onTextChangeCustomCategoryTextField = onTextChangeCustomCategoryTextField, - onClickTextFieldInnerButton = onClickTextFieldInnerButton, + LedgerAddStep.CATEGORY -> CategoryContentRoute( updateParentSelectedCategory = updateParentSelectedCategory, ) - LedgerAddStep.NAME -> NameContent( - uiState = nameState, - onTextChangeName = onTextChangeName, + LedgerAddStep.NAME -> NameContentRoute( + updateParentName = updateParentName, ) - LedgerAddStep.DATE -> DateContent( - uiState = dateState, - onStartDateItemSelected = onStartDateItemSelected, - onClickStartDateText = onClickStartDateText, - onDismissStartDateBottomSheet = onDismissStartDateBottomSheet, - onEndDateItemSelected = onEndDateItemSelected, - onClickEndDateText = onClickEndDateText, - onDismissEndDateBottomSheet = onDismissEndDateBottomSheet, + LedgerAddStep.DATE -> DateContentRoute( + name = dateContentName, + categoryName = dateContentCategoryName, updateParentDate = updateParentDate, ) } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt index 3e795b65..200fa96b 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/LedgerAddViewModel.kt @@ -19,8 +19,10 @@ class LedgerAddViewModel @Inject constructor( ) : BaseViewModel( LedgerAddState(), ) { - private var selectedCategory: Category? = null - private var name: String = "" + var selectedCategory: Category? = null + private set + var name: String = "" + private set private var startAt: LocalDateTime? = null private var endAt: LocalDateTime? = null diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContent.kt index 92af6616..566f29ea 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContent.kt @@ -13,11 +13,14 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.susu.core.designsystem.component.button.FilledButtonColor import com.susu.core.designsystem.component.button.GhostButtonColor import com.susu.core.designsystem.component.button.MediumButtonStyle @@ -28,8 +31,63 @@ import com.susu.core.designsystem.component.textfieldbutton.TextFieldButtonColor import com.susu.core.designsystem.component.textfieldbutton.style.MediumTextFieldButtonStyle import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.model.Category +import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.received.R -import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.android.awaitFrame +import kotlinx.coroutines.launch + +@Composable +fun CategoryContentRoute( + viewModel: CategoryViewModel = hiltViewModel(), + updateParentSelectedCategory: (Category?) -> Unit = {}, +) { + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + val focusRequester = remember { FocusRequester() } + val scope = rememberCoroutineScope() + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is CategorySideEffect.UpdateParentSelectedCategory -> { + updateParentSelectedCategory(sideEffect.category) +// viewModel.updateSelectedCategory(sideEffect.category) +// dateViewModel.updateNameAndCategory( +// name = null, +// categoryName = sideEffect.category?.customCategory ?: sideEffect.category?.name, +// ) + } + + CategorySideEffect.FocusCustomCategory -> scope.launch { + awaitFrame() + focusRequester.requestFocus() + } + } + } + + LaunchedEffect(key1 = Unit) { + viewModel.getCategoryConfig() + } + + LaunchedEffect( + key1 = uiState.selectedCategory, + key2 = uiState.isSavedCustomCategory, + ) { + snapshotFlow { uiState.selectedCategory } + .collect { + viewModel.updateParentSelectedCategory() + } + } + + CategoryContent( + uiState = uiState, + focusRequester = focusRequester, + onClickCategoryButton = viewModel::selectCategory, + onClickCustomCategoryButton = viewModel::showCustomCategoryTextField, + onClickCustomCategoryTextFieldCloseIcon = viewModel::hideCustomCategoryTextField, + onClickCustomCategoryTextField = viewModel::selectCustomCategory, + onClickCustomCategoryTextFieldClearIcon = { viewModel.updateCustomCategoryText("") }, + onTextChangeCustomCategoryTextField = viewModel::updateCustomCategoryText, + onClickTextFieldInnerButton = viewModel::toggleTextFieldSaved, + ) +} @Composable fun CategoryContent( @@ -42,18 +100,7 @@ fun CategoryContent( onClickCustomCategoryTextFieldClearIcon: () -> Unit = {}, onTextChangeCustomCategoryTextField: (String) -> Unit = {}, onClickTextFieldInnerButton: () -> Unit = {}, - updateParentSelectedCategory: () -> Unit = {}, ) { - LaunchedEffect( - key1 = uiState.selectedCategory, - key2 = uiState.isSavedCustomCategory, - ) { - snapshotFlow { uiState.selectedCategory } - .collect { - updateParentSelectedCategory() - } - } - val scrollState = rememberScrollState() Column( diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryViewModel.kt index fa45f756..c4d8b580 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryViewModel.kt @@ -1,11 +1,9 @@ -package com.susu.feature.received.Category.category +package com.susu.feature.received.ledgeradd.content.category import androidx.lifecycle.viewModelScope import com.susu.core.model.Category import com.susu.core.ui.base.BaseViewModel import com.susu.domain.usecase.categoryconfig.GetCategoryConfigUseCase -import com.susu.feature.received.ledgeradd.content.category.CategorySideEffect -import com.susu.feature.received.ledgeradd.content.category.CategoryState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.launch @@ -27,6 +25,8 @@ class CategoryViewModel @Inject constructor( } fun getCategoryConfig() = viewModelScope.launch { + if (currentState.categoryConfig.isNotEmpty()) return@launch + getCategoryConfigUseCase() .onSuccess { intent { @@ -75,5 +75,7 @@ class CategoryViewModel @Inject constructor( ) } - fun updateParentSelectedCategory() = postSideEffect(CategorySideEffect.UpdateParentSelectedCategory(parentSelectedCategory)) + fun updateParentSelectedCategory(category: Category? = parentSelectedCategory) = postSideEffect( + CategorySideEffect.UpdateParentSelectedCategory(category), + ) } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt index 1de34115..c992de57 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateContent.kt @@ -12,14 +12,51 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.susu.core.designsystem.component.bottomsheet.datepicker.SusuLimitDatePickerBottomSheet import com.susu.core.designsystem.theme.Gray60 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.util.AnnotatedText import com.susu.core.ui.util.currentDate import com.susu.core.ui.util.minDate import com.susu.feature.received.R import com.susu.feature.received.ledgeradd.content.date.component.SelectDateRow +import java.time.LocalDateTime + +@Composable +fun DateContentRoute( + viewModel: DateViewModel = hiltViewModel(), + name: String, + categoryName: String, + updateParentDate: (LocalDateTime?, LocalDateTime?) -> Unit, +) { + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is DateSideEffect.UpdateParentDate -> updateParentDate(sideEffect.startAt, sideEffect.endAt) + } + } + + LaunchedEffect(key1 = Unit) { + updateParentDate(uiState.startAt, uiState.endAt) + } + + LaunchedEffect(key1 = Unit) { + viewModel.updateNameAndCategory(name, categoryName) + } + + DateContent( + uiState = uiState, + onStartDateItemSelected = viewModel::updateStartDate, + onClickStartDateText = viewModel::showStartDateBottomSheet, + onDismissStartDateBottomSheet = viewModel::hideStartDateBottomSheet, + onEndDateItemSelected = viewModel::updateEndDate, + onClickEndDateText = viewModel::showEndDateBottomSheet, + onDismissEndDateBottomSheet = viewModel::hideEndDateBottomSheet, + ) +} @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -31,11 +68,7 @@ fun DateContent( onEndDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, onClickEndDateText: () -> Unit = {}, onDismissEndDateBottomSheet: () -> Unit = {}, - updateParentDate: () -> Unit = {}, ) { - LaunchedEffect(key1 = Unit) { - updateParentDate() - } Column( modifier = Modifier .fillMaxSize() diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt index 0724095b..c64ac824 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/date/DateViewModel.kt @@ -10,10 +10,10 @@ import javax.inject.Inject class DateViewModel @Inject constructor() : BaseViewModel( DateState(), ) { - fun updateNameAndCategory(name: String?, categoryName: String?) = intent { + fun updateNameAndCategory(name: String, categoryName: String) = intent { copy( - name = name ?: this.name, - categoryName = categoryName ?: this.categoryName, + name = name, + categoryName = categoryName, ) } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt index 01775166..66a09f86 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt @@ -11,10 +11,37 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.susu.core.designsystem.component.textfield.SusuBasicTextField import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.received.R +@Composable +fun NameContentRoute( + viewModel: NameViewModel = hiltViewModel(), + updateParentName: (String) -> Unit = {}, +) { + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is NameSideEffect.UpdateParentName -> { + updateParentName(sideEffect.name) +// dateViewModel.updateNameAndCategory( +// name = sideEffect.name, +// categoryName = null, +// ) + } + } + } + + NameContent( + uiState = uiState, + onTextChangeName = viewModel::updateName, + ) +} + @Composable fun NameContent( uiState: NameState = NameState(), From a9a726131e69c61bd958017f939a39f7ad32d6fe Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sun, 21 Jan 2024 18:00:35 +0900 Subject: [PATCH 14/14] =?UTF-8?q?chore:=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../received/ledgeradd/content/category/CategoryContent.kt | 5 ----- .../feature/received/ledgeradd/content/name/NameContent.kt | 4 ---- 2 files changed, 9 deletions(-) diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContent.kt index 566f29ea..49324d44 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/category/CategoryContent.kt @@ -48,11 +48,6 @@ fun CategoryContentRoute( when (sideEffect) { is CategorySideEffect.UpdateParentSelectedCategory -> { updateParentSelectedCategory(sideEffect.category) -// viewModel.updateSelectedCategory(sideEffect.category) -// dateViewModel.updateNameAndCategory( -// name = null, -// categoryName = sideEffect.category?.customCategory ?: sideEffect.category?.name, -// ) } CategorySideEffect.FocusCustomCategory -> scope.launch { diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt index 66a09f86..0dd35924 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeradd/content/name/NameContent.kt @@ -28,10 +28,6 @@ fun NameContentRoute( when (sideEffect) { is NameSideEffect.UpdateParentName -> { updateParentName(sideEffect.name) -// dateViewModel.updateNameAndCategory( -// name = sideEffect.name, -// categoryName = null, -// ) } } }