From 0fe3f575f5265717fcc5aeb9f736fdb6117a7e65 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Thu, 3 Apr 2025 15:11:09 +0900 Subject: [PATCH 1/9] =?UTF-8?q?[TNT-275]=20refactor:=20=EC=95=BD=EA=B4=80?= =?UTF-8?q?=20=EC=83=88=EB=A1=9C=EC=9A=B4=20=EB=85=B8=EC=85=98=20=EC=A3=BC?= =?UTF-8?q?=EC=86=8C=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- domain/src/main/java/co/kr/tnt/domain/utils/AppUrls.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/domain/src/main/java/co/kr/tnt/domain/utils/AppUrls.kt b/domain/src/main/java/co/kr/tnt/domain/utils/AppUrls.kt index 9892dd5b..5f27347a 100644 --- a/domain/src/main/java/co/kr/tnt/domain/utils/AppUrls.kt +++ b/domain/src/main/java/co/kr/tnt/domain/utils/AppUrls.kt @@ -1,7 +1,6 @@ package co.kr.tnt.domain.utils object AppUrls { - // TODO - const val PRIVACY_POLICY_URL = "https://fluffy-router-d0b.notion.site/775bc037dd1b4e8ba56679e51a7321e5" - const val TERMS_OF_SERVICE_URL = "https://fluffy-router-d0b.notion.site/f1ee7a43b6d941068723163fda127699" + const val PRIVACY_POLICY_URL = "https://ymkim97.notion.site/1bcd727836a3813e9f5dd60ed9620612" + const val TERMS_OF_SERVICE_URL = "https://ymkim97.notion.site/1bcd727836a381c08c7bdf4d70c3639b" } From 1727ca04ace6a978014f8b89649a7350ac0ea34b Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Thu, 3 Apr 2025 17:29:32 +0900 Subject: [PATCH 2/9] =?UTF-8?q?[TNT-272]=20refactor:=20TraineeMealRecordVi?= =?UTF-8?q?ewModel=20=EB=82=B4=20Context=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - context 대신 이미지 파일 전달 --- .../mealrecord/TraineeMealRecordContract.kt | 4 +-- .../mealrecord/TraineeMealRecordScreen.kt | 28 +++++++++++++------ .../mealrecord/TraineeMealRecordViewModel.kt | 10 ++----- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordContract.kt b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordContract.kt index 8064ac21..7e2f70f5 100644 --- a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordContract.kt +++ b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordContract.kt @@ -1,10 +1,10 @@ package co.kr.tnt.trainee.mealrecord -import android.content.Context import android.net.Uri import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import java.io.File import java.time.LocalDate import java.time.LocalDateTime import java.time.LocalTime @@ -52,7 +52,7 @@ internal class TraineeMealRecordContract { data object OnClickCloseBottomSheet : TraineeMealRecordUiEvent data class OnSelectMealType(val mealType: String) : TraineeMealRecordUiEvent data class OnChangeMemo(val memo: String) : TraineeMealRecordUiEvent - data class OnClickSave(val context: Context) : TraineeMealRecordUiEvent + data class OnClickSave(val imageFile: File?) : TraineeMealRecordUiEvent data object OnClickBack : TraineeMealRecordUiEvent data object OnClickDialogConfirm : TraineeMealRecordUiEvent data object OnDismissDialog : TraineeMealRecordUiEvent diff --git a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt index 6c4d8e0c..ce677610 100644 --- a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt +++ b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt @@ -77,11 +77,15 @@ import co.kr.tnt.ui.coil.ResizeTransformation import co.kr.tnt.ui.component.TnTLoadingScreen import co.kr.tnt.ui.extensions.clearFocusOnTap import co.kr.tnt.ui.model.RecordChip +import co.kr.tnt.ui.utils.convertToAllowedImageFormat import co.kr.tnt.ui.utils.throttled import coil.compose.rememberAsyncImagePainter import coil.request.ImageRequest import com.kizitonwose.calendar.compose.rememberCalendarState +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File import java.time.DayOfWeek import java.time.LocalDate import java.time.LocalTime @@ -101,22 +105,30 @@ internal fun TraineeMealRecordRoute( val state by viewModel.uiState.collectAsStateWithLifecycle() val dateFormatter = remember { DateFormatter() } + var imageFile by rememberSaveable { mutableStateOf(null) } var showBottomSheet by rememberSaveable { mutableStateOf(false) } LaunchedEffect(selectedDate) { viewModel.setEvent( TraineeMealRecordUiEvent.OnSelectMealDate( - dateFormatter.parse( - selectedDate, - ), + dateFormatter.parse(selectedDate), ), ) } + LaunchedEffect(state.image) { + state.image?.let { uri -> + withContext(Dispatchers.IO) { + val file = uri.convertToAllowedImageFormat(context) + imageFile = file + } + } + } + TraineeMealRecordScreen( state = state, context = context, - onImageSelect = { uri -> + onSelectImage = { uri -> viewModel.setEvent(TraineeMealRecordUiEvent.OnSelectImage(imageUri = uri)) }, onClickDeleteImage = { viewModel.setEvent(TraineeMealRecordUiEvent.OnClickDeleteImage) }, @@ -137,7 +149,7 @@ internal fun TraineeMealRecordRoute( onClickBack = { viewModel.setEvent(TraineeMealRecordUiEvent.OnClickBack) }, - onClickSaveButton = { viewModel.setEvent(TraineeMealRecordUiEvent.OnClickSave(context)) }, + onClickSaveButton = { viewModel.setEvent(TraineeMealRecordUiEvent.OnClickSave(imageFile)) }, ) if (showBottomSheet) { @@ -201,7 +213,7 @@ internal fun TraineeMealRecordRoute( private fun TraineeMealRecordScreen( state: TraineeMealRecordUiState, context: Context, - onImageSelect: (url: Uri) -> Unit, + onSelectImage: (url: Uri) -> Unit, onClickDeleteImage: () -> Unit, onClickDateSection: () -> Unit, onClickTimeSection: () -> Unit, @@ -214,7 +226,7 @@ private fun TraineeMealRecordScreen( val pickMediaLauncher = rememberLauncherForActivityResult(PickVisualMedia()) { uri -> if (uri != null) { - onImageSelect(uri) + onSelectImage(uri) } } @@ -672,7 +684,7 @@ private fun TraineeMealRecordScreenPreview() { memo = "", ), context = LocalContext.current, - onImageSelect = { }, + onSelectImage = { }, onClickDeleteImage = { }, onClickDateSection = { }, onClickTimeSection = { }, diff --git a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordViewModel.kt b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordViewModel.kt index b29f66f4..cc228deb 100644 --- a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordViewModel.kt +++ b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordViewModel.kt @@ -1,6 +1,5 @@ package co.kr.tnt.trainee.mealrecord -import android.content.Context import androidx.lifecycle.viewModelScope import co.kr.tnt.domain.repository.TraineeRepository import co.kr.tnt.domain.utils.DateFormatter @@ -9,7 +8,6 @@ import co.kr.tnt.trainee.mealrecord.TraineeMealRecordContract.TraineeMealRecordU import co.kr.tnt.trainee.mealrecord.TraineeMealRecordContract.TraineeMealRecordUiState import co.kr.tnt.trainee.mealrecord.TraineeMealRecordContract.TraineeMealRecordUiState.DialogState import co.kr.tnt.ui.base.BaseViewModel -import co.kr.tnt.ui.utils.convertToAllowedImageFormat import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import java.io.File @@ -45,14 +43,13 @@ internal class TraineeMealRecordViewModel @Inject constructor( } TraineeMealRecordUiEvent.OnClickCloseBottomSheet -> clearFocusState() - is TraineeMealRecordUiEvent.OnSelectMealType -> updateState { copy(mealType = event.mealType).validateMealRecord() } is TraineeMealRecordUiEvent.OnChangeMemo -> updateMemo(event.memo) TraineeMealRecordUiEvent.OnClickBack -> handleBackClick() - is TraineeMealRecordUiEvent.OnClickSave -> postMealRecord(event.context) + is TraineeMealRecordUiEvent.OnClickSave -> postMealRecord(event.imageFile) TraineeMealRecordUiEvent.OnClickDialogConfirm -> { updateState { copy(dialogState = DialogState.NONE) } sendEffect(TraineeMealRecordSideEffect.NavigateToHome) @@ -90,18 +87,15 @@ internal class TraineeMealRecordViewModel @Inject constructor( } } - // TODO Context 제거 - private fun postMealRecord(context: Context) { + private fun postMealRecord(imageFile: File?) { updateState { copy(isLoading = true) } val mealDateTime = dateFormatter.format( LocalDateTime.of(currentState.date, currentState.time), "yyyy-MM-dd'T'HH:mm:ss", ) - viewModelScope.launch { val state = currentState - val imageFile: File? = state.image?.convertToAllowedImageFormat(context) runCatching { traineeRepository.postMealRecord( mealImage = imageFile, From 600c5e143aba723fc86974db1336b614b1a175a3 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Thu, 3 Apr 2025 17:52:28 +0900 Subject: [PATCH 3/9] =?UTF-8?q?[TNT-272]=20fix:=20=EC=8B=9D=EB=8B=A8=20?= =?UTF-8?q?=EA=B8=B0=EB=A1=9D=20=EC=A4=91=EB=8B=A8=20dialog=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EB=8F=99=EC=9E=91=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt index ce677610..7f4a4f46 100644 --- a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt +++ b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt @@ -339,8 +339,8 @@ private fun Dialog( content = "기록이 저장되지 않아요!", leftButtonText = "취소", rightButtonText = "확인", - onLeftButtonClick = onClickExit, - onRightButtonClick = onDismissDialog, + onLeftButtonClick = onDismissDialog, + onRightButtonClick = onClickExit, onDismiss = onDismissDialog, ) } From 2c1a8c8a59b8e5aa0c9d810efd1f1d5376edcb89 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Thu, 3 Apr 2025 18:12:53 +0900 Subject: [PATCH 4/9] =?UTF-8?q?[TNT-272]=20refactor:=20TraineeSignUpViewMo?= =?UTF-8?q?del=20=EB=82=B4=20Context=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signup/TraineeSignUpCompletePage.kt | 14 ++++++++--- .../trainee/signup/TraineeSignUpContract.kt | 5 ++-- .../tnt/trainee/signup/TraineeSignUpScreen.kt | 24 +++++++++---------- .../trainee/signup/TraineeSignUpViewModel.kt | 12 +++------- 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpCompletePage.kt b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpCompletePage.kt index 7103c6d6..23791f1b 100644 --- a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpCompletePage.kt +++ b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpCompletePage.kt @@ -1,6 +1,5 @@ package co.kr.tnt.trainee.signup -import android.net.Uri import androidx.activity.compose.BackHandler import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -14,6 +13,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign.Companion.Center @@ -26,18 +26,26 @@ import co.kr.tnt.feature.trainee.signup.R import co.kr.tnt.trainee.signup.TraineeSignUpContract.TraineeSignUpUiState import co.kr.tnt.ui.component.TnTLoadingScreen import co.kr.tnt.ui.model.DefaultUserProfile +import co.kr.tnt.ui.utils.convertToAllowedImageFormat import co.kr.tnt.ui.utils.throttled import coil.compose.rememberAsyncImagePainter +import java.io.File import co.kr.tnt.core.ui.R as uiResource @Composable internal fun TraineeSignUpCompletePage( state: TraineeSignUpUiState, onBackClick: () -> Unit, - onNextClick: (Uri?) -> Unit, + onNextClick: (image: File?) -> Unit, ) { BackHandler { onBackClick() } + val context = LocalContext.current + val onClickComplete = { + val imageFile = state.image?.convertToAllowedImageFormat(context) + onNextClick(imageFile) + } + Scaffold( containerColor = TnTTheme.colors.commonColors.Common0, ) { innerPadding -> @@ -79,7 +87,7 @@ internal fun TraineeSignUpCompletePage( } TnTBottomButton( text = stringResource(uiResource.string.start), - onClick = throttled { onNextClick(state.image) }, + onClick = throttled { onClickComplete() }, modifier = Modifier.align(Alignment.BottomCenter), ) } diff --git a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpContract.kt b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpContract.kt index b89ee334..f504bde1 100644 --- a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpContract.kt +++ b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpContract.kt @@ -1,10 +1,10 @@ package co.kr.tnt.trainee.signup -import android.content.Context import android.net.Uri import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import java.io.File import java.time.LocalDate private const val MAX_NAME_LENGTH = 15 @@ -67,8 +67,7 @@ internal class TraineeSignUpContract { data object OnNextClick : TraineeSignUpUiEvent data object OnBackClick : TraineeSignUpUiEvent data class RequestSignUp( - val context: Context, - val imageUri: Uri?, + val imageFile: File?, val id: String, val email: String, val authType: String, diff --git a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpScreen.kt b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpScreen.kt index d13782cf..d3997dd0 100644 --- a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpScreen.kt +++ b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpScreen.kt @@ -4,7 +4,6 @@ import android.net.Uri import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.ui.platform.LocalContext import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import co.kr.tnt.designsystem.snackbar.LocalSnackbar @@ -12,6 +11,7 @@ import co.kr.tnt.trainee.signup.TraineeSignUpContract.TraineeSignUpEffect import co.kr.tnt.trainee.signup.TraineeSignUpContract.TraineeSignUpPage import co.kr.tnt.trainee.signup.TraineeSignUpContract.TraineeSignUpUiEvent import co.kr.tnt.trainee.signup.TraineeSignUpContract.TraineeSignUpUiState +import java.io.File import java.time.LocalDate @Composable @@ -24,7 +24,6 @@ internal fun TraineeSignUpRoute( navigateToConnect: () -> Unit, viewModel: TraineeSignUpViewModel = hiltViewModel(), ) { - val context = LocalContext.current val snackbar = LocalSnackbar.current val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -39,11 +38,10 @@ internal fun TraineeSignUpRoute( onCautionChange = { viewModel.setEvent(TraineeSignUpUiEvent.OnCautionChange(it)) }, onBackClick = { viewModel.setEvent(TraineeSignUpUiEvent.OnBackClick) }, onNextClick = { viewModel.setEvent(TraineeSignUpUiEvent.OnNextClick) }, - onSubmitSignUp = { uri -> + onSubmitSignUp = { file -> viewModel.setEvent( TraineeSignUpUiEvent.RequestSignUp( - context = context, - imageUri = uri, + imageFile = file, id = authId, email = email, authType = authType, @@ -67,14 +65,14 @@ internal fun TraineeSignUpRoute( @Composable private fun TraineeSignUpScreen( state: TraineeSignUpUiState, - onProfileImageSelect: (Uri) -> Unit, - onNameChange: (String) -> Unit, - onHeightChange: (String) -> Unit, - onWeightChange: (String) -> Unit, - onCautionChange: (String) -> Unit, - onBirthdayChange: (LocalDate) -> Unit, - onPurposeSelected: (String) -> Unit, - onSubmitSignUp: (Uri?) -> Unit, + onProfileImageSelect: (imageUri: Uri) -> Unit, + onNameChange: (name: String) -> Unit, + onHeightChange: (height: String) -> Unit, + onWeightChange: (weight: String) -> Unit, + onCautionChange: (caution: String) -> Unit, + onBirthdayChange: (birthday: LocalDate) -> Unit, + onPurposeSelected: (purpose: String) -> Unit, + onSubmitSignUp: (imageFile: File?) -> Unit, onNextClick: () -> Unit, onBackClick: () -> Unit, ) { diff --git a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpViewModel.kt b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpViewModel.kt index f3d75948..c663dca1 100644 --- a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpViewModel.kt +++ b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpViewModel.kt @@ -1,6 +1,5 @@ package co.kr.tnt.trainee.signup -import android.content.Context import android.net.Uri import androidx.lifecycle.viewModelScope import co.kr.tnt.domain.model.User @@ -10,7 +9,6 @@ import co.kr.tnt.trainee.signup.TraineeSignUpContract.TraineeSignUpPage import co.kr.tnt.trainee.signup.TraineeSignUpContract.TraineeSignUpUiEvent import co.kr.tnt.trainee.signup.TraineeSignUpContract.TraineeSignUpUiState import co.kr.tnt.ui.base.BaseViewModel -import co.kr.tnt.ui.utils.convertToAllowedImageFormat import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import java.io.File @@ -35,8 +33,7 @@ internal class TraineeSignUpViewModel @Inject constructor( TraineeSignUpUiEvent.OnBackClick -> navigateToBack() TraineeSignUpUiEvent.OnNextClick -> navigateToNext() is TraineeSignUpUiEvent.RequestSignUp -> signUp( - context = event.context, - imageUri = event.imageUri, + imageFile = event.imageFile, id = event.id, email = event.email, authType = event.authType, @@ -46,8 +43,7 @@ internal class TraineeSignUpViewModel @Inject constructor( } private fun signUp( - context: Context, - imageUri: Uri?, + imageFile: File?, id: String, email: String, authType: String, @@ -57,11 +53,9 @@ internal class TraineeSignUpViewModel @Inject constructor( updateState { copy(isLoading = true) } val state = currentState - val profileImageFile: File? = imageUri?.convertToAllowedImageFormat(context) - runCatching { signUpRepository.signUp( - profileImage = profileImageFile, + profileImage = imageFile, user = User.Trainee( id = id, name = state.name, From c84c3706ceb857bf5491f369fe9a78a79a719a5e Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Thu, 3 Apr 2025 18:28:31 +0900 Subject: [PATCH 5/9] =?UTF-8?q?[TNT-272]=20refactor:=20TrainerSignUpViewMo?= =?UTF-8?q?del=20=EB=82=B4=20Context=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trainer/signup/TrainerSignUpCompletePage.kt | 15 +++++++++++---- .../tnt/trainer/signup/TrainerSignUpContract.kt | 5 ++--- .../kr/tnt/trainer/signup/TrainerSignUpScreen.kt | 14 ++++++-------- .../tnt/trainer/signup/TrainerSignUpViewModel.kt | 11 +++-------- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt index 03ed2d0b..8a97c041 100644 --- a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt +++ b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt @@ -1,6 +1,5 @@ package co.kr.tnt.trainer.signup -import android.net.Uri import androidx.activity.compose.BackHandler import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -14,6 +13,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign.Companion.Center @@ -26,18 +26,26 @@ import co.kr.tnt.feature.trainer.signup.R import co.kr.tnt.trainer.signup.TrainerSignUpContract.TrainerSignUpUiState import co.kr.tnt.ui.component.TnTLoadingScreen import co.kr.tnt.ui.model.DefaultUserProfile +import co.kr.tnt.ui.utils.convertToAllowedImageFormat import co.kr.tnt.ui.utils.throttled import coil.compose.rememberAsyncImagePainter +import java.io.File import co.kr.tnt.core.ui.R as uiResource @Composable internal fun TrainerSignUpCompletePage( state: TrainerSignUpUiState, onBackClick: () -> Unit, - onNextClick: (Uri?) -> Unit, + onNextClick: (image: File?) -> Unit, ) { BackHandler { onBackClick() } + val context = LocalContext.current + val onClickComplete = { + val imageFile = state.image?.convertToAllowedImageFormat(context) + onNextClick(imageFile) + } + Scaffold( containerColor = TnTTheme.colors.commonColors.Common0, ) { innerPadding -> @@ -79,12 +87,11 @@ internal fun TrainerSignUpCompletePage( } TnTBottomButton( text = stringResource(uiResource.string.start), - onClick = throttled { onNextClick(state.image) }, + onClick = throttled { onClickComplete() }, modifier = Modifier.align(Alignment.BottomCenter), ) } } - if (state.isLoading) { TnTLoadingScreen() } diff --git a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpContract.kt b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpContract.kt index c5cc62fb..95896dcc 100644 --- a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpContract.kt +++ b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpContract.kt @@ -1,10 +1,10 @@ package co.kr.tnt.trainer.signup -import android.content.Context import android.net.Uri import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import java.io.File private const val MAX_LENGTH = 15 @@ -28,8 +28,7 @@ internal class TrainerSignUpContract { data object OnNextClick : TrainerSignUpUiEvent data object OnBackClick : TrainerSignUpUiEvent data class RequestSignUp( - val context: Context, - val imageUri: Uri?, + val imageFile: File?, val id: String, val email: String, val authType: String, diff --git a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpScreen.kt b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpScreen.kt index 949668bc..f59e4948 100644 --- a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpScreen.kt +++ b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpScreen.kt @@ -4,13 +4,13 @@ import android.net.Uri import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.ui.platform.LocalContext import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import co.kr.tnt.designsystem.snackbar.LocalSnackbar import co.kr.tnt.navigation.model.ScreenMode import co.kr.tnt.trainer.signup.TrainerSignUpContract.TrainerSignUpUiEvent import co.kr.tnt.trainer.signup.TrainerSignUpContract.TrainerSignUpUiState +import java.io.File @Composable internal fun TrainerSignUpRoute( @@ -22,7 +22,6 @@ internal fun TrainerSignUpRoute( navigateToInvite: (ScreenMode) -> Unit, viewModel: TrainerSignUpViewModel = hiltViewModel(), ) { - val context = LocalContext.current val snackbar = LocalSnackbar.current val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -32,11 +31,10 @@ internal fun TrainerSignUpRoute( onProfileImageSelect = { viewModel.setEvent(TrainerSignUpUiEvent.OnImageChange(it)) }, onNextClick = { viewModel.setEvent(TrainerSignUpUiEvent.OnNextClick) }, onBackClick = { viewModel.setEvent(TrainerSignUpUiEvent.OnBackClick) }, - onSubmitSignUp = { uri -> + onSubmitSignUp = { file -> viewModel.setEvent( TrainerSignUpUiEvent.RequestSignUp( - context = context, - imageUri = uri, + imageFile = file, id = authId, email = email, authType = authType, @@ -60,9 +58,9 @@ internal fun TrainerSignUpRoute( @Composable private fun TrainerSignUpScreen( state: TrainerSignUpUiState, - onProfileImageSelect: (Uri) -> Unit, - onNameChange: (String) -> Unit, - onSubmitSignUp: (Uri?) -> Unit, + onProfileImageSelect: (imageUri: Uri) -> Unit, + onNameChange: (name: String) -> Unit, + onSubmitSignUp: (imageFile: File?) -> Unit, onNextClick: () -> Unit, onBackClick: () -> Unit, ) { diff --git a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpViewModel.kt b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpViewModel.kt index da9b826c..a579fffb 100644 --- a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpViewModel.kt +++ b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpViewModel.kt @@ -1,6 +1,5 @@ package co.kr.tnt.trainer.signup -import android.content.Context import android.net.Uri import androidx.lifecycle.viewModelScope import co.kr.tnt.domain.model.User @@ -11,7 +10,6 @@ import co.kr.tnt.trainer.signup.TrainerSignUpContract.TrainerSignUpPage import co.kr.tnt.trainer.signup.TrainerSignUpContract.TrainerSignUpUiEvent import co.kr.tnt.trainer.signup.TrainerSignUpContract.TrainerSignUpUiState import co.kr.tnt.ui.base.BaseViewModel -import co.kr.tnt.ui.utils.convertToAllowedImageFormat import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -31,8 +29,7 @@ internal class TrainerSignUpViewModel @Inject constructor( TrainerSignUpUiEvent.OnNextClick -> navigateToNext() TrainerSignUpUiEvent.OnBackClick -> navigateToBack() is TrainerSignUpUiEvent.RequestSignUp -> signUp( - context = event.context, - imageUri = event.imageUri, + imageFile = event.imageFile, id = event.id, email = event.email, authType = event.authType, @@ -42,8 +39,7 @@ internal class TrainerSignUpViewModel @Inject constructor( } private fun signUp( - context: Context, - imageUri: Uri?, + imageFile: File?, id: String, email: String, authType: String, @@ -51,11 +47,10 @@ internal class TrainerSignUpViewModel @Inject constructor( ) { viewModelScope.launch(Dispatchers.IO) { updateState { copy(isLoading = true) } - val profileImageFile: File? = imageUri?.convertToAllowedImageFormat(context) runCatching { signUpRepository.signUp( - profileImage = profileImageFile, + profileImage = imageFile, user = User.Trainer( id = id, name = currentState.name, From 22b56f9d11a742ff69c0c64d78f411b8d886833f Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Thu, 3 Apr 2025 18:46:06 +0900 Subject: [PATCH 6/9] =?UTF-8?q?[TNT-272]=20refactor:=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=83=9D=EC=84=B1=20=EB=B9=84=EB=8F=99=EA=B8=B0=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signup/TraineeSignUpCompletePage.kt | 20 +++++++++++++++---- .../signup/TrainerSignUpCompletePage.kt | 20 +++++++++++++++---- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpCompletePage.kt b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpCompletePage.kt index 23791f1b..0274b94c 100644 --- a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpCompletePage.kt +++ b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeSignUpCompletePage.kt @@ -11,6 +11,9 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -29,6 +32,8 @@ import co.kr.tnt.ui.model.DefaultUserProfile import co.kr.tnt.ui.utils.convertToAllowedImageFormat import co.kr.tnt.ui.utils.throttled import coil.compose.rememberAsyncImagePainter +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import java.io.File import co.kr.tnt.core.ui.R as uiResource @@ -41,9 +46,16 @@ internal fun TraineeSignUpCompletePage( BackHandler { onBackClick() } val context = LocalContext.current - val onClickComplete = { - val imageFile = state.image?.convertToAllowedImageFormat(context) - onNextClick(imageFile) + val completeState = remember { mutableStateOf(false) } + + LaunchedEffect(completeState.value) { + if (completeState.value) { + val imageFile = withContext(Dispatchers.IO) { + state.image?.convertToAllowedImageFormat(context) + } + onNextClick(imageFile) + completeState.value = false + } } Scaffold( @@ -87,7 +99,7 @@ internal fun TraineeSignUpCompletePage( } TnTBottomButton( text = stringResource(uiResource.string.start), - onClick = throttled { onClickComplete() }, + onClick = throttled { completeState.value = true }, modifier = Modifier.align(Alignment.BottomCenter), ) } diff --git a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt index 8a97c041..9bd726bd 100644 --- a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt +++ b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt @@ -11,6 +11,9 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -29,6 +32,8 @@ import co.kr.tnt.ui.model.DefaultUserProfile import co.kr.tnt.ui.utils.convertToAllowedImageFormat import co.kr.tnt.ui.utils.throttled import coil.compose.rememberAsyncImagePainter +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import java.io.File import co.kr.tnt.core.ui.R as uiResource @@ -41,9 +46,16 @@ internal fun TrainerSignUpCompletePage( BackHandler { onBackClick() } val context = LocalContext.current - val onClickComplete = { - val imageFile = state.image?.convertToAllowedImageFormat(context) - onNextClick(imageFile) + val completeState = remember { mutableStateOf(false) } + + LaunchedEffect(completeState.value) { + if (completeState.value) { + val imageFile = withContext(Dispatchers.IO) { + state.image?.convertToAllowedImageFormat(context) + } + onNextClick(imageFile) + completeState.value = false + } } Scaffold( @@ -87,7 +99,7 @@ internal fun TrainerSignUpCompletePage( } TnTBottomButton( text = stringResource(uiResource.string.start), - onClick = throttled { onClickComplete() }, + onClick = throttled { completeState.value = true }, modifier = Modifier.align(Alignment.BottomCenter), ) } From d4bcf11d1afbe271dd77b990e3fe86882068c19e Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Thu, 3 Apr 2025 18:48:41 +0900 Subject: [PATCH 7/9] =?UTF-8?q?[TNT-272]=20refactor:=20=EC=8B=9D=EB=8B=A8?= =?UTF-8?q?=20=EA=B8=B0=EB=A1=9D=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=83=9D=EC=84=B1=20=EB=B9=84=EB=8F=99=EA=B8=B0=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt index 7f4a4f46..2fc3ecb2 100644 --- a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt +++ b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt @@ -117,12 +117,10 @@ internal fun TraineeMealRecordRoute( } LaunchedEffect(state.image) { - state.image?.let { uri -> - withContext(Dispatchers.IO) { - val file = uri.convertToAllowedImageFormat(context) - imageFile = file - } + val file = withContext(Dispatchers.IO) { + state.image?.convertToAllowedImageFormat(context) } + imageFile = file } TraineeMealRecordScreen( From e9762f887d5340f5a522ead5355a1b9daad02278 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Tue, 6 May 2025 14:39:28 +0900 Subject: [PATCH 8/9] =?UTF-8?q?[TNT-272]=20fix:=20completeState=20?= =?UTF-8?q?=EC=97=86=EC=9D=B4=20=EC=82=AC=EC=A7=84=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EB=B3=80=ED=99=98=20=ED=9B=84=20=EC=A0=84=EC=86=A1=ED=95=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 --- .../signup/TrainerSignUpCompletePage.kt | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt index 9bd726bd..a21859a3 100644 --- a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt +++ b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerSignUpCompletePage.kt @@ -11,9 +11,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -33,6 +31,7 @@ import co.kr.tnt.ui.utils.convertToAllowedImageFormat import co.kr.tnt.ui.utils.throttled import coil.compose.rememberAsyncImagePainter import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File import co.kr.tnt.core.ui.R as uiResource @@ -46,17 +45,7 @@ internal fun TrainerSignUpCompletePage( BackHandler { onBackClick() } val context = LocalContext.current - val completeState = remember { mutableStateOf(false) } - - LaunchedEffect(completeState.value) { - if (completeState.value) { - val imageFile = withContext(Dispatchers.IO) { - state.image?.convertToAllowedImageFormat(context) - } - onNextClick(imageFile) - completeState.value = false - } - } + val coroutineScope = rememberCoroutineScope() Scaffold( containerColor = TnTTheme.colors.commonColors.Common0, @@ -99,7 +88,14 @@ internal fun TrainerSignUpCompletePage( } TnTBottomButton( text = stringResource(uiResource.string.start), - onClick = throttled { completeState.value = true }, + onClick = throttled { + coroutineScope.launch { + val imageFile = withContext(Dispatchers.IO) { + state.image?.convertToAllowedImageFormat(context) + } + onNextClick(imageFile) + } + }, modifier = Modifier.align(Alignment.BottomCenter), ) } From 2b002b13e694473eede16ab1618098309d628782 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Tue, 6 May 2025 14:51:24 +0900 Subject: [PATCH 9/9] =?UTF-8?q?[TNT-272]=20fix:=20=EC=A0=80=EC=9E=A5=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=ED=81=B4=EB=A6=AD=20=EC=8B=9C,=20?= =?UTF-8?q?=ED=95=9C=20=EB=B2=88=EB=A7=8C=20=EC=82=AC=EC=A7=84=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=B3=80=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mealrecord/TraineeMealRecordScreen.kt | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt index 2fc3ecb2..e59060e4 100644 --- a/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt +++ b/feature/trainee/mealrecord/src/main/java/co/kr/tnt/trainee/mealrecord/TraineeMealRecordScreen.kt @@ -85,7 +85,6 @@ import com.kizitonwose.calendar.compose.rememberCalendarState import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import java.io.File import java.time.DayOfWeek import java.time.LocalDate import java.time.LocalTime @@ -102,10 +101,10 @@ internal fun TraineeMealRecordRoute( val context = LocalContext.current val snackbar = LocalSnackbar.current + val coroutineScope = rememberCoroutineScope() val state by viewModel.uiState.collectAsStateWithLifecycle() val dateFormatter = remember { DateFormatter() } - var imageFile by rememberSaveable { mutableStateOf(null) } var showBottomSheet by rememberSaveable { mutableStateOf(false) } LaunchedEffect(selectedDate) { @@ -116,13 +115,6 @@ internal fun TraineeMealRecordRoute( ) } - LaunchedEffect(state.image) { - val file = withContext(Dispatchers.IO) { - state.image?.convertToAllowedImageFormat(context) - } - imageFile = file - } - TraineeMealRecordScreen( state = state, context = context, @@ -147,7 +139,14 @@ internal fun TraineeMealRecordRoute( onClickBack = { viewModel.setEvent(TraineeMealRecordUiEvent.OnClickBack) }, - onClickSaveButton = { viewModel.setEvent(TraineeMealRecordUiEvent.OnClickSave(imageFile)) }, + onClickSaveButton = { + coroutineScope.launch { + val imageFile = withContext(Dispatchers.IO) { + state.image?.convertToAllowedImageFormat(context) + } + viewModel.setEvent(TraineeMealRecordUiEvent.OnClickSave(imageFile)) + } + }, ) if (showBottomSheet) {