diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt index c2701c25..f653eb21 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt @@ -11,6 +11,7 @@ import androidx.navigation.navOptions import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.model.Envelope import com.susu.core.model.EnvelopeDetail +import com.susu.core.model.Friend import com.susu.core.model.Ledger import com.susu.core.model.Vote import com.susu.feature.community.navigation.CommunityRoute @@ -123,8 +124,8 @@ internal class MainNavigator( navController.navigateSentEnvelopeEdit(envelopeDetail) } - fun navigateSentEnvelopeAdd() { - navController.navigateSentEnvelopeAdd() + fun navigateSentEnvelopeAdd(friend: Friend? = null) { + navController.navigateSentEnvelopeAdd(friend) } fun navigateSentEnvelopeSearch() { diff --git a/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeContract.kt b/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeContract.kt index e6d595c8..a35d2040 100644 --- a/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeContract.kt +++ b/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeContract.kt @@ -1,6 +1,7 @@ package com.susu.feature.envelope import com.susu.core.model.EnvelopeSearch +import com.susu.core.model.Friend import com.susu.core.model.FriendStatistics import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState @@ -15,6 +16,7 @@ data class SentEnvelopeState( sealed interface SentEnvelopeSideEffect : SideEffect { data class NavigateEnvelopeDetail(val id: Long) : SentEnvelopeSideEffect + data class NavigateEnvelopeAdd(val friend: Friend) : SentEnvelopeSideEffect data object PopBackStack : SentEnvelopeSideEffect data class PopBackStackWithDeleteFriendId(val id: Long) : SentEnvelopeSideEffect } diff --git a/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeScreen.kt b/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeScreen.kt index 51034e9b..9738e823 100644 --- a/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeScreen.kt +++ b/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeScreen.kt @@ -39,6 +39,7 @@ import com.susu.core.designsystem.component.appbar.icon.BackIcon import com.susu.core.designsystem.component.badge.BadgeColor import com.susu.core.designsystem.component.badge.BadgeStyle import com.susu.core.designsystem.component.badge.SusuBadge +import com.susu.core.designsystem.component.button.SusuFloatingButton import com.susu.core.designsystem.theme.Gray10 import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.Gray20 @@ -46,6 +47,7 @@ import com.susu.core.designsystem.theme.Gray60 import com.susu.core.designsystem.theme.Gray90 import com.susu.core.designsystem.theme.Orange20 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.model.Friend import com.susu.core.ui.extension.OnBottomReached import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.toMoneyFormat @@ -63,6 +65,7 @@ fun SentEnvelopeRoute( popBackStackWithEditedFriendId: (Long) -> Unit, editedFriendId: Long?, navigateSentEnvelopeDetail: (Long) -> Unit, + navigateSentEnvelopeAdd: (Friend) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value val historyListState = rememberLazyListState() @@ -79,6 +82,7 @@ fun SentEnvelopeRoute( is SentEnvelopeSideEffect.NavigateEnvelopeDetail -> navigateSentEnvelopeDetail(sideEffect.id) is SentEnvelopeSideEffect.PopBackStackWithDeleteFriendId -> popBackStackWithDeleteFriendId(sideEffect.id) + is SentEnvelopeSideEffect.NavigateEnvelopeAdd -> navigateSentEnvelopeAdd(sideEffect.friend) } } @@ -107,6 +111,7 @@ fun SentEnvelopeRoute( refreshState = refreshState, onClickBackIcon = viewModel::popBackStack, onClickEnvelopeDetail = viewModel::navigateSentEnvelopeDetail, + onClickAddEnvelope = viewModel::navigateSentEnvelopeAdd, ) } @@ -119,6 +124,7 @@ fun SentEnvelopeScreen( historyListState: LazyListState = rememberLazyListState(), onClickBackIcon: () -> Unit = {}, onClickEnvelopeDetail: (Long) -> Unit = {}, + onClickAddEnvelope: () -> Unit = {}, ) { val sent = uiState.envelopeInfo.sentAmounts val received = uiState.envelopeInfo.receivedAmounts @@ -234,6 +240,13 @@ fun SentEnvelopeScreen( state = refreshState, containerColor = Gray10, ) + + SusuFloatingButton( + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(SusuTheme.spacing.spacing_l), + onClick = onClickAddEnvelope, + ) } } diff --git a/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeViewModel.kt b/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeViewModel.kt index 22e11f9f..75323f83 100644 --- a/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeViewModel.kt +++ b/feature/sent/src/main/java/com/susu/feature/envelope/SentEnvelopeViewModel.kt @@ -58,6 +58,7 @@ class SentEnvelopeViewModel @Inject constructor( } } + fun navigateSentEnvelopeAdd() = postSideEffect(SentEnvelopeSideEffect.NavigateEnvelopeAdd(currentState.envelopeInfo.friend)) fun navigateSentEnvelopeDetail(id: Long) = postSideEffect(SentEnvelopeSideEffect.NavigateEnvelopeDetail(id = id)) fun popBackStack() = postSideEffect(SentEnvelopeSideEffect.PopBackStack) } diff --git a/feature/sent/src/main/java/com/susu/feature/envelopeadd/EnvelopeAddContract.kt b/feature/sent/src/main/java/com/susu/feature/envelopeadd/EnvelopeAddContract.kt index 52705939..598e2072 100644 --- a/feature/sent/src/main/java/com/susu/feature/envelopeadd/EnvelopeAddContract.kt +++ b/feature/sent/src/main/java/com/susu/feature/envelopeadd/EnvelopeAddContract.kt @@ -9,11 +9,16 @@ sealed interface EnvelopeAddEffect : SideEffect { data class HandleException(val throwable: Throwable, val retry: () -> Unit) : EnvelopeAddEffect } +/** + * @param fromEnvelope 보내요 봉투 화면에서 추가 화면으로 진입할 시 true. MORE STEP에서 전화번호를 감추기 위함. + * */ data class EnvelopeAddState( val isLoading: Boolean = false, val buttonEnabled: Boolean = false, val currentStep: EnvelopeAddStep = EnvelopeAddStep.MONEY, val lastPage: Boolean = false, + val friendName: String = "", + val fromEnvelope: Boolean = false, ) : UiState { val buttonResId = if (lastPage) { com.susu.core.ui.R.string.word_done diff --git a/feature/sent/src/main/java/com/susu/feature/envelopeadd/EnvelopeAddViewModel.kt b/feature/sent/src/main/java/com/susu/feature/envelopeadd/EnvelopeAddViewModel.kt index bdee2b79..ee0d323b 100644 --- a/feature/sent/src/main/java/com/susu/feature/envelopeadd/EnvelopeAddViewModel.kt +++ b/feature/sent/src/main/java/com/susu/feature/envelopeadd/EnvelopeAddViewModel.kt @@ -1,24 +1,34 @@ package com.susu.feature.envelopeadd +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import com.susu.core.model.Category +import com.susu.core.model.Friend import com.susu.core.model.Relationship import com.susu.core.ui.MONEY_MAX_VALUE import com.susu.core.ui.base.BaseViewModel +import com.susu.core.ui.extension.decodeFromUri import com.susu.domain.usecase.envelope.CreateSentEnvelopeUseCase +import com.susu.feature.sent.navigation.SentRoute import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import kotlinx.datetime.toKotlinLocalDateTime +import kotlinx.serialization.json.Json import java.time.LocalDateTime import javax.inject.Inject @HiltViewModel class EnvelopeAddViewModel @Inject constructor( private val createSentEnvelopeUseCase: CreateSentEnvelopeUseCase, + savedStateHandle: SavedStateHandle, ) : BaseViewModel(EnvelopeAddState()) { + private val friendArgument = runCatching { + savedStateHandle.get(SentRoute.FRIEND_ARGUMENT_NAME)?.let { + Json.decodeFromUri(it) + } + }.getOrNull() private var money: Long = 0 - private var name: String = "" private var friendId: Long? = null private var relationShip: Relationship? = null private var category: Category? = null @@ -29,12 +39,21 @@ class EnvelopeAddViewModel @Inject constructor( private var phoneNumber: String? = null private var memo: String? = null + fun initData() { + friendArgument?.let { + updateFriendId(it.id) + updateName(it.name) + updatePhoneNumber(it.phoneNumber.ifEmpty { null }) + intent { copy(fromEnvelope = true) } + } ?: intent { copy(fromEnvelope = false) } + } + private fun createEnvelope() { viewModelScope.launch { createSentEnvelopeUseCase( param = CreateSentEnvelopeUseCase.Param( friendId = friendId, - friendName = name, + friendName = currentState.friendName, phoneNumber = phoneNumber, relationshipId = relationShip?.id, customRelation = relationShip?.customRelation, @@ -55,7 +74,14 @@ class EnvelopeAddViewModel @Inject constructor( fun goNextStep() { when (uiState.value.currentStep) { - EnvelopeAddStep.MONEY -> intent { copy(currentStep = EnvelopeAddStep.NAME) } + EnvelopeAddStep.MONEY -> { + if (friendArgument == null) { + intent { copy(currentStep = EnvelopeAddStep.NAME) } + } else { + intent { copy(currentStep = EnvelopeAddStep.EVENT) } + } + } + EnvelopeAddStep.NAME -> { intent { if (friendId == null) { @@ -89,13 +115,12 @@ class EnvelopeAddViewModel @Inject constructor( EnvelopeAddStep.NAME -> intent { copy(currentStep = EnvelopeAddStep.MONEY) } EnvelopeAddStep.RELATIONSHIP -> intent { copy(currentStep = EnvelopeAddStep.NAME) } EnvelopeAddStep.EVENT -> { - intent { - if (friendId == null) { - copy(currentStep = EnvelopeAddStep.RELATIONSHIP) - } else { - copy(currentStep = EnvelopeAddStep.NAME) - } + val prevStep = when { + friendId == null -> EnvelopeAddStep.RELATIONSHIP + friendArgument != null -> EnvelopeAddStep.MONEY + else -> EnvelopeAddStep.NAME } + intent { copy(currentStep = prevStep) } } EnvelopeAddStep.DATE -> intent { copy(currentStep = EnvelopeAddStep.EVENT) } @@ -125,8 +150,7 @@ class EnvelopeAddViewModel @Inject constructor( } fun updateName(name: String) = intent { - this@EnvelopeAddViewModel.name = name - copy(buttonEnabled = name.isNotEmpty()) + copy(friendName = name, buttonEnabled = name.isNotEmpty()) } fun updateFriendId(friendId: Long?) { diff --git a/feature/sent/src/main/java/com/susu/feature/envelopeadd/SentEnvelopeAddScreen.kt b/feature/sent/src/main/java/com/susu/feature/envelopeadd/SentEnvelopeAddScreen.kt index 63be65cb..0739bdcf 100644 --- a/feature/sent/src/main/java/com/susu/feature/envelopeadd/SentEnvelopeAddScreen.kt +++ b/feature/sent/src/main/java/com/susu/feature/envelopeadd/SentEnvelopeAddScreen.kt @@ -8,6 +8,7 @@ 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 @@ -59,12 +60,12 @@ fun SentEnvelopeAddRoute( } } - var friendName by remember { + var categoryName by remember { mutableStateOf("") } - var categoryName by remember { - mutableStateOf("") + LaunchedEffect(key1 = Unit) { + viewModel.initData() } BackHandler { @@ -73,15 +74,11 @@ fun SentEnvelopeAddRoute( SentEnvelopeAddScreen( uiState = uiState, - friendName = friendName, categoryName = categoryName, onClickBack = viewModel::goPrevStep, onClickNext = viewModel::goNextStep, updateParentMoney = viewModel::updateMoney, - updateParentName = { name -> - viewModel.updateName(name) - friendName = name - }, + updateParentName = viewModel::updateName, updateParentFriendId = viewModel::updateFriendId, updateParentSelectedRelation = viewModel::updateSelectedRelationShip, updateParentCategory = { category -> @@ -101,7 +98,6 @@ fun SentEnvelopeAddRoute( @Composable fun SentEnvelopeAddScreen( uiState: EnvelopeAddState = EnvelopeAddState(), - friendName: String = "", onClickBack: () -> Unit = {}, onClickNext: () -> Unit = {}, updateParentMoney: (Long) -> Unit = {}, @@ -165,11 +161,12 @@ fun SentEnvelopeAddScreen( ) EnvelopeAddStep.DATE -> DateContentRoute( - friendName = friendName, + friendName = uiState.friendName, updateParentDate = updateParentDate, ) EnvelopeAddStep.MORE -> MoreContentRoute( + fromEnvelope = uiState.fromEnvelope, updateParentMoreStep = updateParentMoreStep, ) @@ -184,7 +181,7 @@ fun SentEnvelopeAddScreen( ) EnvelopeAddStep.PHONE -> PhoneContentRoute( - friendName = friendName, + friendName = uiState.friendName, updateParentPhone = updateParentPhoneNumber, onShowSnackbar = onShowSnackbar, ) diff --git a/feature/sent/src/main/java/com/susu/feature/envelopeadd/content/more/MoreContent.kt b/feature/sent/src/main/java/com/susu/feature/envelopeadd/content/more/MoreContent.kt index e49d815a..bd447079 100644 --- a/feature/sent/src/main/java/com/susu/feature/envelopeadd/content/more/MoreContent.kt +++ b/feature/sent/src/main/java/com/susu/feature/envelopeadd/content/more/MoreContent.kt @@ -34,6 +34,7 @@ import com.susu.feature.sent.R @Composable fun MoreContentRoute( viewModel: MoreViewModel = hiltViewModel(), + fromEnvelope: Boolean, updateParentMoreStep: (List) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value @@ -45,6 +46,7 @@ fun MoreContentRoute( MoreContent( uiState = uiState, + fromEnvelope = fromEnvelope, onClickStepButton = viewModel::toggleStep, ) } @@ -57,6 +59,7 @@ fun MoreContent( vertical = SusuTheme.spacing.spacing_xl, ), uiState: MoreState = MoreState(), + fromEnvelope: Boolean = false, onClickStepButton: (EnvelopeAddStep) -> Unit = {}, ) { val scrollState = rememberScrollState() @@ -88,7 +91,9 @@ fun MoreContent( Column( verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), ) { - moreStep.forEach { (step, stringRes) -> + for ((step, stringRes) in moreStep) { + if (fromEnvelope && step == EnvelopeAddStep.PHONE) continue + if (step in uiState.selectedMoreStop) { SusuFilledButton( color = FilledButtonColor.Orange, diff --git a/feature/sent/src/main/java/com/susu/feature/sent/navigation/SentNavigation.kt b/feature/sent/src/main/java/com/susu/feature/sent/navigation/SentNavigation.kt index 64f5bcd6..c7d2fc3f 100644 --- a/feature/sent/src/main/java/com/susu/feature/sent/navigation/SentNavigation.kt +++ b/feature/sent/src/main/java/com/susu/feature/sent/navigation/SentNavigation.kt @@ -8,6 +8,7 @@ import androidx.navigation.NavType import androidx.navigation.compose.composable import androidx.navigation.navArgument import com.susu.core.model.EnvelopeDetail +import com.susu.core.model.Friend import com.susu.core.ui.DialogToken import com.susu.core.ui.SnackbarToken import com.susu.core.ui.extension.encodeToUri @@ -36,8 +37,8 @@ fun NavController.navigateSentEnvelopeEdit(envelopeDetail: EnvelopeDetail) { navigate(SentRoute.sentEnvelopeEditRoute(Json.encodeToUri(envelopeDetail))) } -fun NavController.navigateSentEnvelopeAdd() { - navigate(SentRoute.sentEnvelopeAddRoute) +fun NavController.navigateSentEnvelopeAdd(friend: Friend?) { + navigate(SentRoute.sentEnvelopeAddRoute(Json.encodeToUri(friend))) } fun NavController.navigateSentEnvelopeSearch() { @@ -57,7 +58,7 @@ fun NavGraphBuilder.sentNavGraph( navigateSentEnvelope: (Long) -> Unit, navigateSentEnvelopeDetail: (Long) -> Unit, navigateSentEnvelopeEdit: (EnvelopeDetail) -> Unit, - navigateSentEnvelopeAdd: () -> Unit, + navigateSentEnvelopeAdd: (Friend?) -> Unit, navigateSentEnvelopeSearch: () -> Unit, navigateEnvelopeFilter: (String) -> Unit, onShowSnackbar: (SnackbarToken) -> Unit, @@ -81,7 +82,7 @@ fun NavGraphBuilder.sentNavGraph( editedFriendId = editedFriendId, refresh = refresh, navigateSentEnvelope = navigateSentEnvelope, - navigateSentEnvelopeAdd = navigateSentEnvelopeAdd, + navigateSentEnvelopeAdd = { navigateSentEnvelopeAdd(null) }, navigateSentEnvelopeSearch = navigateSentEnvelopeSearch, navigateEnvelopeFilter = navigateEnvelopeFilter, ) @@ -102,6 +103,7 @@ fun NavGraphBuilder.sentNavGraph( popBackStackWithEditedFriendId = popBackStackWithEditedFriendId, navigateSentEnvelopeDetail = navigateSentEnvelopeDetail, popBackStackWithDeleteFriendId = popBackStackWithDeleteFriendId, + navigateSentEnvelopeAdd = navigateSentEnvelopeAdd, ) } @@ -134,7 +136,7 @@ fun NavGraphBuilder.sentNavGraph( ) } - composable(route = SentRoute.sentEnvelopeAddRoute) { + composable(route = SentRoute.sentEnvelopeAddRoute("{${SentRoute.FRIEND_ARGUMENT_NAME}}")) { SentEnvelopeAddRoute( popBackStack = popBackStack, popBackStackWithRefresh = popBackStackWithRefresh, @@ -163,8 +165,10 @@ fun NavGraphBuilder.sentNavGraph( object SentRoute { const val route = "sent" - const val sentEnvelopeAddRoute = "sent-envelope-add" const val SENT_REFRESH_ARGUMENT_NAME = "sent-refresh" + fun sentEnvelopeAddRoute(friend: String) = "sent-envelope-add/$friend" + const val FRIEND_ARGUMENT_NAME = "sent-friend" + fun sentEnvelopeRoute(id: String) = "sent-envelope/$id" const val FRIEND_ID_ARGUMENT_NAME = "sent-envelope-id" const val EDITED_FRIEND_ID_ARGUMENT_NAME = "edited-friend-id"