From 56ed85b1cf162b9b60aa1b1b7547f403b1ed15da Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 16 Feb 2024 15:26:43 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=EC=98=A8=EB=B3=B4=EB=94=A9=20?= =?UTF-8?q?=ED=88=AC=ED=91=9C=20api=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/susu/core/model/OnboardVote.kt | 9 +++++++++ .../com/susu/data/data/di/RepositoryModule.kt | 7 +++++++ .../data/repository/OnboardRepositoryImpl.kt | 20 +++++++++++++++++++ .../susu/data/remote/api/OnboardService.kt | 10 ++++++++++ .../susu/data/remote/di/ApiServiceModule.kt | 7 +++++++ .../model/response/OnboardVoteResponse.kt | 14 +++++++++++++ .../domain/repository/OnboardRepository.kt | 7 +++++++ .../loginsignup/GetOnboardVoteUseCase.kt | 14 +++++++++++++ .../loginsignup/login/LoginContract.kt | 2 ++ .../feature/loginsignup/login/LoginScreen.kt | 17 +++++++++------- .../loginsignup/login/LoginViewModel.kt | 10 ++++++++++ 11 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 core/model/src/main/java/com/susu/core/model/OnboardVote.kt create mode 100644 data/src/main/java/com/susu/data/data/repository/OnboardRepositoryImpl.kt create mode 100644 data/src/main/java/com/susu/data/remote/api/OnboardService.kt create mode 100644 data/src/main/java/com/susu/data/remote/model/response/OnboardVoteResponse.kt create mode 100644 domain/src/main/java/com/susu/domain/repository/OnboardRepository.kt create mode 100644 domain/src/main/java/com/susu/domain/usecase/loginsignup/GetOnboardVoteUseCase.kt diff --git a/core/model/src/main/java/com/susu/core/model/OnboardVote.kt b/core/model/src/main/java/com/susu/core/model/OnboardVote.kt new file mode 100644 index 00000000..529cc1fb --- /dev/null +++ b/core/model/src/main/java/com/susu/core/model/OnboardVote.kt @@ -0,0 +1,9 @@ +package com.susu.core.model + +import androidx.compose.runtime.Stable + +@Stable +data class OnboardVote( + val mostContent: String, + val mostPercentage: Int, +) 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 20b0792d..4effc251 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 @@ -9,6 +9,7 @@ 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 +import com.susu.data.data.repository.OnboardRepositoryImpl import com.susu.data.data.repository.ReportRepositoryImpl import com.susu.data.data.repository.SignUpRepositoryImpl import com.susu.data.data.repository.StatisticsRepositoryImpl @@ -26,6 +27,7 @@ import com.susu.domain.repository.FriendRepository import com.susu.domain.repository.LedgerRecentSearchRepository import com.susu.domain.repository.LedgerRepository import com.susu.domain.repository.LoginRepository +import com.susu.domain.repository.OnboardRepository import com.susu.domain.repository.ReportRepository import com.susu.domain.repository.SignUpRepository import com.susu.domain.repository.StatisticsRepository @@ -127,4 +129,9 @@ abstract class RepositoryModule { abstract fun bindReportRepository( reportRepositoryImpl: ReportRepositoryImpl, ): ReportRepository + + @Binds + abstract fun bindOnboardRepository( + onboardRepositoryImpl: OnboardRepositoryImpl, + ): OnboardRepository } diff --git a/data/src/main/java/com/susu/data/data/repository/OnboardRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/OnboardRepositoryImpl.kt new file mode 100644 index 00000000..c5b39d36 --- /dev/null +++ b/data/src/main/java/com/susu/data/data/repository/OnboardRepositoryImpl.kt @@ -0,0 +1,20 @@ +package com.susu.data.data.repository + +import com.susu.core.model.OnboardVote +import com.susu.data.remote.api.OnboardService +import com.susu.domain.repository.OnboardRepository +import javax.inject.Inject + +class OnboardRepositoryImpl @Inject constructor( + private val onboardService: OnboardService, +) : OnboardRepository { + override suspend fun getOnboardVote(): OnboardVote { + val result = onboardService.getOnboardVote().getOrThrow().options + val mostOption = result.maxBy { it.count } + + return OnboardVote( + mostContent = mostOption.content, + mostPercentage = mostOption.count / result.sumOf { it.count } * 100, + ) + } +} diff --git a/data/src/main/java/com/susu/data/remote/api/OnboardService.kt b/data/src/main/java/com/susu/data/remote/api/OnboardService.kt new file mode 100644 index 00000000..676a092b --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/api/OnboardService.kt @@ -0,0 +1,10 @@ +package com.susu.data.remote.api + +import com.susu.data.remote.model.response.OnboardVoteResponse +import com.susu.data.remote.retrofit.ApiResult +import retrofit2.http.GET + +interface OnboardService { + @GET("votes/onboarding") + suspend fun getOnboardVote(): 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 6b5041c4..38edfbf2 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 @@ -6,6 +6,7 @@ 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.OnboardService import com.susu.data.remote.api.ReportService import com.susu.data.remote.api.SignUpService import com.susu.data.remote.api.StatisticsService @@ -101,4 +102,10 @@ object ApiServiceModule { fun providesBlockService(retrofit: Retrofit): BlockService { return retrofit.create(BlockService::class.java) } + + @Singleton + @Provides + fun providesOnboardService(retrofit: Retrofit): OnboardService { + return retrofit.create(OnboardService::class.java) + } } diff --git a/data/src/main/java/com/susu/data/remote/model/response/OnboardVoteResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/OnboardVoteResponse.kt new file mode 100644 index 00000000..db9aeb30 --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/response/OnboardVoteResponse.kt @@ -0,0 +1,14 @@ +package com.susu.data.remote.model.response + +import kotlinx.serialization.Serializable + +@Serializable +data class OnboardVoteResponse( + val options: List, +) + +@Serializable +data class OnboardVoteOption( + val content: String = "", + val count: Int = 0, +) diff --git a/domain/src/main/java/com/susu/domain/repository/OnboardRepository.kt b/domain/src/main/java/com/susu/domain/repository/OnboardRepository.kt new file mode 100644 index 00000000..f1686555 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/repository/OnboardRepository.kt @@ -0,0 +1,7 @@ +package com.susu.domain.repository + +import com.susu.core.model.OnboardVote + +interface OnboardRepository { + suspend fun getOnboardVote(): OnboardVote +} diff --git a/domain/src/main/java/com/susu/domain/usecase/loginsignup/GetOnboardVoteUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/loginsignup/GetOnboardVoteUseCase.kt new file mode 100644 index 00000000..22ff2c31 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/loginsignup/GetOnboardVoteUseCase.kt @@ -0,0 +1,14 @@ +package com.susu.domain.usecase.loginsignup + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.OnboardRepository +import javax.inject.Inject + +class GetOnboardVoteUseCase @Inject constructor( + private val onboardRepository: OnboardRepository, +) { + + suspend operator fun invoke() = runCatchingIgnoreCancelled { + onboardRepository.getOnboardVote() + } +} diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginContract.kt index c22a5b99..16665e78 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginContract.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginContract.kt @@ -1,5 +1,6 @@ package com.susu.feature.loginsignup.login +import com.susu.core.model.OnboardVote import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState @@ -11,4 +12,5 @@ sealed interface LoginEffect : SideEffect { data class LoginState( val isLoading: Boolean = false, + val onboardVote: OnboardVote? = null, ) : UiState diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt index c9ab7d72..10849271 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt @@ -46,6 +46,7 @@ import com.susu.core.designsystem.theme.Orange60 import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.ui.SnackbarToken import com.susu.core.ui.SnsProviders +import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuClickable import com.susu.feature.loginsignup.R import com.susu.feature.loginsignup.social.KakaoLoginHelper @@ -65,16 +66,18 @@ fun LoginRoute( } } - LaunchedEffect(key1 = viewModel.sideEffect) { - viewModel.sideEffect.collect { sideEffect -> - when (sideEffect) { - is LoginEffect.ShowSnackBar -> onShowSnackBar(SnackbarToken(message = sideEffect.message)) - LoginEffect.NavigateToReceived -> navigateToReceived() - LoginEffect.NavigateToSignUp -> navigateToSignUp() - } + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is LoginEffect.ShowSnackBar -> onShowSnackBar(SnackbarToken(message = sideEffect.message)) + LoginEffect.NavigateToReceived -> navigateToReceived() + LoginEffect.NavigateToSignUp -> navigateToSignUp() } } + LaunchedEffect(key1 = Unit) { + viewModel.initData() + } + LoginScreen( uiState = uiState, transitionState = transitionState, diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginViewModel.kt index c1e7f6e6..5e2708b1 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginViewModel.kt @@ -5,6 +5,7 @@ import com.susu.core.model.exception.UnknownException import com.susu.core.ui.SnsProviders import com.susu.core.ui.base.BaseViewModel import com.susu.domain.usecase.loginsignup.CheckCanRegisterUseCase +import com.susu.domain.usecase.loginsignup.GetOnboardVoteUseCase import com.susu.domain.usecase.loginsignup.LoginUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch @@ -14,8 +15,17 @@ import javax.inject.Inject class LoginViewModel @Inject constructor( private val checkCanRegisterUseCase: CheckCanRegisterUseCase, private val loginUseCase: LoginUseCase, + private val getOnboardVoteUseCase: GetOnboardVoteUseCase, ) : BaseViewModel(LoginState()) { + fun initData() = viewModelScope.launch { + getOnboardVoteUseCase().onSuccess { + intent { copy(onboardVote = it) } + }.onFailure { + intent { copy(onboardVote = null) } + } + } + fun login(provider: SnsProviders, oauthAccessToken: String) { viewModelScope.launch { intent { copy(isLoading = true) } From b3964eaf3419aa2fc1d7dad2bce99c3793f82563 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 16 Feb 2024 15:36:29 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20LoginScreen=20=ED=95=98=EB=8B=A8=20?= =?UTF-8?q?=EB=A1=9C=EA=B3=A0=20=EC=9C=84=EC=B9=98=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/susu/feature/loginsignup/login/LoginScreen.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt index 10849271..e004dfbc 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt @@ -134,8 +134,11 @@ fun LoginScreen( Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xxxxs)) Text(text = stringResource(R.string.login_sub_header), style = SusuTheme.typography.title_m, color = Gray50) Spacer(modifier = Modifier.height(64.dp)) + LoginArchGraph(modifier = Modifier.size(200.dp)) + Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xxxxl)) + Row( horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs), ) { @@ -143,16 +146,22 @@ fun LoginScreen( LoginBlankText(text = "87%", state = transitionState) // TODO: 임시 하드코딩 Text(text = stringResource(R.string.login_statistics_2), style = SusuTheme.typography.title_s) } + Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xxs)) + Row( horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs), ) { LoginBlankText(text = "10만원", state = transitionState) // TODO: 임시 하드코딩 Text(text = stringResource(R.string.login_statistics_3), style = SusuTheme.typography.title_s) } + Spacer(modifier = Modifier.height(64.dp)) + KakaoLoginButton(onClick = onLoginClick) - Spacer(modifier = Modifier.height(24.dp)) + + Spacer(modifier = Modifier.weight(1f)) + Image( modifier = Modifier.align(Alignment.CenterHorizontally), painter = painterResource(id = com.susu.core.designsystem.R.drawable.ic_susu_logo_weak), From e58003abd2c772589de21208bf142761b2f63cda Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 16 Feb 2024 15:55:01 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20LoginScreen=20UI=EC=97=90=20?= =?UTF-8?q?=EC=98=A8=EB=B3=B4=EB=94=A9=20=ED=88=AC=ED=91=9C=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/OnboardRepositoryImpl.kt | 2 +- .../loginsignup/login/LoginArchGraph.kt | 2 +- .../feature/loginsignup/login/LoginScreen.kt | 20 ++++++++++++++++--- .../src/main/res/values/strings.xml | 3 +++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/data/src/main/java/com/susu/data/data/repository/OnboardRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/OnboardRepositoryImpl.kt index c5b39d36..cfbc8e78 100644 --- a/data/src/main/java/com/susu/data/data/repository/OnboardRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/OnboardRepositoryImpl.kt @@ -14,7 +14,7 @@ class OnboardRepositoryImpl @Inject constructor( return OnboardVote( mostContent = mostOption.content, - mostPercentage = mostOption.count / result.sumOf { it.count } * 100, + mostPercentage = (mostOption.count.toFloat() / result.sumOf { it.count } * 100).toInt(), ) } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginArchGraph.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginArchGraph.kt index 75b0f322..91449474 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginArchGraph.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginArchGraph.kt @@ -27,7 +27,7 @@ fun LoginArchGraph( ) { val fillAngle = remember { Animatable(fillFrom) } - LaunchedEffect(key1 = Unit) { + LaunchedEffect(key1 = fillUntil) { fillAngle.animateTo( targetValue = fillUntil, animationSpec = tween( diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt index e004dfbc..c61593b8 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt @@ -135,7 +135,10 @@ fun LoginScreen( Text(text = stringResource(R.string.login_sub_header), style = SusuTheme.typography.title_m, color = Gray50) Spacer(modifier = Modifier.height(64.dp)) - LoginArchGraph(modifier = Modifier.size(200.dp)) + LoginArchGraph( + modifier = Modifier.size(200.dp), + fillUntil = uiState.onboardVote?.let { it.mostPercentage.toFloat() / 100f } ?: 0f, + ) Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xxxxl)) @@ -143,7 +146,14 @@ fun LoginScreen( horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs), ) { Text(text = stringResource(R.string.login_statistics_1), style = SusuTheme.typography.title_s) - LoginBlankText(text = "87%", state = transitionState) // TODO: 임시 하드코딩 + LoginBlankText( + text = stringResource( + id = R.string.login_percentage_format, + uiState.onboardVote?.mostPercentage?.toString() + ?: stringResource(id = R.string.login_statistics_unknown_percentage), + ), + state = transitionState, + ) Text(text = stringResource(R.string.login_statistics_2), style = SusuTheme.typography.title_s) } @@ -152,7 +162,11 @@ fun LoginScreen( Row( horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs), ) { - LoginBlankText(text = "10만원", state = transitionState) // TODO: 임시 하드코딩 + LoginBlankText( + text = uiState.onboardVote?.mostContent + ?: stringResource(id = R.string.login_statistics_unknown_content), + state = transitionState, + ) Text(text = stringResource(R.string.login_statistics_3), style = SusuTheme.typography.title_s) } diff --git a/feature/loginsignup/src/main/res/values/strings.xml b/feature/loginsignup/src/main/res/values/strings.xml index 7931166a..0404248a 100644 --- a/feature/loginsignup/src/main/res/values/strings.xml +++ b/feature/loginsignup/src/main/res/values/strings.xml @@ -10,6 +10,9 @@ 수수 가입자 이 적당하다고 답했어요 + %s%% + \?만원 + \? 친구의 결혼식, 축의금 "은 " From a3d0365ff5497125a87dfd63af02e94db6da38f0 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 16 Feb 2024 16:13:06 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20LoginScreen=20=EB=84=A4=ED=8A=B8?= =?UTF-8?q?=EC=9B=8C=ED=81=AC=20=EB=AF=B8=EC=97=B0=EA=B2=B0=20=EC=8B=9C=20?= =?UTF-8?q?=EA=B7=B8=EB=9E=98=ED=94=84=20=EA=B8=B0=EB=B3=B8=EA=B0=92=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/susu/feature/loginsignup/login/LoginScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt index c61593b8..65ba5a38 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/login/LoginScreen.kt @@ -137,7 +137,7 @@ fun LoginScreen( LoginArchGraph( modifier = Modifier.size(200.dp), - fillUntil = uiState.onboardVote?.let { it.mostPercentage.toFloat() / 100f } ?: 0f, + fillUntil = uiState.onboardVote?.let { it.mostPercentage.toFloat() / 100f } ?: 0.85f, ) Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xxxxl))