From f4f3f3bfe39cc6e9d6570e4690c30a4ec49fbd94 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sun, 21 Jan 2024 10:22:39 +0900 Subject: [PATCH 01/28] feat: ReceivedEnvelopeAddContract.kt, ReceivedEnvelopeAddViewModel --- .../ReceivedEnvelopeAddContract.kt | 14 +++++++++++ .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 5 ++++ .../ReceivedEnvelopeAddViewModel.kt | 24 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt new file mode 100644 index 00000000..4b773ea7 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt @@ -0,0 +1,14 @@ +package com.susu.feature.received.envelopeadd + +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState + +data class ReceivedEnvelopeAddState( + val temp: String = "", +) : UiState + +sealed interface ReceivedEnvelopeAddSideEffect : SideEffect { + data object PopBackStack : ReceivedEnvelopeAddSideEffect + data class ShowSnackbar(val msg: String) : ReceivedEnvelopeAddSideEffect + data class HandleException(val throwable: Throwable, val retry: () -> Unit) : ReceivedEnvelopeAddSideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index 865a75dc..4ff2ee18 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -15,6 +15,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 @@ -45,8 +47,11 @@ enum class EnvelopeAddStep { @Composable fun ReceivedEnvelopeAddRoute( + viewModel: ReceivedEnvelopeAddViewModel = hiltViewModel(), popBackStack: () -> Unit, ) { + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + var currentStep by remember { mutableStateOf(EnvelopeAddStep.MONEY) } ReceivedEnvelopeAddScreen( diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt new file mode 100644 index 00000000..40682c2b --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -0,0 +1,24 @@ +package com.susu.feature.received.envelopeadd + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import com.susu.core.model.Ledger +import com.susu.core.model.exception.NotFoundLedgerException +import com.susu.core.ui.base.BaseViewModel +import com.susu.core.ui.extension.decodeFromUri +import com.susu.core.ui.extension.encodeToUri +import com.susu.core.ui.util.to_yyyy_dot_MM_dot_dd +import com.susu.domain.usecase.ledger.DeleteLedgerUseCase +import com.susu.feature.received.navigation.ReceivedRoute +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import kotlinx.datetime.toJavaLocalDateTime +import kotlinx.serialization.json.Json +import javax.inject.Inject + +@HiltViewModel +class ReceivedEnvelopeAddViewModel @Inject constructor( +) : BaseViewModel( + ReceivedEnvelopeAddState(), +) { +} From 6aace0701da39001d92b87b6e9fdaa10ef5fbb8a Mon Sep 17 00:00:00 2001 From: jinukeu Date: Mon, 22 Jan 2024 01:13:35 +0900 Subject: [PATCH 02/28] =?UTF-8?q?feat:=20ReceivedEnvelopeAdd=20Contract,?= =?UTF-8?q?=20ViewModel=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReceivedEnvelopeAddContract.kt | 17 +++++- .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 57 +++++++------------ .../ReceivedEnvelopeAddViewModel.kt | 41 +++++++++++++ .../received/ledgeradd/LedgerAddViewModel.kt | 6 +- .../received/navigation/ReceivedNavigation.kt | 1 + 5 files changed, 81 insertions(+), 41 deletions(-) diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt index 4b773ea7..f06a54a6 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt @@ -2,13 +2,26 @@ package com.susu.feature.received.envelopeadd import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState +import com.susu.feature.received.ledgeradd.LedgerAddStep data class ReceivedEnvelopeAddState( - val temp: String = "", + val currentStep: EnvelopeAddStep = EnvelopeAddStep.MONEY, + val buttonEnabled: Boolean = false, + val isLoading: Boolean = false, ) : UiState +enum class EnvelopeAddStep { + MONEY, + NAME, + RELATIONSHIP, + MORE, + VISITED, + PRESENT, + PHONE, + MEMO, +} + sealed interface ReceivedEnvelopeAddSideEffect : SideEffect { data object PopBackStack : ReceivedEnvelopeAddSideEffect - data class ShowSnackbar(val msg: String) : ReceivedEnvelopeAddSideEffect data class HandleException(val throwable: Throwable, val retry: () -> Unit) : ReceivedEnvelopeAddSideEffect } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index 4ff2ee18..8e4ef5da 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -1,5 +1,6 @@ package com.susu.feature.received.envelopeadd +import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column @@ -23,6 +24,7 @@ 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.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec import com.susu.feature.received.R import com.susu.feature.received.envelopeadd.content.MemoContent @@ -34,49 +36,34 @@ import com.susu.feature.received.envelopeadd.content.PresentContent import com.susu.feature.received.envelopeadd.content.RelationshipContent import com.susu.feature.received.envelopeadd.content.VisitedContent -enum class EnvelopeAddStep { - MONEY, - NAME, - RELATIONSHIP, - MORE, - VISITED, - PRESENT, - PHONE, - MEMO, -} - @Composable fun ReceivedEnvelopeAddRoute( viewModel: ReceivedEnvelopeAddViewModel = hiltViewModel(), popBackStack: () -> Unit, + handleException: (Throwable, () -> Unit) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is ReceivedEnvelopeAddSideEffect.HandleException -> handleException(sideEffect.throwable, sideEffect.retry) + ReceivedEnvelopeAddSideEffect.PopBackStack -> popBackStack() + } + } - var currentStep by remember { mutableStateOf(EnvelopeAddStep.MONEY) } + BackHandler { + viewModel.goToPrevStep() + } ReceivedEnvelopeAddScreen( - currentStep = currentStep, - onClickBack = popBackStack, - onClickNext = { - // TODO: 수정 필요 (MORE 이후 분리 필요) - currentStep = when (currentStep) { - EnvelopeAddStep.MONEY -> EnvelopeAddStep.NAME - EnvelopeAddStep.NAME -> EnvelopeAddStep.RELATIONSHIP - EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.MORE - EnvelopeAddStep.MORE -> EnvelopeAddStep.VISITED - EnvelopeAddStep.VISITED -> EnvelopeAddStep.PRESENT - EnvelopeAddStep.PRESENT -> EnvelopeAddStep.PHONE - EnvelopeAddStep.PHONE -> EnvelopeAddStep.MEMO - else -> EnvelopeAddStep.MEMO - } - }, + uiState = uiState, + onClickBack = viewModel::goToPrevStep, + onClickNext = viewModel::goToNextStep, ) } @Composable fun ReceivedEnvelopeAddScreen( - modifier: Modifier = Modifier, - currentStep: EnvelopeAddStep = EnvelopeAddStep.MONEY, + uiState: ReceivedEnvelopeAddState = ReceivedEnvelopeAddState(), onClickBack: () -> Unit = {}, onClickNext: () -> Unit = {}, ) { @@ -87,7 +74,7 @@ fun ReceivedEnvelopeAddScreen( val visitedList = listOf("예", "아니요") Column( - modifier = modifier + modifier = Modifier .background(SusuTheme.colorScheme.background15) .fillMaxSize(), ) { @@ -97,13 +84,13 @@ fun ReceivedEnvelopeAddScreen( onClick = onClickBack, ) }, - currentStep = currentStep.ordinal + 1, + currentStep = uiState.currentStep.ordinal + 1, entireStep = EnvelopeAddStep.entries.size, ) AnimatedContent( - modifier = modifier.weight(1f), - targetState = currentStep, - label = "SentEnvelopeAddScreen", + modifier = Modifier.weight(1f), + targetState = uiState.currentStep, + label = "ReceivedEnvelopeAddScreen", transitionSpec = { susuDefaultAnimatedContentTransitionSpec( leftDirectionCondition = targetState.ordinal > initialState.ordinal, @@ -130,7 +117,7 @@ fun ReceivedEnvelopeAddScreen( shape = RectangleShape, text = stringResource(id = com.susu.core.ui.R.string.word_next), onClick = onClickNext, - modifier = modifier + modifier = Modifier .fillMaxWidth() .imePadding(), ) diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index 40682c2b..be1dba3a 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -2,6 +2,7 @@ package com.susu.feature.received.envelopeadd import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope +import com.susu.core.model.Category import com.susu.core.model.Ledger import com.susu.core.model.exception.NotFoundLedgerException import com.susu.core.ui.base.BaseViewModel @@ -9,11 +10,15 @@ import com.susu.core.ui.extension.decodeFromUri import com.susu.core.ui.extension.encodeToUri import com.susu.core.ui.util.to_yyyy_dot_MM_dot_dd import com.susu.domain.usecase.ledger.DeleteLedgerUseCase +import com.susu.feature.received.ledgeradd.LedgerAddSideEffect +import com.susu.feature.received.ledgeradd.LedgerAddStep import com.susu.feature.received.navigation.ReceivedRoute import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import kotlinx.datetime.toJavaLocalDateTime +import kotlinx.datetime.toKotlinLocalDateTime import kotlinx.serialization.json.Json +import java.time.LocalDateTime import javax.inject.Inject @HiltViewModel @@ -21,4 +26,40 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( ) : BaseViewModel( ReceivedEnvelopeAddState(), ) { + fun goToPrevStep() = intent { + val prevStep = when (currentState.currentStep) { + EnvelopeAddStep.MONEY -> { + postSideEffect(ReceivedEnvelopeAddSideEffect.PopBackStack) + EnvelopeAddStep.MONEY + } + + EnvelopeAddStep.NAME -> EnvelopeAddStep.MONEY + EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.NAME + EnvelopeAddStep.MORE -> EnvelopeAddStep.RELATIONSHIP + EnvelopeAddStep.VISITED -> EnvelopeAddStep.MORE + EnvelopeAddStep.PRESENT -> EnvelopeAddStep.VISITED + EnvelopeAddStep.PHONE -> EnvelopeAddStep.PRESENT + EnvelopeAddStep.MEMO -> EnvelopeAddStep.PHONE + } + + copy(currentStep = prevStep) + } + + fun goToNextStep() = intent { + val nextStep = when (currentState.currentStep) { + EnvelopeAddStep.MONEY -> EnvelopeAddStep.NAME + EnvelopeAddStep.NAME -> EnvelopeAddStep.RELATIONSHIP + EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.MORE + EnvelopeAddStep.MORE -> EnvelopeAddStep.VISITED + EnvelopeAddStep.VISITED -> EnvelopeAddStep.PRESENT + EnvelopeAddStep.PRESENT -> EnvelopeAddStep.PHONE + EnvelopeAddStep.PHONE -> EnvelopeAddStep.MEMO + EnvelopeAddStep.MEMO -> { + /* 봉투 생성 */ + EnvelopeAddStep.MEMO + } + } + + copy(currentStep = nextStep) + } } 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 200fa96b..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 @@ -19,10 +19,8 @@ class LedgerAddViewModel @Inject constructor( ) : BaseViewModel( LedgerAddState(), ) { - var selectedCategory: Category? = null - private set - var name: String = "" - private set + private var selectedCategory: Category? = null + private var name: String = "" private var startAt: LocalDateTime? = null private var endAt: LocalDateTime? = null 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 415b51b1..b73fe44a 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 @@ -147,6 +147,7 @@ fun NavGraphBuilder.receivedNavGraph( ) { ReceivedEnvelopeAddRoute( popBackStack = popBackStack, + handleException = handleException, ) } From 088cd7670e9c3e9deec7e26bc539b9e435cdd92e Mon Sep 17 00:00:00 2001 From: syb8200 Date: Sat, 20 Jan 2024 23:21:10 +0900 Subject: [PATCH 03/28] =?UTF-8?q?feat:=20=EB=B3=B4=EB=82=B4=EC=9A=94=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=84=9C=EB=B2=84=20=ED=86=B5?= =?UTF-8?q?=EC=8B=A0=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/susu/core/model/Envelope.kt | 8 ++++ .../main/java/com/susu/core/model/Friend.kt | 10 +++++ .../com/susu/data/data/di/RepositoryModule.kt | 7 ++++ .../repository/EnvelopesRepositoryImpl.kt | 27 +++++++++++++ .../susu/data/remote/api/EnvelopesService.kt | 18 +++++++++ .../susu/data/remote/di/ApiServiceModule.kt | 9 ++++- .../model/response/EnvelopesListResponse.kt | 26 +++++++++++++ .../model/response/EnvelopesResponse.kt | 39 +++++++++++++++++++ .../domain/repository/EnvelopesRepository.kt | 14 +++++++ .../envelope/GetEnvelopesListUseCase.kt | 31 +++++++++++++++ .../com/susu/feature/sent/SentContract.kt | 19 +++++++++ .../com/susu/feature/sent/SentViewModel.kt | 21 ++++++++++ 12 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 core/model/src/main/java/com/susu/core/model/Envelope.kt create mode 100644 core/model/src/main/java/com/susu/core/model/Friend.kt create mode 100644 data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt create mode 100644 data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt create mode 100644 data/src/main/java/com/susu/data/remote/model/response/EnvelopesListResponse.kt create mode 100644 data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt create mode 100644 domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt create mode 100644 domain/src/main/java/com/susu/domain/usecase/envelope/GetEnvelopesListUseCase.kt create mode 100644 feature/sent/src/main/java/com/susu/feature/sent/SentContract.kt create mode 100644 feature/sent/src/main/java/com/susu/feature/sent/SentViewModel.kt diff --git a/core/model/src/main/java/com/susu/core/model/Envelope.kt b/core/model/src/main/java/com/susu/core/model/Envelope.kt new file mode 100644 index 00000000..8877563d --- /dev/null +++ b/core/model/src/main/java/com/susu/core/model/Envelope.kt @@ -0,0 +1,8 @@ +package com.susu.core.model + +data class Envelope( + val friend: Friend = Friend(), + val receivedAmounts: Int = 0, + val sentAmounts: Int = 0, + val totalAmounts: Int = 0, +) diff --git a/core/model/src/main/java/com/susu/core/model/Friend.kt b/core/model/src/main/java/com/susu/core/model/Friend.kt new file mode 100644 index 00000000..cd92c296 --- /dev/null +++ b/core/model/src/main/java/com/susu/core/model/Friend.kt @@ -0,0 +1,10 @@ +package com.susu.core.model + +data class Friend( + val id: Int = 0, + val uid: Int = 0, + val name: String = "", + val phoneNumber: String = "", + val createdAt: String = "", + val modifiedAt: String = "", +) diff --git a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt index 9eaffd4a..9fa47264 100644 --- a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt +++ b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt @@ -2,6 +2,7 @@ package com.susu.data.data.di import com.susu.data.data.repository.CategoryConfigRepositoryImpl import com.susu.data.data.repository.ExcelRepositoryImpl +import com.susu.data.data.repository.EnvelopesRepositoryImpl import com.susu.data.data.repository.LedgerRecentSearchRepositoryImpl import com.susu.data.data.repository.LedgerRepositoryImpl import com.susu.data.data.repository.LoginRepositoryImpl @@ -10,6 +11,7 @@ import com.susu.data.data.repository.TermRepositoryImpl import com.susu.data.data.repository.TokenRepositoryImpl import com.susu.data.data.repository.UserRepositoryImpl import com.susu.domain.repository.CategoryConfigRepository +import com.susu.domain.repository.EnvelopesRepository import com.susu.domain.repository.ExcelRepository import com.susu.domain.repository.LedgerRecentSearchRepository import com.susu.domain.repository.LedgerRepository @@ -71,4 +73,9 @@ abstract class RepositoryModule { abstract fun bindExcelRepository( excelRepositoryImpl: ExcelRepositoryImpl, ): ExcelRepository + + @Binds + abstract fun bindEnvelopesRepository( + envelopesRepositoryImpl: EnvelopesRepositoryImpl, + ): EnvelopesRepository } diff --git a/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt new file mode 100644 index 00000000..c9078b98 --- /dev/null +++ b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt @@ -0,0 +1,27 @@ +package com.susu.data.data.repository + +import com.susu.core.model.Envelope +import com.susu.data.remote.api.EnvelopesService +import com.susu.data.remote.model.response.toModel +import com.susu.domain.repository.EnvelopesRepository +import javax.inject.Inject + +class EnvelopesRepositoryImpl @Inject constructor( + private val envelopesService: EnvelopesService, +) : EnvelopesRepository { + override suspend fun getEnvelopesList( + friendIds: List?, + fromTotalAmounts: Int?, + toTotalAmounts: Int?, + page: Int?, + size: Int?, + sort: String?, + ): List = envelopesService.getEnvelopesList( + friendIds = friendIds, + fromTotalAmounts = fromTotalAmounts, + toTotalMounts = toTotalAmounts, + page = page, + size = size, + sort = sort, + ).getOrThrow().toModel() +} diff --git a/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt b/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt new file mode 100644 index 00000000..010ea7dc --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt @@ -0,0 +1,18 @@ +package com.susu.data.remote.api + +import com.susu.data.remote.model.response.EnvelopesListResponse +import com.susu.data.remote.retrofit.ApiResult +import retrofit2.http.GET +import retrofit2.http.Query + +interface EnvelopesService { + @GET("envelopes/friend-statistics") + suspend fun getEnvelopesList( + @Query("friendIds") friendIds: List?, + @Query("fromTotalAmounts") fromTotalAmounts: Int?, + @Query("toTotalAmounts") toTotalMounts: Int?, + @Query("page") page: Int?, + @Query("size") size: Int?, + @Query("sort") sort: String?, + ): ApiResult +} diff --git a/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt b/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt index 5b4f7dd4..26559bef 100644 --- a/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt +++ b/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt @@ -2,6 +2,7 @@ package com.susu.data.remote.di import com.susu.data.remote.api.AuthService import com.susu.data.remote.api.CategoryService +import com.susu.data.remote.api.EnvelopesService import com.susu.data.remote.api.LedgerService import com.susu.data.remote.api.SignUpService import com.susu.data.remote.api.TermService @@ -20,7 +21,7 @@ object ApiServiceModule { @Singleton @Provides - fun provideUserService(retrofit: Retrofit): AuthService { + fun provideAuthService(retrofit: Retrofit): AuthService { return retrofit.create(AuthService::class.java) } @@ -54,6 +55,12 @@ object ApiServiceModule { return retrofit.create(CategoryService::class.java) } + @Singleton + @Provides + fun providesEnvelopeService(retrofit: Retrofit): EnvelopesService { + return retrofit.create(EnvelopesService::class.java) + } + @Singleton @Provides fun providesUserService(retrofit: Retrofit): UserService { diff --git a/data/src/main/java/com/susu/data/remote/model/response/EnvelopesListResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/EnvelopesListResponse.kt new file mode 100644 index 00000000..ac76868f --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/response/EnvelopesListResponse.kt @@ -0,0 +1,26 @@ +package com.susu.data.remote.model.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class EnvelopesListResponse( + @SerialName("data") + val envelopesList: List, + val page: Int, + val size: Int, + val sort: Sort, + val totalCount: Int, + val totalPage: Int, +) + +@Serializable +data class Sort( + val empty: Boolean, + val sorted: Boolean, + val unsorted: Boolean, +) + +internal fun EnvelopesListResponse.toModel() = this.envelopesList.map { envelopes -> + envelopes.toModel() +} diff --git a/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt new file mode 100644 index 00000000..83d1218d --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt @@ -0,0 +1,39 @@ +package com.susu.data.remote.model.response + +import com.susu.core.model.Envelope +import com.susu.core.model.Friend +import kotlinx.serialization.Serializable + +@Serializable +data class EnvelopesResponse( + val friend: FriendInfo, + val receivedAmounts: Int, + val sentAmounts: Int, + val totalAmounts: Int, +) + +@Serializable +data class FriendInfo( + val id: Int, + val uid: Int, + val createdAt: String, + val modifiedAt: String, + val name: String, + val phoneNumber: String, +) + +internal fun FriendInfo.toModel() = Friend( + id = id, + uid = uid, + name = name, + phoneNumber = phoneNumber, + createdAt = createdAt, + modifiedAt = modifiedAt, +) + +internal fun EnvelopesResponse.toModel() = Envelope( + friend = friend.toModel(), + receivedAmounts = receivedAmounts, + sentAmounts = sentAmounts, + totalAmounts = totalAmounts, +) diff --git a/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt b/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt new file mode 100644 index 00000000..c9348c70 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt @@ -0,0 +1,14 @@ +package com.susu.domain.repository + +import com.susu.core.model.Envelope + +interface EnvelopesRepository { + suspend fun getEnvelopesList( + friendIds: List?, + fromTotalAmounts: Int?, + toTotalAmounts: Int?, + page: Int?, + size: Int?, + sort: String?, + ): List +} diff --git a/domain/src/main/java/com/susu/domain/usecase/envelope/GetEnvelopesListUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/envelope/GetEnvelopesListUseCase.kt new file mode 100644 index 00000000..ae47170b --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/envelope/GetEnvelopesListUseCase.kt @@ -0,0 +1,31 @@ +package com.susu.domain.usecase.envelope + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.EnvelopesRepository +import javax.inject.Inject + +class GetEnvelopesListUseCase @Inject constructor( + private val envelopesRepository: EnvelopesRepository, +) { + suspend operator fun invoke(param: Param) = runCatchingIgnoreCancelled { + with(param) { + envelopesRepository.getEnvelopesList( + friendIds = friendIds, + fromTotalAmounts = fromTotalAmounts, + toTotalAmounts = toTotalAmounts, + page = page, + size = size, + sort = sort, + ) + } + } + + data class Param( + val friendIds: List? = emptyList(), + val fromTotalAmounts: Int? = null, + val toTotalAmounts: Int? = null, + val page: Int? = null, + val size: Int? = null, + val sort: String? = null, + ) +} diff --git a/feature/sent/src/main/java/com/susu/feature/sent/SentContract.kt b/feature/sent/src/main/java/com/susu/feature/sent/SentContract.kt new file mode 100644 index 00000000..8c897ddc --- /dev/null +++ b/feature/sent/src/main/java/com/susu/feature/sent/SentContract.kt @@ -0,0 +1,19 @@ +package com.susu.feature.sent + +import com.susu.core.model.Envelope +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 SentState( + val isLoading: Boolean = false, + val envelopesList: PersistentList = persistentListOf(), + val showEmptyEnvelopes: Boolean = false, +) : UiState + +sealed interface SentSideEffect : SideEffect { + data object NavigateEnvelopeDetail : SentSideEffect + data object NavigateEnvelopeAdd : SentSideEffect + data object NavigateEnvelopeSearch : SentSideEffect +} diff --git a/feature/sent/src/main/java/com/susu/feature/sent/SentViewModel.kt b/feature/sent/src/main/java/com/susu/feature/sent/SentViewModel.kt new file mode 100644 index 00000000..2bbeba06 --- /dev/null +++ b/feature/sent/src/main/java/com/susu/feature/sent/SentViewModel.kt @@ -0,0 +1,21 @@ +package com.susu.feature.sent + +import androidx.lifecycle.viewModelScope +import com.susu.core.ui.base.BaseViewModel +import com.susu.domain.usecase.envelope.GetEnvelopesListUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class SentViewModel @Inject constructor( + private val getEnvelopesListUseCase: GetEnvelopesListUseCase, +) : BaseViewModel( + SentState(), +) { + private var page = 0 + + fun getEnvelopesList() = viewModelScope.launch { + // TODO: 리스트 불러오기 + } +} From 1b4b0bbe91ff8ac463af366e675bb4511600c0cb Mon Sep 17 00:00:00 2001 From: jinukeu Date: Mon, 22 Jan 2024 01:42:01 +0900 Subject: [PATCH 04/28] =?UTF-8?q?feat:=20RelationShip=20Api=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/susu/core/model/RelationShip.kt | 10 ++++++++ .../repository/EnvelopesRepositoryImpl.kt | 3 +++ .../susu/data/remote/api/EnvelopesService.kt | 5 ++++ .../response/RelationShipListResponse.kt | 23 +++++++++++++++++++ .../domain/repository/EnvelopesRepository.kt | 3 +++ .../GetRelationShipConfigListUseCase.kt | 13 +++++++++++ 6 files changed, 57 insertions(+) create mode 100644 core/model/src/main/java/com/susu/core/model/RelationShip.kt create mode 100644 data/src/main/java/com/susu/data/remote/model/response/RelationShipListResponse.kt create mode 100644 domain/src/main/java/com/susu/domain/usecase/envelope/GetRelationShipConfigListUseCase.kt diff --git a/core/model/src/main/java/com/susu/core/model/RelationShip.kt b/core/model/src/main/java/com/susu/core/model/RelationShip.kt new file mode 100644 index 00000000..9bcb3fcf --- /dev/null +++ b/core/model/src/main/java/com/susu/core/model/RelationShip.kt @@ -0,0 +1,10 @@ +package com.susu.core.model + +import androidx.compose.runtime.Stable + +@Stable +data class RelationShip( + val id: Int, + val relation: String, + val customRelation: String? = null +) diff --git a/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt index c9078b98..cf608c6e 100644 --- a/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt @@ -1,6 +1,7 @@ package com.susu.data.data.repository import com.susu.core.model.Envelope +import com.susu.core.model.RelationShip import com.susu.data.remote.api.EnvelopesService import com.susu.data.remote.model.response.toModel import com.susu.domain.repository.EnvelopesRepository @@ -24,4 +25,6 @@ class EnvelopesRepositoryImpl @Inject constructor( size = size, sort = sort, ).getOrThrow().toModel() + + override suspend fun getRelationShipConfigList(): List = envelopesService.getRelationShipConfigList().getOrThrow().toModel() } diff --git a/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt b/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt index 010ea7dc..5d6ab9ed 100644 --- a/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt +++ b/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt @@ -1,6 +1,8 @@ package com.susu.data.remote.api import com.susu.data.remote.model.response.EnvelopesListResponse +import com.susu.data.remote.model.response.RelationConfigShipResponse +import com.susu.data.remote.model.response.RelationShipListResponse import com.susu.data.remote.retrofit.ApiResult import retrofit2.http.GET import retrofit2.http.Query @@ -15,4 +17,7 @@ interface EnvelopesService { @Query("size") size: Int?, @Query("sort") sort: String?, ): ApiResult + + @GET("envelopes/configs/create-envelopes") + suspend fun getRelationShipConfigList(): ApiResult } diff --git a/data/src/main/java/com/susu/data/remote/model/response/RelationShipListResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/RelationShipListResponse.kt new file mode 100644 index 00000000..e1fef451 --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/response/RelationShipListResponse.kt @@ -0,0 +1,23 @@ +package com.susu.data.remote.model.response + +import com.susu.core.model.Category +import com.susu.core.model.RelationShip +import kotlinx.serialization.Serializable + +@Serializable +data class RelationShipListResponse( + val relationships: List = emptyList(), +) + +@Serializable +data class RelationConfigShipResponse( + val id: Int, + val relation: String, +) + +internal fun RelationShipListResponse.toModel() = relationships.map { it.toModel() } + +internal fun RelationConfigShipResponse.toModel() = RelationShip( + id = id, + relation = relation, +) diff --git a/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt b/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt index c9348c70..6316b1bf 100644 --- a/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt +++ b/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt @@ -1,6 +1,7 @@ package com.susu.domain.repository import com.susu.core.model.Envelope +import com.susu.core.model.RelationShip interface EnvelopesRepository { suspend fun getEnvelopesList( @@ -11,4 +12,6 @@ interface EnvelopesRepository { size: Int?, sort: String?, ): List + + suspend fun getRelationShipConfigList(): List } diff --git a/domain/src/main/java/com/susu/domain/usecase/envelope/GetRelationShipConfigListUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/envelope/GetRelationShipConfigListUseCase.kt new file mode 100644 index 00000000..bba412b1 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/envelope/GetRelationShipConfigListUseCase.kt @@ -0,0 +1,13 @@ +package com.susu.domain.usecase.envelope + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.EnvelopesRepository +import javax.inject.Inject + +class GetRelationShipConfigListUseCase @Inject constructor( + private val envelopesRepository: EnvelopesRepository, +) { + suspend operator fun invoke() = runCatchingIgnoreCancelled { + envelopesRepository.getRelationShipConfigList() + } +} From 57067ac1b89cb166736c226064f65862b46fa971 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Mon, 22 Jan 2024 14:29:54 +0900 Subject: [PATCH 05/28] =?UTF-8?q?feat:=20=EB=B0=9B=EC=9D=80=20=EB=B4=89?= =?UTF-8?q?=ED=88=AC=20=EC=83=9D=EC=84=B1=20-=20=EA=B8=88=EC=95=A1=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/ui/build.gradle.kts | 1 + .../src/main/java/com/susu/core/ui/Consts.kt | 4 ++ .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 18 +++--- .../ReceivedEnvelopeAddViewModel.kt | 9 +++ .../content/{ => money}/MoneyContent.kt | 63 ++++++++++++------- .../content/money/MoneyContract.kt | 13 ++++ .../content/money/MoneyViewModel.kt | 24 +++++++ 7 files changed, 104 insertions(+), 28 deletions(-) rename feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/{ => money}/MoneyContent.kt (64%) create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyViewModel.kt diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 8b3390ab..6232672f 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -11,4 +11,5 @@ android { dependencies { implementation(libs.kotlinx.serialization.json) + implementation(libs.kotlinx.immutable) } diff --git a/core/ui/src/main/java/com/susu/core/ui/Consts.kt b/core/ui/src/main/java/com/susu/core/ui/Consts.kt index 3df5e883..bf6e85f0 100644 --- a/core/ui/src/main/java/com/susu/core/ui/Consts.kt +++ b/core/ui/src/main/java/com/susu/core/ui/Consts.kt @@ -5,7 +5,9 @@ import androidx.annotation.StringRes import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import kotlinx.collections.immutable.persistentListOf +// TODO REMOVE val alignList @Composable get() = listOf( @@ -15,6 +17,8 @@ val alignList stringResource(id = R.string.word_align_low_amount), ) +val moneyList = persistentListOf(10_000, 30_000, 50_000, 100_000, 500_000) + const val USER_NAME_MAX_LENGTH = 10 val nameRegex = Regex("[a-zA-Z가-힣]{0,10}") diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index 8e4ef5da..2f4ddb4e 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -8,10 +8,6 @@ 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.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.res.stringResource @@ -26,15 +22,15 @@ import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec -import com.susu.feature.received.R import com.susu.feature.received.envelopeadd.content.MemoContent -import com.susu.feature.received.envelopeadd.content.MoneyContent +import com.susu.feature.received.envelopeadd.content.money.MoneyContent import com.susu.feature.received.envelopeadd.content.MoreContent import com.susu.feature.received.envelopeadd.content.NameContent import com.susu.feature.received.envelopeadd.content.PhoneContent import com.susu.feature.received.envelopeadd.content.PresentContent import com.susu.feature.received.envelopeadd.content.RelationshipContent import com.susu.feature.received.envelopeadd.content.VisitedContent +import com.susu.feature.received.envelopeadd.content.money.MoneyContentRoute @Composable fun ReceivedEnvelopeAddRoute( @@ -58,6 +54,7 @@ fun ReceivedEnvelopeAddRoute( uiState = uiState, onClickBack = viewModel::goToPrevStep, onClickNext = viewModel::goToNextStep, + updateParentMoney = viewModel::updateMoney ) } @@ -66,6 +63,7 @@ fun ReceivedEnvelopeAddScreen( uiState: ReceivedEnvelopeAddState = ReceivedEnvelopeAddState(), onClickBack: () -> Unit = {}, onClickNext: () -> Unit = {}, + updateParentMoney: (Long) -> Unit = {}, ) { // TODO: 수정 필요 val relationshipList = listOf("친구", "가족", "친척", "동료", "직접 입력") @@ -98,7 +96,10 @@ fun ReceivedEnvelopeAddScreen( }, ) { targetState -> when (targetState) { - EnvelopeAddStep.MONEY -> MoneyContent() + EnvelopeAddStep.MONEY -> MoneyContentRoute( + updateParentMoney = updateParentMoney, + ) + EnvelopeAddStep.NAME -> NameContent(friendList = friendList) EnvelopeAddStep.RELATIONSHIP -> RelationshipContent(relationshipList = relationshipList) EnvelopeAddStep.MORE -> MoreContent(moreList = moreList) @@ -106,6 +107,7 @@ fun ReceivedEnvelopeAddScreen( event = "결혼식", visitedList = visitedList, ) + EnvelopeAddStep.PRESENT -> PresentContent() EnvelopeAddStep.PHONE -> PhoneContent(name = "김철수") EnvelopeAddStep.MEMO -> MemoContent() @@ -117,6 +119,8 @@ fun ReceivedEnvelopeAddScreen( shape = RectangleShape, text = stringResource(id = com.susu.core.ui.R.string.word_next), onClick = onClickNext, + isClickable = uiState.buttonEnabled, + isActive = uiState.buttonEnabled, modifier = Modifier .fillMaxWidth() .imePadding(), diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index be1dba3a..00f46705 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -26,6 +26,8 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( ) : BaseViewModel( ReceivedEnvelopeAddState(), ) { + private var money: Long = 0 + fun goToPrevStep() = intent { val prevStep = when (currentState.currentStep) { EnvelopeAddStep.MONEY -> { @@ -62,4 +64,11 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( copy(currentStep = nextStep) } + + fun updateMoney(money: Long) = intent { + this@ReceivedEnvelopeAddViewModel.money = money + copy( + buttonEnabled = money > 0, + ) + } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/MoneyContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContent.kt similarity index 64% rename from feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/MoneyContent.kt rename to feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContent.kt index 9637b13b..13846c3b 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/MoneyContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContent.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.envelopeadd.content +package com.susu.feature.received.envelopeadd.content.money import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -11,6 +11,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.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -18,37 +19,57 @@ import androidx.compose.runtime.setValue 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.button.FilledButtonColor import com.susu.core.designsystem.component.button.SmallButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.component.textfield.SusuPriceTextField import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.toMoneyFormat +import com.susu.core.ui.moneyList import com.susu.feature.received.R +@Composable +fun MoneyContentRoute( + viewModel: MoneyViewModel = hiltViewModel(), + updateParentMoney: (Long) -> Unit, +) { + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is MoneySideEffect.UpdateParentMoney -> updateParentMoney(sideEffect.money) + } + } + + LaunchedEffect(key1 = Unit) { + updateParentMoney(uiState.money.toLongOrNull() ?: 0) + } + + MoneyContent( + uiState = uiState, + onTextChangeMoney = viewModel::updateMoney, + onClickMoneyButton = viewModel::addMoney, + ) +} + @OptIn(ExperimentalLayoutApi::class) @Composable fun MoneyContent( - modifier: Modifier = Modifier, - padding: PaddingValues = PaddingValues( - horizontal = SusuTheme.spacing.spacing_m, - vertical = SusuTheme.spacing.spacing_xl, - ), + uiState: MoneyState = MoneyState(), + onTextChangeMoney: (String) -> Unit = {}, + onClickMoneyButton: (Int) -> Unit = {}, ) { - val moneyList = listOf( - 10000, - 30000, - 50000, - 100000, - 500000, - ) - var clickedMoney by remember { mutableStateOf("") } Column( - modifier = modifier + modifier = Modifier .fillMaxSize() - .padding(padding), + .padding( + horizontal = SusuTheme.spacing.spacing_m, + vertical = SusuTheme.spacing.spacing_xl, + ), ) { Text( text = stringResource(R.string.money_content_title), @@ -56,16 +77,16 @@ fun MoneyContent( color = Gray100, ) Spacer( - modifier = modifier + modifier = Modifier .size(SusuTheme.spacing.spacing_m), ) SusuPriceTextField( - text = clickedMoney, - onTextChange = { clickedMoney = it }, + text = uiState.money, + onTextChange = onTextChangeMoney, placeholder = stringResource(R.string.money_content_placeholder), ) Spacer( - modifier = modifier + modifier = Modifier .size(SusuTheme.spacing.spacing_xxl), ) FlowRow( @@ -78,7 +99,7 @@ fun MoneyContent( style = SmallButtonStyle.height32, text = stringResource(id = com.susu.core.ui.R.string.money_unit_format, money.toMoneyFormat()), onClick = { - clickedMoney = money.toString() + onClickMoneyButton(money) }, ) } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContract.kt new file mode 100644 index 00000000..cbac312f --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContract.kt @@ -0,0 +1,13 @@ +package com.susu.feature.received.envelopeadd.content.money + +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import com.susu.feature.received.ledgeradd.LedgerAddStep + +data class MoneyState( + val money: String = "", +) : UiState + +sealed interface MoneySideEffect : SideEffect { + data class UpdateParentMoney(val money: Long) : MoneySideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyViewModel.kt new file mode 100644 index 00000000..fadb6dbd --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyViewModel.kt @@ -0,0 +1,24 @@ +package com.susu.feature.received.envelopeadd.content.money + +import com.susu.core.ui.base.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class MoneyViewModel @Inject constructor() : BaseViewModel( + MoneyState(), +) { + fun updateMoney(money: String) = intent { + postSideEffect(MoneySideEffect.UpdateParentMoney(money.toLongOrNull() ?: 0)) + copy(money = money) + } + + fun addMoney(money: Int) = intent { + val currentMoney = this.money.toLongOrNull() ?: 0 + val addedMoney = money + currentMoney + postSideEffect(MoneySideEffect.UpdateParentMoney(addedMoney)) + copy( + money = addedMoney.toString() + ) + } +} From 6a0654914bd93be30f73b218db9f7db13c4aa828 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Mon, 22 Jan 2024 15:04:17 +0900 Subject: [PATCH 06/28] =?UTF-8?q?feat:=20=EB=B0=9B=EC=9D=80=20=EB=B4=89?= =?UTF-8?q?=ED=88=AC=20=EC=83=9D=EC=84=B1=20-=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 13 +++-- .../ReceivedEnvelopeAddViewModel.kt | 8 +++ .../content/{ => name}/NameContent.kt | 56 ++++++++++++++----- .../envelopeadd/content/name/NameContract.kt | 13 +++++ .../envelopeadd/content/name/NameViewModel.kt | 15 +++++ 5 files changed, 85 insertions(+), 20 deletions(-) rename feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/{ => name}/NameContent.kt (59%) create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index 2f4ddb4e..89728e07 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -23,14 +23,14 @@ import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec import com.susu.feature.received.envelopeadd.content.MemoContent -import com.susu.feature.received.envelopeadd.content.money.MoneyContent import com.susu.feature.received.envelopeadd.content.MoreContent -import com.susu.feature.received.envelopeadd.content.NameContent +import com.susu.feature.received.envelopeadd.content.name.NameContent import com.susu.feature.received.envelopeadd.content.PhoneContent import com.susu.feature.received.envelopeadd.content.PresentContent import com.susu.feature.received.envelopeadd.content.RelationshipContent import com.susu.feature.received.envelopeadd.content.VisitedContent import com.susu.feature.received.envelopeadd.content.money.MoneyContentRoute +import com.susu.feature.received.envelopeadd.content.name.NameContentRoute @Composable fun ReceivedEnvelopeAddRoute( @@ -54,7 +54,8 @@ fun ReceivedEnvelopeAddRoute( uiState = uiState, onClickBack = viewModel::goToPrevStep, onClickNext = viewModel::goToNextStep, - updateParentMoney = viewModel::updateMoney + updateParentMoney = viewModel::updateMoney, + updateParentName = viewModel::updateName, ) } @@ -64,10 +65,10 @@ fun ReceivedEnvelopeAddScreen( onClickBack: () -> Unit = {}, onClickNext: () -> Unit = {}, updateParentMoney: (Long) -> Unit = {}, + updateParentName: (String) -> Unit = {}, ) { // TODO: 수정 필요 val relationshipList = listOf("친구", "가족", "친척", "동료", "직접 입력") - val friendList = listOf("김철수", "국영수", "신짱구", "홍길동") val moreList = listOf("방문여부", "선물", "메모", "보낸 이의 연락처") val visitedList = listOf("예", "아니요") @@ -100,7 +101,9 @@ fun ReceivedEnvelopeAddScreen( updateParentMoney = updateParentMoney, ) - EnvelopeAddStep.NAME -> NameContent(friendList = friendList) + EnvelopeAddStep.NAME -> NameContentRoute( + updateParentName = updateParentName, + ) EnvelopeAddStep.RELATIONSHIP -> RelationshipContent(relationshipList = relationshipList) EnvelopeAddStep.MORE -> MoreContent(moreList = moreList) EnvelopeAddStep.VISITED -> VisitedContent( diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index 00f46705..81696978 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -27,6 +27,7 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( ReceivedEnvelopeAddState(), ) { private var money: Long = 0 + private var name: String = "" fun goToPrevStep() = intent { val prevStep = when (currentState.currentStep) { @@ -71,4 +72,11 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( buttonEnabled = money > 0, ) } + + fun updateName(name: String) = intent { + this@ReceivedEnvelopeAddViewModel.name = name + copy( + buttonEnabled = name.isNotEmpty(), + ) + } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt similarity index 59% rename from feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/NameContent.kt rename to feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt index 970f876d..81010735 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.envelopeadd.content +package com.susu.feature.received.envelopeadd.content.name import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -11,6 +11,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text 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 @@ -18,28 +19,53 @@ import androidx.compose.runtime.setValue 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.Gray100 import com.susu.core.designsystem.theme.Gray40 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.received.R import com.susu.feature.received.envelopeadd.content.component.FriendListItem +import com.susu.feature.received.envelopeadd.content.money.MoneySideEffect +import com.susu.feature.received.envelopeadd.content.money.MoneyState + +@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) + } + } + + LaunchedEffect(key1 = Unit) { + updateParentName(uiState.name) + } + + NameContent( + uiState = uiState, + onTextChangeName = viewModel::updateName, + ) +} @Composable fun NameContent( - modifier: Modifier = Modifier, - padding: PaddingValues = PaddingValues( - horizontal = SusuTheme.spacing.spacing_m, - vertical = SusuTheme.spacing.spacing_xl, - ), + uiState: NameState = NameState(), + onTextChangeName: (String) -> Unit = {}, friendList: List = emptyList(), ) { - var name by remember { mutableStateOf("") } - Column( - modifier = modifier + modifier = Modifier .fillMaxSize() - .padding(padding), + .padding( + horizontal = SusuTheme.spacing.spacing_m, + vertical = SusuTheme.spacing.spacing_xl, + ), ) { Text( text = stringResource(R.string.name_content_title), @@ -47,17 +73,17 @@ fun NameContent( color = Gray100, ) Spacer( - modifier = modifier + modifier = Modifier .size(SusuTheme.spacing.spacing_m), ) SusuBasicTextField( - text = name, - onTextChange = { name = it }, + text = uiState.name, + onTextChange = onTextChangeName, placeholder = stringResource(R.string.name_content_placeholder), placeholderColor = Gray40, - modifier = modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), ) - Spacer(modifier = modifier.size(SusuTheme.spacing.spacing_xl)) + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xl)) if (friendList.isNotEmpty()) { // TODO: 친구 목록 서버 연동 diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt new file mode 100644 index 00000000..8eeab82e --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt @@ -0,0 +1,13 @@ +package com.susu.feature.received.envelopeadd.content.name + +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import com.susu.feature.received.ledgeradd.LedgerAddStep + +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/envelopeadd/content/name/NameViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt new file mode 100644 index 00000000..7a400c7c --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt @@ -0,0 +1,15 @@ +package com.susu.feature.received.envelopeadd.content.name + +import com.susu.core.ui.base.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class NameViewModel @Inject constructor() : BaseViewModel( + NameState(), +) { + fun updateName(name: String) = intent { + postSideEffect(NameSideEffect.UpdateParentName(name)) + copy(name = name) + } +} From 58ac1336ba77f0c7488cc351c9bf5462ef3f6a3b Mon Sep 17 00:00:00 2001 From: jinukeu Date: Mon, 22 Jan 2024 16:29:12 +0900 Subject: [PATCH 07/28] =?UTF-8?q?feat:=20=EB=B0=9B=EC=9D=80=20=EB=B4=89?= =?UTF-8?q?=ED=88=AC=20=EC=83=9D=EC=84=B1=20-=20=EA=B4=80=EA=B3=84=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/susu/core/model/RelationShip.kt | 4 +- .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 13 +- .../ReceivedEnvelopeAddViewModel.kt | 9 + .../content/RelationshipContent.kt | 96 --------- .../relationship/RelationShipContent.kt | 187 ++++++++++++++++++ .../relationship/RelationShipContract.kt | 22 +++ .../relationship/RelationShipViewModel.kt | 81 ++++++++ .../received/ledgeradd/LedgerAddScreen.kt | 4 +- 8 files changed, 311 insertions(+), 105 deletions(-) delete mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/RelationshipContent.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt diff --git a/core/model/src/main/java/com/susu/core/model/RelationShip.kt b/core/model/src/main/java/com/susu/core/model/RelationShip.kt index 9bcb3fcf..19c6b251 100644 --- a/core/model/src/main/java/com/susu/core/model/RelationShip.kt +++ b/core/model/src/main/java/com/susu/core/model/RelationShip.kt @@ -4,7 +4,7 @@ import androidx.compose.runtime.Stable @Stable data class RelationShip( - val id: Int, - val relation: String, + val id: Int = -1, + val relation: String = "", val customRelation: String? = null ) diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index 89728e07..747b7b35 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -20,17 +20,19 @@ 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.model.RelationShip import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec import com.susu.feature.received.envelopeadd.content.MemoContent import com.susu.feature.received.envelopeadd.content.MoreContent -import com.susu.feature.received.envelopeadd.content.name.NameContent import com.susu.feature.received.envelopeadd.content.PhoneContent import com.susu.feature.received.envelopeadd.content.PresentContent -import com.susu.feature.received.envelopeadd.content.RelationshipContent +import com.susu.feature.received.envelopeadd.content.relationship.RelationShipContent import com.susu.feature.received.envelopeadd.content.VisitedContent import com.susu.feature.received.envelopeadd.content.money.MoneyContentRoute import com.susu.feature.received.envelopeadd.content.name.NameContentRoute +import com.susu.feature.received.envelopeadd.content.relationship.RelationShipContentRoute @Composable fun ReceivedEnvelopeAddRoute( @@ -56,6 +58,7 @@ fun ReceivedEnvelopeAddRoute( onClickNext = viewModel::goToNextStep, updateParentMoney = viewModel::updateMoney, updateParentName = viewModel::updateName, + updateParentSelectedRelationShip = viewModel::updateSelectedRelationShip ) } @@ -66,9 +69,9 @@ fun ReceivedEnvelopeAddScreen( onClickNext: () -> Unit = {}, updateParentMoney: (Long) -> Unit = {}, updateParentName: (String) -> Unit = {}, + updateParentSelectedRelationShip: (RelationShip?) -> Unit = {}, ) { // TODO: 수정 필요 - val relationshipList = listOf("친구", "가족", "친척", "동료", "직접 입력") val moreList = listOf("방문여부", "선물", "메모", "보낸 이의 연락처") val visitedList = listOf("예", "아니요") @@ -104,7 +107,9 @@ fun ReceivedEnvelopeAddScreen( EnvelopeAddStep.NAME -> NameContentRoute( updateParentName = updateParentName, ) - EnvelopeAddStep.RELATIONSHIP -> RelationshipContent(relationshipList = relationshipList) + EnvelopeAddStep.RELATIONSHIP -> RelationShipContentRoute( + updateParentSelectedRelation = updateParentSelectedRelationShip, + ) EnvelopeAddStep.MORE -> MoreContent(moreList = moreList) EnvelopeAddStep.VISITED -> VisitedContent( event = "결혼식", diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index 81696978..022414e6 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import com.susu.core.model.Category import com.susu.core.model.Ledger +import com.susu.core.model.RelationShip import com.susu.core.model.exception.NotFoundLedgerException import com.susu.core.ui.base.BaseViewModel import com.susu.core.ui.extension.decodeFromUri @@ -28,6 +29,7 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( ) { private var money: Long = 0 private var name: String = "" + private var relationShip: RelationShip? = null fun goToPrevStep() = intent { val prevStep = when (currentState.currentStep) { @@ -79,4 +81,11 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( buttonEnabled = name.isNotEmpty(), ) } + + fun updateSelectedRelationShip(relationShip: RelationShip?) = intent { + this@ReceivedEnvelopeAddViewModel.relationShip = relationShip + copy( + buttonEnabled = relationShip != null + ) + } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/RelationshipContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/RelationshipContent.kt deleted file mode 100644 index 3bea7a52..00000000 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/RelationshipContent.kt +++ /dev/null @@ -1,96 +0,0 @@ -package com.susu.feature.received.envelopeadd.content - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -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.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -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.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.theme.Gray100 -import com.susu.core.designsystem.theme.SusuTheme -import com.susu.feature.received.R - -@Composable -fun RelationshipContent( - modifier: Modifier = Modifier, - padding: PaddingValues = PaddingValues( - horizontal = SusuTheme.spacing.spacing_m, - vertical = SusuTheme.spacing.spacing_xl, - ), - relationshipList: List, -) { - val scrollState = rememberScrollState() - var selectedItem by remember { mutableStateOf(-1) } - - Column( - modifier = modifier - .fillMaxSize() - .padding(padding) - .verticalScroll(scrollState), - ) { - Text( - text = stringResource(R.string.relationship_content_title), - style = SusuTheme.typography.title_m, - color = Gray100, - ) - Spacer( - modifier = modifier - .size(SusuTheme.spacing.spacing_xxl), - ) - Column( - verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), - ) { - relationshipList.forEachIndexed { index, relationship -> - if (selectedItem == index) { - SusuFilledButton( - color = FilledButtonColor.Orange, - style = MediumButtonStyle.height60, - text = relationship, - onClick = { - selectedItem = index - }, - modifier = modifier.fillMaxWidth(), - ) - } else { - SusuGhostButton( - color = GhostButtonColor.Black, - style = MediumButtonStyle.height60, - text = relationship, - onClick = { - selectedItem = index - }, - modifier = modifier.fillMaxWidth(), - ) - } - } - } - } -} - -@Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) -@Composable -fun RelationshipContentPreview() { - val relationshipList = mutableListOf("친구", "가족", "친척", "동료", "직접 입력") - - SusuTheme { - RelationshipContent(relationshipList = relationshipList) - } -} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt new file mode 100644 index 00000000..63f89093 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt @@ -0,0 +1,187 @@ +package com.susu.feature.received.envelopeadd.content.relationship + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +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.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.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 +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.Gray100 +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.model.Category +import com.susu.core.model.RelationShip +import com.susu.core.ui.extension.collectWithLifecycle +import com.susu.feature.received.R +import com.susu.feature.received.ledgeradd.content.category.CategoryContent +import com.susu.feature.received.ledgeradd.content.category.CategorySideEffect +import kotlinx.coroutines.android.awaitFrame +import kotlinx.coroutines.launch + +@Composable +fun RelationShipContentRoute( + viewModel: RelationShipViewModel = hiltViewModel(), + updateParentSelectedRelation: (RelationShip?) -> Unit = {}, +) { + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + val focusRequester = remember { FocusRequester() } + val scope = rememberCoroutineScope() + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is RelationShipSideEffect.UpdateParentSelectedRelationShip -> { + updateParentSelectedRelation(sideEffect.relationShip) + } + + RelationShipSideEffect.FocusCustomRelationShip -> scope.launch { + awaitFrame() + focusRequester.requestFocus() + } + } + } + + LaunchedEffect(key1 = Unit) { + viewModel.getRelationShipConfig() + } + + LaunchedEffect( + key1 = uiState.selectedRelationShip, + key2 = uiState.isSavedCustomRelationShip, + ) { + snapshotFlow { uiState.selectedRelationShip } + .collect { + viewModel.updateParentSelectedRelationShip() + } + } + + RelationShipContent( + uiState = uiState, + focusRequester = focusRequester, + onClickRelationShipButton = viewModel::selectRelationShip, + onClickCustomRelationShipButton = viewModel::showCustomRelationShipTextField, + onClickCustomRelationShipTextFieldCloseIcon = viewModel::hideCustomRelationShipTextField, + onClickCustomRelationShipTextField = viewModel::selectCustomRelationShip, + onClickCustomRelationShipTextFieldClearIcon = { viewModel.updateCustomRelationShipText("") }, + onTextChangeCustomRelationShipTextField = viewModel::updateCustomRelationShipText, + onClickTextFieldInnerButton = viewModel::toggleTextFieldSaved, + ) +} + +@Composable +fun RelationShipContent( + uiState: RelationShipState = RelationShipState(), + focusRequester: FocusRequester = remember { FocusRequester() }, + onClickRelationShipButton: (RelationShip) -> Unit = {}, + onClickCustomRelationShipButton: () -> Unit = {}, + onClickCustomRelationShipTextFieldCloseIcon: () -> Unit = {}, + onClickCustomRelationShipTextField: () -> Unit = {}, + onClickCustomRelationShipTextFieldClearIcon: () -> Unit = {}, + onTextChangeCustomRelationShipTextField: (String) -> Unit = {}, + onClickTextFieldInnerButton: () -> Unit = {}, +) { + val scrollState = rememberScrollState() + + Column( + modifier = Modifier + .fillMaxSize() + .padding( + horizontal = SusuTheme.spacing.spacing_m, + vertical = SusuTheme.spacing.spacing_xl, + ) + .verticalScroll(scrollState), + ) { + Text( + text = stringResource(R.string.relationship_content_title), + style = SusuTheme.typography.title_m, + color = Gray100, + ) + Spacer( + modifier = Modifier + .size(SusuTheme.spacing.spacing_xxl), + ) + Column( + verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), + ) { + uiState.relationShipConfig.forEach { relationship -> + if (relationship == uiState.selectedRelationShip) { + SusuFilledButton( + color = FilledButtonColor.Orange, + style = MediumButtonStyle.height60, + text = relationship.relation, + modifier = Modifier.fillMaxWidth(), + ) + } else { + SusuGhostButton( + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + text = relationship.relation, + onClick = { + onClickRelationShipButton(relationship) + }, + rippleEnabled = false, + modifier = Modifier.fillMaxWidth(), + ) + } + } + if (uiState.showTextFieldButton) { + SusuTextFieldFillMaxButton( + color = if (uiState.isCustomRelationShipSelected) TextFieldButtonColor.Orange else TextFieldButtonColor.Black, + text = uiState.customRelationShip.customRelation ?: "", + onTextChange = onTextChangeCustomRelationShipTextField, + focusRequester = focusRequester, + style = MediumTextFieldButtonStyle.height60, + isSaved = uiState.isSavedCustomRelationShip, + isFocused = uiState.customRelationShip == uiState.selectedRelationShip, + placeholder = stringResource(com.susu.core.ui.R.string.word_input_placeholder), + onClickCloseIcon = onClickCustomRelationShipTextFieldCloseIcon, + onClickClearIcon = onClickCustomRelationShipTextFieldClearIcon, + onClickButton = { onClickCustomRelationShipTextField() }, + onClickFilledButton = onClickTextFieldInnerButton, + ) + } 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 = onClickCustomRelationShipButton, + ) + } + } + } +} + +@Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) +@Composable +fun RelationshipContentPreview() { + + SusuTheme { + RelationShipContent() + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContract.kt new file mode 100644 index 00000000..9628ebee --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContract.kt @@ -0,0 +1,22 @@ +package com.susu.feature.received.envelopeadd.content.relationship + +import com.susu.core.model.RelationShip +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 RelationShipState( + val selectedRelationShip: RelationShip? = null, + val relationShipConfig: PersistentList = persistentListOf(), + val customRelationShip: RelationShip = RelationShip(), + val showTextFieldButton: Boolean = false, + val isSavedCustomRelationShip: Boolean = false, +) : UiState { + val isCustomRelationShipSelected = customRelationShip == selectedRelationShip +} + +sealed interface RelationShipSideEffect : SideEffect { + data object FocusCustomRelationShip : RelationShipSideEffect + data class UpdateParentSelectedRelationShip(val relationShip: RelationShip?) : RelationShipSideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt new file mode 100644 index 00000000..cf6e5bfe --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt @@ -0,0 +1,81 @@ +package com.susu.feature.received.envelopeadd.content.relationship + +import androidx.lifecycle.viewModelScope +import com.susu.core.model.RelationShip +import com.susu.core.ui.base.BaseViewModel +import com.susu.domain.usecase.envelope.GetRelationShipConfigListUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toPersistentList +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class RelationShipViewModel @Inject constructor( + private val getRelationShipConfigUseCase: GetRelationShipConfigListUseCase, +) : BaseViewModel( + RelationShipState(), +) { + private val parentSelectedRelationShip + get() = with(currentState) { + if (selectedRelationShip == customRelationShip && (customRelationShip.customRelation.isNullOrEmpty() || isSavedCustomRelationShip.not())) { + null + } else { + selectedRelationShip + } + } + + fun getRelationShipConfig() = viewModelScope.launch { + if (currentState.relationShipConfig.isNotEmpty()) return@launch + + getRelationShipConfigUseCase() + .onSuccess { + intent { + copy( + relationShipConfig = it.dropLast(1).toPersistentList(), + customRelationShip = it.last(), + ) + } + } + .onFailure { } + } + + fun selectRelationShip(relationShip: RelationShip) = intent { copy(selectedRelationShip = relationShip) } + + fun selectCustomRelationShip() = intent { + postSideEffect(RelationShipSideEffect.FocusCustomRelationShip) + copy(selectedRelationShip = customRelationShip) + } + + fun updateCustomRelationShipText(text: String) = intent { + copy( + selectedRelationShip = customRelationShip.copy(customRelation = text), + customRelationShip = customRelationShip.copy(customRelation = text), + ) + } + + fun showCustomRelationShipTextField() = intent { + copy( + showTextFieldButton = true, + selectedRelationShip = customRelationShip, + ) + } + + fun hideCustomRelationShipTextField() = intent { + copy( + isSavedCustomRelationShip = false, + showTextFieldButton = false, + selectedRelationShip = if (isCustomRelationShipSelected) null else selectedRelationShip, + customRelationShip = customRelationShip.copy(customRelation = ""), + ) + } + + fun toggleTextFieldSaved() = intent { + copy( + isSavedCustomRelationShip = !isSavedCustomRelationShip, + ) + } + + fun updateParentSelectedRelationShip(relationShip: RelationShip? = parentSelectedRelationShip) = postSideEffect( + RelationShipSideEffect.UpdateParentSelectedRelationShip(relationShip), + ) +} 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 61f261ec..c7ae86ad 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 @@ -77,9 +77,7 @@ fun LedgerAddRoute( }, dateContentName = dateContentName, dateContentCategoryName = dateContentCategoryName, - updateParentDate = { startAt, endAt -> - viewModel.updateDate(startAt, endAt) - }, + updateParentDate = viewModel::updateDate, ) } From 0ad6b71b4b64517caf092fd9bcb882e56c4b547f Mon Sep 17 00:00:00 2001 From: jinukeu Date: Mon, 22 Jan 2024 18:00:49 +0900 Subject: [PATCH 08/28] =?UTF-8?q?feat:=20=EB=B0=9B=EC=9D=80=20=EB=B4=89?= =?UTF-8?q?=ED=88=AC=20=EC=83=9D=EC=84=B1=20-=20=EB=8D=94=20=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=ED=95=A0=20=EB=82=B4=EC=9A=A9=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReceivedEnvelopeAddContract.kt | 25 ++++-- .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 18 ++-- .../ReceivedEnvelopeAddViewModel.kt | 86 +++++++++++-------- .../content/{ => more}/MoreContent.kt | 64 +++++++++----- .../envelopeadd/content/more/MoreContract.kt | 24 ++++++ .../envelopeadd/content/more/MoreViewModel.kt | 26 ++++++ .../received/src/main/res/values/strings.xml | 4 + 7 files changed, 177 insertions(+), 70 deletions(-) rename feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/{ => more}/MoreContent.kt (63%) create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreViewModel.kt diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt index f06a54a6..f24809b7 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt @@ -1,24 +1,37 @@ package com.susu.feature.received.envelopeadd +import androidx.annotation.StringRes import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState +import com.susu.feature.received.R import com.susu.feature.received.ledgeradd.LedgerAddStep data class ReceivedEnvelopeAddState( val currentStep: EnvelopeAddStep = EnvelopeAddStep.MONEY, val buttonEnabled: Boolean = false, + val lastPage: Boolean = false, val isLoading: Boolean = false, -) : UiState +) : UiState { + val buttonResId = if (lastPage) { + com.susu.core.ui.R.string.word_done + } else { + com.susu.core.ui.R.string.word_next + } -enum class EnvelopeAddStep { + val progress = if (lastPage) EnvelopeAddStep.entries.size else currentStep.ordinal + 1 +} + +enum class EnvelopeAddStep( + @StringRes val stringResId: Int? = null, +) { MONEY, NAME, RELATIONSHIP, MORE, - VISITED, - PRESENT, - PHONE, - MEMO, + VISITED(R.string.envelop_add_step_visited), + PRESENT(R.string.envelop_add_step_present), + MEMO(R.string.envelop_add_step_memo), + PHONE(R.string.envelop_add_step_phone), } sealed interface ReceivedEnvelopeAddSideEffect : SideEffect { diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index 747b7b35..b804c3d3 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -20,17 +20,16 @@ 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.model.RelationShip import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec import com.susu.feature.received.envelopeadd.content.MemoContent -import com.susu.feature.received.envelopeadd.content.MoreContent +import com.susu.feature.received.envelopeadd.content.more.MoreContent import com.susu.feature.received.envelopeadd.content.PhoneContent import com.susu.feature.received.envelopeadd.content.PresentContent -import com.susu.feature.received.envelopeadd.content.relationship.RelationShipContent import com.susu.feature.received.envelopeadd.content.VisitedContent import com.susu.feature.received.envelopeadd.content.money.MoneyContentRoute +import com.susu.feature.received.envelopeadd.content.more.MoreContentRoute import com.susu.feature.received.envelopeadd.content.name.NameContentRoute import com.susu.feature.received.envelopeadd.content.relationship.RelationShipContentRoute @@ -58,7 +57,8 @@ fun ReceivedEnvelopeAddRoute( onClickNext = viewModel::goToNextStep, updateParentMoney = viewModel::updateMoney, updateParentName = viewModel::updateName, - updateParentSelectedRelationShip = viewModel::updateSelectedRelationShip + updateParentSelectedRelationShip = viewModel::updateSelectedRelationShip, + updateParentMoreStep = viewModel::updateMoreStep, ) } @@ -70,9 +70,9 @@ fun ReceivedEnvelopeAddScreen( updateParentMoney: (Long) -> Unit = {}, updateParentName: (String) -> Unit = {}, updateParentSelectedRelationShip: (RelationShip?) -> Unit = {}, + updateParentMoreStep: (List) -> Unit = {}, ) { // TODO: 수정 필요 - val moreList = listOf("방문여부", "선물", "메모", "보낸 이의 연락처") val visitedList = listOf("예", "아니요") Column( @@ -86,7 +86,7 @@ fun ReceivedEnvelopeAddScreen( onClick = onClickBack, ) }, - currentStep = uiState.currentStep.ordinal + 1, + currentStep = uiState.progress, entireStep = EnvelopeAddStep.entries.size, ) AnimatedContent( @@ -110,7 +110,9 @@ fun ReceivedEnvelopeAddScreen( EnvelopeAddStep.RELATIONSHIP -> RelationShipContentRoute( updateParentSelectedRelation = updateParentSelectedRelationShip, ) - EnvelopeAddStep.MORE -> MoreContent(moreList = moreList) + EnvelopeAddStep.MORE -> MoreContentRoute( + updateParentMoreStep = updateParentMoreStep, + ) EnvelopeAddStep.VISITED -> VisitedContent( event = "결혼식", visitedList = visitedList, @@ -125,7 +127,7 @@ fun ReceivedEnvelopeAddScreen( color = FilledButtonColor.Black, style = MediumButtonStyle.height60, shape = RectangleShape, - text = stringResource(id = com.susu.core.ui.R.string.word_next), + text = stringResource(id = uiState.buttonResId), onClick = onClickNext, isClickable = uiState.buttonEnabled, isActive = uiState.buttonEnabled, diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index 022414e6..979b84d3 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -1,25 +1,8 @@ package com.susu.feature.received.envelopeadd -import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.viewModelScope -import com.susu.core.model.Category -import com.susu.core.model.Ledger import com.susu.core.model.RelationShip -import com.susu.core.model.exception.NotFoundLedgerException import com.susu.core.ui.base.BaseViewModel -import com.susu.core.ui.extension.decodeFromUri -import com.susu.core.ui.extension.encodeToUri -import com.susu.core.ui.util.to_yyyy_dot_MM_dot_dd -import com.susu.domain.usecase.ledger.DeleteLedgerUseCase -import com.susu.feature.received.ledgeradd.LedgerAddSideEffect -import com.susu.feature.received.ledgeradd.LedgerAddStep -import com.susu.feature.received.navigation.ReceivedRoute import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch -import kotlinx.datetime.toJavaLocalDateTime -import kotlinx.datetime.toKotlinLocalDateTime -import kotlinx.serialization.json.Json -import java.time.LocalDateTime import javax.inject.Inject @HiltViewModel @@ -30,9 +13,10 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( private var money: Long = 0 private var name: String = "" private var relationShip: RelationShip? = null + private var moreStep: List = emptyList() fun goToPrevStep() = intent { - val prevStep = when (currentState.currentStep) { + val prevStep = when (currentStep) { EnvelopeAddStep.MONEY -> { postSideEffect(ReceivedEnvelopeAddSideEffect.PopBackStack) EnvelopeAddStep.MONEY @@ -41,31 +25,61 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( EnvelopeAddStep.NAME -> EnvelopeAddStep.MONEY EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.NAME EnvelopeAddStep.MORE -> EnvelopeAddStep.RELATIONSHIP - EnvelopeAddStep.VISITED -> EnvelopeAddStep.MORE - EnvelopeAddStep.PRESENT -> EnvelopeAddStep.VISITED - EnvelopeAddStep.PHONE -> EnvelopeAddStep.PRESENT - EnvelopeAddStep.MEMO -> EnvelopeAddStep.PHONE + else -> goToPrevStepInMore(currentStep) } - copy(currentStep = prevStep) + copy( + currentStep = prevStep, + lastPage = false, + ) + } + + private fun goToPrevStepInMore(currentStep: EnvelopeAddStep): EnvelopeAddStep { + if (moreStep.isEmpty()) { + return EnvelopeAddStep.MORE + } + + val prevStepIndex = run { + val currentStepIndex = moreStep.indexOf(currentStep) + if (currentStepIndex == -1) EnvelopeAddStep.MORE.ordinal else currentStepIndex - 1 + } + + return moreStep.getOrNull(prevStepIndex) ?: EnvelopeAddStep.MORE } fun goToNextStep() = intent { - val nextStep = when (currentState.currentStep) { + val nextStep = when (currentStep) { EnvelopeAddStep.MONEY -> EnvelopeAddStep.NAME EnvelopeAddStep.NAME -> EnvelopeAddStep.RELATIONSHIP EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.MORE - EnvelopeAddStep.MORE -> EnvelopeAddStep.VISITED - EnvelopeAddStep.VISITED -> EnvelopeAddStep.PRESENT - EnvelopeAddStep.PRESENT -> EnvelopeAddStep.PHONE - EnvelopeAddStep.PHONE -> EnvelopeAddStep.MEMO - EnvelopeAddStep.MEMO -> { - /* 봉투 생성 */ - EnvelopeAddStep.MEMO - } + else -> goToNextStepInMore(currentStep) } - copy(currentStep = nextStep) + if (nextStep == null) { + // TODO 봉투 생성 + copy() + } else { + copy( + currentStep = nextStep, + lastPage = nextStep == moreStep.lastOrNull(), + ) + } + } + + private fun goToNextStepInMore(currentStep: EnvelopeAddStep): EnvelopeAddStep? { + if (moreStep.isEmpty() || currentState.lastPage) { + return null + } + + val nextStepIndex = when (currentStep) { + EnvelopeAddStep.MORE -> 0 + else -> { + val currentStepIndex = moreStep.indexOf(currentStep) + if (currentStepIndex == -1) null else currentStepIndex + 1 + } + } ?: return null + + return moreStep.getOrNull(nextStepIndex) } fun updateMoney(money: Long) = intent { @@ -85,7 +99,11 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( fun updateSelectedRelationShip(relationShip: RelationShip?) = intent { this@ReceivedEnvelopeAddViewModel.relationShip = relationShip copy( - buttonEnabled = relationShip != null + buttonEnabled = relationShip != null, ) } + + fun updateMoreStep(moreStep: List) { + this@ReceivedEnvelopeAddViewModel.moreStep = moreStep + } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/MoreContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreContent.kt similarity index 63% rename from feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/MoreContent.kt rename to feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreContent.kt index 92cbddc0..a7b3aae3 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/MoreContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreContent.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.envelopeadd.content +package com.susu.feature.received.envelopeadd.content.more import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -19,6 +19,8 @@ import androidx.compose.runtime.setValue 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.button.FilledButtonColor import com.susu.core.designsystem.component.button.GhostButtonColor import com.susu.core.designsystem.component.button.MediumButtonStyle @@ -27,24 +29,42 @@ import com.susu.core.designsystem.component.button.SusuGhostButton import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.Gray70 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.received.R +import com.susu.feature.received.envelopeadd.EnvelopeAddStep + +@Composable +fun MoreContentRoute( + viewModel: MoreViewModel = hiltViewModel(), + updateParentMoreStep: (List) -> Unit, +) { + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is MoreSideEffect.UpdateParentMoreStep -> updateParentMoreStep(sideEffect.moreStep) + } + } + + MoreContent( + uiState = uiState, + onClickStepButton = viewModel::toggleStep, + ) +} @Composable fun MoreContent( - modifier: Modifier = Modifier, - padding: PaddingValues = PaddingValues( - horizontal = SusuTheme.spacing.spacing_m, - vertical = SusuTheme.spacing.spacing_xl, - ), - moreList: List, + uiState: MoreState = MoreState(), + onClickStepButton: (EnvelopeAddStep) -> Unit = {}, ) { val scrollState = rememberScrollState() - var selectedItem by remember { mutableStateOf(-1) } Column( - modifier = modifier + modifier = Modifier .fillMaxSize() - .padding(padding) + .padding( + horizontal = SusuTheme.spacing.spacing_m, + vertical = SusuTheme.spacing.spacing_xl, + ) .verticalScroll(scrollState), ) { Text( @@ -53,7 +73,7 @@ fun MoreContent( color = Gray100, ) Spacer( - modifier = modifier + modifier = Modifier .size(SusuTheme.spacing.spacing_xxxxs), ) Text( @@ -62,32 +82,33 @@ fun MoreContent( color = Gray70, ) Spacer( - modifier = modifier + modifier = Modifier .size(SusuTheme.spacing.spacing_xxl), ) Column( verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), ) { - moreList.forEachIndexed { index, category -> - if (selectedItem == index) { + moreStep.forEach { step -> + if (step in uiState.selectedMoreStop) { SusuFilledButton( color = FilledButtonColor.Orange, style = MediumButtonStyle.height60, - text = category, + text = stringResource(id = step.stringResId!!), onClick = { - selectedItem = index + onClickStepButton(step) }, - modifier = modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), ) } else { SusuGhostButton( color = GhostButtonColor.Black, style = MediumButtonStyle.height60, - text = category, + text = stringResource(id = step.stringResId!!), + rippleEnabled = false, onClick = { - selectedItem = index + onClickStepButton(step) }, - modifier = modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), ) } } @@ -98,9 +119,8 @@ fun MoreContent( @Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) @Composable fun MoreContentPreview() { - val moreList = mutableListOf("방문여부", "선물", "메모", "보낸 이의 연락처") SusuTheme { - MoreContent(moreList = moreList) + MoreContent() } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreContract.kt new file mode 100644 index 00000000..ec18deff --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreContract.kt @@ -0,0 +1,24 @@ +package com.susu.feature.received.envelopeadd.content.more + +import com.susu.core.model.RelationShip +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import com.susu.feature.received.envelopeadd.EnvelopeAddStep +import com.susu.feature.received.ledgeradd.LedgerAddStep +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf + +data class MoreState( + val selectedMoreStop: PersistentList = persistentListOf(), +) : UiState + +val moreStep = persistentListOf( + EnvelopeAddStep.VISITED, + EnvelopeAddStep.PRESENT, + EnvelopeAddStep.MEMO, + EnvelopeAddStep.PHONE, +) + +sealed interface MoreSideEffect : SideEffect { + data class UpdateParentMoreStep(val moreStep: List) : MoreSideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreViewModel.kt new file mode 100644 index 00000000..c50bf5c2 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreViewModel.kt @@ -0,0 +1,26 @@ +package com.susu.feature.received.envelopeadd.content.more + +import com.susu.core.ui.base.BaseViewModel +import com.susu.feature.received.envelopeadd.EnvelopeAddStep +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toPersistentList +import javax.inject.Inject + +@HiltViewModel +class MoreViewModel @Inject constructor() : BaseViewModel( + MoreState(), +) { + fun toggleStep(envelopeAddStep: EnvelopeAddStep) = intent { + val newStep = if (envelopeAddStep in selectedMoreStop) { + selectedMoreStop.minus(envelopeAddStep) + } else { + selectedMoreStop.plus(envelopeAddStep) + } + + postSideEffect(MoreSideEffect.UpdateParentMoreStep(newStep.sortedBy { it.ordinal })) + copy( + selectedMoreStop = newStep.toPersistentList() + ) + } + +} diff --git a/feature/received/src/main/res/values/strings.xml b/feature/received/src/main/res/values/strings.xml index 3778cf6d..e63a6a6d 100644 --- a/feature/received/src/main/res/values/strings.xml +++ b/feature/received/src/main/res/values/strings.xml @@ -53,4 +53,8 @@ 한끼 식사 01012345678 입력해주세요 + 방문여부 + 선물 + 메모 + 보낸 이의 연락처 From 419856d7cb7f8703f3859534d28dd2d730e7da97 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Mon, 22 Jan 2024 20:14:44 +0900 Subject: [PATCH 09/28] =?UTF-8?q?feat:=20=EB=B0=9B=EC=9D=80=20=EB=B4=89?= =?UTF-8?q?=ED=88=AC=20=EC=83=9D=EC=84=B1=20-=20=EB=B0=A9=EB=AC=B8=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../susu/feature/navigator/MainNavigator.kt | 4 +- .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 26 +++- .../ReceivedEnvelopeAddViewModel.kt | 13 ++ .../envelopeadd/content/VisitedContent.kt | 97 ------------- .../content/visited/VisitedContent.kt | 129 ++++++++++++++++++ .../content/visited/VisitedContract.kt | 14 ++ .../content/visited/VisitedViewModel.kt | 20 +++ .../ledgerdetail/LedgerDetailContract.kt | 2 +- .../ledgerdetail/LedgerDetailScreen.kt | 4 +- .../ledgerdetail/LedgerDetailViewModel.kt | 2 +- .../received/navigation/ReceivedNavigation.kt | 17 ++- 11 files changed, 213 insertions(+), 115 deletions(-) delete mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/VisitedContent.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContent.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedViewModel.kt 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 d2fd7660..c54d6e76 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 @@ -149,8 +149,8 @@ internal class MainNavigator( navController.navigateMyPageSocial() } - fun navigateReceivedEnvelopeAdd() { - navController.navigateReceivedEnvelopeAdd() + fun navigateReceivedEnvelopeAdd(categoryName: String) { + navController.navigateReceivedEnvelopeAdd(categoryName) } fun navigateReceivedEnvelopeDetail() { diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index b804c3d3..36644811 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -7,7 +7,12 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.rememberScrollState import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.res.stringResource @@ -24,14 +29,15 @@ import com.susu.core.model.RelationShip import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec import com.susu.feature.received.envelopeadd.content.MemoContent -import com.susu.feature.received.envelopeadd.content.more.MoreContent import com.susu.feature.received.envelopeadd.content.PhoneContent import com.susu.feature.received.envelopeadd.content.PresentContent -import com.susu.feature.received.envelopeadd.content.VisitedContent +import com.susu.feature.received.envelopeadd.content.visited.VisitedContent import com.susu.feature.received.envelopeadd.content.money.MoneyContentRoute import com.susu.feature.received.envelopeadd.content.more.MoreContentRoute import com.susu.feature.received.envelopeadd.content.name.NameContentRoute import com.susu.feature.received.envelopeadd.content.relationship.RelationShipContentRoute +import com.susu.feature.received.envelopeadd.content.visited.VisitedContentRoute +import com.susu.feature.received.envelopeadd.content.visited.VisitedViewModel @Composable fun ReceivedEnvelopeAddRoute( @@ -47,6 +53,10 @@ fun ReceivedEnvelopeAddRoute( } } + var friendName by remember { + mutableStateOf("") + } + BackHandler { viewModel.goToPrevStep() } @@ -59,6 +69,8 @@ fun ReceivedEnvelopeAddRoute( updateParentName = viewModel::updateName, updateParentSelectedRelationShip = viewModel::updateSelectedRelationShip, updateParentMoreStep = viewModel::updateMoreStep, + categoryName = viewModel.categoryName, + updateParentVisited = viewModel::updateHasVisited, ) } @@ -71,9 +83,9 @@ fun ReceivedEnvelopeAddScreen( updateParentName: (String) -> Unit = {}, updateParentSelectedRelationShip: (RelationShip?) -> Unit = {}, updateParentMoreStep: (List) -> Unit = {}, + categoryName: String = "", + updateParentVisited: (Boolean?) -> Unit = {}, ) { - // TODO: 수정 필요 - val visitedList = listOf("예", "아니요") Column( modifier = Modifier @@ -113,9 +125,9 @@ fun ReceivedEnvelopeAddScreen( EnvelopeAddStep.MORE -> MoreContentRoute( updateParentMoreStep = updateParentMoreStep, ) - EnvelopeAddStep.VISITED -> VisitedContent( - event = "결혼식", - visitedList = visitedList, + EnvelopeAddStep.VISITED -> VisitedContentRoute( + categoryName = categoryName, + updateParentVisited = updateParentVisited, ) EnvelopeAddStep.PRESENT -> PresentContent() diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index 979b84d3..53a68179 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -1,19 +1,25 @@ package com.susu.feature.received.envelopeadd +import androidx.lifecycle.SavedStateHandle import com.susu.core.model.RelationShip import com.susu.core.ui.base.BaseViewModel +import com.susu.feature.received.navigation.ReceivedRoute import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @HiltViewModel class ReceivedEnvelopeAddViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, ) : BaseViewModel( ReceivedEnvelopeAddState(), ) { + val categoryName = savedStateHandle.get(ReceivedRoute.CATEGORY_ARGUMENT_NAME)!! + private var money: Long = 0 private var name: String = "" private var relationShip: RelationShip? = null private var moreStep: List = emptyList() + private var hasVisited: Boolean? = null fun goToPrevStep() = intent { val prevStep = when (currentStep) { @@ -106,4 +112,11 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( fun updateMoreStep(moreStep: List) { this@ReceivedEnvelopeAddViewModel.moreStep = moreStep } + + fun updateHasVisited(hasVisited: Boolean?) = intent { + this@ReceivedEnvelopeAddViewModel.hasVisited = hasVisited + copy( + buttonEnabled = hasVisited != null, + ) + } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/VisitedContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/VisitedContent.kt deleted file mode 100644 index f5e7de51..00000000 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/VisitedContent.kt +++ /dev/null @@ -1,97 +0,0 @@ -package com.susu.feature.received.envelopeadd.content - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -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.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -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.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.theme.Gray60 -import com.susu.core.designsystem.theme.SusuTheme -import com.susu.core.ui.util.AnnotatedText -import com.susu.feature.received.R - -@Composable -fun VisitedContent( - modifier: Modifier = Modifier, - padding: PaddingValues = PaddingValues( - horizontal = SusuTheme.spacing.spacing_m, - vertical = SusuTheme.spacing.spacing_xl, - ), - event: String, - visitedList: List, -) { - var selectedItem by remember { mutableStateOf(-1) } - - Column( - modifier = modifier - .fillMaxSize() - .padding(padding), - ) { - AnnotatedText( - originalText = stringResource(R.string.visited_content_title, event), - originalTextStyle = SusuTheme.typography.title_m, - targetTextList = listOf(stringResource(R.string.visited_content_title_highlight, event)), - spanStyle = SusuTheme.typography.title_m.copy(Gray60).toSpanStyle(), - ) - Spacer( - modifier = modifier - .size(SusuTheme.spacing.spacing_xxl), - ) - Column( - verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), - ) { - visitedList.forEachIndexed { index, answer -> - if (selectedItem == index) { - SusuFilledButton( - color = FilledButtonColor.Orange, - style = MediumButtonStyle.height60, - text = answer, - onClick = { - selectedItem = index - }, - modifier = modifier.fillMaxWidth(), - ) - } else { - SusuGhostButton( - color = GhostButtonColor.Black, - style = MediumButtonStyle.height60, - text = answer, - onClick = { - selectedItem = index - }, - modifier = modifier.fillMaxWidth(), - ) - } - } - } - } -} - -@Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) -@Composable -fun VisitedContentPreview() { - val visitedList = mutableListOf("예", "아니요") - - SusuTheme { - VisitedContent( - event = "결혼식", - visitedList = visitedList, - ) - } -} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContent.kt new file mode 100644 index 00000000..db3b1ec2 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContent.kt @@ -0,0 +1,129 @@ +package com.susu.feature.received.envelopeadd.content.visited + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +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.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.setValue +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.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.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.feature.received.R + +@Composable +fun VisitedContentRoute( + viewModel: VisitedViewModel = hiltViewModel(), + categoryName: String, + updateParentVisited: (Boolean?) -> Unit, +) { + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is VisitedSideEffect.UpdateParentVisited -> updateParentVisited(sideEffect.visited) + } + } + + LaunchedEffect(key1 = Unit) { + viewModel.updateCategoryName(categoryName) + viewModel.updateVisited(uiState.visited) + } + + VisitedContent( + uiState = uiState, + onClickVisitedButton = { viewModel.updateVisited(true) }, + onClickNotVisitedButton = { viewModel.updateVisited(false) }, + ) +} + +@Composable +fun VisitedContent( + uiState: VisitedState = VisitedState(), + onClickVisitedButton: () -> Unit = {}, + onClickNotVisitedButton: () -> Unit = {}, +) { + Column( + modifier = Modifier + .fillMaxSize() + .padding( + horizontal = SusuTheme.spacing.spacing_m, + vertical = SusuTheme.spacing.spacing_xl, + ), + ) { + AnnotatedText( + originalText = stringResource(R.string.visited_content_title, uiState.categoryName), + originalTextStyle = SusuTheme.typography.title_m, + targetTextList = listOf(stringResource(R.string.visited_content_title_highlight, uiState.categoryName)), + spanStyle = SusuTheme.typography.title_m.copy(Gray60).toSpanStyle(), + ) + Spacer( + modifier = Modifier + .size(SusuTheme.spacing.spacing_xxl), + ) + Column( + verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), + ) { + if (uiState.visited == true) { + SusuFilledButton( + color = FilledButtonColor.Orange, + style = MediumButtonStyle.height60, + text = stringResource(id = com.susu.core.ui.R.string.word_yes), + modifier = Modifier.fillMaxWidth(), + ) + } else { + SusuGhostButton( + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + text = stringResource(id = com.susu.core.ui.R.string.word_yes), + onClick = onClickVisitedButton, + modifier = Modifier.fillMaxWidth(), + ) + } + + if (uiState.visited == false) { + SusuFilledButton( + color = FilledButtonColor.Orange, + style = MediumButtonStyle.height60, + text = stringResource(id = com.susu.core.ui.R.string.word_no), + modifier = Modifier.fillMaxWidth(), + ) + } else { + SusuGhostButton( + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + text = stringResource(id = com.susu.core.ui.R.string.word_no), + onClick = onClickNotVisitedButton, + modifier = Modifier.fillMaxWidth(), + ) + } + } + } +} + +@Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) +@Composable +fun VisitedContentPreview() { + + SusuTheme { + VisitedContent() + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContract.kt new file mode 100644 index 00000000..87633bb6 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContract.kt @@ -0,0 +1,14 @@ +package com.susu.feature.received.envelopeadd.content.visited + +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import com.susu.feature.received.ledgeradd.LedgerAddStep + +data class VisitedState( + val categoryName: String = "", + val visited: Boolean? = null, +) : UiState + +sealed interface VisitedSideEffect : SideEffect { + data class UpdateParentVisited(val visited: Boolean?) : VisitedSideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedViewModel.kt new file mode 100644 index 00000000..edb5ff1c --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedViewModel.kt @@ -0,0 +1,20 @@ +package com.susu.feature.received.envelopeadd.content.visited + +import com.susu.core.ui.base.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class VisitedViewModel @Inject constructor() : BaseViewModel( + VisitedState(), +) { + fun updateCategoryName(name: String) = intent { + copy(categoryName = name) + } + + + fun updateVisited(visited: Boolean?) = intent { + postSideEffect(VisitedSideEffect.UpdateParentVisited(visited)) + copy(visited = visited) + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailContract.kt index 4bfd6851..547c4475 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailContract.kt @@ -14,7 +14,7 @@ data class LedgerDetailState( ) : UiState sealed interface LedgerDetailSideEffect : SideEffect { - data object NavigateEnvelopeAdd : LedgerDetailSideEffect + data class NavigateEnvelopeAdd(val categoryName: String) : LedgerDetailSideEffect data object NavigateEnvelopeDetail : LedgerDetailSideEffect data class NavigateLedgerEdit(val ledger: Ledger) : LedgerDetailSideEffect data class PopBackStackWithLedger(val ledger: String) : LedgerDetailSideEffect diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailScreen.kt index d6dcd1ba..ce14271e 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailScreen.kt @@ -52,7 +52,7 @@ fun LedgerDetailRoute( viewModel: LedgerDetailViewModel = hiltViewModel(), ledger: String?, navigateLedgerEdit: (Ledger) -> Unit, - navigateEnvelopAdd: () -> Unit, + navigateEnvelopAdd: (String) -> Unit, navigateEnvelopeDetail: () -> Unit, popBackStackWithLedger: (String) -> Unit, popBackStackWithDeleteLedgerId: (Int) -> Unit, @@ -89,7 +89,7 @@ fun LedgerDetailRoute( is LedgerDetailSideEffect.PopBackStackWithDeleteLedgerId -> popBackStackWithDeleteLedgerId(sideEffect.ledgerId) is LedgerDetailSideEffect.HandleException -> handleException(sideEffect.throwable, sideEffect.retry) is LedgerDetailSideEffect.ShowSnackbar -> onShowSnackbar(SnackbarToken(message = sideEffect.msg)) - LedgerDetailSideEffect.NavigateEnvelopeAdd -> navigateEnvelopAdd() + is LedgerDetailSideEffect.NavigateEnvelopeAdd -> navigateEnvelopAdd(sideEffect.categoryName) LedgerDetailSideEffect.NavigateEnvelopeDetail -> navigateEnvelopeDetail() } } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailViewModel.kt index 38b72ab2..7faa88d7 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailViewModel.kt @@ -81,6 +81,6 @@ class LedgerDetailViewModel @Inject constructor( } } - fun navigateEnvelopeAdd() = postSideEffect(LedgerDetailSideEffect.NavigateEnvelopeAdd) + fun navigateEnvelopeAdd() = postSideEffect(LedgerDetailSideEffect.NavigateEnvelopeAdd(ledger.category.customCategory ?: ledger.category.name)) fun navigateEnvelopeDetail() = postSideEffect(LedgerDetailSideEffect.NavigateEnvelopeDetail) } 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 b73fe44a..25cf322b 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 @@ -46,8 +46,8 @@ fun NavController.navigateLedgerAdd() { navigate(ReceivedRoute.ledgerAddRoute) } -fun NavController.navigateReceivedEnvelopeAdd() { - navigate(ReceivedRoute.envelopeAddRoute) +fun NavController.navigateReceivedEnvelopeAdd(categoryName: String) { + navigate(ReceivedRoute.envelopeAddRoute(categoryName)) } fun NavController.navigateReceivedEnvelopeDetail() { @@ -68,7 +68,7 @@ fun NavGraphBuilder.receivedNavGraph( navigateLedgerEdit: (Ledger) -> Unit, navigateLedgerFilter: () -> Unit, navigateLedgerAdd: () -> Unit, - navigateEnvelopAdd: () -> Unit, + navigateEnvelopAdd: (String) -> Unit, navigateEnvelopeDetail: () -> Unit, navigateEnvelopeEdit: () -> Unit, onShowSnackbar: (SnackbarToken) -> Unit, @@ -143,7 +143,12 @@ fun NavGraphBuilder.receivedNavGraph( } composable( - route = ReceivedRoute.envelopeAddRoute, + route = ReceivedRoute.envelopeAddRoute("{${ReceivedRoute.CATEGORY_ARGUMENT_NAME}}"), + arguments = listOf( + navArgument(ReceivedRoute.CATEGORY_ARGUMENT_NAME) { + type = NavType.StringType + }, + ), ) { ReceivedEnvelopeAddRoute( popBackStack = popBackStack, @@ -171,6 +176,8 @@ object ReceivedRoute { const val route = "received" const val LEDGER_ARGUMENT_NAME = "ledger" const val LEDGER_ID_ARGUMENT_NAME = "ledger-id" + const val CATEGORY_ARGUMENT_NAME = "category-name" + fun ledgerDetailRoute(ledger: String) = "ledger-detail/$ledger" fun ledgerEditRoute(ledger: String) = "ledger-edit/$ledger" const val ledgerSearchRoute = "ledger-search" @@ -178,7 +185,7 @@ object ReceivedRoute { const val ledgerAddRoute = "ledger-add" // TODO 파라미터 넘기는 방식으로 수정해야함. const val ledgerFilterRoute = "ledger-filter" // TODO 파라미터 넘기는 방식으로 수정해야함. - const val envelopeAddRoute = "envelope-add" + fun envelopeAddRoute(categoryName: String) = "envelope-add/$categoryName" const val envelopeDetailRoute = "envelope-detail" // TODO 파라미터 넘기는 방식으로 수정해야함. const val envelopeEditRoute = "envelope-edit" // TODO 파라미터 넘기는 방식으로 수정해야함. } From c13905d151ae7ea647c18d2e62f7156e1ffcf35a Mon Sep 17 00:00:00 2001 From: jinukeu Date: Mon, 22 Jan 2024 21:50:32 +0900 Subject: [PATCH 10/28] =?UTF-8?q?feat:=20=EB=B0=9B=EC=9D=80=20=EB=B4=89?= =?UTF-8?q?=ED=88=AC=20=EC=83=9D=EC=84=B1=20-=20=EC=84=A0=EB=AC=BC,=20?= =?UTF-8?q?=EC=97=B0=EB=9D=BD=EC=B2=98,=20=EB=A9=94=EB=AA=A8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReceivedEnvelopeAddContract.kt | 2 +- .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 36 +++++++--- .../ReceivedEnvelopeAddViewModel.kt | 24 +++++++ .../content/{ => memo}/MemoContent.kt | 55 +++++++++++----- .../envelopeadd/content/memo/MemoState.kt | 12 ++++ .../envelopeadd/content/memo/MemoViewModel.kt | 15 +++++ .../envelopeadd/content/name/NameContent.kt | 2 +- .../content/{ => phone}/PhoneContent.kt | 65 +++++++++++++------ .../content/phone/PhoneContract.kt | 14 ++++ .../content/phone/PhoneViewModel.kt | 16 +++++ .../content/{ => present}/PresentContent.kt | 56 +++++++++++----- .../content/present/PresentContract.kt | 13 ++++ .../content/present/PresentViewModel.kt | 15 +++++ 13 files changed, 264 insertions(+), 61 deletions(-) rename feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/{ => memo}/MemoContent.kt (55%) create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoState.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoViewModel.kt rename feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/{ => phone}/PhoneContent.kt (52%) create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneViewModel.kt rename feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/{ => present}/PresentContent.kt (52%) create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentViewModel.kt diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt index f24809b7..2df83b31 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt @@ -30,8 +30,8 @@ enum class EnvelopeAddStep( MORE, VISITED(R.string.envelop_add_step_visited), PRESENT(R.string.envelop_add_step_present), - MEMO(R.string.envelop_add_step_memo), PHONE(R.string.envelop_add_step_phone), + MEMO(R.string.envelop_add_step_memo), } sealed interface ReceivedEnvelopeAddSideEffect : SideEffect { diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index 36644811..2dbf2962 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.rememberScrollState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -28,16 +27,15 @@ import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.model.RelationShip import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec -import com.susu.feature.received.envelopeadd.content.MemoContent -import com.susu.feature.received.envelopeadd.content.PhoneContent -import com.susu.feature.received.envelopeadd.content.PresentContent -import com.susu.feature.received.envelopeadd.content.visited.VisitedContent +import com.susu.feature.received.envelopeadd.content.memo.MemoContent +import com.susu.feature.received.envelopeadd.content.memo.MemoContentRoute import com.susu.feature.received.envelopeadd.content.money.MoneyContentRoute import com.susu.feature.received.envelopeadd.content.more.MoreContentRoute import com.susu.feature.received.envelopeadd.content.name.NameContentRoute +import com.susu.feature.received.envelopeadd.content.phone.PhoneContentRoute +import com.susu.feature.received.envelopeadd.content.present.PresentContentRoute import com.susu.feature.received.envelopeadd.content.relationship.RelationShipContentRoute import com.susu.feature.received.envelopeadd.content.visited.VisitedContentRoute -import com.susu.feature.received.envelopeadd.content.visited.VisitedViewModel @Composable fun ReceivedEnvelopeAddRoute( @@ -66,11 +64,18 @@ fun ReceivedEnvelopeAddRoute( onClickBack = viewModel::goToPrevStep, onClickNext = viewModel::goToNextStep, updateParentMoney = viewModel::updateMoney, - updateParentName = viewModel::updateName, + updateParentName = { name -> + viewModel.updateName(name) + friendName = name + }, updateParentSelectedRelationShip = viewModel::updateSelectedRelationShip, updateParentMoreStep = viewModel::updateMoreStep, categoryName = viewModel.categoryName, updateParentVisited = viewModel::updateHasVisited, + updateParentPresent = viewModel::updatePresent, + friendName = friendName, + updateParentPhoneNumber = viewModel::updatePhoneNumber, + updateParentMemo = viewModel::updateMemo, ) } @@ -85,6 +90,10 @@ fun ReceivedEnvelopeAddScreen( updateParentMoreStep: (List) -> Unit = {}, categoryName: String = "", updateParentVisited: (Boolean?) -> Unit = {}, + updateParentPresent: (String?) -> Unit = {}, + friendName: String = "", + updateParentPhoneNumber: (String?) -> Unit = {}, + updateParentMemo: (String?) -> Unit = {}, ) { Column( @@ -130,9 +139,16 @@ fun ReceivedEnvelopeAddScreen( updateParentVisited = updateParentVisited, ) - EnvelopeAddStep.PRESENT -> PresentContent() - EnvelopeAddStep.PHONE -> PhoneContent(name = "김철수") - EnvelopeAddStep.MEMO -> MemoContent() + EnvelopeAddStep.PRESENT -> PresentContentRoute( + updateParentPresent = updateParentPresent, + ) + EnvelopeAddStep.PHONE -> PhoneContentRoute( + friendName = friendName, + updateParentPhone = updateParentPhoneNumber, + ) + EnvelopeAddStep.MEMO -> MemoContentRoute( + updateParentMemo = updateParentMemo, + ) } } SusuFilledButton( diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index 53a68179..f026ea02 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -20,6 +20,9 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( private var relationShip: RelationShip? = null private var moreStep: List = emptyList() private var hasVisited: Boolean? = null + private var present: String? = null + private var phoneNumber: String? = null + private var memo: String? = null fun goToPrevStep() = intent { val prevStep = when (currentStep) { @@ -119,4 +122,25 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( buttonEnabled = hasVisited != null, ) } + + fun updatePresent(present: String?) = intent { + this@ReceivedEnvelopeAddViewModel.present = present + copy( + buttonEnabled = !present.isNullOrEmpty(), + ) + } + + fun updatePhoneNumber(phoneNumber: String?) = intent { + this@ReceivedEnvelopeAddViewModel.phoneNumber = phoneNumber + copy( + buttonEnabled = !phoneNumber.isNullOrEmpty(), + ) + } + + fun updateMemo(memo: String?) = intent { + this@ReceivedEnvelopeAddViewModel.memo = memo + copy( + buttonEnabled = !memo.isNullOrEmpty(), + ) + } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/MemoContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoContent.kt similarity index 55% rename from feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/MemoContent.kt rename to feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoContent.kt index a64a3c4c..e5ba8276 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/MemoContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoContent.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.envelopeadd.content +package com.susu.feature.received.envelopeadd.content.memo import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -9,6 +9,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.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -16,26 +17,50 @@ import androidx.compose.runtime.setValue 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.Gray100 import com.susu.core.designsystem.theme.Gray40 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.received.R + @Composable -fun MemoContent( - modifier: Modifier = Modifier, - padding: PaddingValues = PaddingValues( - horizontal = SusuTheme.spacing.spacing_m, - vertical = SusuTheme.spacing.spacing_xl, - ), +fun MemoContentRoute( + viewModel: MemoViewModel = hiltViewModel(), + updateParentMemo: (String?) -> Unit, ) { - var memo by remember { mutableStateOf("") } + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is MemoSideEffect.UpdateParentMemo -> updateParentMemo(sideEffect.memo) + } + } + + LaunchedEffect(key1 = Unit) { + viewModel.updateMemo(uiState.memo) + } + MemoContent( + uiState = uiState, + onTextChangeMemo = viewModel::updateMemo, + ) +} + +@Composable +fun MemoContent( + uiState: MemoState = MemoState(), + onTextChangeMemo: (String) -> Unit = {}, +) { Column( - modifier = modifier + modifier = Modifier .fillMaxSize() - .padding(padding), + .padding( + horizontal = SusuTheme.spacing.spacing_m, + vertical = SusuTheme.spacing.spacing_xl, + ), ) { Text( text = stringResource(R.string.memo_content_title), @@ -43,17 +68,17 @@ fun MemoContent( color = Gray100, ) Spacer( - modifier = modifier + modifier = Modifier .size(SusuTheme.spacing.spacing_m), ) SusuBasicTextField( - text = memo, - onTextChange = { memo = it }, + text = uiState.memo, + onTextChange = onTextChangeMemo, placeholder = stringResource(R.string.memo_content_placeholder), placeholderColor = Gray40, - modifier = modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), ) - Spacer(modifier = modifier.size(SusuTheme.spacing.spacing_xl)) + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xl)) } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoState.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoState.kt new file mode 100644 index 00000000..b9cc3215 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoState.kt @@ -0,0 +1,12 @@ +package com.susu.feature.received.envelopeadd.content.memo + +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState + +data class MemoState( + val memo: String = "", +) : UiState + +sealed interface MemoSideEffect : SideEffect { + data class UpdateParentMemo(val memo: String?) : MemoSideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoViewModel.kt new file mode 100644 index 00000000..a2e012e9 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoViewModel.kt @@ -0,0 +1,15 @@ +package com.susu.feature.received.envelopeadd.content.memo + +import com.susu.core.ui.base.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class MemoViewModel @Inject constructor() : BaseViewModel( + MemoState(), +) { + fun updateMemo(memo: String?) = intent { + postSideEffect(MemoSideEffect.UpdateParentMemo(memo)) + copy(memo = memo ?: "") + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt index 81010735..fab65c4c 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt @@ -44,7 +44,7 @@ fun NameContentRoute( } LaunchedEffect(key1 = Unit) { - updateParentName(uiState.name) + viewModel.updateName(uiState.name) } NameContent( diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/PhoneContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContent.kt similarity index 52% rename from feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/PhoneContent.kt rename to feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContent.kt index 191d349d..5a9f9f16 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/PhoneContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContent.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.envelopeadd.content +package com.susu.feature.received.envelopeadd.content.phone import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.text.KeyboardOptions 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 @@ -17,48 +18,74 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType 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.Gray40 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.feature.received.R +import com.susu.feature.received.envelopeadd.content.present.PresentContent +import com.susu.feature.received.envelopeadd.content.present.PresentSideEffect +import com.susu.feature.received.envelopeadd.content.present.PresentViewModel +import kotlin.io.path.fileVisitor @Composable -fun PhoneContent( - modifier: Modifier = Modifier, - padding: PaddingValues = PaddingValues( - horizontal = SusuTheme.spacing.spacing_m, - vertical = SusuTheme.spacing.spacing_xl, - ), - name: String, +fun PhoneContentRoute( + viewModel: PhoneViewModel = hiltViewModel(), + friendName: String, + updateParentPhone: (String?) -> Unit ) { - var phoneNumber by remember { mutableStateOf("") } + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is PhoneSideEffect.UpdateParentPhone -> updateParentPhone(sideEffect.phone) + } + } + LaunchedEffect(key1 = Unit) { + viewModel.updateName(friendName) + viewModel.updatePhone(uiState.phone) + } + + PhoneContent( + uiState = uiState, + onTextChangePhone = viewModel::updatePhone, + ) +} + +@Composable +fun PhoneContent( + uiState: PhoneState = PhoneState(), + onTextChangePhone: (String) -> Unit = {}, +) { Column( - modifier = modifier + modifier = Modifier .fillMaxSize() - .padding(padding), + .padding(horizontal = SusuTheme.spacing.spacing_m, + vertical = SusuTheme.spacing.spacing_xl,), ) { AnnotatedText( - originalText = stringResource(R.string.phone_content_title, name), + originalText = stringResource(R.string.phone_content_title, uiState.name), originalTextStyle = SusuTheme.typography.title_m, - targetTextList = listOf(stringResource(R.string.phone_content_title_highlight, name)), + targetTextList = listOf(stringResource(R.string.phone_content_title_highlight, uiState.name)), spanStyle = SusuTheme.typography.title_m.copy(Gray60).toSpanStyle(), ) Spacer( - modifier = modifier + modifier = Modifier .size(SusuTheme.spacing.spacing_m), ) SusuBasicTextField( - text = phoneNumber, - onTextChange = { phoneNumber = it }, + text = uiState.phone, + onTextChange = onTextChangePhone, placeholder = stringResource(R.string.phone_content_placeholder), placeholderColor = Gray40, - modifier = modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), ) - Spacer(modifier = modifier.size(SusuTheme.spacing.spacing_xl)) + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xl)) } } @@ -66,6 +93,6 @@ fun PhoneContent( @Composable fun PhoneContentPreview() { SusuTheme { - PhoneContent(name = "김철수") + PhoneContent() } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContract.kt new file mode 100644 index 00000000..0322096e --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContract.kt @@ -0,0 +1,14 @@ +package com.susu.feature.received.envelopeadd.content.phone + +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import com.susu.feature.received.ledgeradd.LedgerAddStep + +data class PhoneState( + val phone: String = "", + val name: String = "", +) : UiState + +sealed interface PhoneSideEffect : SideEffect { + data class UpdateParentPhone(val phone: String?) : PhoneSideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneViewModel.kt new file mode 100644 index 00000000..d262e12f --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneViewModel.kt @@ -0,0 +1,16 @@ +package com.susu.feature.received.envelopeadd.content.phone + +import com.susu.core.ui.base.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class PhoneViewModel @Inject constructor() : BaseViewModel( + PhoneState(), +) { + fun updateName(name: String) = intent { copy(name = name) } + fun updatePhone(phone: String?) = intent { + postSideEffect(PhoneSideEffect.UpdateParentPhone(phone)) + copy(phone = phone ?: "") + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/PresentContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContent.kt similarity index 52% rename from feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/PresentContent.kt rename to feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContent.kt index b18e7cf3..8a537d98 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/PresentContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContent.kt @@ -1,4 +1,4 @@ -package com.susu.feature.received.envelopeadd.content +package com.susu.feature.received.envelopeadd.content.present import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -9,6 +9,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.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -16,26 +17,51 @@ import androidx.compose.runtime.setValue 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.Gray100 import com.susu.core.designsystem.theme.Gray40 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.received.R +import com.susu.feature.received.envelopeadd.content.name.NameSideEffect +import com.susu.feature.received.envelopeadd.content.name.NameState @Composable -fun PresentContent( - modifier: Modifier = Modifier, - padding: PaddingValues = PaddingValues( - horizontal = SusuTheme.spacing.spacing_m, - vertical = SusuTheme.spacing.spacing_xl, - ), +fun PresentContentRoute( + viewModel: PresentViewModel = hiltViewModel(), + updateParentPresent: (String?) -> Unit ) { - var sentPresent by remember { mutableStateOf("") } + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is PresentSideEffect.UpdateParentPresent -> updateParentPresent(sideEffect.present) + } + } + LaunchedEffect(key1 = Unit) { + viewModel.updatePresent(uiState.present) + } + + PresentContent( + uiState = uiState, + onTextChangeName = viewModel::updatePresent, + ) +} + +@Composable +fun PresentContent( + uiState: PresentState = PresentState(), + onTextChangeName: (String) -> Unit = {}, +) { Column( - modifier = modifier + modifier = Modifier .fillMaxSize() - .padding(padding), + .padding( + horizontal = SusuTheme.spacing.spacing_m, + vertical = SusuTheme.spacing.spacing_xl, + ), ) { Text( text = stringResource(R.string.present_content_title), @@ -43,17 +69,17 @@ fun PresentContent( color = Gray100, ) Spacer( - modifier = modifier + modifier = Modifier .size(SusuTheme.spacing.spacing_m), ) SusuBasicTextField( - text = sentPresent, - onTextChange = { sentPresent = it }, + text = uiState.present, + onTextChange = onTextChangeName, placeholder = stringResource(R.string.present_content_placeholder), placeholderColor = Gray40, - modifier = modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), ) - Spacer(modifier = modifier.size(SusuTheme.spacing.spacing_xl)) + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xl)) } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContract.kt new file mode 100644 index 00000000..1153087a --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContract.kt @@ -0,0 +1,13 @@ +package com.susu.feature.received.envelopeadd.content.present + +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import com.susu.feature.received.ledgeradd.LedgerAddStep + +data class PresentState( + val present: String = "", +) : UiState + +sealed interface PresentSideEffect : SideEffect { + data class UpdateParentPresent(val present: String?) : PresentSideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentViewModel.kt new file mode 100644 index 00000000..828e65be --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentViewModel.kt @@ -0,0 +1,15 @@ +package com.susu.feature.received.envelopeadd.content.present + +import com.susu.core.ui.base.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class PresentViewModel @Inject constructor() : BaseViewModel( + PresentState(), +) { + fun updatePresent(present: String?) = intent { + postSideEffect(PresentSideEffect.UpdateParentPresent(present)) + copy(present = present ?: "") + } +} From 8727b5392f4cb40aae36c1cdfca24e204b7947ce Mon Sep 17 00:00:00 2001 From: jinukeu Date: Tue, 23 Jan 2024 20:14:07 +0900 Subject: [PATCH 11/28] =?UTF-8?q?fix:=20=EC=9E=A5=EB=B6=80=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1,=20=EC=82=AD=EC=A0=9C=20=EC=8B=9C=20=EC=9E=A5?= =?UTF-8?q?=EB=B6=80=20=EC=97=86=EC=9D=8C=20=ED=99=94=EB=A9=B4=EC=9D=B4=20?= =?UTF-8?q?=EC=A0=9C=EB=8C=80=EB=A1=9C=20=ED=91=9C=EA=B8=B0=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8D=98=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../susu/feature/received/received/ReceivedViewModel.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 b6918f27..6f07a7d9 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 @@ -128,7 +128,12 @@ class ReceivedViewModel @Inject constructor( .map { if (it.id == toUpdateLedger.id) toUpdateLedger else it } .toPersistentList() - intent { copy(ledgerList = newList) } + intent { + copy( + ledgerList = newList, + showEmptyLedger = newList.isEmpty(), + ) + } } fun addLedgerIfNeed(ledger: String?) { @@ -143,6 +148,7 @@ class ReceivedViewModel @Inject constructor( ledgerList = currentState .ledgerList .add(0, toAddLedger), + showEmptyLedger = false, ) } } From 87f3cb4ad29a2ec7ba6b36214251eb37233c5b6c Mon Sep 17 00:00:00 2001 From: jinukeu Date: Tue, 23 Jan 2024 21:23:03 +0900 Subject: [PATCH 12/28] =?UTF-8?q?feat:=20Category=20style=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 --- core/model/src/main/java/com/susu/core/model/Category.kt | 1 + .../java/com/susu/data/local/model/CategoryConfigEntity.kt | 3 +++ .../susu/data/remote/model/response/CategoryConfigResponse.kt | 2 ++ .../java/com/susu/data/remote/model/response/LedgerResponse.kt | 2 ++ 4 files changed, 8 insertions(+) diff --git a/core/model/src/main/java/com/susu/core/model/Category.kt b/core/model/src/main/java/com/susu/core/model/Category.kt index a10be68f..8919864d 100644 --- a/core/model/src/main/java/com/susu/core/model/Category.kt +++ b/core/model/src/main/java/com/susu/core/model/Category.kt @@ -10,4 +10,5 @@ data class Category( val seq: Int = 0, val name: String = "", val customCategory: String? = null, + val style: String = "", ) diff --git a/data/src/main/java/com/susu/data/local/model/CategoryConfigEntity.kt b/data/src/main/java/com/susu/data/local/model/CategoryConfigEntity.kt index 0c84f2dd..c623c65a 100644 --- a/data/src/main/java/com/susu/data/local/model/CategoryConfigEntity.kt +++ b/data/src/main/java/com/susu/data/local/model/CategoryConfigEntity.kt @@ -10,16 +10,19 @@ data class CategoryConfigEntity( val id: Int, val seq: Int, val name: String, + val style: String, ) internal fun CategoryConfigEntity.toModel() = Category( id = id, seq = seq, name = name, + style = style, ) internal fun Category.toEntity() = CategoryConfigEntity( id = id, seq = seq, name = name, + style = style, ) diff --git a/data/src/main/java/com/susu/data/remote/model/response/CategoryConfigResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/CategoryConfigResponse.kt index cc701b65..2ca0d38d 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/CategoryConfigResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/CategoryConfigResponse.kt @@ -8,10 +8,12 @@ data class CategoryConfigResponse( val id: Int, val seq: Int, val name: String, + val style: String, ) internal fun CategoryConfigResponse.toModel() = Category( id = id, seq = seq, name = name, + style = style, ) diff --git a/data/src/main/java/com/susu/data/remote/model/response/LedgerResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/LedgerResponse.kt index cf7d0450..f86c32ac 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/LedgerResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/LedgerResponse.kt @@ -30,6 +30,7 @@ data class CategoryInfo( val seq: Int, val category: String, val customCategory: String? = null, + val style: String, ) internal fun LedgerResponse.toModel() = Ledger( @@ -48,4 +49,5 @@ internal fun CategoryInfo.toModel() = Category( seq = seq, name = category, customCategory = customCategory, + style = style, ) From 925970cc45f826e7b32535ad0a43476ec0e89554 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Tue, 23 Jan 2024 21:37:46 +0900 Subject: [PATCH 13/28] =?UTF-8?q?feat:=20Friend=20Service=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 --- .../com/susu/data/remote/api/FriendService.kt | 15 +++++++++++++++ .../com/susu/data/remote/di/ApiServiceModule.kt | 7 +++++++ .../data/remote/model/request/FriendRequest.kt | 11 +++++++++++ .../data/remote/model/response/FriendResponse.kt | 6 ++++++ 4 files changed, 39 insertions(+) create mode 100644 data/src/main/java/com/susu/data/remote/api/FriendService.kt create mode 100644 data/src/main/java/com/susu/data/remote/model/request/FriendRequest.kt create mode 100644 data/src/main/java/com/susu/data/remote/model/response/FriendResponse.kt diff --git a/data/src/main/java/com/susu/data/remote/api/FriendService.kt b/data/src/main/java/com/susu/data/remote/api/FriendService.kt new file mode 100644 index 00000000..18d055d4 --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/api/FriendService.kt @@ -0,0 +1,15 @@ +package com.susu.data.remote.api + +import com.susu.data.remote.model.request.FriendRequest +import com.susu.data.remote.model.response.FriendResponse +import com.susu.data.remote.retrofit.ApiResult +import retrofit2.http.Body +import retrofit2.http.POST + +interface FriendService { + + @POST("friends") + suspend fun createFriend( + @Body friendRequest: FriendRequest + ): ApiResult +} diff --git a/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt b/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt index 26559bef..5660edbe 100644 --- a/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt +++ b/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt @@ -3,6 +3,7 @@ package com.susu.data.remote.di import com.susu.data.remote.api.AuthService import com.susu.data.remote.api.CategoryService import com.susu.data.remote.api.EnvelopesService +import com.susu.data.remote.api.FriendService import com.susu.data.remote.api.LedgerService import com.susu.data.remote.api.SignUpService import com.susu.data.remote.api.TermService @@ -66,4 +67,10 @@ object ApiServiceModule { fun providesUserService(retrofit: Retrofit): UserService { return retrofit.create(UserService::class.java) } + + @Singleton + @Provides + fun providesFriendService(retrofit: Retrofit): FriendService { + return retrofit.create(FriendService::class.java) + } } diff --git a/data/src/main/java/com/susu/data/remote/model/request/FriendRequest.kt b/data/src/main/java/com/susu/data/remote/model/request/FriendRequest.kt new file mode 100644 index 00000000..b69afebc --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/request/FriendRequest.kt @@ -0,0 +1,11 @@ +package com.susu.data.remote.model.request + +import kotlinx.serialization.Serializable + +@Serializable +data class FriendRequest( + val name: String, + val phoneNumber: String? = null, + val relationshipId: Int, + val customRelation: String? = null, +) diff --git a/data/src/main/java/com/susu/data/remote/model/response/FriendResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/FriendResponse.kt new file mode 100644 index 00000000..8234fd4e --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/response/FriendResponse.kt @@ -0,0 +1,6 @@ +package com.susu.data.remote.model.response + +import kotlinx.serialization.Serializable + +@Serializable +data class FriendResponse(val id: Int) From bceb087171563c5801e269d340db23958a408523 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 10:58:13 +0900 Subject: [PATCH 14/28] =?UTF-8?q?fix:=20=ED=95=84=ED=84=B0=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/designsystem/component/badge/BadgeColor.kt | 13 ++++++++++++- .../received/navigation/ReceivedNavigation.kt | 1 + .../feature/received/received/ReceivedScreen.kt | 2 ++ .../received/received/component/LedgerCard.kt | 10 +++++++--- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/badge/BadgeColor.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/badge/BadgeColor.kt index 1e8a723d..cc91eaf2 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/badge/BadgeColor.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/badge/BadgeColor.kt @@ -1,8 +1,10 @@ package com.susu.core.designsystem.component.badge +import android.util.Log import androidx.compose.ui.graphics.Color import com.susu.core.designsystem.theme.Gray10 import com.susu.core.designsystem.theme.Gray70 +import java.lang.IllegalArgumentException enum class BadgeColor( val backgroundColor: Color, @@ -35,5 +37,14 @@ enum class BadgeColor( Red60( backgroundColor = com.susu.core.designsystem.theme.Red60, textColor = Gray10, - ), + ); + + companion object { + fun safeValueOf(value: String) = try { + valueOf(value) + } catch (e: IllegalArgumentException) { + Log.e("SafeValueOfError", "Invalid value provided", e) + Gray40 + } + } } 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 84896aed..dcee893d 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 @@ -81,6 +81,7 @@ fun NavGraphBuilder.receivedNavGraph( val ledger = navBackStackEntry.savedStateHandle.get(ReceivedRoute.LEDGER_ARGUMENT_NAME) val toDeleteLedgerId = navBackStackEntry.savedStateHandle.get(ReceivedRoute.LEDGER_ID_ARGUMENT_NAME) ?: -1 val filter = navBackStackEntry.savedStateHandle.get(ReceivedRoute.FILTER_ARGUMENT_NAME) + navBackStackEntry.savedStateHandle.set(ReceivedRoute.FILTER_ARGUMENT_NAME, null) ReceivedRoute( ledger = ledger, toDeleteLedgerId = toDeleteLedgerId, 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 a53099a9..1be618d4 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 @@ -257,6 +257,7 @@ fun ReceiveScreen( title = ledger.title, money = ledger.totalAmounts, count = ledger.totalCounts, + style = ledger.category.style, onClick = { onClickLedgerCard(ledger) }, ) } @@ -271,6 +272,7 @@ fun ReceiveScreen( title = ledger.title, money = ledger.totalAmounts, count = ledger.totalCounts, + style = ledger.category.style, onClick = { onClickLedgerCard(ledger) }, ) } diff --git a/feature/received/src/main/java/com/susu/feature/received/received/component/LedgerCard.kt b/feature/received/src/main/java/com/susu/feature/received/received/component/LedgerCard.kt index 6af323d1..e56e732f 100644 --- a/feature/received/src/main/java/com/susu/feature/received/received/component/LedgerCard.kt +++ b/feature/received/src/main/java/com/susu/feature/received/received/component/LedgerCard.kt @@ -24,12 +24,15 @@ import com.susu.core.ui.extension.toMoneyFormat @Composable fun LedgerCard( modifier: Modifier = Modifier, - ledgerType: String, // TODO LedgerType에 따라 Badger 색상 변경 필요 + ledgerType: String, + style: String, title: String, money: Int, count: Int, onClick: () -> Unit = {}, ) { + val badgeColor = BadgeColor.safeValueOf(style) + Column( modifier = modifier .aspectRatio(1f) @@ -38,7 +41,7 @@ fun LedgerCard( .padding(SusuTheme.spacing.spacing_m), ) { SusuBadge( - color = BadgeColor.Orange60, + color = badgeColor, text = ledgerType, padding = BadgeStyle.smallBadge, ) @@ -75,8 +78,9 @@ fun LedgerCardPreview() { LedgerCard( ledgerType = "결혼식", title = "나의 결혼식", - money = 4335000, + style = "", count = 164, + money = 10000, ) } } From bcddb8bb622c90d2881985d5329fa72abd3fbc85 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 12:18:29 +0900 Subject: [PATCH 15/28] =?UTF-8?q?feat:=20CreateFriendUseCase,=20SearchFrie?= =?UTF-8?q?ndUseCase=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/susu/core/model/FriendSearch.kt | 15 ++++++ .../{RelationShip.kt => Relationship.kt} | 2 +- .../com/susu/data/data/di/RepositoryModule.kt | 7 +++ .../repository/EnvelopesRepositoryImpl.kt | 4 +- .../data/repository/FriendRepositoryImpl.kt | 34 ++++++++++++ .../com/susu/data/remote/api/FriendService.kt | 8 +++ .../model/response/FriendSearchResponse.kt | 52 +++++++++++++++++++ .../response/RelationShipListResponse.kt | 5 +- .../domain/repository/EnvelopesRepository.kt | 4 +- .../domain/repository/FriendRepository.kt | 18 +++++++ .../usecase/friend/CreateFriendUseCase.kt | 28 ++++++++++ .../usecase/friend/SearchFriendUseCase.kt | 16 ++++++ .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 5 +- .../ReceivedEnvelopeAddViewModel.kt | 6 +-- .../envelopeadd/content/more/MoreContract.kt | 2 - .../relationship/RelationShipContent.kt | 25 ++++----- .../relationship/RelationShipContract.kt | 12 ++--- .../relationship/RelationShipViewModel.kt | 28 +++++----- 18 files changed, 219 insertions(+), 52 deletions(-) create mode 100644 core/model/src/main/java/com/susu/core/model/FriendSearch.kt rename core/model/src/main/java/com/susu/core/model/{RelationShip.kt => Relationship.kt} (87%) create mode 100644 data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt create mode 100644 data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt create mode 100644 domain/src/main/java/com/susu/domain/repository/FriendRepository.kt create mode 100644 domain/src/main/java/com/susu/domain/usecase/friend/CreateFriendUseCase.kt create mode 100644 domain/src/main/java/com/susu/domain/usecase/friend/SearchFriendUseCase.kt diff --git a/core/model/src/main/java/com/susu/core/model/FriendSearch.kt b/core/model/src/main/java/com/susu/core/model/FriendSearch.kt new file mode 100644 index 00000000..c65e3571 --- /dev/null +++ b/core/model/src/main/java/com/susu/core/model/FriendSearch.kt @@ -0,0 +1,15 @@ +package com.susu.core.model + +import java.time.LocalDateTime + + +data class FriendSearch( + val friend: Friend, + val relationship: Relationship, + val recentEnvelope: RecentEnvelope? = null, +) + +data class RecentEnvelope( + val category: String, + val handedOverAt: LocalDateTime +) diff --git a/core/model/src/main/java/com/susu/core/model/RelationShip.kt b/core/model/src/main/java/com/susu/core/model/Relationship.kt similarity index 87% rename from core/model/src/main/java/com/susu/core/model/RelationShip.kt rename to core/model/src/main/java/com/susu/core/model/Relationship.kt index 19c6b251..ac1c9e28 100644 --- a/core/model/src/main/java/com/susu/core/model/RelationShip.kt +++ b/core/model/src/main/java/com/susu/core/model/Relationship.kt @@ -3,7 +3,7 @@ package com.susu.core.model import androidx.compose.runtime.Stable @Stable -data class RelationShip( +data class Relationship( val id: Int = -1, val relation: String = "", val customRelation: String? = null diff --git a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt index 9fa47264..2451900f 100644 --- a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt +++ b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt @@ -3,6 +3,7 @@ package com.susu.data.data.di import com.susu.data.data.repository.CategoryConfigRepositoryImpl import com.susu.data.data.repository.ExcelRepositoryImpl import com.susu.data.data.repository.EnvelopesRepositoryImpl +import com.susu.data.data.repository.FriendRepositoryImpl import com.susu.data.data.repository.LedgerRecentSearchRepositoryImpl import com.susu.data.data.repository.LedgerRepositoryImpl import com.susu.data.data.repository.LoginRepositoryImpl @@ -13,6 +14,7 @@ import com.susu.data.data.repository.UserRepositoryImpl import com.susu.domain.repository.CategoryConfigRepository import com.susu.domain.repository.EnvelopesRepository import com.susu.domain.repository.ExcelRepository +import com.susu.domain.repository.FriendRepository import com.susu.domain.repository.LedgerRecentSearchRepository import com.susu.domain.repository.LedgerRepository import com.susu.domain.repository.LoginRepository @@ -78,4 +80,9 @@ abstract class RepositoryModule { abstract fun bindEnvelopesRepository( envelopesRepositoryImpl: EnvelopesRepositoryImpl, ): EnvelopesRepository + + @Binds + abstract fun bindFriendRepository( + friendRepositoryImpl: FriendRepositoryImpl, + ): FriendRepository } diff --git a/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt index cf608c6e..34206816 100644 --- a/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt @@ -1,7 +1,7 @@ package com.susu.data.data.repository import com.susu.core.model.Envelope -import com.susu.core.model.RelationShip +import com.susu.core.model.Relationship import com.susu.data.remote.api.EnvelopesService import com.susu.data.remote.model.response.toModel import com.susu.domain.repository.EnvelopesRepository @@ -26,5 +26,5 @@ class EnvelopesRepositoryImpl @Inject constructor( sort = sort, ).getOrThrow().toModel() - override suspend fun getRelationShipConfigList(): List = envelopesService.getRelationShipConfigList().getOrThrow().toModel() + override suspend fun getRelationShipConfigList(): List = envelopesService.getRelationShipConfigList().getOrThrow().toModel() } diff --git a/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt new file mode 100644 index 00000000..7f564137 --- /dev/null +++ b/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt @@ -0,0 +1,34 @@ +package com.susu.data.data.repository + +import com.susu.core.model.Envelope +import com.susu.core.model.FriendSearch +import com.susu.core.model.Relationship +import com.susu.data.remote.api.EnvelopesService +import com.susu.data.remote.api.FriendService +import com.susu.data.remote.model.request.FriendRequest +import com.susu.data.remote.model.response.toModel +import com.susu.domain.repository.EnvelopesRepository +import com.susu.domain.repository.FriendRepository +import javax.inject.Inject + +class FriendRepositoryImpl @Inject constructor( + private val friendService: FriendService, +) : FriendRepository { + override suspend fun createFriend( + name: String, + phoneNumber: String?, + relationshipId: Int, + customRelation: String?, + ): Int = friendService.createFriend( + FriendRequest( + name = name, + phoneNumber = phoneNumber, + relationshipId = relationshipId, + customRelation = customRelation, + ), + ).getOrThrow().id + + override suspend fun searchFriend(name: String): FriendSearch = friendService.searchFriend( + name = name, + ).getOrThrow().toModel() +} diff --git a/data/src/main/java/com/susu/data/remote/api/FriendService.kt b/data/src/main/java/com/susu/data/remote/api/FriendService.kt index 18d055d4..99073e45 100644 --- a/data/src/main/java/com/susu/data/remote/api/FriendService.kt +++ b/data/src/main/java/com/susu/data/remote/api/FriendService.kt @@ -2,9 +2,12 @@ package com.susu.data.remote.api import com.susu.data.remote.model.request.FriendRequest import com.susu.data.remote.model.response.FriendResponse +import com.susu.data.remote.model.response.FriendSearchResponse import com.susu.data.remote.retrofit.ApiResult import retrofit2.http.Body +import retrofit2.http.GET import retrofit2.http.POST +import retrofit2.http.Query interface FriendService { @@ -12,4 +15,9 @@ interface FriendService { suspend fun createFriend( @Body friendRequest: FriendRequest ): ApiResult + + @GET("friends") + suspend fun searchFriend( + @Query("name") name: String, + ): ApiResult } diff --git a/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt new file mode 100644 index 00000000..4142c3ce --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt @@ -0,0 +1,52 @@ +package com.susu.data.remote.model.response + +import com.susu.core.model.FriendSearch +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.toJavaLocalDateTime +import kotlinx.serialization.Serializable + +@Serializable +data class FriendSearchResponse( + val friend: Friend, + val relationship: Relationship, + val recentEnvelope: RecentEnvelope? = null, +) + +@Serializable +data class Friend( + val id: Int, + val name: String, + val phoneNumber: String? = null, +) + +@Serializable +data class Relationship( + val id: Int, + val relation: String, + val customRelation: String? = null, +) + +@Serializable +data class RecentEnvelope( + val category: String, + val handedOverAt: LocalDateTime, +) + +internal fun FriendSearchResponse.toModel() = FriendSearch( + friend = com.susu.core.model.Friend( + id = friend.id, + name = friend.name, + phoneNumber = friend.phoneNumber ?: "", + ), + relationship = com.susu.core.model.Relationship( + id = relationship.id, + relation = relationship.relation, + customRelation = relationship.customRelation, + ), + recentEnvelope = recentEnvelope?.toModel(), +) + +internal fun RecentEnvelope.toModel() = com.susu.core.model.RecentEnvelope( + category = category, + handedOverAt = handedOverAt.toJavaLocalDateTime(), +) diff --git a/data/src/main/java/com/susu/data/remote/model/response/RelationShipListResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/RelationShipListResponse.kt index e1fef451..3b73868c 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/RelationShipListResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/RelationShipListResponse.kt @@ -1,7 +1,6 @@ package com.susu.data.remote.model.response -import com.susu.core.model.Category -import com.susu.core.model.RelationShip +import com.susu.core.model.Relationship import kotlinx.serialization.Serializable @Serializable @@ -17,7 +16,7 @@ data class RelationConfigShipResponse( internal fun RelationShipListResponse.toModel() = relationships.map { it.toModel() } -internal fun RelationConfigShipResponse.toModel() = RelationShip( +internal fun RelationConfigShipResponse.toModel() = Relationship( id = id, relation = relation, ) diff --git a/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt b/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt index 6316b1bf..c7add06b 100644 --- a/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt +++ b/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt @@ -1,7 +1,7 @@ package com.susu.domain.repository import com.susu.core.model.Envelope -import com.susu.core.model.RelationShip +import com.susu.core.model.Relationship interface EnvelopesRepository { suspend fun getEnvelopesList( @@ -13,5 +13,5 @@ interface EnvelopesRepository { sort: String?, ): List - suspend fun getRelationShipConfigList(): List + suspend fun getRelationShipConfigList(): List } diff --git a/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt b/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt new file mode 100644 index 00000000..eff0e0bc --- /dev/null +++ b/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt @@ -0,0 +1,18 @@ +package com.susu.domain.repository + +import com.susu.core.model.Envelope +import com.susu.core.model.FriendSearch +import com.susu.core.model.Relationship + +interface FriendRepository { + suspend fun createFriend( + name: String, + phoneNumber: String? = null, + relationshipId: Int, + customRelation: String? = null, + ): Int + + suspend fun searchFriend( + name: String, + ): FriendSearch +} diff --git a/domain/src/main/java/com/susu/domain/usecase/friend/CreateFriendUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/friend/CreateFriendUseCase.kt new file mode 100644 index 00000000..4c238f41 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/friend/CreateFriendUseCase.kt @@ -0,0 +1,28 @@ +package com.susu.domain.usecase.friend + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.CategoryConfigRepository +import com.susu.domain.repository.FriendRepository +import javax.inject.Inject + +class CreateFriendUseCase @Inject constructor( + private val friendRepository: FriendRepository, +) { + suspend operator fun invoke(param: Param) = runCatchingIgnoreCancelled { + with(param) { + friendRepository.createFriend( + name = name, + phoneNumber = phoneNumber, + relationshipId = relationshipId, + customRelation = customRelation, + ) + } + } + + data class Param( + val name: String = "", + val phoneNumber: String? = null, + val relationshipId: Int = 0, + val customRelation: String? = null, + ) +} diff --git a/domain/src/main/java/com/susu/domain/usecase/friend/SearchFriendUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/friend/SearchFriendUseCase.kt new file mode 100644 index 00000000..7fe331e1 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/friend/SearchFriendUseCase.kt @@ -0,0 +1,16 @@ +package com.susu.domain.usecase.friend + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.CategoryConfigRepository +import com.susu.domain.repository.FriendRepository +import javax.inject.Inject + +class SearchFriendUseCase @Inject constructor( + private val friendRepository: FriendRepository, +) { + suspend operator fun invoke(name: String) = runCatchingIgnoreCancelled { + friendRepository.searchFriend( + name = name, + ) + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index 2dbf2962..eb5ee8fb 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -24,10 +24,9 @@ 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.RelationShip +import com.susu.core.model.Relationship import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec -import com.susu.feature.received.envelopeadd.content.memo.MemoContent import com.susu.feature.received.envelopeadd.content.memo.MemoContentRoute import com.susu.feature.received.envelopeadd.content.money.MoneyContentRoute import com.susu.feature.received.envelopeadd.content.more.MoreContentRoute @@ -86,7 +85,7 @@ fun ReceivedEnvelopeAddScreen( onClickNext: () -> Unit = {}, updateParentMoney: (Long) -> Unit = {}, updateParentName: (String) -> Unit = {}, - updateParentSelectedRelationShip: (RelationShip?) -> Unit = {}, + updateParentSelectedRelationShip: (Relationship?) -> Unit = {}, updateParentMoreStep: (List) -> Unit = {}, categoryName: String = "", updateParentVisited: (Boolean?) -> Unit = {}, diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index f026ea02..554f4326 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -1,7 +1,7 @@ package com.susu.feature.received.envelopeadd import androidx.lifecycle.SavedStateHandle -import com.susu.core.model.RelationShip +import com.susu.core.model.Relationship import com.susu.core.ui.base.BaseViewModel import com.susu.feature.received.navigation.ReceivedRoute import dagger.hilt.android.lifecycle.HiltViewModel @@ -17,7 +17,7 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( private var money: Long = 0 private var name: String = "" - private var relationShip: RelationShip? = null + private var relationShip: Relationship? = null private var moreStep: List = emptyList() private var hasVisited: Boolean? = null private var present: String? = null @@ -105,7 +105,7 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( ) } - fun updateSelectedRelationShip(relationShip: RelationShip?) = intent { + fun updateSelectedRelationShip(relationShip: Relationship?) = intent { this@ReceivedEnvelopeAddViewModel.relationShip = relationShip copy( buttonEnabled = relationShip != null, diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreContract.kt index ec18deff..a2e04e09 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/more/MoreContract.kt @@ -1,10 +1,8 @@ package com.susu.feature.received.envelopeadd.content.more -import com.susu.core.model.RelationShip import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState import com.susu.feature.received.envelopeadd.EnvelopeAddStep -import com.susu.feature.received.ledgeradd.LedgerAddStep import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt index 63f89093..8d4642e7 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt @@ -2,7 +2,6 @@ package com.susu.feature.received.envelopeadd.content.relationship import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -13,11 +12,8 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text 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.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester @@ -35,19 +31,16 @@ import com.susu.core.designsystem.component.textfieldbutton.TextFieldButtonColor import com.susu.core.designsystem.component.textfieldbutton.style.MediumTextFieldButtonStyle import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.SusuTheme -import com.susu.core.model.Category -import com.susu.core.model.RelationShip +import com.susu.core.model.Relationship import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.received.R -import com.susu.feature.received.ledgeradd.content.category.CategoryContent -import com.susu.feature.received.ledgeradd.content.category.CategorySideEffect import kotlinx.coroutines.android.awaitFrame import kotlinx.coroutines.launch @Composable fun RelationShipContentRoute( viewModel: RelationShipViewModel = hiltViewModel(), - updateParentSelectedRelation: (RelationShip?) -> Unit = {}, + updateParentSelectedRelation: (Relationship?) -> Unit = {}, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value val focusRequester = remember { FocusRequester() } @@ -70,10 +63,10 @@ fun RelationShipContentRoute( } LaunchedEffect( - key1 = uiState.selectedRelationShip, + key1 = uiState.selectedRelationship, key2 = uiState.isSavedCustomRelationShip, ) { - snapshotFlow { uiState.selectedRelationShip } + snapshotFlow { uiState.selectedRelationship } .collect { viewModel.updateParentSelectedRelationShip() } @@ -96,7 +89,7 @@ fun RelationShipContentRoute( fun RelationShipContent( uiState: RelationShipState = RelationShipState(), focusRequester: FocusRequester = remember { FocusRequester() }, - onClickRelationShipButton: (RelationShip) -> Unit = {}, + onClickRelationShipButton: (Relationship) -> Unit = {}, onClickCustomRelationShipButton: () -> Unit = {}, onClickCustomRelationShipTextFieldCloseIcon: () -> Unit = {}, onClickCustomRelationShipTextField: () -> Unit = {}, @@ -127,8 +120,8 @@ fun RelationShipContent( Column( verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), ) { - uiState.relationShipConfig.forEach { relationship -> - if (relationship == uiState.selectedRelationShip) { + uiState.relationshipConfig.forEach { relationship -> + if (relationship == uiState.selectedRelationship) { SusuFilledButton( color = FilledButtonColor.Orange, style = MediumButtonStyle.height60, @@ -151,12 +144,12 @@ fun RelationShipContent( if (uiState.showTextFieldButton) { SusuTextFieldFillMaxButton( color = if (uiState.isCustomRelationShipSelected) TextFieldButtonColor.Orange else TextFieldButtonColor.Black, - text = uiState.customRelationShip.customRelation ?: "", + text = uiState.customRelationship.customRelation ?: "", onTextChange = onTextChangeCustomRelationShipTextField, focusRequester = focusRequester, style = MediumTextFieldButtonStyle.height60, isSaved = uiState.isSavedCustomRelationShip, - isFocused = uiState.customRelationShip == uiState.selectedRelationShip, + isFocused = uiState.customRelationship == uiState.selectedRelationship, placeholder = stringResource(com.susu.core.ui.R.string.word_input_placeholder), onClickCloseIcon = onClickCustomRelationShipTextFieldCloseIcon, onClickClearIcon = onClickCustomRelationShipTextFieldClearIcon, diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContract.kt index 9628ebee..6cad6733 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContract.kt @@ -1,22 +1,22 @@ package com.susu.feature.received.envelopeadd.content.relationship -import com.susu.core.model.RelationShip +import com.susu.core.model.Relationship 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 RelationShipState( - val selectedRelationShip: RelationShip? = null, - val relationShipConfig: PersistentList = persistentListOf(), - val customRelationShip: RelationShip = RelationShip(), + val selectedRelationship: Relationship? = null, + val relationshipConfig: PersistentList = persistentListOf(), + val customRelationship: Relationship = Relationship(), val showTextFieldButton: Boolean = false, val isSavedCustomRelationShip: Boolean = false, ) : UiState { - val isCustomRelationShipSelected = customRelationShip == selectedRelationShip + val isCustomRelationShipSelected = customRelationship == selectedRelationship } sealed interface RelationShipSideEffect : SideEffect { data object FocusCustomRelationShip : RelationShipSideEffect - data class UpdateParentSelectedRelationShip(val relationShip: RelationShip?) : RelationShipSideEffect + data class UpdateParentSelectedRelationShip(val relationShip: Relationship?) : RelationShipSideEffect } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt index cf6e5bfe..895871b1 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt @@ -1,7 +1,7 @@ package com.susu.feature.received.envelopeadd.content.relationship import androidx.lifecycle.viewModelScope -import com.susu.core.model.RelationShip +import com.susu.core.model.Relationship import com.susu.core.ui.base.BaseViewModel import com.susu.domain.usecase.envelope.GetRelationShipConfigListUseCase import dagger.hilt.android.lifecycle.HiltViewModel @@ -17,46 +17,46 @@ class RelationShipViewModel @Inject constructor( ) { private val parentSelectedRelationShip get() = with(currentState) { - if (selectedRelationShip == customRelationShip && (customRelationShip.customRelation.isNullOrEmpty() || isSavedCustomRelationShip.not())) { + if (selectedRelationship == customRelationship && (customRelationship.customRelation.isNullOrEmpty() || isSavedCustomRelationShip.not())) { null } else { - selectedRelationShip + selectedRelationship } } fun getRelationShipConfig() = viewModelScope.launch { - if (currentState.relationShipConfig.isNotEmpty()) return@launch + if (currentState.relationshipConfig.isNotEmpty()) return@launch getRelationShipConfigUseCase() .onSuccess { intent { copy( - relationShipConfig = it.dropLast(1).toPersistentList(), - customRelationShip = it.last(), + relationshipConfig = it.dropLast(1).toPersistentList(), + customRelationship = it.last(), ) } } .onFailure { } } - fun selectRelationShip(relationShip: RelationShip) = intent { copy(selectedRelationShip = relationShip) } + fun selectRelationShip(relationShip: Relationship) = intent { copy(selectedRelationship = relationShip) } fun selectCustomRelationShip() = intent { postSideEffect(RelationShipSideEffect.FocusCustomRelationShip) - copy(selectedRelationShip = customRelationShip) + copy(selectedRelationship = customRelationship) } fun updateCustomRelationShipText(text: String) = intent { copy( - selectedRelationShip = customRelationShip.copy(customRelation = text), - customRelationShip = customRelationShip.copy(customRelation = text), + selectedRelationship = customRelationship.copy(customRelation = text), + customRelationship = customRelationship.copy(customRelation = text), ) } fun showCustomRelationShipTextField() = intent { copy( showTextFieldButton = true, - selectedRelationShip = customRelationShip, + selectedRelationship = customRelationship, ) } @@ -64,8 +64,8 @@ class RelationShipViewModel @Inject constructor( copy( isSavedCustomRelationShip = false, showTextFieldButton = false, - selectedRelationShip = if (isCustomRelationShipSelected) null else selectedRelationShip, - customRelationShip = customRelationShip.copy(customRelation = ""), + selectedRelationship = if (isCustomRelationShipSelected) null else selectedRelationship, + customRelationship = customRelationship.copy(customRelation = ""), ) } @@ -75,7 +75,7 @@ class RelationShipViewModel @Inject constructor( ) } - fun updateParentSelectedRelationShip(relationShip: RelationShip? = parentSelectedRelationShip) = postSideEffect( + fun updateParentSelectedRelationShip(relationShip: Relationship? = parentSelectedRelationShip) = postSideEffect( RelationShipSideEffect.UpdateParentSelectedRelationShip(relationShip), ) } From e5cf031eaf94a700b9e06e62a8eba0a0eccd5fb0 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 14:28:28 +0900 Subject: [PATCH 16/28] =?UTF-8?q?feat:=20CreateReceivedEnvelopeUseCase=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/susu/core/model/EnvelopeResponse.kt | 15 ++++++ .../model/{Envelope.kt => EnvelopeStatics.kt} | 2 +- .../repository/EnvelopesRepositoryImpl.kt | 38 ++++++++++++++- .../data/repository/FriendRepositoryImpl.kt | 6 +-- .../susu/data/remote/api/EnvelopesService.kt | 10 +++- .../remote/model/request/EnvelopeRequest.kt | 23 ++++++++++ .../remote/model/response/EnvelopeResponse.kt | 31 +++++++++++++ .../model/response/EnvelopesResponse.kt | 4 +- .../remote/model/response/FriendResponse.kt | 2 +- domain/build.gradle.kts | 2 + .../domain/repository/EnvelopesRepository.kt | 17 ++++++- .../domain/repository/FriendRepository.kt | 4 +- .../envelope/CreateReceivedEnvelopeUseCase.kt | 46 +++++++++++++++++++ .../com/susu/feature/sent/SentContract.kt | 4 +- 14 files changed, 186 insertions(+), 18 deletions(-) create mode 100644 core/model/src/main/java/com/susu/core/model/EnvelopeResponse.kt rename core/model/src/main/java/com/susu/core/model/{Envelope.kt => EnvelopeStatics.kt} (85%) create mode 100644 data/src/main/java/com/susu/data/remote/model/request/EnvelopeRequest.kt create mode 100644 data/src/main/java/com/susu/data/remote/model/response/EnvelopeResponse.kt create mode 100644 domain/src/main/java/com/susu/domain/usecase/envelope/CreateReceivedEnvelopeUseCase.kt diff --git a/core/model/src/main/java/com/susu/core/model/EnvelopeResponse.kt b/core/model/src/main/java/com/susu/core/model/EnvelopeResponse.kt new file mode 100644 index 00000000..9328f617 --- /dev/null +++ b/core/model/src/main/java/com/susu/core/model/EnvelopeResponse.kt @@ -0,0 +1,15 @@ +package com.susu.core.model + +import java.time.LocalDateTime + +data class Envelope( + val id: Long, + val uid: Long, + val type: String, + val friendId: Long, + val amount: Long, + val gift: String? = null, + val memo: String? = null, + val hasVisited: Boolean? = null, + val handedOverAt: LocalDateTime? = null +) diff --git a/core/model/src/main/java/com/susu/core/model/Envelope.kt b/core/model/src/main/java/com/susu/core/model/EnvelopeStatics.kt similarity index 85% rename from core/model/src/main/java/com/susu/core/model/Envelope.kt rename to core/model/src/main/java/com/susu/core/model/EnvelopeStatics.kt index 8877563d..f123fb2e 100644 --- a/core/model/src/main/java/com/susu/core/model/Envelope.kt +++ b/core/model/src/main/java/com/susu/core/model/EnvelopeStatics.kt @@ -1,6 +1,6 @@ package com.susu.core.model -data class Envelope( +data class EnvelopeStatics( val friend: Friend = Friend(), val receivedAmounts: Int = 0, val sentAmounts: Int = 0, diff --git a/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt index 34206816..ec328f4e 100644 --- a/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt @@ -1,8 +1,11 @@ package com.susu.data.data.repository import com.susu.core.model.Envelope +import com.susu.core.model.EnvelopeStatics import com.susu.core.model.Relationship import com.susu.data.remote.api.EnvelopesService +import com.susu.data.remote.model.request.CategoryRequest +import com.susu.data.remote.model.request.EnvelopeRequest import com.susu.data.remote.model.response.toModel import com.susu.domain.repository.EnvelopesRepository import javax.inject.Inject @@ -17,7 +20,7 @@ class EnvelopesRepositoryImpl @Inject constructor( page: Int?, size: Int?, sort: String?, - ): List = envelopesService.getEnvelopesList( + ): List = envelopesService.getEnvelopesList( friendIds = friendIds, fromTotalAmounts = fromTotalAmounts, toTotalMounts = toTotalAmounts, @@ -26,5 +29,36 @@ class EnvelopesRepositoryImpl @Inject constructor( sort = sort, ).getOrThrow().toModel() - override suspend fun getRelationShipConfigList(): List = envelopesService.getRelationShipConfigList().getOrThrow().toModel() + override suspend fun getRelationShipConfigList(): List = envelopesService + .getRelationShipConfigList() + .getOrThrow() + .toModel() + + override suspend fun createEnvelope( + type: String, + friendId: Long, + ledgerId: Long?, + amount: Long, + gift: String?, + memo: String?, + hasVisited: Boolean?, + handedOverAt: kotlinx.datetime.LocalDateTime?, + categoryId: Long?, + customCategory: String?, + ): Envelope = envelopesService.createEnvelope( + envelopeRequest = EnvelopeRequest( + type = type, + friendId = friendId, + ledgerId = ledgerId, + amount = amount, + gift = gift, + memo = memo, + hasVisited = hasVisited, + handedOverAt = handedOverAt, + category = if (categoryId != null) CategoryRequest( + id = categoryId, + customCategory = customCategory, + ) else null, + ), + ).getOrThrow().toModel() } diff --git a/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt index 7f564137..b73b5d1f 100644 --- a/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt @@ -1,13 +1,9 @@ package com.susu.data.data.repository -import com.susu.core.model.Envelope import com.susu.core.model.FriendSearch -import com.susu.core.model.Relationship -import com.susu.data.remote.api.EnvelopesService import com.susu.data.remote.api.FriendService import com.susu.data.remote.model.request.FriendRequest import com.susu.data.remote.model.response.toModel -import com.susu.domain.repository.EnvelopesRepository import com.susu.domain.repository.FriendRepository import javax.inject.Inject @@ -19,7 +15,7 @@ class FriendRepositoryImpl @Inject constructor( phoneNumber: String?, relationshipId: Int, customRelation: String?, - ): Int = friendService.createFriend( + ): Long = friendService.createFriend( FriendRequest( name = name, phoneNumber = phoneNumber, diff --git a/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt b/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt index 5d6ab9ed..36be0e97 100644 --- a/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt +++ b/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt @@ -1,10 +1,13 @@ package com.susu.data.remote.api +import com.susu.data.remote.model.request.EnvelopeRequest +import com.susu.data.remote.model.response.EnvelopeResponse import com.susu.data.remote.model.response.EnvelopesListResponse -import com.susu.data.remote.model.response.RelationConfigShipResponse import com.susu.data.remote.model.response.RelationShipListResponse import com.susu.data.remote.retrofit.ApiResult +import retrofit2.http.Body import retrofit2.http.GET +import retrofit2.http.POST import retrofit2.http.Query interface EnvelopesService { @@ -20,4 +23,9 @@ interface EnvelopesService { @GET("envelopes/configs/create-envelopes") suspend fun getRelationShipConfigList(): ApiResult + + @POST("envelopes") + suspend fun createEnvelope( + @Body envelopeRequest: EnvelopeRequest + ): ApiResult } diff --git a/data/src/main/java/com/susu/data/remote/model/request/EnvelopeRequest.kt b/data/src/main/java/com/susu/data/remote/model/request/EnvelopeRequest.kt new file mode 100644 index 00000000..588b9d57 --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/request/EnvelopeRequest.kt @@ -0,0 +1,23 @@ +package com.susu.data.remote.model.request + +import kotlinx.datetime.LocalDateTime +import kotlinx.serialization.Serializable + +@Serializable +data class EnvelopeRequest( + val type: String, + val friendId: Long, + val ledgerId: Long? = null, + val amount: Long, + val gift: String? = null, + val memo: String? = null, + val hasVisited: Boolean? = null, + val handedOverAt: LocalDateTime? = null, + val category: CategoryRequest? = null, +) + +@Serializable +data class CategoryRequest( + val id: Long, + val customCategory: String? = null +) diff --git a/data/src/main/java/com/susu/data/remote/model/response/EnvelopeResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/EnvelopeResponse.kt new file mode 100644 index 00000000..c4b6b0a4 --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/response/EnvelopeResponse.kt @@ -0,0 +1,31 @@ +package com.susu.data.remote.model.response + +import com.susu.core.model.Envelope +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.toJavaLocalDateTime +import kotlinx.serialization.Serializable + +@Serializable +data class EnvelopeResponse( + val id: Long, + val uid: Long, + val type: String, + val friendId: Long, + val amount: Long, + val gift: String? = null, + val memo: String? = null, + val hasVisited: Boolean? = null, + val handedOverAt: LocalDateTime? = null, +) + +internal fun EnvelopeResponse.toModel() = Envelope( + id = id, + uid = uid, + type = type, + friendId = friendId, + amount = amount, + gift = gift, + memo = memo, + hasVisited = hasVisited, + handedOverAt = handedOverAt?.toJavaLocalDateTime(), +) diff --git a/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt index 83d1218d..a4389751 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt @@ -1,6 +1,6 @@ package com.susu.data.remote.model.response -import com.susu.core.model.Envelope +import com.susu.core.model.EnvelopeStatics import com.susu.core.model.Friend import kotlinx.serialization.Serializable @@ -31,7 +31,7 @@ internal fun FriendInfo.toModel() = Friend( modifiedAt = modifiedAt, ) -internal fun EnvelopesResponse.toModel() = Envelope( +internal fun EnvelopesResponse.toModel() = EnvelopeStatics( friend = friend.toModel(), receivedAmounts = receivedAmounts, sentAmounts = sentAmounts, diff --git a/data/src/main/java/com/susu/data/remote/model/response/FriendResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/FriendResponse.kt index 8234fd4e..68ee47e6 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/FriendResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/FriendResponse.kt @@ -3,4 +3,4 @@ package com.susu.data.remote.model.response import kotlinx.serialization.Serializable @Serializable -data class FriendResponse(val id: Int) +data class FriendResponse(val id: Long) diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index ae1c9f8d..f4faa7d9 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -9,4 +9,6 @@ dependencies { implementation(libs.kotlinx.coroutines.core) implementation(libs.hilt.core) + + implementation(libs.kotlinx.datetime) } diff --git a/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt b/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt index c7add06b..9393c2eb 100644 --- a/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt +++ b/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt @@ -1,7 +1,9 @@ package com.susu.domain.repository import com.susu.core.model.Envelope +import com.susu.core.model.EnvelopeStatics import com.susu.core.model.Relationship +import kotlinx.datetime.LocalDateTime interface EnvelopesRepository { suspend fun getEnvelopesList( @@ -11,7 +13,20 @@ interface EnvelopesRepository { page: Int?, size: Int?, sort: String?, - ): List + ): List suspend fun getRelationShipConfigList(): List + + suspend fun createEnvelope( + type: String, + friendId: Long, + ledgerId: Long? = null, + amount: Long, + gift: String? = null, + memo: String? = null, + hasVisited: Boolean? = null, + handedOverAt: LocalDateTime? = null, + categoryId: Long? = null, + customCategory: String? = null, + ): Envelope } diff --git a/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt b/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt index eff0e0bc..74a29ec3 100644 --- a/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt +++ b/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt @@ -1,8 +1,6 @@ package com.susu.domain.repository -import com.susu.core.model.Envelope import com.susu.core.model.FriendSearch -import com.susu.core.model.Relationship interface FriendRepository { suspend fun createFriend( @@ -10,7 +8,7 @@ interface FriendRepository { phoneNumber: String? = null, relationshipId: Int, customRelation: String? = null, - ): Int + ): Long suspend fun searchFriend( name: String, diff --git a/domain/src/main/java/com/susu/domain/usecase/envelope/CreateReceivedEnvelopeUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/envelope/CreateReceivedEnvelopeUseCase.kt new file mode 100644 index 00000000..0596c3ec --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/envelope/CreateReceivedEnvelopeUseCase.kt @@ -0,0 +1,46 @@ +package com.susu.domain.usecase.envelope + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.EnvelopesRepository +import com.susu.domain.repository.FriendRepository +import kotlinx.datetime.LocalDateTime +import javax.inject.Inject + +class CreateReceivedEnvelopeUseCase @Inject constructor( + private val friendRepository: FriendRepository, + private val envelopesRepository: EnvelopesRepository, +) { + suspend operator fun invoke(param: Param) = runCatchingIgnoreCancelled { + with(param) { + val friendId = friendId ?: friendRepository.createFriend( + name = friendName!!, + phoneNumber = phoneNumber, + relationshipId = relationshipId!!, + customRelation = customRelation, + ) + + envelopesRepository.createEnvelope( + type = "RECEIVED", + friendId = friendId, + ledgerId = ledgerId, + amount = amount, + gift = gift, + memo = memo, + hasVisited = hasVisited, + ) + } + } + + data class Param( + val friendId: Long? = null, + val friendName: String? = null, + val phoneNumber: String? = null, + val relationshipId: Int? = null, + val customRelation: String? = null, + val ledgerId: Long, + val amount: Long, + val gift: String? = null, + val memo: String? = null, + val hasVisited: Boolean? = null, + ) +} diff --git a/feature/sent/src/main/java/com/susu/feature/sent/SentContract.kt b/feature/sent/src/main/java/com/susu/feature/sent/SentContract.kt index 8c897ddc..c93f4654 100644 --- a/feature/sent/src/main/java/com/susu/feature/sent/SentContract.kt +++ b/feature/sent/src/main/java/com/susu/feature/sent/SentContract.kt @@ -1,6 +1,6 @@ package com.susu.feature.sent -import com.susu.core.model.Envelope +import com.susu.core.model.EnvelopeStatics import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState import kotlinx.collections.immutable.PersistentList @@ -8,7 +8,7 @@ import kotlinx.collections.immutable.persistentListOf data class SentState( val isLoading: Boolean = false, - val envelopesList: PersistentList = persistentListOf(), + val envelopesList: PersistentList = persistentListOf(), val showEmptyEnvelopes: Boolean = false, ) : UiState From f1a94f6172781102ac812f1bcdb27f83c8c19c82 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 14:30:37 +0900 Subject: [PATCH 17/28] remove: CreateFriendUseCase.kt --- .../usecase/friend/CreateFriendUseCase.kt | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 domain/src/main/java/com/susu/domain/usecase/friend/CreateFriendUseCase.kt diff --git a/domain/src/main/java/com/susu/domain/usecase/friend/CreateFriendUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/friend/CreateFriendUseCase.kt deleted file mode 100644 index 4c238f41..00000000 --- a/domain/src/main/java/com/susu/domain/usecase/friend/CreateFriendUseCase.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.susu.domain.usecase.friend - -import com.susu.core.common.runCatchingIgnoreCancelled -import com.susu.domain.repository.CategoryConfigRepository -import com.susu.domain.repository.FriendRepository -import javax.inject.Inject - -class CreateFriendUseCase @Inject constructor( - private val friendRepository: FriendRepository, -) { - suspend operator fun invoke(param: Param) = runCatchingIgnoreCancelled { - with(param) { - friendRepository.createFriend( - name = name, - phoneNumber = phoneNumber, - relationshipId = relationshipId, - customRelation = customRelation, - ) - } - } - - data class Param( - val name: String = "", - val phoneNumber: String? = null, - val relationshipId: Int = 0, - val customRelation: String? = null, - ) -} From 5379a8aab5590a84fe98218e6ad4a4043c3c5735 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 14:41:42 +0900 Subject: [PATCH 18/28] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B6=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20LedgerId=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/susu/core/model/Ledger.kt | 2 +- .../data/repository/LedgerRepositoryImpl.kt | 2 +- .../com/susu/data/remote/api/LedgerService.kt | 4 ++-- .../remote/model/response/LedgerResponse.kt | 2 +- .../susu/domain/repository/LedgerRepository.kt | 2 +- .../usecase/ledger/DeleteLedgerUseCase.kt | 2 +- .../com/susu/feature/navigator/MainNavigator.kt | 4 ++-- .../envelopeadd/ReceivedEnvelopeAddViewModel.kt | 2 ++ .../ledgerdetail/LedgerDetailContract.kt | 4 ++-- .../received/ledgerdetail/LedgerDetailScreen.kt | 6 +++--- .../ledgerdetail/LedgerDetailViewModel.kt | 2 +- .../received/ledgeredit/LedgerEditViewModel.kt | 2 +- .../received/navigation/ReceivedNavigation.kt | 17 ++++++++++------- .../feature/received/received/ReceivedScreen.kt | 2 +- .../received/received/ReceivedViewModel.kt | 2 +- 15 files changed, 30 insertions(+), 25 deletions(-) diff --git a/core/model/src/main/java/com/susu/core/model/Ledger.kt b/core/model/src/main/java/com/susu/core/model/Ledger.kt index 5bd7b56b..d03acf55 100644 --- a/core/model/src/main/java/com/susu/core/model/Ledger.kt +++ b/core/model/src/main/java/com/susu/core/model/Ledger.kt @@ -8,7 +8,7 @@ import kotlinx.serialization.Serializable @Stable @Serializable data class Ledger( - val id: Int = -1, + val id: Long = -1, val title: String = "", val description: String = "", val startAt: LocalDateTime = java.time.LocalDateTime.now().toKotlinLocalDateTime(), 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 4ea4bfd5..4a505248 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 @@ -37,7 +37,7 @@ class LedgerRepositoryImpl @Inject constructor( ledgerRequest = ledger.toData(), ).getOrThrow().toModel() - override suspend fun deleteLedger(id: Int) = ledgerService.deleteLedgerList( + override suspend fun deleteLedger(id: Long) = ledgerService.deleteLedgerList( listOf(id), ).getOrThrow() } 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 08b9ea12..e1b0628f 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 @@ -26,7 +26,7 @@ interface LedgerService { @PATCH("ledgers/{id}") suspend fun editLedger( - @Path("id") id: Int, + @Path("id") id: Long, @Body ledgerRequest: LedgerRequest, ): ApiResult @@ -36,5 +36,5 @@ interface LedgerService { ): ApiResult @DELETE("ledgers") - suspend fun deleteLedgerList(@Query("ids") idList: List): ApiResult + suspend fun deleteLedgerList(@Query("ids") idList: List): ApiResult } diff --git a/data/src/main/java/com/susu/data/remote/model/response/LedgerResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/LedgerResponse.kt index f86c32ac..e3a372fb 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/LedgerResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/LedgerResponse.kt @@ -17,7 +17,7 @@ data class LedgerResponse( @Serializable data class LedgerInfo( - val id: Int, + val id: Long, val title: String, val description: String = "", val startAt: LocalDateTime, 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 96926852..43df0c4d 100644 --- a/domain/src/main/java/com/susu/domain/repository/LedgerRepository.kt +++ b/domain/src/main/java/com/susu/domain/repository/LedgerRepository.kt @@ -22,6 +22,6 @@ interface LedgerRepository { ): Ledger suspend fun deleteLedger( - id: Int, + id: Long, ) } diff --git a/domain/src/main/java/com/susu/domain/usecase/ledger/DeleteLedgerUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/ledger/DeleteLedgerUseCase.kt index 43d143ef..10495fec 100644 --- a/domain/src/main/java/com/susu/domain/usecase/ledger/DeleteLedgerUseCase.kt +++ b/domain/src/main/java/com/susu/domain/usecase/ledger/DeleteLedgerUseCase.kt @@ -7,7 +7,7 @@ import javax.inject.Inject class DeleteLedgerUseCase @Inject constructor( private val ledgerRepository: LedgerRepository, ) { - suspend operator fun invoke(id: Int) = runCatchingIgnoreCancelled { + suspend operator fun invoke(id: Long) = runCatchingIgnoreCancelled { ledgerRepository.deleteLedger(id) } } 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 15c18bd0..26b62b07 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 @@ -150,8 +150,8 @@ internal class MainNavigator( navController.navigateMyPageSocial() } - fun navigateReceivedEnvelopeAdd(categoryName: String) { - navController.navigateReceivedEnvelopeAdd(categoryName) + fun navigateReceivedEnvelopeAdd(categoryName: String, ledgerId: Long) { + navController.navigateReceivedEnvelopeAdd(categoryName, ledgerId) } fun navigateReceivedEnvelopeDetail() { diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index 554f4326..8b40dd87 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -5,6 +5,7 @@ import com.susu.core.model.Relationship import com.susu.core.ui.base.BaseViewModel import com.susu.feature.received.navigation.ReceivedRoute import dagger.hilt.android.lifecycle.HiltViewModel +import timber.log.Timber import javax.inject.Inject @HiltViewModel @@ -14,6 +15,7 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( ReceivedEnvelopeAddState(), ) { val categoryName = savedStateHandle.get(ReceivedRoute.CATEGORY_ARGUMENT_NAME)!! + val ledgerId = savedStateHandle.get(ReceivedRoute.LEDGER_ID_ARGUMENT_NAME)!! private var money: Long = 0 private var name: String = "" diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailContract.kt b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailContract.kt index 547c4475..c8802a15 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailContract.kt @@ -14,11 +14,11 @@ data class LedgerDetailState( ) : UiState sealed interface LedgerDetailSideEffect : SideEffect { - data class NavigateEnvelopeAdd(val categoryName: String) : LedgerDetailSideEffect + data class NavigateEnvelopeAdd(val categoryName: String, val ledgerId: Long) : LedgerDetailSideEffect data object NavigateEnvelopeDetail : LedgerDetailSideEffect data class NavigateLedgerEdit(val ledger: Ledger) : LedgerDetailSideEffect data class PopBackStackWithLedger(val ledger: String) : LedgerDetailSideEffect - data class PopBackStackWithDeleteLedgerId(val ledgerId: Int) : LedgerDetailSideEffect + data class PopBackStackWithDeleteLedgerId(val ledgerId: Long) : LedgerDetailSideEffect data class ShowDeleteDialog(val onConfirmRequest: () -> Unit) : LedgerDetailSideEffect data object ShowDeleteSuccessSnackbar : LedgerDetailSideEffect data class ShowSnackbar(val msg: String) : LedgerDetailSideEffect diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailScreen.kt b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailScreen.kt index ce14271e..d61f09a9 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailScreen.kt @@ -52,10 +52,10 @@ fun LedgerDetailRoute( viewModel: LedgerDetailViewModel = hiltViewModel(), ledger: String?, navigateLedgerEdit: (Ledger) -> Unit, - navigateEnvelopAdd: (String) -> Unit, + navigateEnvelopAdd: (String, Long) -> Unit, navigateEnvelopeDetail: () -> Unit, popBackStackWithLedger: (String) -> Unit, - popBackStackWithDeleteLedgerId: (Int) -> Unit, + popBackStackWithDeleteLedgerId: (Long) -> Unit, onShowSnackbar: (SnackbarToken) -> Unit, onShowDialog: (DialogToken) -> Unit, handleException: (Throwable, () -> Unit) -> Unit, @@ -89,7 +89,7 @@ fun LedgerDetailRoute( is LedgerDetailSideEffect.PopBackStackWithDeleteLedgerId -> popBackStackWithDeleteLedgerId(sideEffect.ledgerId) is LedgerDetailSideEffect.HandleException -> handleException(sideEffect.throwable, sideEffect.retry) is LedgerDetailSideEffect.ShowSnackbar -> onShowSnackbar(SnackbarToken(message = sideEffect.msg)) - is LedgerDetailSideEffect.NavigateEnvelopeAdd -> navigateEnvelopAdd(sideEffect.categoryName) + is LedgerDetailSideEffect.NavigateEnvelopeAdd -> navigateEnvelopAdd(sideEffect.categoryName, sideEffect.ledgerId) LedgerDetailSideEffect.NavigateEnvelopeDetail -> navigateEnvelopeDetail() } } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailViewModel.kt index 7faa88d7..de0dff6e 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgerdetail/LedgerDetailViewModel.kt @@ -81,6 +81,6 @@ class LedgerDetailViewModel @Inject constructor( } } - fun navigateEnvelopeAdd() = postSideEffect(LedgerDetailSideEffect.NavigateEnvelopeAdd(ledger.category.customCategory ?: ledger.category.name)) + fun navigateEnvelopeAdd() = postSideEffect(LedgerDetailSideEffect.NavigateEnvelopeAdd(ledger.category.customCategory ?: ledger.category.name, ledger.id)) fun navigateEnvelopeDetail() = postSideEffect(LedgerDetailSideEffect.NavigateEnvelopeDetail) } diff --git a/feature/received/src/main/java/com/susu/feature/received/ledgeredit/LedgerEditViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/ledgeredit/LedgerEditViewModel.kt index 40a7a23f..30f3486c 100644 --- a/feature/received/src/main/java/com/susu/feature/received/ledgeredit/LedgerEditViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/ledgeredit/LedgerEditViewModel.kt @@ -28,7 +28,7 @@ class LedgerEditViewModel @Inject constructor( LedgerEditState(), ) { private val argument = savedStateHandle.get(ReceivedRoute.LEDGER_ARGUMENT_NAME)!! - private var ledgerId = 0 + private var ledgerId = 0L private val toEditLedger get() = with(currentState) { Ledger( 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 dcee893d..98fce7e5 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 @@ -47,8 +47,8 @@ fun NavController.navigateLedgerAdd() { navigate(ReceivedRoute.ledgerAddRoute) } -fun NavController.navigateReceivedEnvelopeAdd(categoryName: String) { - navigate(ReceivedRoute.envelopeAddRoute(categoryName)) +fun NavController.navigateReceivedEnvelopeAdd(categoryName: String, ledgerId: Long) { + navigate(ReceivedRoute.envelopeAddRoute(categoryName, ledgerId.toString())) } fun NavController.navigateReceivedEnvelopeDetail() { @@ -64,13 +64,13 @@ fun NavGraphBuilder.receivedNavGraph( navigateLedgerDetail: (Ledger) -> Unit, popBackStack: () -> Unit, popBackStackWithLedger: (String) -> Unit, - popBackStackWithDeleteLedgerId: (Int) -> Unit, + popBackStackWithDeleteLedgerId: (Long) -> Unit, popBackStackWithFilter: (String) -> Unit, navigateLedgerSearch: () -> Unit, navigateLedgerEdit: (Ledger) -> Unit, navigateLedgerFilter: (FilterArgument) -> Unit, navigateLedgerAdd: () -> Unit, - navigateEnvelopAdd: (String) -> Unit, + navigateEnvelopAdd: (String, Long) -> Unit, navigateEnvelopeDetail: () -> Unit, navigateEnvelopeEdit: () -> Unit, onShowSnackbar: (SnackbarToken) -> Unit, @@ -79,7 +79,7 @@ fun NavGraphBuilder.receivedNavGraph( ) { composable(route = ReceivedRoute.route) { navBackStackEntry -> val ledger = navBackStackEntry.savedStateHandle.get(ReceivedRoute.LEDGER_ARGUMENT_NAME) - val toDeleteLedgerId = navBackStackEntry.savedStateHandle.get(ReceivedRoute.LEDGER_ID_ARGUMENT_NAME) ?: -1 + val toDeleteLedgerId = navBackStackEntry.savedStateHandle.get(ReceivedRoute.LEDGER_ID_ARGUMENT_NAME) ?: -1 val filter = navBackStackEntry.savedStateHandle.get(ReceivedRoute.FILTER_ARGUMENT_NAME) navBackStackEntry.savedStateHandle.set(ReceivedRoute.FILTER_ARGUMENT_NAME, null) ReceivedRoute( @@ -152,7 +152,10 @@ fun NavGraphBuilder.receivedNavGraph( } composable( - route = ReceivedRoute.envelopeAddRoute("{${ReceivedRoute.CATEGORY_ARGUMENT_NAME}}"), + route = ReceivedRoute.envelopeAddRoute( + categoryName = "{${ReceivedRoute.CATEGORY_ARGUMENT_NAME}}", + ledgerId = "{${ReceivedRoute.LEDGER_ID_ARGUMENT_NAME}}", + ), arguments = listOf( navArgument(ReceivedRoute.CATEGORY_ARGUMENT_NAME) { type = NavType.StringType @@ -195,7 +198,7 @@ object ReceivedRoute { const val ledgerAddRoute = "ledger-add" // TODO 파라미터 넘기는 방식으로 수정해야함. - fun envelopeAddRoute(categoryName: String) = "envelope-add/$categoryName" + fun envelopeAddRoute(categoryName: String, ledgerId: String) = "envelope-add/$categoryName/$ledgerId" const val envelopeDetailRoute = "envelope-detail" // TODO 파라미터 넘기는 방식으로 수정해야함. const val envelopeEditRoute = "envelope-edit" // TODO 파라미터 넘기는 방식으로 수정해야함. } 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 1be618d4..9346b05c 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 @@ -70,7 +70,7 @@ import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState fun ReceivedRoute( viewModel: ReceivedViewModel = hiltViewModel(), ledger: String?, - toDeleteLedgerId: Int, + toDeleteLedgerId: Long, filter: String?, padding: PaddingValues, navigateLedgerDetail: (Ledger) -> Unit, 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 6f07a7d9..bf3a54e2 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 @@ -118,7 +118,7 @@ class ReceivedViewModel @Inject constructor( } } - fun updateLedgerIfNeed(ledger: String?, toDeleteLedgerId: Int) { + fun updateLedgerIfNeed(ledger: String?, toDeleteLedgerId: Long) { val toUpdateLedger = ledger?.let { Json.decodeFromUri(ledger) } ?: Ledger() From f14b05fc4497e0f711bd53f954f9d17565c66999 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 15:25:09 +0900 Subject: [PATCH 19/28] =?UTF-8?q?feat:=20=EB=B4=89=ED=88=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20=EC=B9=9C=EA=B5=AC=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/FriendRepositoryImpl.kt | 4 +- .../com/susu/data/remote/api/FriendService.kt | 3 +- .../model/response/FriendSearchResponse.kt | 5 +++ .../domain/repository/FriendRepository.kt | 2 +- .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 3 ++ .../ReceivedEnvelopeAddViewModel.kt | 18 +++++++- .../content/component/FriendListItem.kt | 32 +++++++++----- .../envelopeadd/content/name/NameContent.kt | 41 ++++++++++++++---- .../envelopeadd/content/name/NameContract.kt | 7 ++- .../envelopeadd/content/name/NameViewModel.kt | 43 +++++++++++++++++-- 10 files changed, 129 insertions(+), 29 deletions(-) diff --git a/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt index b73b5d1f..5111a7cd 100644 --- a/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt @@ -24,7 +24,7 @@ class FriendRepositoryImpl @Inject constructor( ), ).getOrThrow().id - override suspend fun searchFriend(name: String): FriendSearch = friendService.searchFriend( + override suspend fun searchFriend(name: String): List = friendService.searchFriend( name = name, - ).getOrThrow().toModel() + ).getOrThrow().data.map { it.toModel() } } diff --git a/data/src/main/java/com/susu/data/remote/api/FriendService.kt b/data/src/main/java/com/susu/data/remote/api/FriendService.kt index 99073e45..99612d55 100644 --- a/data/src/main/java/com/susu/data/remote/api/FriendService.kt +++ b/data/src/main/java/com/susu/data/remote/api/FriendService.kt @@ -2,6 +2,7 @@ package com.susu.data.remote.api import com.susu.data.remote.model.request.FriendRequest import com.susu.data.remote.model.response.FriendResponse +import com.susu.data.remote.model.response.FriendSearchListResponse import com.susu.data.remote.model.response.FriendSearchResponse import com.susu.data.remote.retrofit.ApiResult import retrofit2.http.Body @@ -19,5 +20,5 @@ interface FriendService { @GET("friends") suspend fun searchFriend( @Query("name") name: String, - ): ApiResult + ): ApiResult } diff --git a/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt index 4142c3ce..5106ee0e 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt @@ -5,6 +5,11 @@ import kotlinx.datetime.LocalDateTime import kotlinx.datetime.toJavaLocalDateTime import kotlinx.serialization.Serializable +@Serializable +data class FriendSearchListResponse( + val data: List, +) + @Serializable data class FriendSearchResponse( val friend: Friend, diff --git a/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt b/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt index 74a29ec3..3093f9f0 100644 --- a/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt +++ b/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt @@ -12,5 +12,5 @@ interface FriendRepository { suspend fun searchFriend( name: String, - ): FriendSearch + ): List } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index eb5ee8fb..ddc7d352 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -67,6 +67,7 @@ fun ReceivedEnvelopeAddRoute( viewModel.updateName(name) friendName = name }, + updateParentFriendId = viewModel::updateFriendId, updateParentSelectedRelationShip = viewModel::updateSelectedRelationShip, updateParentMoreStep = viewModel::updateMoreStep, categoryName = viewModel.categoryName, @@ -85,6 +86,7 @@ fun ReceivedEnvelopeAddScreen( onClickNext: () -> Unit = {}, updateParentMoney: (Long) -> Unit = {}, updateParentName: (String) -> Unit = {}, + updateParentFriendId: (Int?) -> Unit = {}, updateParentSelectedRelationShip: (Relationship?) -> Unit = {}, updateParentMoreStep: (List) -> Unit = {}, categoryName: String = "", @@ -126,6 +128,7 @@ fun ReceivedEnvelopeAddScreen( EnvelopeAddStep.NAME -> NameContentRoute( updateParentName = updateParentName, + updateParentFriendId = updateParentFriendId, ) EnvelopeAddStep.RELATIONSHIP -> RelationShipContentRoute( updateParentSelectedRelation = updateParentSelectedRelationShip, diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index 8b40dd87..9f4623dc 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -19,6 +19,7 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( private var money: Long = 0 private var name: String = "" + private var friendId: Int? = null private var relationShip: Relationship? = null private var moreStep: List = emptyList() private var hasVisited: Boolean? = null @@ -26,6 +27,9 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( private var phoneNumber: String? = null private var memo: String? = null + private val skipRelationshipStep + get() = friendId != null + fun goToPrevStep() = intent { val prevStep = when (currentStep) { EnvelopeAddStep.MONEY -> { @@ -35,7 +39,10 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( EnvelopeAddStep.NAME -> EnvelopeAddStep.MONEY EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.NAME - EnvelopeAddStep.MORE -> EnvelopeAddStep.RELATIONSHIP + EnvelopeAddStep.MORE -> { + if (skipRelationshipStep) EnvelopeAddStep.NAME + else EnvelopeAddStep.RELATIONSHIP + } else -> goToPrevStepInMore(currentStep) } @@ -61,7 +68,10 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( fun goToNextStep() = intent { val nextStep = when (currentStep) { EnvelopeAddStep.MONEY -> EnvelopeAddStep.NAME - EnvelopeAddStep.NAME -> EnvelopeAddStep.RELATIONSHIP + EnvelopeAddStep.NAME -> { + if (skipRelationshipStep) EnvelopeAddStep.MORE + else EnvelopeAddStep.RELATIONSHIP + } EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.MORE else -> goToNextStepInMore(currentStep) } @@ -107,6 +117,10 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( ) } + fun updateFriendId(friendId: Int?) { + this.friendId = friendId + } + fun updateSelectedRelationShip(relationShip: Relationship?) = intent { this@ReceivedEnvelopeAddViewModel.relationShip = relationShip copy( diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt index 759a3213..06e10abc 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt @@ -14,15 +14,22 @@ import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.Gray40 import com.susu.core.designsystem.theme.Gray60 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.susuClickable +import com.susu.core.ui.util.to_yyyy_dot_MM_dot_dd +import java.time.LocalDateTime @Composable fun FriendListItem( - friend: String, - modifier: Modifier = Modifier, + name: String, + relationship: String, + category: String?, + visitedAt: LocalDateTime?, + onClick: () -> Unit, ) { Row( - modifier = modifier + modifier = Modifier .fillMaxWidth() + .susuClickable(onClick = onClick) .padding( vertical = SusuTheme.spacing.spacing_s, ), @@ -30,22 +37,22 @@ fun FriendListItem( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = friend, + text = name, style = SusuTheme.typography.title_xs, color = Gray100, ) Text( - text = "친구", + text = relationship, style = SusuTheme.typography.title_xs, color = Gray60, ) Text( - text = "결혼식", + text = category ?: "", style = SusuTheme.typography.text_xs, color = Gray40, ) Text( - text = "2022.01.11", + text = visitedAt?.to_yyyy_dot_MM_dot_dd() ?: "", style = SusuTheme.typography.text_xs, color = Gray40, ) @@ -55,13 +62,16 @@ fun FriendListItem( @Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) @Composable fun FriendListItemPreview() { - val friendList = listOf("김철수", "국영수", "가나다") SusuTheme { Column { - for (friend in friendList) { - FriendListItem(friend = friend) - } + FriendListItem( + name = "", + relationship = "", + category = null, + visitedAt = null, + onClick = {}, + ) } } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt index fab65c4c..86fd16a2 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn @@ -16,30 +17,38 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow 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.textfield.SusuBasicTextField import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.Gray40 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.model.FriendSearch import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.received.R import com.susu.feature.received.envelopeadd.content.component.FriendListItem import com.susu.feature.received.envelopeadd.content.money.MoneySideEffect import com.susu.feature.received.envelopeadd.content.money.MoneyState +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.flow.debounce +@OptIn(FlowPreview::class) @Composable fun NameContentRoute( viewModel: NameViewModel = hiltViewModel(), updateParentName: (String) -> Unit, + updateParentFriendId: (Int?) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value viewModel.sideEffect.collectWithLifecycle { sideEffect -> when (sideEffect) { is NameSideEffect.UpdateParentName -> updateParentName(sideEffect.name) + is NameSideEffect.UpdateParentFriendId -> updateParentFriendId(sideEffect.friendId) } } @@ -47,9 +56,16 @@ fun NameContentRoute( viewModel.updateName(uiState.name) } + LaunchedEffect(key1 = uiState.name) { + snapshotFlow { uiState.name } + .debounce(100L) + .collect(viewModel::getFriendList) + } + NameContent( uiState = uiState, onTextChangeName = viewModel::updateName, + onClickFriendItem = viewModel::selectFriend, ) } @@ -57,7 +73,7 @@ fun NameContentRoute( fun NameContent( uiState: NameState = NameState(), onTextChangeName: (String) -> Unit = {}, - friendList: List = emptyList(), + onClickFriendItem: (FriendSearch) -> Unit = {}, ) { Column( modifier = Modifier @@ -85,11 +101,21 @@ fun NameContent( ) Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xl)) - if (friendList.isNotEmpty()) { - // TODO: 친구 목록 서버 연동 - LazyColumn { - items(friendList) { friend -> - FriendListItem(friend) + if (uiState.friendList.isNotEmpty() && uiState.isSelectedFriend.not()) { + LazyColumn( + modifier = Modifier.height(208.dp), + ) { + items( + items = uiState.friendList, + key = { it.friend.id }, + ) { + FriendListItem( + name = it.friend.name, + relationship = it.relationship.customRelation ?: it.relationship.relation, + category = it.recentEnvelope?.category, + visitedAt = it.recentEnvelope?.handedOverAt, + onClick = { onClickFriendItem(it) } + ) } } } @@ -100,8 +126,7 @@ fun NameContent( @Composable fun NameContentPreview() { SusuTheme { - val friendList = listOf("김철수", "국영수", "가나다") - NameContent(friendList = friendList) + NameContent() } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt index 8eeab82e..25a02674 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt @@ -1,13 +1,18 @@ package com.susu.feature.received.envelopeadd.content.name +import com.susu.core.model.FriendSearch import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -import com.susu.feature.received.ledgeradd.LedgerAddStep +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf data class NameState( val name: String = "", + val isSelectedFriend: Boolean = false, + val friendList: PersistentList = persistentListOf() ) : UiState sealed interface NameSideEffect : SideEffect { data class UpdateParentName(val name: String) : NameSideEffect + data class UpdateParentFriendId(val friendId: Int?) : NameSideEffect } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt index 7a400c7c..4cb52981 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt @@ -1,15 +1,52 @@ package com.susu.feature.received.envelopeadd.content.name +import androidx.lifecycle.viewModelScope +import com.susu.core.model.FriendSearch import com.susu.core.ui.base.BaseViewModel +import com.susu.domain.usecase.friend.SearchFriendUseCase 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( + private val searchFriendUseCase: SearchFriendUseCase, +) : BaseViewModel( NameState(), ) { fun updateName(name: String) = intent { - postSideEffect(NameSideEffect.UpdateParentName(name)) - copy(name = name) + postSideEffect( + NameSideEffect.UpdateParentName(name), + NameSideEffect.UpdateParentFriendId(null), + ) + copy( + name = name, + isSelectedFriend = false, + ) + } + + fun selectFriend(friend: FriendSearch) = intent { + postSideEffect( + NameSideEffect.UpdateParentName(name), + NameSideEffect.UpdateParentFriendId(friend.friend.id), + ) + copy( + name = friend.friend.name, + isSelectedFriend = true, + ) + } + + fun getFriendList(search: String) = viewModelScope.launch { + if (currentState.isSelectedFriend) return@launch + + searchFriendUseCase(name = search) + .onSuccess { + intent { + copy( + friendList = it.toPersistentList(), + ) + } + } } } From 8563daf78fa6e7901dd1f00e8939508101182f19 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 15:25:09 +0900 Subject: [PATCH 20/28] =?UTF-8?q?feat:=20=EB=B4=89=ED=88=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20=EC=B9=9C=EA=B5=AC=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/FriendRepositoryImpl.kt | 4 +- .../com/susu/data/remote/api/FriendService.kt | 3 +- .../model/response/FriendSearchResponse.kt | 5 +++ .../domain/repository/FriendRepository.kt | 2 +- .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 3 ++ .../ReceivedEnvelopeAddViewModel.kt | 18 +++++++- .../content/component/FriendListItem.kt | 32 +++++++++----- .../envelopeadd/content/name/NameContent.kt | 43 +++++++++++++++---- .../envelopeadd/content/name/NameContract.kt | 7 ++- .../envelopeadd/content/name/NameViewModel.kt | 43 +++++++++++++++++-- 10 files changed, 130 insertions(+), 30 deletions(-) diff --git a/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt index b73b5d1f..5111a7cd 100644 --- a/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/FriendRepositoryImpl.kt @@ -24,7 +24,7 @@ class FriendRepositoryImpl @Inject constructor( ), ).getOrThrow().id - override suspend fun searchFriend(name: String): FriendSearch = friendService.searchFriend( + override suspend fun searchFriend(name: String): List = friendService.searchFriend( name = name, - ).getOrThrow().toModel() + ).getOrThrow().data.map { it.toModel() } } diff --git a/data/src/main/java/com/susu/data/remote/api/FriendService.kt b/data/src/main/java/com/susu/data/remote/api/FriendService.kt index 99073e45..99612d55 100644 --- a/data/src/main/java/com/susu/data/remote/api/FriendService.kt +++ b/data/src/main/java/com/susu/data/remote/api/FriendService.kt @@ -2,6 +2,7 @@ package com.susu.data.remote.api import com.susu.data.remote.model.request.FriendRequest import com.susu.data.remote.model.response.FriendResponse +import com.susu.data.remote.model.response.FriendSearchListResponse import com.susu.data.remote.model.response.FriendSearchResponse import com.susu.data.remote.retrofit.ApiResult import retrofit2.http.Body @@ -19,5 +20,5 @@ interface FriendService { @GET("friends") suspend fun searchFriend( @Query("name") name: String, - ): ApiResult + ): ApiResult } diff --git a/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt index 4142c3ce..5106ee0e 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt @@ -5,6 +5,11 @@ import kotlinx.datetime.LocalDateTime import kotlinx.datetime.toJavaLocalDateTime import kotlinx.serialization.Serializable +@Serializable +data class FriendSearchListResponse( + val data: List, +) + @Serializable data class FriendSearchResponse( val friend: Friend, diff --git a/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt b/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt index 74a29ec3..3093f9f0 100644 --- a/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt +++ b/domain/src/main/java/com/susu/domain/repository/FriendRepository.kt @@ -12,5 +12,5 @@ interface FriendRepository { suspend fun searchFriend( name: String, - ): FriendSearch + ): List } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index eb5ee8fb..ddc7d352 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -67,6 +67,7 @@ fun ReceivedEnvelopeAddRoute( viewModel.updateName(name) friendName = name }, + updateParentFriendId = viewModel::updateFriendId, updateParentSelectedRelationShip = viewModel::updateSelectedRelationShip, updateParentMoreStep = viewModel::updateMoreStep, categoryName = viewModel.categoryName, @@ -85,6 +86,7 @@ fun ReceivedEnvelopeAddScreen( onClickNext: () -> Unit = {}, updateParentMoney: (Long) -> Unit = {}, updateParentName: (String) -> Unit = {}, + updateParentFriendId: (Int?) -> Unit = {}, updateParentSelectedRelationShip: (Relationship?) -> Unit = {}, updateParentMoreStep: (List) -> Unit = {}, categoryName: String = "", @@ -126,6 +128,7 @@ fun ReceivedEnvelopeAddScreen( EnvelopeAddStep.NAME -> NameContentRoute( updateParentName = updateParentName, + updateParentFriendId = updateParentFriendId, ) EnvelopeAddStep.RELATIONSHIP -> RelationShipContentRoute( updateParentSelectedRelation = updateParentSelectedRelationShip, diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index 8b40dd87..9f4623dc 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -19,6 +19,7 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( private var money: Long = 0 private var name: String = "" + private var friendId: Int? = null private var relationShip: Relationship? = null private var moreStep: List = emptyList() private var hasVisited: Boolean? = null @@ -26,6 +27,9 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( private var phoneNumber: String? = null private var memo: String? = null + private val skipRelationshipStep + get() = friendId != null + fun goToPrevStep() = intent { val prevStep = when (currentStep) { EnvelopeAddStep.MONEY -> { @@ -35,7 +39,10 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( EnvelopeAddStep.NAME -> EnvelopeAddStep.MONEY EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.NAME - EnvelopeAddStep.MORE -> EnvelopeAddStep.RELATIONSHIP + EnvelopeAddStep.MORE -> { + if (skipRelationshipStep) EnvelopeAddStep.NAME + else EnvelopeAddStep.RELATIONSHIP + } else -> goToPrevStepInMore(currentStep) } @@ -61,7 +68,10 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( fun goToNextStep() = intent { val nextStep = when (currentStep) { EnvelopeAddStep.MONEY -> EnvelopeAddStep.NAME - EnvelopeAddStep.NAME -> EnvelopeAddStep.RELATIONSHIP + EnvelopeAddStep.NAME -> { + if (skipRelationshipStep) EnvelopeAddStep.MORE + else EnvelopeAddStep.RELATIONSHIP + } EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.MORE else -> goToNextStepInMore(currentStep) } @@ -107,6 +117,10 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( ) } + fun updateFriendId(friendId: Int?) { + this.friendId = friendId + } + fun updateSelectedRelationShip(relationShip: Relationship?) = intent { this@ReceivedEnvelopeAddViewModel.relationShip = relationShip copy( diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt index 759a3213..06e10abc 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt @@ -14,15 +14,22 @@ import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.Gray40 import com.susu.core.designsystem.theme.Gray60 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.susuClickable +import com.susu.core.ui.util.to_yyyy_dot_MM_dot_dd +import java.time.LocalDateTime @Composable fun FriendListItem( - friend: String, - modifier: Modifier = Modifier, + name: String, + relationship: String, + category: String?, + visitedAt: LocalDateTime?, + onClick: () -> Unit, ) { Row( - modifier = modifier + modifier = Modifier .fillMaxWidth() + .susuClickable(onClick = onClick) .padding( vertical = SusuTheme.spacing.spacing_s, ), @@ -30,22 +37,22 @@ fun FriendListItem( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = friend, + text = name, style = SusuTheme.typography.title_xs, color = Gray100, ) Text( - text = "친구", + text = relationship, style = SusuTheme.typography.title_xs, color = Gray60, ) Text( - text = "결혼식", + text = category ?: "", style = SusuTheme.typography.text_xs, color = Gray40, ) Text( - text = "2022.01.11", + text = visitedAt?.to_yyyy_dot_MM_dot_dd() ?: "", style = SusuTheme.typography.text_xs, color = Gray40, ) @@ -55,13 +62,16 @@ fun FriendListItem( @Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) @Composable fun FriendListItemPreview() { - val friendList = listOf("김철수", "국영수", "가나다") SusuTheme { Column { - for (friend in friendList) { - FriendListItem(friend = friend) - } + FriendListItem( + name = "", + relationship = "", + category = null, + visitedAt = null, + onClick = {}, + ) } } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt index fab65c4c..effeb6d3 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn @@ -16,40 +17,55 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow 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.textfield.SusuBasicTextField import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.Gray40 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.model.FriendSearch import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.received.R import com.susu.feature.received.envelopeadd.content.component.FriendListItem import com.susu.feature.received.envelopeadd.content.money.MoneySideEffect import com.susu.feature.received.envelopeadd.content.money.MoneyState +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.flow.debounce +@OptIn(FlowPreview::class) @Composable fun NameContentRoute( viewModel: NameViewModel = hiltViewModel(), updateParentName: (String) -> Unit, + updateParentFriendId: (Int?) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value viewModel.sideEffect.collectWithLifecycle { sideEffect -> when (sideEffect) { is NameSideEffect.UpdateParentName -> updateParentName(sideEffect.name) + is NameSideEffect.UpdateParentFriendId -> updateParentFriendId(sideEffect.friendId) } } LaunchedEffect(key1 = Unit) { - viewModel.updateName(uiState.name) + updateParentName(uiState.name) + } + + LaunchedEffect(key1 = uiState.name) { + snapshotFlow { uiState.name } + .debounce(100L) + .collect(viewModel::getFriendList) } NameContent( uiState = uiState, onTextChangeName = viewModel::updateName, + onClickFriendItem = viewModel::selectFriend, ) } @@ -57,7 +73,7 @@ fun NameContentRoute( fun NameContent( uiState: NameState = NameState(), onTextChangeName: (String) -> Unit = {}, - friendList: List = emptyList(), + onClickFriendItem: (FriendSearch) -> Unit = {}, ) { Column( modifier = Modifier @@ -85,11 +101,21 @@ fun NameContent( ) Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xl)) - if (friendList.isNotEmpty()) { - // TODO: 친구 목록 서버 연동 - LazyColumn { - items(friendList) { friend -> - FriendListItem(friend) + if (uiState.friendList.isNotEmpty() && uiState.isSelectedFriend.not()) { + LazyColumn( + modifier = Modifier.height(208.dp), + ) { + items( + items = uiState.friendList, + key = { it.friend.id }, + ) { + FriendListItem( + name = it.friend.name, + relationship = it.relationship.customRelation ?: it.relationship.relation, + category = it.recentEnvelope?.category, + visitedAt = it.recentEnvelope?.handedOverAt, + onClick = { onClickFriendItem(it) } + ) } } } @@ -100,8 +126,7 @@ fun NameContent( @Composable fun NameContentPreview() { SusuTheme { - val friendList = listOf("김철수", "국영수", "가나다") - NameContent(friendList = friendList) + NameContent() } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt index 8eeab82e..25a02674 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt @@ -1,13 +1,18 @@ package com.susu.feature.received.envelopeadd.content.name +import com.susu.core.model.FriendSearch import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -import com.susu.feature.received.ledgeradd.LedgerAddStep +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf data class NameState( val name: String = "", + val isSelectedFriend: Boolean = false, + val friendList: PersistentList = persistentListOf() ) : UiState sealed interface NameSideEffect : SideEffect { data class UpdateParentName(val name: String) : NameSideEffect + data class UpdateParentFriendId(val friendId: Int?) : NameSideEffect } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt index 7a400c7c..4cb52981 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt @@ -1,15 +1,52 @@ package com.susu.feature.received.envelopeadd.content.name +import androidx.lifecycle.viewModelScope +import com.susu.core.model.FriendSearch import com.susu.core.ui.base.BaseViewModel +import com.susu.domain.usecase.friend.SearchFriendUseCase 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( + private val searchFriendUseCase: SearchFriendUseCase, +) : BaseViewModel( NameState(), ) { fun updateName(name: String) = intent { - postSideEffect(NameSideEffect.UpdateParentName(name)) - copy(name = name) + postSideEffect( + NameSideEffect.UpdateParentName(name), + NameSideEffect.UpdateParentFriendId(null), + ) + copy( + name = name, + isSelectedFriend = false, + ) + } + + fun selectFriend(friend: FriendSearch) = intent { + postSideEffect( + NameSideEffect.UpdateParentName(name), + NameSideEffect.UpdateParentFriendId(friend.friend.id), + ) + copy( + name = friend.friend.name, + isSelectedFriend = true, + ) + } + + fun getFriendList(search: String) = viewModelScope.launch { + if (currentState.isSelectedFriend) return@launch + + searchFriendUseCase(name = search) + .onSuccess { + intent { + copy( + friendList = it.toPersistentList(), + ) + } + } } } From 6999694dc1e580bc54d4d07481030c225fe49cf5 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 15:34:24 +0900 Subject: [PATCH 21/28] =?UTF-8?q?chore:=20=EC=A4=91=EB=B3=B5=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../received/envelopeadd/content/name/NameContent.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt index 402b4725..effeb6d3 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt @@ -62,12 +62,6 @@ fun NameContentRoute( .collect(viewModel::getFriendList) } - LaunchedEffect(key1 = uiState.name) { - snapshotFlow { uiState.name } - .debounce(100L) - .collect(viewModel::getFriendList) - } - NameContent( uiState = uiState, onTextChangeName = viewModel::updateName, From 4c31d767d194e5fc760d8da461237524d87f9480 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Fri, 26 Jan 2024 22:52:33 +0900 Subject: [PATCH 22/28] =?UTF-8?q?feat:=20=EB=B0=9B=EC=9D=80=20=EB=B4=89?= =?UTF-8?q?=ED=88=AC=20=EC=B6=94=EA=B0=80=20=EC=8B=9C,=20=EB=82=A0?= =?UTF-8?q?=EC=A7=9C=20=EC=9E=85=EB=A0=A5=20=ED=99=94=EB=A9=B4=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 --- .../ReceivedEnvelopeAddContract.kt | 1 + .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 8 ++ .../ReceivedEnvelopeAddViewModel.kt | 19 +++- .../envelopeadd/content/date/DateContent.kt | 105 ++++++++++++++++++ .../envelopeadd/content/date/DateContract.kt | 15 +++ .../envelopeadd/content/date/DateViewModel.kt | 24 ++++ .../envelopeadd/content/phone/PhoneContent.kt | 9 -- .../received/src/main/res/values/strings.xml | 2 + 8 files changed, 171 insertions(+), 12 deletions(-) create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContract.kt create mode 100644 feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateViewModel.kt diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt index 2df83b31..91bd3681 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt @@ -27,6 +27,7 @@ enum class EnvelopeAddStep( MONEY, NAME, RELATIONSHIP, + DATE, MORE, VISITED(R.string.envelop_add_step_visited), PRESENT(R.string.envelop_add_step_present), diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index ddc7d352..ba5ea74e 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -27,6 +27,7 @@ import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.model.Relationship import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuDefaultAnimatedContentTransitionSpec +import com.susu.feature.received.envelopeadd.content.date.DateContentRoute import com.susu.feature.received.envelopeadd.content.memo.MemoContentRoute import com.susu.feature.received.envelopeadd.content.money.MoneyContentRoute import com.susu.feature.received.envelopeadd.content.more.MoreContentRoute @@ -35,6 +36,7 @@ import com.susu.feature.received.envelopeadd.content.phone.PhoneContentRoute import com.susu.feature.received.envelopeadd.content.present.PresentContentRoute import com.susu.feature.received.envelopeadd.content.relationship.RelationShipContentRoute import com.susu.feature.received.envelopeadd.content.visited.VisitedContentRoute +import java.time.LocalDateTime @Composable fun ReceivedEnvelopeAddRoute( @@ -70,6 +72,7 @@ fun ReceivedEnvelopeAddRoute( updateParentFriendId = viewModel::updateFriendId, updateParentSelectedRelationShip = viewModel::updateSelectedRelationShip, updateParentMoreStep = viewModel::updateMoreStep, + updateParentDate = viewModel::updateDate, categoryName = viewModel.categoryName, updateParentVisited = viewModel::updateHasVisited, updateParentPresent = viewModel::updatePresent, @@ -88,6 +91,7 @@ fun ReceivedEnvelopeAddScreen( updateParentName: (String) -> Unit = {}, updateParentFriendId: (Int?) -> Unit = {}, updateParentSelectedRelationShip: (Relationship?) -> Unit = {}, + updateParentDate: (LocalDateTime?) -> Unit = {}, updateParentMoreStep: (List) -> Unit = {}, categoryName: String = "", updateParentVisited: (Boolean?) -> Unit = {}, @@ -133,6 +137,10 @@ fun ReceivedEnvelopeAddScreen( EnvelopeAddStep.RELATIONSHIP -> RelationShipContentRoute( updateParentSelectedRelation = updateParentSelectedRelationShip, ) + EnvelopeAddStep.DATE -> DateContentRoute( + friendName = friendName, + updateParentDate = updateParentDate, + ) EnvelopeAddStep.MORE -> MoreContentRoute( updateParentMoreStep = updateParentMoreStep, ) diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index 9f4623dc..de76089b 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -6,6 +6,7 @@ import com.susu.core.ui.base.BaseViewModel import com.susu.feature.received.navigation.ReceivedRoute import dagger.hilt.android.lifecycle.HiltViewModel import timber.log.Timber +import java.time.LocalDateTime import javax.inject.Inject @HiltViewModel @@ -21,6 +22,7 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( private var name: String = "" private var friendId: Int? = null private var relationShip: Relationship? = null + private var date: LocalDateTime? = null private var moreStep: List = emptyList() private var hasVisited: Boolean? = null private var present: String? = null @@ -39,10 +41,12 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( EnvelopeAddStep.NAME -> EnvelopeAddStep.MONEY EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.NAME - EnvelopeAddStep.MORE -> { + EnvelopeAddStep.DATE -> { if (skipRelationshipStep) EnvelopeAddStep.NAME else EnvelopeAddStep.RELATIONSHIP } + + EnvelopeAddStep.MORE -> EnvelopeAddStep.DATE else -> goToPrevStepInMore(currentStep) } @@ -69,10 +73,12 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( val nextStep = when (currentStep) { EnvelopeAddStep.MONEY -> EnvelopeAddStep.NAME EnvelopeAddStep.NAME -> { - if (skipRelationshipStep) EnvelopeAddStep.MORE + if (skipRelationshipStep) EnvelopeAddStep.DATE else EnvelopeAddStep.RELATIONSHIP } - EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.MORE + + EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.DATE + EnvelopeAddStep.DATE -> EnvelopeAddStep.MORE else -> goToNextStepInMore(currentStep) } @@ -159,4 +165,11 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( buttonEnabled = !memo.isNullOrEmpty(), ) } + + fun updateDate(date: LocalDateTime?) = intent { + this@ReceivedEnvelopeAddViewModel.date = date + copy( + buttonEnabled = date != null, + ) + } } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt new file mode 100644 index 00000000..b0f73304 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt @@ -0,0 +1,105 @@ +package com.susu.feature.received.envelopeadd.content.date + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +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.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 androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.susu.core.designsystem.component.bottomsheet.datepicker.SusuDatePickerBottomSheet +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.feature.received.R +import com.susu.feature.received.ledgeradd.content.date.component.SelectDateRow +import java.time.LocalDateTime + +@Composable +fun DateContentRoute( + viewModel: DateViewModel = hiltViewModel(), + friendName: String, + updateParentDate: (LocalDateTime?) -> Unit +) { + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is DateSideEffect.UpdateParentDate -> updateParentDate(sideEffect.date) + } + } + + LaunchedEffect(key1 = Unit) { + viewModel.updateName(friendName) + updateParentDate(uiState.date) + } + + DateContent( + uiState = uiState, + onDateItemSelected = viewModel::updateDate, + onClickDateText = viewModel::showDateBottomSheet, + onDismissDateBottomSheet = viewModel::hideDateBottomSheet, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DateContent( + uiState: DateState = DateState(), + onDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, + onClickDateText: () -> Unit = {}, + onDismissDateBottomSheet: () -> Unit = {}, +) { + Column( + modifier = Modifier + .fillMaxSize() + .padding( + horizontal = SusuTheme.spacing.spacing_m, + vertical = SusuTheme.spacing.spacing_xl, + ), + ) { + AnnotatedText( + originalText = stringResource(R.string.envelope_date_content_title, uiState.name), + originalTextStyle = SusuTheme.typography.title_m, + targetTextList = listOf(stringResource(R.string.envelope_date_content_title_highlight, uiState.name)), + spanStyle = SusuTheme.typography.title_m.copy(Gray60).toSpanStyle(), + ) + Spacer( + modifier = Modifier + .size(SusuTheme.spacing.spacing_m), + ) + SelectDateRow( + year = uiState.date?.year, + month = uiState.date?.monthValue, + day = uiState.date?.dayOfMonth, + onClick = onClickDateText, + ) + } + + if (uiState.showDateBottomSheet) { + SusuDatePickerBottomSheet( + initialYear = uiState.date?.year ?: currentDate.year, + initialMonth = uiState.date?.monthValue ?: currentDate.monthValue, + initialDay = uiState.date?.dayOfMonth ?: currentDate.dayOfMonth, + maximumContainerHeight = 346.dp, + onDismissRequest = { _, _, _ -> onDismissDateBottomSheet() }, + onItemSelected = onDateItemSelected, + ) + } +} + +@Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) +@Composable +fun DateContentPreview() { + SusuTheme { + DateContent() + } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContract.kt new file mode 100644 index 00000000..12e4b68b --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContract.kt @@ -0,0 +1,15 @@ +package com.susu.feature.received.envelopeadd.content.date + +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import java.time.LocalDateTime + +data class DateState( + val name: String = "", + val date: LocalDateTime? = null, + val showDateBottomSheet: Boolean = false, +) : UiState + +sealed interface DateSideEffect : SideEffect { + data class UpdateParentDate(val date: LocalDateTime?) : DateSideEffect +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateViewModel.kt new file mode 100644 index 00000000..99fcbbe4 --- /dev/null +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateViewModel.kt @@ -0,0 +1,24 @@ +package com.susu.feature.received.envelopeadd.content.date + +import com.susu.core.ui.base.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import java.time.LocalDateTime +import javax.inject.Inject + +@HiltViewModel +class DateViewModel @Inject constructor() : BaseViewModel( + DateState(), +) { + fun updateName(name: String) = intent { copy(name = name) } + + fun updateDate(year: Int, month: Int, day: Int) = intent { + val toUpdateDate = LocalDateTime.of(year, month, day, 0, 0) + postSideEffect(DateSideEffect.UpdateParentDate(toUpdateDate)) + copy( + date = toUpdateDate, + ) + } + + fun showDateBottomSheet() = intent { copy(showDateBottomSheet = true) } + fun hideDateBottomSheet() = intent { copy(showDateBottomSheet = false) } +} diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContent.kt index 5a9f9f16..140f86a6 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContent.kt @@ -1,7 +1,6 @@ package com.susu.feature.received.envelopeadd.content.phone import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -10,10 +9,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.text.KeyboardOptions 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.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType @@ -27,10 +22,6 @@ import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.util.AnnotatedText import com.susu.feature.received.R -import com.susu.feature.received.envelopeadd.content.present.PresentContent -import com.susu.feature.received.envelopeadd.content.present.PresentSideEffect -import com.susu.feature.received.envelopeadd.content.present.PresentViewModel -import kotlin.io.path.fileVisitor @Composable fun PhoneContentRoute( diff --git a/feature/received/src/main/res/values/strings.xml b/feature/received/src/main/res/values/strings.xml index 597006e5..04738681 100644 --- a/feature/received/src/main/res/values/strings.xml +++ b/feature/received/src/main/res/values/strings.xml @@ -57,4 +57,6 @@ 선물 메모 보낸 이의 연락처 + %s님에게 언제 받았나요 + %s님에게 From 9d97efd29b9d632f09ada3c0a07fd9a8bba64ccb Mon Sep 17 00:00:00 2001 From: jinukeu Date: Fri, 26 Jan 2024 23:12:40 +0900 Subject: [PATCH 23/28] =?UTF-8?q?feat:=20=EB=B0=9B=EC=9D=80=20=EB=B4=89?= =?UTF-8?q?=ED=88=AC=20=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5=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 --- .../main/java/com/susu/core/model/Friend.kt | 4 +- .../repository/EnvelopesRepositoryImpl.kt | 2 +- .../model/response/EnvelopesResponse.kt | 4 +- .../model/response/FriendSearchResponse.kt | 2 +- .../domain/repository/EnvelopesRepository.kt | 2 +- .../envelope/CreateReceivedEnvelopeUseCase.kt | 2 + .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 2 +- .../ReceivedEnvelopeAddViewModel.kt | 48 +++++++++++++++---- .../envelopeadd/content/name/NameContent.kt | 2 +- .../envelopeadd/content/name/NameContract.kt | 2 +- 10 files changed, 50 insertions(+), 20 deletions(-) diff --git a/core/model/src/main/java/com/susu/core/model/Friend.kt b/core/model/src/main/java/com/susu/core/model/Friend.kt index cd92c296..9c924f02 100644 --- a/core/model/src/main/java/com/susu/core/model/Friend.kt +++ b/core/model/src/main/java/com/susu/core/model/Friend.kt @@ -1,8 +1,8 @@ package com.susu.core.model data class Friend( - val id: Int = 0, - val uid: Int = 0, + val id: Long = 0, + val uid: Long = 0, val name: String = "", val phoneNumber: String = "", val createdAt: String = "", diff --git a/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt index ec328f4e..0f89cce3 100644 --- a/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt @@ -42,7 +42,7 @@ class EnvelopesRepositoryImpl @Inject constructor( gift: String?, memo: String?, hasVisited: Boolean?, - handedOverAt: kotlinx.datetime.LocalDateTime?, + handedOverAt: kotlinx.datetime.LocalDateTime, categoryId: Long?, customCategory: String?, ): Envelope = envelopesService.createEnvelope( diff --git a/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt index a4389751..142a73ab 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt @@ -14,8 +14,8 @@ data class EnvelopesResponse( @Serializable data class FriendInfo( - val id: Int, - val uid: Int, + val id: Long, + val uid: Long, val createdAt: String, val modifiedAt: String, val name: String, diff --git a/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt index 5106ee0e..21c3ca84 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/FriendSearchResponse.kt @@ -19,7 +19,7 @@ data class FriendSearchResponse( @Serializable data class Friend( - val id: Int, + val id: Long, val name: String, val phoneNumber: String? = null, ) diff --git a/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt b/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt index 9393c2eb..1a82425b 100644 --- a/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt +++ b/domain/src/main/java/com/susu/domain/repository/EnvelopesRepository.kt @@ -25,7 +25,7 @@ interface EnvelopesRepository { gift: String? = null, memo: String? = null, hasVisited: Boolean? = null, - handedOverAt: LocalDateTime? = null, + handedOverAt: LocalDateTime, categoryId: Long? = null, customCategory: String? = null, ): Envelope diff --git a/domain/src/main/java/com/susu/domain/usecase/envelope/CreateReceivedEnvelopeUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/envelope/CreateReceivedEnvelopeUseCase.kt index 0596c3ec..eabd92a2 100644 --- a/domain/src/main/java/com/susu/domain/usecase/envelope/CreateReceivedEnvelopeUseCase.kt +++ b/domain/src/main/java/com/susu/domain/usecase/envelope/CreateReceivedEnvelopeUseCase.kt @@ -27,6 +27,7 @@ class CreateReceivedEnvelopeUseCase @Inject constructor( gift = gift, memo = memo, hasVisited = hasVisited, + handedOverAt = handedOverAt, ) } } @@ -41,6 +42,7 @@ class CreateReceivedEnvelopeUseCase @Inject constructor( val amount: Long, val gift: String? = null, val memo: String? = null, + val handedOverAt: LocalDateTime, val hasVisited: Boolean? = null, ) } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index ba5ea74e..ed9486dd 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -89,7 +89,7 @@ fun ReceivedEnvelopeAddScreen( onClickNext: () -> Unit = {}, updateParentMoney: (Long) -> Unit = {}, updateParentName: (String) -> Unit = {}, - updateParentFriendId: (Int?) -> Unit = {}, + updateParentFriendId: (Long?) -> Unit = {}, updateParentSelectedRelationShip: (Relationship?) -> Unit = {}, updateParentDate: (LocalDateTime?) -> Unit = {}, updateParentMoreStep: (List) -> Unit = {}, diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index de76089b..bb0db117 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -1,26 +1,31 @@ package com.susu.feature.received.envelopeadd import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope import com.susu.core.model.Relationship import com.susu.core.ui.base.BaseViewModel +import com.susu.domain.usecase.envelope.CreateReceivedEnvelopeUseCase import com.susu.feature.received.navigation.ReceivedRoute import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import kotlinx.datetime.toKotlinLocalDateTime import timber.log.Timber import java.time.LocalDateTime import javax.inject.Inject @HiltViewModel class ReceivedEnvelopeAddViewModel @Inject constructor( + private val createReceivedEnvelopeUseCase: CreateReceivedEnvelopeUseCase, savedStateHandle: SavedStateHandle, ) : BaseViewModel( ReceivedEnvelopeAddState(), ) { val categoryName = savedStateHandle.get(ReceivedRoute.CATEGORY_ARGUMENT_NAME)!! - val ledgerId = savedStateHandle.get(ReceivedRoute.LEDGER_ID_ARGUMENT_NAME)!! + private val ledgerId = savedStateHandle.get(ReceivedRoute.LEDGER_ID_ARGUMENT_NAME)!! private var money: Long = 0 private var name: String = "" - private var friendId: Int? = null + private var friendId: Long? = null private var relationShip: Relationship? = null private var date: LocalDateTime? = null private var moreStep: List = emptyList() @@ -32,6 +37,29 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( private val skipRelationshipStep get() = friendId != null + private fun createEnvelope() = viewModelScope.launch { + createReceivedEnvelopeUseCase( + param = CreateReceivedEnvelopeUseCase.Param( + friendId = friendId, + friendName = name, + phoneNumber = phoneNumber, + relationshipId = relationShip?.id, + customRelation = relationShip?.customRelation, + ledgerId = ledgerId.toLong(), + amount = money, + gift = present, + memo = memo, + handedOverAt = date!!.toKotlinLocalDateTime(), + hasVisited = hasVisited + ) + ).onSuccess { + // TODO PopBackStackWithEnvelope로 변경 필요, 또한 Envelope에 friendName 추가 필요 + postSideEffect(ReceivedEnvelopeAddSideEffect.PopBackStack) + }.onFailure { + postSideEffect(ReceivedEnvelopeAddSideEffect.HandleException(it, ::createEnvelope)) + } + } + fun goToPrevStep() = intent { val prevStep = when (currentStep) { EnvelopeAddStep.MONEY -> { @@ -83,14 +111,14 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( } if (nextStep == null) { - // TODO 봉투 생성 - copy() - } else { - copy( - currentStep = nextStep, - lastPage = nextStep == moreStep.lastOrNull(), - ) + createEnvelope() + return@intent this } + + copy( + currentStep = nextStep, + lastPage = nextStep == moreStep.lastOrNull(), + ) } private fun goToNextStepInMore(currentStep: EnvelopeAddStep): EnvelopeAddStep? { @@ -123,7 +151,7 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( ) } - fun updateFriendId(friendId: Int?) { + fun updateFriendId(friendId: Long?) { this.friendId = friendId } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt index effeb6d3..4fb0d329 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt @@ -42,7 +42,7 @@ import kotlinx.coroutines.flow.debounce fun NameContentRoute( viewModel: NameViewModel = hiltViewModel(), updateParentName: (String) -> Unit, - updateParentFriendId: (Int?) -> Unit, + updateParentFriendId: (Long?) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value viewModel.sideEffect.collectWithLifecycle { sideEffect -> diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt index 25a02674..1f28bdbb 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt @@ -14,5 +14,5 @@ data class NameState( sealed interface NameSideEffect : SideEffect { data class UpdateParentName(val name: String) : NameSideEffect - data class UpdateParentFriendId(val friendId: Int?) : NameSideEffect + data class UpdateParentFriendId(val friendId: Long?) : NameSideEffect } From 4c9f436ce0b4ec459afa72a03b89df0ce935004d Mon Sep 17 00:00:00 2001 From: jinukeu Date: Fri, 26 Jan 2024 23:16:15 +0900 Subject: [PATCH 24/28] chore: ktlint, detekt --- .../component/badge/BadgeColor.kt | 3 ++- .../{EnvelopeResponse.kt => Envelope.kt} | 2 +- .../java/com/susu/core/model/FriendSearch.kt | 3 +-- .../java/com/susu/core/model/Relationship.kt | 2 +- .../com/susu/data/data/di/RepositoryModule.kt | 2 +- .../repository/EnvelopesRepositoryImpl.kt | 12 ++++++++---- .../susu/data/remote/api/EnvelopesService.kt | 2 +- .../com/susu/data/remote/api/FriendService.kt | 3 +-- .../remote/model/request/EnvelopeRequest.kt | 2 +- .../usecase/friend/SearchFriendUseCase.kt | 1 - .../ReceivedEnvelopeAddContract.kt | 1 - .../envelopeadd/ReceivedEnvelopeAddScreen.kt | 1 - .../ReceivedEnvelopeAddViewModel.kt | 19 ++++++++++++------- .../content/component/FriendListItem.kt | 1 - .../envelopeadd/content/date/DateContent.kt | 2 +- .../envelopeadd/content/memo/MemoContent.kt | 4 ---- .../envelopeadd/content/money/MoneyContent.kt | 4 ---- .../content/money/MoneyContract.kt | 1 - .../content/money/MoneyViewModel.kt | 2 +- .../envelopeadd/content/more/MoreContent.kt | 4 ---- .../envelopeadd/content/more/MoreViewModel.kt | 3 +-- .../envelopeadd/content/name/NameContent.kt | 8 +------- .../envelopeadd/content/name/NameContract.kt | 2 +- .../envelopeadd/content/phone/PhoneContent.kt | 8 +++++--- .../content/phone/PhoneContract.kt | 1 - .../content/present/PresentContent.kt | 7 +------ .../content/present/PresentContract.kt | 1 - .../relationship/RelationShipContent.kt | 1 - .../content/visited/VisitedContent.kt | 4 ---- .../content/visited/VisitedContract.kt | 1 - .../content/visited/VisitedViewModel.kt | 1 - .../ledgerdetail/LedgerDetailViewModel.kt | 4 +++- .../received/navigation/ReceivedNavigation.kt | 1 + .../com/susu/feature/sent/SentViewModel.kt | 2 ++ 34 files changed, 46 insertions(+), 69 deletions(-) rename core/model/src/main/java/com/susu/core/model/{EnvelopeResponse.kt => Envelope.kt} (86%) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/badge/BadgeColor.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/badge/BadgeColor.kt index cc91eaf2..4c6916b9 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/badge/BadgeColor.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/badge/BadgeColor.kt @@ -37,7 +37,8 @@ enum class BadgeColor( Red60( backgroundColor = com.susu.core.designsystem.theme.Red60, textColor = Gray10, - ); + ), + ; companion object { fun safeValueOf(value: String) = try { diff --git a/core/model/src/main/java/com/susu/core/model/EnvelopeResponse.kt b/core/model/src/main/java/com/susu/core/model/Envelope.kt similarity index 86% rename from core/model/src/main/java/com/susu/core/model/EnvelopeResponse.kt rename to core/model/src/main/java/com/susu/core/model/Envelope.kt index 9328f617..3e4a6e66 100644 --- a/core/model/src/main/java/com/susu/core/model/EnvelopeResponse.kt +++ b/core/model/src/main/java/com/susu/core/model/Envelope.kt @@ -11,5 +11,5 @@ data class Envelope( val gift: String? = null, val memo: String? = null, val hasVisited: Boolean? = null, - val handedOverAt: LocalDateTime? = null + val handedOverAt: LocalDateTime? = null, ) diff --git a/core/model/src/main/java/com/susu/core/model/FriendSearch.kt b/core/model/src/main/java/com/susu/core/model/FriendSearch.kt index c65e3571..9be3f87f 100644 --- a/core/model/src/main/java/com/susu/core/model/FriendSearch.kt +++ b/core/model/src/main/java/com/susu/core/model/FriendSearch.kt @@ -2,7 +2,6 @@ package com.susu.core.model import java.time.LocalDateTime - data class FriendSearch( val friend: Friend, val relationship: Relationship, @@ -11,5 +10,5 @@ data class FriendSearch( data class RecentEnvelope( val category: String, - val handedOverAt: LocalDateTime + val handedOverAt: LocalDateTime, ) diff --git a/core/model/src/main/java/com/susu/core/model/Relationship.kt b/core/model/src/main/java/com/susu/core/model/Relationship.kt index ac1c9e28..b4d8589b 100644 --- a/core/model/src/main/java/com/susu/core/model/Relationship.kt +++ b/core/model/src/main/java/com/susu/core/model/Relationship.kt @@ -6,5 +6,5 @@ import androidx.compose.runtime.Stable data class Relationship( val id: Int = -1, val relation: String = "", - val customRelation: String? = null + val customRelation: String? = null, ) diff --git a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt index 2451900f..0731c97a 100644 --- a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt +++ b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt @@ -1,8 +1,8 @@ package com.susu.data.data.di import com.susu.data.data.repository.CategoryConfigRepositoryImpl -import com.susu.data.data.repository.ExcelRepositoryImpl import com.susu.data.data.repository.EnvelopesRepositoryImpl +import com.susu.data.data.repository.ExcelRepositoryImpl import com.susu.data.data.repository.FriendRepositoryImpl import com.susu.data.data.repository.LedgerRecentSearchRepositoryImpl import com.susu.data.data.repository.LedgerRepositoryImpl diff --git a/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt index 0f89cce3..943628e8 100644 --- a/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/EnvelopesRepositoryImpl.kt @@ -55,10 +55,14 @@ class EnvelopesRepositoryImpl @Inject constructor( memo = memo, hasVisited = hasVisited, handedOverAt = handedOverAt, - category = if (categoryId != null) CategoryRequest( - id = categoryId, - customCategory = customCategory, - ) else null, + category = if (categoryId != null) { + CategoryRequest( + id = categoryId, + customCategory = customCategory, + ) + } else { + null + }, ), ).getOrThrow().toModel() } diff --git a/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt b/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt index 36be0e97..947e1c33 100644 --- a/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt +++ b/data/src/main/java/com/susu/data/remote/api/EnvelopesService.kt @@ -26,6 +26,6 @@ interface EnvelopesService { @POST("envelopes") suspend fun createEnvelope( - @Body envelopeRequest: EnvelopeRequest + @Body envelopeRequest: EnvelopeRequest, ): ApiResult } diff --git a/data/src/main/java/com/susu/data/remote/api/FriendService.kt b/data/src/main/java/com/susu/data/remote/api/FriendService.kt index 99612d55..9274a7b4 100644 --- a/data/src/main/java/com/susu/data/remote/api/FriendService.kt +++ b/data/src/main/java/com/susu/data/remote/api/FriendService.kt @@ -3,7 +3,6 @@ package com.susu.data.remote.api import com.susu.data.remote.model.request.FriendRequest import com.susu.data.remote.model.response.FriendResponse import com.susu.data.remote.model.response.FriendSearchListResponse -import com.susu.data.remote.model.response.FriendSearchResponse import com.susu.data.remote.retrofit.ApiResult import retrofit2.http.Body import retrofit2.http.GET @@ -14,7 +13,7 @@ interface FriendService { @POST("friends") suspend fun createFriend( - @Body friendRequest: FriendRequest + @Body friendRequest: FriendRequest, ): ApiResult @GET("friends") diff --git a/data/src/main/java/com/susu/data/remote/model/request/EnvelopeRequest.kt b/data/src/main/java/com/susu/data/remote/model/request/EnvelopeRequest.kt index 588b9d57..45d33e5d 100644 --- a/data/src/main/java/com/susu/data/remote/model/request/EnvelopeRequest.kt +++ b/data/src/main/java/com/susu/data/remote/model/request/EnvelopeRequest.kt @@ -19,5 +19,5 @@ data class EnvelopeRequest( @Serializable data class CategoryRequest( val id: Long, - val customCategory: String? = null + val customCategory: String? = null, ) diff --git a/domain/src/main/java/com/susu/domain/usecase/friend/SearchFriendUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/friend/SearchFriendUseCase.kt index 7fe331e1..e8ba6943 100644 --- a/domain/src/main/java/com/susu/domain/usecase/friend/SearchFriendUseCase.kt +++ b/domain/src/main/java/com/susu/domain/usecase/friend/SearchFriendUseCase.kt @@ -1,7 +1,6 @@ package com.susu.domain.usecase.friend import com.susu.core.common.runCatchingIgnoreCancelled -import com.susu.domain.repository.CategoryConfigRepository import com.susu.domain.repository.FriendRepository import javax.inject.Inject diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt index 91bd3681..e4ac460e 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddContract.kt @@ -4,7 +4,6 @@ import androidx.annotation.StringRes import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState import com.susu.feature.received.R -import com.susu.feature.received.ledgeradd.LedgerAddStep data class ReceivedEnvelopeAddState( val currentStep: EnvelopeAddStep = EnvelopeAddStep.MONEY, diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt index ed9486dd..6900eaf4 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddScreen.kt @@ -100,7 +100,6 @@ fun ReceivedEnvelopeAddScreen( updateParentPhoneNumber: (String?) -> Unit = {}, updateParentMemo: (String?) -> Unit = {}, ) { - Column( modifier = Modifier .background(SusuTheme.colorScheme.background15) diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt index bb0db117..54016c8a 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/ReceivedEnvelopeAddViewModel.kt @@ -9,7 +9,6 @@ import com.susu.feature.received.navigation.ReceivedRoute import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import kotlinx.datetime.toKotlinLocalDateTime -import timber.log.Timber import java.time.LocalDateTime import javax.inject.Inject @@ -50,8 +49,8 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( gift = present, memo = memo, handedOverAt = date!!.toKotlinLocalDateTime(), - hasVisited = hasVisited - ) + hasVisited = hasVisited, + ), ).onSuccess { // TODO PopBackStackWithEnvelope로 변경 필요, 또한 Envelope에 friendName 추가 필요 postSideEffect(ReceivedEnvelopeAddSideEffect.PopBackStack) @@ -70,8 +69,11 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( EnvelopeAddStep.NAME -> EnvelopeAddStep.MONEY EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.NAME EnvelopeAddStep.DATE -> { - if (skipRelationshipStep) EnvelopeAddStep.NAME - else EnvelopeAddStep.RELATIONSHIP + if (skipRelationshipStep) { + EnvelopeAddStep.NAME + } else { + EnvelopeAddStep.RELATIONSHIP + } } EnvelopeAddStep.MORE -> EnvelopeAddStep.DATE @@ -101,8 +103,11 @@ class ReceivedEnvelopeAddViewModel @Inject constructor( val nextStep = when (currentStep) { EnvelopeAddStep.MONEY -> EnvelopeAddStep.NAME EnvelopeAddStep.NAME -> { - if (skipRelationshipStep) EnvelopeAddStep.DATE - else EnvelopeAddStep.RELATIONSHIP + if (skipRelationshipStep) { + EnvelopeAddStep.DATE + } else { + EnvelopeAddStep.RELATIONSHIP + } } EnvelopeAddStep.RELATIONSHIP -> EnvelopeAddStep.DATE diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt index 06e10abc..0482afbe 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/component/FriendListItem.kt @@ -62,7 +62,6 @@ fun FriendListItem( @Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) @Composable fun FriendListItemPreview() { - SusuTheme { Column { FriendListItem( diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt index b0f73304..e251f4c3 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt @@ -28,7 +28,7 @@ import java.time.LocalDateTime fun DateContentRoute( viewModel: DateViewModel = hiltViewModel(), friendName: String, - updateParentDate: (LocalDateTime?) -> Unit + updateParentDate: (LocalDateTime?) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value viewModel.sideEffect.collectWithLifecycle { sideEffect -> diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoContent.kt index e5ba8276..964ecadb 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/memo/MemoContent.kt @@ -1,7 +1,6 @@ package com.susu.feature.received.envelopeadd.content.memo import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -11,8 +10,6 @@ import androidx.compose.material3.Text 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.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -26,7 +23,6 @@ import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.received.R - @Composable fun MemoContentRoute( viewModel: MemoViewModel = hiltViewModel(), diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContent.kt index 13846c3b..2e90910c 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContent.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -13,8 +12,6 @@ import androidx.compose.material3.Text 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.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -62,7 +59,6 @@ fun MoneyContent( onTextChangeMoney: (String) -> Unit = {}, onClickMoneyButton: (Int) -> Unit = {}, ) { - Column( modifier = Modifier .fillMaxSize() diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContract.kt index cbac312f..d1ae6828 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyContract.kt @@ -2,7 +2,6 @@ package com.susu.feature.received.envelopeadd.content.money import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -import com.susu.feature.received.ledgeradd.LedgerAddStep data class MoneyState( val money: String = "", diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyViewModel.kt index fadb6dbd..3061286d 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/money/MoneyViewModel.kt @@ -18,7 +18,7 @@ class MoneyViewModel @Inject constructor() : BaseViewModel = persistentListOf() + val friendList: PersistentList = persistentListOf(), ) : UiState sealed interface NameSideEffect : SideEffect { diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContent.kt index 140f86a6..92632116 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContent.kt @@ -27,7 +27,7 @@ import com.susu.feature.received.R fun PhoneContentRoute( viewModel: PhoneViewModel = hiltViewModel(), friendName: String, - updateParentPhone: (String?) -> Unit + updateParentPhone: (String?) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value viewModel.sideEffect.collectWithLifecycle { sideEffect -> @@ -55,8 +55,10 @@ fun PhoneContent( Column( modifier = Modifier .fillMaxSize() - .padding(horizontal = SusuTheme.spacing.spacing_m, - vertical = SusuTheme.spacing.spacing_xl,), + .padding( + horizontal = SusuTheme.spacing.spacing_m, + vertical = SusuTheme.spacing.spacing_xl, + ), ) { AnnotatedText( originalText = stringResource(R.string.phone_content_title, uiState.name), diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContract.kt index 0322096e..e3062997 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/phone/PhoneContract.kt @@ -2,7 +2,6 @@ package com.susu.feature.received.envelopeadd.content.phone import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -import com.susu.feature.received.ledgeradd.LedgerAddStep data class PhoneState( val phone: String = "", diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContent.kt index 8a537d98..a1830e60 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContent.kt @@ -1,7 +1,6 @@ package com.susu.feature.received.envelopeadd.content.present import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -11,8 +10,6 @@ import androidx.compose.material3.Text 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.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -25,13 +22,11 @@ import com.susu.core.designsystem.theme.Gray40 import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.received.R -import com.susu.feature.received.envelopeadd.content.name.NameSideEffect -import com.susu.feature.received.envelopeadd.content.name.NameState @Composable fun PresentContentRoute( viewModel: PresentViewModel = hiltViewModel(), - updateParentPresent: (String?) -> Unit + updateParentPresent: (String?) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value viewModel.sideEffect.collectWithLifecycle { sideEffect -> diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContract.kt index 1153087a..62b092e5 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/present/PresentContract.kt @@ -2,7 +2,6 @@ package com.susu.feature.received.envelopeadd.content.present import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -import com.susu.feature.received.ledgeradd.LedgerAddStep data class PresentState( val present: String = "", diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt index 8d4642e7..0d05d788 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipContent.kt @@ -173,7 +173,6 @@ fun RelationShipContent( @Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) @Composable fun RelationshipContentPreview() { - SusuTheme { RelationShipContent() } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContent.kt index db3b1ec2..399425c1 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContent.kt @@ -2,7 +2,6 @@ package com.susu.feature.received.envelopeadd.content.visited import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -11,8 +10,6 @@ import androidx.compose.foundation.layout.size 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.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -122,7 +119,6 @@ fun VisitedContent( @Preview(showBackground = true, backgroundColor = 0xFFF6F6F6) @Composable fun VisitedContentPreview() { - SusuTheme { VisitedContent() } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContract.kt index 87633bb6..c5b1788c 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedContract.kt @@ -2,7 +2,6 @@ package com.susu.feature.received.envelopeadd.content.visited import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -import com.susu.feature.received.ledgeradd.LedgerAddStep data class VisitedState( val categoryName: String = "", diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedViewModel.kt index edb5ff1c..cd7bec9e 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/visited/VisitedViewModel.kt @@ -12,7 +12,6 @@ class VisitedViewModel @Inject constructor() : BaseViewModel Unit, diff --git a/feature/sent/src/main/java/com/susu/feature/sent/SentViewModel.kt b/feature/sent/src/main/java/com/susu/feature/sent/SentViewModel.kt index 2bbeba06..965509ce 100644 --- a/feature/sent/src/main/java/com/susu/feature/sent/SentViewModel.kt +++ b/feature/sent/src/main/java/com/susu/feature/sent/SentViewModel.kt @@ -9,10 +9,12 @@ import javax.inject.Inject @HiltViewModel class SentViewModel @Inject constructor( + @Suppress("detekt:UnusedPrivateProperty") private val getEnvelopesListUseCase: GetEnvelopesListUseCase, ) : BaseViewModel( SentState(), ) { + @Suppress("detekt:UnusedPrivateProperty") private var page = 0 fun getEnvelopesList() = viewModelScope.launch { From 5b26f323379a00851b50e29acbd14708f195eda5 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Fri, 26 Jan 2024 23:24:34 +0900 Subject: [PATCH 25/28] fix: resolve conflict --- .../src/main/java/com/susu/feature/navigator/MainNavigator.kt | 1 + 1 file changed, 1 insertion(+) 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 ea59b530..c9dac278 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 @@ -157,6 +157,7 @@ internal class MainNavigator( fun navigateReceivedEnvelopeAdd(categoryName: String, ledgerId: Long) { navController.navigateReceivedEnvelopeAdd(categoryName, ledgerId) + } fun navigateMyPagePrivacyPolicy() { navController.navigateMyPagePrivacyPolicy() From d4d349470971d700dd59d6403439d507f4abba99 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Fri, 26 Jan 2024 23:32:11 +0900 Subject: [PATCH 26/28] chore: ktlint --- .../content/relationship/RelationShipViewModel.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt index 895871b1..e1e3daaf 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/relationship/RelationShipViewModel.kt @@ -17,7 +17,12 @@ class RelationShipViewModel @Inject constructor( ) { private val parentSelectedRelationShip get() = with(currentState) { - if (selectedRelationship == customRelationship && (customRelationship.customRelation.isNullOrEmpty() || isSavedCustomRelationShip.not())) { + if (selectedRelationship == customRelationship && + ( + customRelationship.customRelation.isNullOrEmpty() || + isSavedCustomRelationShip.not() + ) + ) { null } else { selectedRelationship From 7649669b55cf6129f17f0997a3b23528592c2b0b Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sat, 27 Jan 2024 00:01:48 +0900 Subject: [PATCH 27/28] =?UTF-8?q?feat:=20=EB=B4=89=ED=88=AC=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20=EA=B0=92=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/susu/core/model/Envelope.kt | 2 +- .../data/remote/model/response/EnvelopeResponse.kt | 4 ++-- .../data/remote/model/response/EnvelopesResponse.kt | 8 ++++---- .../received/envelopeadd/content/name/NameContent.kt | 11 ++++++++++- .../received/envelopeadd/content/name/NameContract.kt | 1 + .../envelopeadd/content/name/NameViewModel.kt | 6 +++++- 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/core/model/src/main/java/com/susu/core/model/Envelope.kt b/core/model/src/main/java/com/susu/core/model/Envelope.kt index 3e4a6e66..a84cb3bc 100644 --- a/core/model/src/main/java/com/susu/core/model/Envelope.kt +++ b/core/model/src/main/java/com/susu/core/model/Envelope.kt @@ -6,7 +6,7 @@ data class Envelope( val id: Long, val uid: Long, val type: String, - val friendId: Long, + val friend: Friend, val amount: Long, val gift: String? = null, val memo: String? = null, diff --git a/data/src/main/java/com/susu/data/remote/model/response/EnvelopeResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/EnvelopeResponse.kt index c4b6b0a4..76ec62f8 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/EnvelopeResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/EnvelopeResponse.kt @@ -10,7 +10,7 @@ data class EnvelopeResponse( val id: Long, val uid: Long, val type: String, - val friendId: Long, + val friend: FriendInfo, val amount: Long, val gift: String? = null, val memo: String? = null, @@ -22,7 +22,7 @@ internal fun EnvelopeResponse.toModel() = Envelope( id = id, uid = uid, type = type, - friendId = friendId, + friend = friend.toModel(), amount = amount, gift = gift, memo = memo, diff --git a/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt index 142a73ab..f64572c6 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/EnvelopesResponse.kt @@ -15,11 +15,11 @@ data class EnvelopesResponse( @Serializable data class FriendInfo( val id: Long, - val uid: Long, - val createdAt: String, - val modifiedAt: String, + val uid: Long = 0, + val createdAt: String = "", + val modifiedAt: String = "", val name: String, - val phoneNumber: String, + val phoneNumber: String = "", ) internal fun FriendInfo.toModel() = Friend( diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt index e9c33c79..3a9adfc2 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContent.kt @@ -13,9 +13,13 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow 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.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -40,10 +44,13 @@ fun NameContentRoute( updateParentFriendId: (Long?) -> Unit, ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + val focusRequester = remember { FocusRequester() } + val focusManager = LocalFocusManager.current viewModel.sideEffect.collectWithLifecycle { sideEffect -> when (sideEffect) { is NameSideEffect.UpdateParentName -> updateParentName(sideEffect.name) is NameSideEffect.UpdateParentFriendId -> updateParentFriendId(sideEffect.friendId) + NameSideEffect.FocusClear -> focusManager.clearFocus() } } @@ -59,6 +66,7 @@ fun NameContentRoute( NameContent( uiState = uiState, + focusRequester = focusRequester, onTextChangeName = viewModel::updateName, onClickFriendItem = viewModel::selectFriend, ) @@ -67,6 +75,7 @@ fun NameContentRoute( @Composable fun NameContent( uiState: NameState = NameState(), + focusRequester: FocusRequester = remember { FocusRequester() }, onTextChangeName: (String) -> Unit = {}, onClickFriendItem: (FriendSearch) -> Unit = {}, ) { @@ -88,11 +97,11 @@ fun NameContent( .size(SusuTheme.spacing.spacing_m), ) SusuBasicTextField( + modifier = Modifier.fillMaxWidth().focusRequester(focusRequester), text = uiState.name, onTextChange = onTextChangeName, placeholder = stringResource(R.string.name_content_placeholder), placeholderColor = Gray40, - modifier = Modifier.fillMaxWidth(), ) Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xl)) diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt index f2ac07e1..ec2f4108 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameContract.kt @@ -15,4 +15,5 @@ data class NameState( sealed interface NameSideEffect : SideEffect { data class UpdateParentName(val name: String) : NameSideEffect data class UpdateParentFriendId(val friendId: Long?) : NameSideEffect + data object FocusClear : NameSideEffect } diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt index 4cb52981..73b726c1 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/name/NameViewModel.kt @@ -5,6 +5,7 @@ import com.susu.core.model.FriendSearch import com.susu.core.ui.base.BaseViewModel import com.susu.domain.usecase.friend.SearchFriendUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.launch import javax.inject.Inject @@ -22,13 +23,15 @@ class NameViewModel @Inject constructor( ) copy( name = name, + friendList = if (name.isEmpty()) persistentListOf() else friendList, isSelectedFriend = false, ) } fun selectFriend(friend: FriendSearch) = intent { postSideEffect( - NameSideEffect.UpdateParentName(name), + NameSideEffect.FocusClear, + NameSideEffect.UpdateParentName(friend.friend.name), NameSideEffect.UpdateParentFriendId(friend.friend.id), ) copy( @@ -38,6 +41,7 @@ class NameViewModel @Inject constructor( } fun getFriendList(search: String) = viewModelScope.launch { + if (search.isEmpty()) return@launch if (currentState.isSelectedFriend) return@launch searchFriendUseCase(name = search) From b343c7436d89d9f2afc92823cffc5c0bedbe5036 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sun, 28 Jan 2024 00:35:20 +0900 Subject: [PATCH 28/28] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B6=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20=EB=B4=89=ED=88=AC=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EC=8B=9C=20=EB=B0=94=ED=85=80=EC=8B=9C=ED=8A=B8=20dismiss=20?= =?UTF-8?q?=EC=8B=9C=EC=97=90=EB=8F=84=20=EC=A7=80=EC=A0=95=EB=90=9C=20?= =?UTF-8?q?=EB=82=A0=EC=A7=9C=EA=B0=80=20=EC=84=A0=ED=83=9D=EB=90=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../envelopeadd/content/date/DateContent.kt | 9 ++++++--- .../ledgeradd/content/date/DateContent.kt | 18 ++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt index e251f4c3..d162711f 100644 --- a/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt +++ b/feature/received/src/main/java/com/susu/feature/received/envelopeadd/content/date/DateContent.kt @@ -46,7 +46,10 @@ fun DateContentRoute( uiState = uiState, onDateItemSelected = viewModel::updateDate, onClickDateText = viewModel::showDateBottomSheet, - onDismissDateBottomSheet = viewModel::hideDateBottomSheet, + onDismissDateBottomSheet = { year, month, day -> + viewModel.updateDate(year, month, day) + viewModel.hideDateBottomSheet() + }, ) } @@ -56,7 +59,7 @@ fun DateContent( uiState: DateState = DateState(), onDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, onClickDateText: () -> Unit = {}, - onDismissDateBottomSheet: () -> Unit = {}, + onDismissDateBottomSheet: (Int, Int, Int) -> Unit = { _, _, _ -> }, ) { Column( modifier = Modifier @@ -90,7 +93,7 @@ fun DateContent( initialMonth = uiState.date?.monthValue ?: currentDate.monthValue, initialDay = uiState.date?.dayOfMonth ?: currentDate.dayOfMonth, maximumContainerHeight = 346.dp, - onDismissRequest = { _, _, _ -> onDismissDateBottomSheet() }, + onDismissRequest = onDismissDateBottomSheet, onItemSelected = onDateItemSelected, ) } 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 b5be883f..e997f823 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 @@ -57,10 +57,16 @@ fun DateContentRoute( uiState = uiState, onStartDateItemSelected = viewModel::updateStartDate, onClickStartDateText = viewModel::showStartDateBottomSheet, - onDismissStartDateBottomSheet = viewModel::hideStartDateBottomSheet, + onDismissStartDateBottomSheet = { year, month, day -> + viewModel.updateStartDate(year, month, day) + viewModel.hideStartDateBottomSheet() + }, onEndDateItemSelected = viewModel::updateEndDate, onClickEndDateText = viewModel::showEndDateBottomSheet, - onDismissEndDateBottomSheet = viewModel::hideEndDateBottomSheet, + onDismissEndDateBottomSheet = { year, month, day -> + viewModel.updateEndDate(year, month, day) + viewModel.hideEndDateBottomSheet() + }, onClickSetDateButton = viewModel::toggleShowOnlyStartAt, ) } @@ -71,10 +77,10 @@ fun DateContent( uiState: DateState = DateState(), onStartDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, onClickStartDateText: () -> Unit = {}, - onDismissStartDateBottomSheet: () -> Unit = {}, + onDismissStartDateBottomSheet: (Int, Int, Int) -> Unit = { _, _, _ -> }, onEndDateItemSelected: (Int, Int, Int) -> Unit = { _, _, _ -> }, onClickEndDateText: () -> Unit = {}, - onDismissEndDateBottomSheet: () -> Unit = {}, + onDismissEndDateBottomSheet: (Int, Int, Int) -> Unit = { _, _, _ -> }, onClickSetDateButton: () -> Unit = {}, ) { Column( @@ -146,7 +152,7 @@ fun DateContent( initialCriteriaDay = uiState.endAt?.dayOfMonth, afterDate = false, maximumContainerHeight = 346.dp, - onDismissRequest = { _, _, _ -> onDismissStartDateBottomSheet() }, + onDismissRequest = onDismissStartDateBottomSheet, onItemSelected = onStartDateItemSelected, ) } @@ -161,7 +167,7 @@ fun DateContent( initialCriteriaDay = uiState.startAt?.dayOfMonth ?: minDate.dayOfMonth, afterDate = true, maximumContainerHeight = 346.dp, - onDismissRequest = { _, _, _ -> onDismissEndDateBottomSheet() }, + onDismissRequest = onDismissEndDateBottomSheet, onItemSelected = onEndDateItemSelected, ) }