diff --git a/core/ui/src/main/java/co/kr/tnt/ui/model/RecordChip.kt b/core/ui/src/main/java/co/kr/tnt/ui/model/RecordChip.kt index c231018d..f667a5b7 100644 --- a/core/ui/src/main/java/co/kr/tnt/ui/model/RecordChip.kt +++ b/core/ui/src/main/java/co/kr/tnt/ui/model/RecordChip.kt @@ -2,7 +2,16 @@ package co.kr.tnt.ui.model import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource -import co.kr.tnt.core.ui.R +import co.kr.tnt.core.ui.R.string.core_exercise_back +import co.kr.tnt.core.ui.R.string.core_exercise_cardio +import co.kr.tnt.core.ui.R.string.core_exercise_lower_body +import co.kr.tnt.core.ui.R.string.core_exercise_shoulder +import co.kr.tnt.core.ui.R.string.core_exercise_upper_body +import co.kr.tnt.core.ui.R.string.core_meal_breakfast +import co.kr.tnt.core.ui.R.string.core_meal_dinner +import co.kr.tnt.core.ui.R.string.core_meal_lunch +import co.kr.tnt.core.ui.R.string.core_meal_snack +import co.kr.tnt.core.ui.R.string.core_pt_session import co.kr.tnt.designsystem.component.chip.model.ChipStyle import co.kr.tnt.domain.model.RecordType @@ -34,10 +43,10 @@ sealed interface RecordChip { return when (type) { is RecordType.MealType -> { val title = when (type) { - RecordType.MealType.BREAKFAST -> stringResource(R.string.meal_breakfast) - RecordType.MealType.LUNCH -> stringResource(R.string.meal_lunch) - RecordType.MealType.DINNER -> stringResource(R.string.meal_dinner) - RecordType.MealType.SNACK -> stringResource(R.string.meal_snack) + RecordType.MealType.BREAKFAST -> stringResource(core_meal_breakfast) + RecordType.MealType.LUNCH -> stringResource(core_meal_lunch) + RecordType.MealType.DINNER -> stringResource(core_meal_dinner) + RecordType.MealType.SNACK -> stringResource(core_meal_snack) } val emoji = when (type) { RecordType.MealType.BREAKFAST -> "🌞" @@ -50,11 +59,11 @@ sealed interface RecordChip { is RecordType.ExerciseType -> { val title = when (type) { - RecordType.ExerciseType.UPPER_BODY -> stringResource(R.string.exercise_upper_body) - RecordType.ExerciseType.LOWER_BODY -> stringResource(R.string.exercise_lower_body) - RecordType.ExerciseType.BACK -> stringResource(R.string.exercise_back) - RecordType.ExerciseType.SHOULDER -> stringResource(R.string.exercise_shoulder) - RecordType.ExerciseType.CARDIO -> stringResource(R.string.exercise_cardio) + RecordType.ExerciseType.UPPER_BODY -> stringResource(core_exercise_upper_body) + RecordType.ExerciseType.LOWER_BODY -> stringResource(core_exercise_lower_body) + RecordType.ExerciseType.BACK -> stringResource(core_exercise_back) + RecordType.ExerciseType.SHOULDER -> stringResource(core_exercise_shoulder) + RecordType.ExerciseType.CARDIO -> stringResource(core_exercise_cardio) } ExerciseChip( title = title, @@ -63,7 +72,7 @@ sealed interface RecordChip { } is RecordType.PTSessionType -> { - val title = stringResource(R.string.pt_session, type.sessionCount) + val title = stringResource(core_pt_session, type.sessionCount) val emoji = "πŸ’ͺ" PTSessionChip(title, type.sessionCount, emoji, ChipStyle.BLUE) } diff --git a/core/ui/src/main/java/co/kr/tnt/ui/permission/PermissionRequestDialog.kt b/core/ui/src/main/java/co/kr/tnt/ui/permission/PermissionRequestDialog.kt index da050d3a..146e3863 100644 --- a/core/ui/src/main/java/co/kr/tnt/ui/permission/PermissionRequestDialog.kt +++ b/core/ui/src/main/java/co/kr/tnt/ui/permission/PermissionRequestDialog.kt @@ -4,7 +4,9 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview -import co.kr.tnt.core.ui.R +import co.kr.tnt.core.ui.R.string.core_close +import co.kr.tnt.core.ui.R.string.core_move_to_setting +import co.kr.tnt.core.ui.R.string.core_ok import co.kr.tnt.designsystem.component.TnTPopupDialog import co.kr.tnt.designsystem.theme.TnTTheme @@ -32,12 +34,12 @@ fun PermissionRequestDialog( permission.description }, ), - leftButtonText = stringResource(R.string.close), + leftButtonText = stringResource(core_close), rightButtonText = stringResource( if (isPermanentlyDenied) { - R.string.move_to_setting + core_move_to_setting } else { - R.string.ok + core_ok }, ), onLeftButtonClick = onDismiss, diff --git a/core/ui/src/main/java/co/kr/tnt/ui/permission/TnTPermission.kt b/core/ui/src/main/java/co/kr/tnt/ui/permission/TnTPermission.kt index 3c929e50..32ff0f27 100644 --- a/core/ui/src/main/java/co/kr/tnt/ui/permission/TnTPermission.kt +++ b/core/ui/src/main/java/co/kr/tnt/ui/permission/TnTPermission.kt @@ -3,7 +3,10 @@ package co.kr.tnt.ui.permission import android.Manifest.permission.POST_NOTIFICATIONS import android.os.Build import androidx.annotation.StringRes -import co.kr.tnt.core.ui.R +import co.kr.tnt.core.ui.R.string.core_alarm_permission_description +import co.kr.tnt.core.ui.R.string.core_alarm_permission_permanently_description +import co.kr.tnt.core.ui.R.string.core_alarm_permission_permanently_title +import co.kr.tnt.core.ui.R.string.core_alarm_permission_title import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.MultiplePermissionsState @@ -20,10 +23,10 @@ enum class TnTPermission( } else { emptyList() }, - title = R.string.alarm_permission_title, - description = R.string.alarm_permission_description, - permanentlyDeniedTitle = R.string.alarm_permission_permanently_title, - permanentlyDeniedDescription = R.string.alarm_permission_permanently_description, + title = core_alarm_permission_title, + description = core_alarm_permission_description, + permanentlyDeniedTitle = core_alarm_permission_permanently_title, + permanentlyDeniedDescription = core_alarm_permission_permanently_description, ), ; diff --git a/core/ui/src/main/java/co/kr/tnt/ui/resource/DisplayText.kt b/core/ui/src/main/java/co/kr/tnt/ui/resource/DisplayText.kt new file mode 100644 index 00000000..0241b0d4 --- /dev/null +++ b/core/ui/src/main/java/co/kr/tnt/ui/resource/DisplayText.kt @@ -0,0 +1,36 @@ +package co.kr.tnt.ui.resource + +import android.content.Context +import androidx.annotation.StringRes +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource + +sealed interface DisplayText { + fun asString(context: Context): String + + @JvmInline + value class Plain( + val value: String, + ) : DisplayText { + override fun asString(context: Context): String = value + } + + class Resource( + @StringRes val resId: Int, + vararg val args: Any, + ) : DisplayText { + override fun asString(context: Context): String = context.getString(resId, *args) + } + + @Composable + fun asString(): String { + return when (this) { + is Plain -> value + is Resource -> stringResource(resId, *args) + } + } + + companion object { + val EMPTY = Plain("") + } +} diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index cfea4e00..b2da9602 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -1,78 +1,84 @@ - μ„Έμ…˜μ΄ λ§Œλ£Œλ˜μ—ˆμ–΄μš” - μž₯μ‹œκ°„ λ―Έμ‚¬μš©μœΌλ‘œ 둜그인 ν™”λ©΄μœΌλ‘œ μ΄λ™ν•΄μš” + μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš” + + μ„Έμ…˜μ΄ λ§Œλ£Œλ˜μ—ˆμ–΄μš” + μž₯μ‹œκ°„ λ―Έμ‚¬μš©μœΌλ‘œ 둜그인 ν™”λ©΄μœΌλ‘œ μ΄λ™ν•΄μš” - TnTμ—μ„œ μ•Œλ¦Όμ„ λ³΄λ‚΄κ³ μž ν•©λ‹ˆλ‹€. - ν•΄λ‹Ή 기기둜 μˆ˜μ—… 일정 λ“± μ„œλΉ„μŠ€ μ΄μš©μ— 도움이 λ˜λŠ” μ•ˆλ‚΄ 사항을 ν‘Έμ‹œ μ•Œλ¦ΌμœΌλ‘œ λ³΄λ‚΄λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€. + TnTμ—μ„œ μ•Œλ¦Όμ„ λ³΄λ‚΄κ³ μž ν•©λ‹ˆλ‹€. + ν•΄λ‹Ή 기기둜 μˆ˜μ—… 일정 λ“± μ„œλΉ„μŠ€ μ΄μš©μ— 도움이 λ˜λŠ” μ•ˆλ‚΄ 사항을 ν‘Έμ‹œ μ•Œλ¦ΌμœΌλ‘œ λ³΄λ‚΄λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€. \nμ•± ν‘Έμ‹œ μ•Œλ¦Όμ— μˆ˜μ‹  λ™μ˜ ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ? - TnTμ—μ„œ μ•Œλ¦Ό κΆŒν•œμ΄ ν•„μš”ν•©λ‹ˆλ‹€. - μˆ˜μ—… 일정 및 μ€‘μš”ν•œ 곡지 μ•Œλ¦Όμ„ λ°›κΈ° μœ„ν•΄ μ•Œλ¦Ό κΆŒν•œμ΄ ν•„μš”ν•©λ‹ˆλ‹€.\nμ„€μ •μ—μ„œ μ•Œλ¦Ό κΆŒν•œμ„ ν™œμ„±ν™”ν•΄μ£Όμ„Έμš”. + TnTμ—μ„œ μ•Œλ¦Ό κΆŒν•œμ΄ ν•„μš”ν•©λ‹ˆλ‹€. + μˆ˜μ—… 일정 및 μ€‘μš”ν•œ 곡지 μ•Œλ¦Όμ„ λ°›κΈ° μœ„ν•΄ μ•Œλ¦Ό κΆŒν•œμ΄ ν•„μš”ν•©λ‹ˆλ‹€.\nμ„€μ •μ—μ„œ μ•Œλ¦Ό κΆŒν•œμ„ ν™œμ„±ν™”ν•΄μ£Όμ„Έμš”. + + ν”„λ‘œν•„ 사진 섀정을 μœ„ν•΄ 사진 μ ‘κ·Ό κΆŒν•œμ΄ ν•„μš”ν•΄μš” + 사진 μΆ”κ°€λŠ” ν”„λ‘œν•„ 말고도 μš΄λ™κ³Ό 식단 기둝에도 μ‚¬μš©λΌμš” - ν”„λ‘œν•„ 사진 섀정을 μœ„ν•΄ 사진 μ ‘κ·Ό κΆŒν•œμ΄ ν•„μš”ν•΄μš” - 사진 μΆ”κ°€λŠ” ν”„λ‘œν•„ 말고도 μš΄λ™κ³Ό 식단 기둝에도 μ‚¬μš©λΌμš” + ν”„λ‘œν•„ 사진 μ„€μ • κΆŒν•œ λͺ…μ‹œ κ±°λΆ€ + κΆŒν•œ 섀정을 μœ„ν•΄ μ„€μ •μ°½μœΌλ‘œ μ΄λ™ν•΄μ£Όμ„Έμš”. - ν”„λ‘œν•„ 사진 μ„€μ • κΆŒν•œ λͺ…μ‹œ κ±°λΆ€ - κΆŒν•œ 섀정을 μœ„ν•΄ μ„€μ •μ°½μœΌλ‘œ μ΄λ™ν•΄μ£Όμ„Έμš”. - λ‹«κΈ° - 확인 - μ„€μ •μœΌλ‘œ 이동 + λ‹«κΈ° + 확인 + μ„€μ •μœΌλ‘œ 이동 - 잘λͺ»λœ 수치λ₯Ό μž…λ ₯ν–ˆμ–΄μš” - %s자 미만의 ν•œκΈ€ λ˜λŠ” 영문으둜 μž…λ ₯ν•΄μ£Όμ„Έμš” + 잘λͺ»λœ 수치λ₯Ό μž…λ ₯ν–ˆμ–΄μš” + %s자 미만의 ν•œκΈ€ λ˜λŠ” 영문으둜 μž…λ ₯ν•΄μ£Όμ„Έμš” - νŠΈλ ˆμ΄λ‹ˆ - νŠΈλ ˆμ΄λ„ˆ + νŠΈλ ˆμ΄λ‹ˆ + νŠΈλ ˆμ΄λ„ˆ - λ‹€μŒ - μ—°κ²°ν•˜κΈ° - μ‹œμž‘ν•˜κΈ° - κ±΄λ„ˆλ›°κΈ° - μ·¨μ†Œ - λ‹€μŒμ— + λ‹€μŒ + μ—°κ²°ν•˜κΈ° + μ‹œμž‘ν•˜κΈ° + κ±΄λ„ˆλ›°κΈ° + μ·¨μ†Œ + λ‹€μŒμ— - 이름 - λ‚˜μ΄ - ν‚€ - 체쀑 - μ„Έ - cm - kg + 이름 + λ‚˜μ΄ + ν‚€ + 체쀑 + μ„Έ + cm + kg - μ•Œλ¦Ό - 졜근 받은 μ•Œλ¦Όμ΄ μ—†μ–΄μš” + μ•Œλ¦Ό + 졜근 받은 μ•Œλ¦Όμ΄ μ—†μ–΄μš” - 3일 λ™μ•ˆ 보지 μ•ŠκΈ° + 3일 λ™μ•ˆ 보지 μ•ŠκΈ° - μ•„μΉ¨ - 점심 - 저녁 - 간식 + μ•„μΉ¨ + 점심 + 저녁 + 간식 - 상체 μš΄λ™ - ν•˜μ²΄ μš΄λ™ - λ“± μš΄λ™ - μ–΄κΉ¨ μš΄λ™ - μœ μ‚°μ†Œ + 상체 μš΄λ™ + ν•˜μ²΄ μš΄λ™ + λ“± μš΄λ™ + μ–΄κΉ¨ μš΄λ™ + μœ μ‚°μ†Œ - %d회차 μˆ˜μ—… + %d회차 μˆ˜μ—… - κ°œμΈμ •λ³΄ μˆ˜μ • - μ•± ν‘Έμ‹œ μ•Œλ¦Ό - μ„œλΉ„μŠ€ μ΄μš©μ•½κ΄€ - κ°œμΈμ •λ³΄ 처리방침 - 버전 정보 - μ˜€ν”ˆμ†ŒμŠ€ λΌμ΄μ„ μŠ€ - λ‘œκ·Έμ•„μ›ƒ - 계정 νƒˆν‡΄ - - ν˜„μž¬ 계정을 λ‘œκ·Έμ•„μ›ƒ ν• κΉŒμš”? - μ–Έμ œλ“ μ§€ λ‹€μ‹œ 둜그인 ν•  수 μžˆμ–΄μš”! - λ‘œκ·Έμ•„μ›ƒμ΄ μ™„λ£Œλ˜μ—ˆμ–΄μš” + κ°œμΈμ •λ³΄ μˆ˜μ • + μ•± ν‘Έμ‹œ μ•Œλ¦Ό + μ„œλΉ„μŠ€ μ΄μš©μ•½κ΄€ + κ°œμΈμ •λ³΄ 처리방침 + 버전 정보 + μ˜€ν”ˆμ†ŒμŠ€ λΌμ΄μ„ μŠ€ + λ‘œκ·Έμ•„μ›ƒ + 계정 νƒˆν‡΄ + + ν˜„μž¬ 계정을 λ‘œκ·Έμ•„μ›ƒ ν• κΉŒμš”? + μ–Έμ œλ“ μ§€ λ‹€μ‹œ 둜그인 ν•  수 μžˆμ–΄μš”! + λ‘œκ·Έμ•„μ›ƒμ΄ μ™„λ£Œλ˜μ—ˆμ–΄μš” + + %d자 미만으둜 μž…λ ₯ν•΄μ£Όμ„Έμš”. + 아직 λ“±λ‘λœ 기둝이 μ—†μ–΄μš” diff --git a/feature/login/src/main/java/co/kr/tnt/login/LoginContract.kt b/feature/login/src/main/java/co/kr/tnt/login/LoginContract.kt index 2bad615e..39e6559a 100644 --- a/feature/login/src/main/java/co/kr/tnt/login/LoginContract.kt +++ b/feature/login/src/main/java/co/kr/tnt/login/LoginContract.kt @@ -8,6 +8,7 @@ import co.kr.tnt.login.model.TermState import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.resource.DisplayText internal class LoginContract { data class LoginUiState( @@ -34,7 +35,7 @@ internal class LoginContract { sealed interface LoginSideEffect : UiSideEffect { data object ShowTermBottomSheet : LoginSideEffect - data class ShowToast(val message: String) : LoginSideEffect + data class ShowToast(val message: DisplayText) : LoginSideEffect data class NavigateToWebView(val url: String) : LoginSideEffect data class NavigateToHome(val userType: UserType) : LoginSideEffect data class NavigateToSignup( diff --git a/feature/login/src/main/java/co/kr/tnt/login/LoginScreen.kt b/feature/login/src/main/java/co/kr/tnt/login/LoginScreen.kt index f56cfacf..e4377a88 100644 --- a/feature/login/src/main/java/co/kr/tnt/login/LoginScreen.kt +++ b/feature/login/src/main/java/co/kr/tnt/login/LoginScreen.kt @@ -42,6 +42,7 @@ 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 co.kr.tnt.core.ui.R.string.core_next import co.kr.tnt.designsystem.component.TnTDivider import co.kr.tnt.designsystem.component.TnTModalBottomSheet import co.kr.tnt.designsystem.component.button.TnTBottomButton @@ -126,7 +127,7 @@ internal fun LoginRoute( showBottomSheet = true } - is LoginSideEffect.ShowToast -> snackbar.show(effect.message) + is LoginSideEffect.ShowToast -> snackbar.show(effect.message.asString(context)) is LoginSideEffect.NavigateToWebView -> { navigateToWebView(effect.url) @@ -289,7 +290,7 @@ private fun TermBottomSheetContent( } Spacer(modifier = Modifier.height(94.dp)) TnTBottomButton( - text = stringResource(R.string.next), + text = stringResource(core_next), enabled = isAllTermChecked, onClick = onClickNext, ) diff --git a/feature/login/src/main/java/co/kr/tnt/login/LoginViewModel.kt b/feature/login/src/main/java/co/kr/tnt/login/LoginViewModel.kt index 2729bace..e2cc7ea9 100644 --- a/feature/login/src/main/java/co/kr/tnt/login/LoginViewModel.kt +++ b/feature/login/src/main/java/co/kr/tnt/login/LoginViewModel.kt @@ -1,14 +1,17 @@ package co.kr.tnt.login import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.model.AuthType import co.kr.tnt.domain.model.LoginResult import co.kr.tnt.domain.repository.LoginRepository +import co.kr.tnt.feature.login.R import co.kr.tnt.login.LoginContract.LoginSideEffect import co.kr.tnt.login.LoginContract.LoginUiEvent import co.kr.tnt.login.LoginContract.LoginUiState import co.kr.tnt.login.model.TermState import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @@ -28,7 +31,11 @@ internal class LoginViewModel @Inject constructor( is LoginUiEvent.OnAuthFail -> { if (event.throwable !is LoginException.CancelException) { - sendEffect(LoginSideEffect.ShowToast("λ‘œκ·ΈμΈμ— μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€. λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”.")) + sendEffect( + LoginSideEffect.ShowToast( + DisplayText.Resource(R.string.failed_login_try_again), + ), + ) } } @@ -67,8 +74,11 @@ internal class LoginViewModel @Inject constructor( clearAllChecks() sendEffect(LoginSideEffect.ShowTermBottomSheet) }.onFailure { - // TODO resource - sendEffect(LoginSideEffect.ShowToast("μ•Œ 수 μ—†λŠ” 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”.")) + sendEffect( + LoginSideEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } } } @@ -106,7 +116,11 @@ internal class LoginViewModel @Inject constructor( sendEffect(LoginSideEffect.NavigateToSignup(loginResult, messagingToken)) this@LoginViewModel.loginResult = null } ?: run { - sendEffect(LoginSideEffect.ShowToast("λ‘œκ·ΈμΈμ— μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€. λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”.")) + sendEffect( + LoginSideEffect.ShowToast( + DisplayText.Resource(R.string.failed_login_try_again), + ), + ) } } } diff --git a/feature/login/src/main/java/co/kr/tnt/login/model/TermState.kt b/feature/login/src/main/java/co/kr/tnt/login/model/TermState.kt index 839b9bfd..cf6240fa 100644 --- a/feature/login/src/main/java/co/kr/tnt/login/model/TermState.kt +++ b/feature/login/src/main/java/co/kr/tnt/login/model/TermState.kt @@ -1,9 +1,10 @@ package co.kr.tnt.login.model import androidx.annotation.StringRes +import co.kr.tnt.core.ui.R.string.core_privacy_policy +import co.kr.tnt.core.ui.R.string.core_terms_of_service import co.kr.tnt.domain.model.Term import co.kr.tnt.domain.utils.AppUrls -import co.kr.tnt.feature.login.R sealed class TermState( @StringRes val titleRes: Int, @@ -14,14 +15,14 @@ sealed class TermState( data class TermsOfServiceState( override val isRequired: Boolean, ) : TermState( - titleRes = R.string.terms_of_service, + titleRes = core_terms_of_service, link = AppUrls.TERMS_OF_SERVICE_URL, ) data class PrivacyPolicyState( override val isRequired: Boolean, ) : TermState( - titleRes = R.string.privacy_policy, + titleRes = core_privacy_policy, link = AppUrls.PRIVACY_POLICY_URL, ) diff --git a/feature/login/src/main/res/values/strings.xml b/feature/login/src/main/res/values/strings.xml index fe340b11..e73a7731 100644 --- a/feature/login/src/main/res/values/strings.xml +++ b/feature/login/src/main/res/values/strings.xml @@ -4,8 +4,6 @@ νŠΈλ ˆμ΄λ„ˆμ™€ νŠΈλ ˆμ΄λ‹ˆ\nμΌ€λ―Έ ν„°νŠΈλ¦¬κΈ° 카카였둜 κ³„μ†ν•˜κΈ° - μ„œλΉ„μŠ€ μ΄μš©μ•½κ΄€ - κ°œμΈμ •λ³΄ 처리방침 λ™μ˜ ν•„μˆ˜ 선택 @@ -13,6 +11,7 @@ μ—¬λŸ¬λΆ„μ˜ κ°œμΈμ •λ³΄μ™€ μ„œλΉ„μŠ€ 이용 ꢌ리\n잘 μ§€μΌœλ“œλ¦΄κ²Œμš” λͺ¨λ‘ λ™μ˜ μ„œλΉ„μŠ€ μ΄μš©μ„ μœ„ν•΄ μ•„λž˜ 약관에 λͺ¨λ‘ λ™μ˜ν•©λ‹ˆλ‹€. - λ‹€μŒ 보기 + + λ‘œκ·ΈμΈμ— μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€. λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”. diff --git a/feature/main/src/main/java/co/kr/tnt/main/MainActivity.kt b/feature/main/src/main/java/co/kr/tnt/main/MainActivity.kt index 143383da..7f2e481b 100644 --- a/feature/main/src/main/java/co/kr/tnt/main/MainActivity.kt +++ b/feature/main/src/main/java/co/kr/tnt/main/MainActivity.kt @@ -63,7 +63,11 @@ class MainActivity : ComponentActivity() { viewModel.effect.collect { effect -> when (effect) { is MainContract.MainSideEffect.ShowToast -> { - Toast.makeText(this@MainActivity, effect.message, Toast.LENGTH_SHORT).show() + Toast.makeText( + this@MainActivity, + effect.message.asString(this@MainActivity), + Toast.LENGTH_SHORT, + ).show() } } } diff --git a/feature/main/src/main/java/co/kr/tnt/main/MainContract.kt b/feature/main/src/main/java/co/kr/tnt/main/MainContract.kt index 878d165e..6cd7bccc 100644 --- a/feature/main/src/main/java/co/kr/tnt/main/MainContract.kt +++ b/feature/main/src/main/java/co/kr/tnt/main/MainContract.kt @@ -4,6 +4,7 @@ import co.kr.tnt.navigation.Route import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.resource.DisplayText internal class MainContract { data class MainUiState( @@ -19,6 +20,6 @@ internal class MainContract { } sealed interface MainSideEffect : UiSideEffect { - data class ShowToast(val message: String) : MainSideEffect + data class ShowToast(val message: DisplayText) : MainSideEffect } } diff --git a/feature/main/src/main/java/co/kr/tnt/main/MainViewModel.kt b/feature/main/src/main/java/co/kr/tnt/main/MainViewModel.kt index 65aa528b..c409e7ab 100644 --- a/feature/main/src/main/java/co/kr/tnt/main/MainViewModel.kt +++ b/feature/main/src/main/java/co/kr/tnt/main/MainViewModel.kt @@ -4,11 +4,13 @@ import androidx.lifecycle.viewModelScope import co.kr.tnt.domain.model.UserType import co.kr.tnt.domain.repository.LoginRepository import co.kr.tnt.domain.repository.SettingRepository +import co.kr.tnt.feature.main.R import co.kr.tnt.main.MainContract.MainSideEffect import co.kr.tnt.main.MainContract.MainUiEvent import co.kr.tnt.main.MainContract.MainUiState import co.kr.tnt.navigation.Route import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @@ -38,7 +40,11 @@ internal class MainViewModel @Inject constructor( // TODO API λ³€κ²½ μ‹œ 제거 μ˜ˆμ • μ½”λ“œ MainUiEvent.OnGetMessagingTokenFailed -> { - sendEffect(MainSideEffect.ShowToast("λ„€νŠΈμ›Œν¬ ν™˜κ²½μ„ ν™•μΈν•˜μ‹  ν›„ 앱을 μž¬μ‹€ν–‰ν•΄μ£Όμ„Έμš”.")) + sendEffect( + MainSideEffect.ShowToast( + DisplayText.Resource(R.string.network_error_check_environment), + ), + ) } } } diff --git a/feature/main/src/main/java/co/kr/tnt/main/ui/TnTApp.kt b/feature/main/src/main/java/co/kr/tnt/main/ui/TnTApp.kt index ac71c19a..8504d620 100644 --- a/feature/main/src/main/java/co/kr/tnt/main/ui/TnTApp.kt +++ b/feature/main/src/main/java/co/kr/tnt/main/ui/TnTApp.kt @@ -5,13 +5,15 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import co.kr.tnt.core.designsystem.R +import co.kr.tnt.core.ui.R.string.core_ok +import co.kr.tnt.core.ui.R.string.core_session_expired +import co.kr.tnt.core.ui.R.string.core_session_expired_description import co.kr.tnt.designsystem.component.TnTIconSingleButtonPopupDialog import co.kr.tnt.designsystem.component.button.model.ButtonType import co.kr.tnt.designsystem.snackbar.LocalSnackbar import co.kr.tnt.designsystem.snackbar.TnTSnackbarLayout import co.kr.tnt.designsystem.snackbar.rememberSnackbarState import co.kr.tnt.login.navigation.navigateToLogin -import co.kr.tnt.core.ui.R as coreR @Composable fun TnTApp( @@ -21,10 +23,10 @@ fun TnTApp( if (appState.showSessionExpiredDialog) { TnTIconSingleButtonPopupDialog( - title = stringResource(coreR.string.session_expired), - content = stringResource(coreR.string.session_expired_description), + title = stringResource(core_session_expired), + content = stringResource(core_session_expired_description), topIcon = painterResource(R.drawable.ic_round_warning), - buttonText = stringResource(coreR.string.ok), + buttonText = stringResource(core_ok), cancelable = false, onButtonClick = { appState.dismissSessionDialog() diff --git a/feature/main/src/main/res/values/strings.xml b/feature/main/src/main/res/values/strings.xml new file mode 100644 index 00000000..997040e1 --- /dev/null +++ b/feature/main/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + "λ„€νŠΈμ›Œν¬ ν™˜κ²½μ„ ν™•μΈν•˜μ‹  ν›„ 앱을 μž¬μ‹€ν–‰ν•΄μ£Όμ„Έμš”." + diff --git a/feature/roleselect/src/main/java/co/kr/tnt/roleselect/RoleSelectionScreen.kt b/feature/roleselect/src/main/java/co/kr/tnt/roleselect/RoleSelectionScreen.kt index 6bf42c65..ba6cbb48 100644 --- a/feature/roleselect/src/main/java/co/kr/tnt/roleselect/RoleSelectionScreen.kt +++ b/feature/roleselect/src/main/java/co/kr/tnt/roleselect/RoleSelectionScreen.kt @@ -26,6 +26,7 @@ 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 co.kr.tnt.core.ui.R.string.core_next import co.kr.tnt.designsystem.component.button.TnTBottomButton import co.kr.tnt.designsystem.component.button.TnTTextButton import co.kr.tnt.designsystem.component.button.model.ButtonSize @@ -36,7 +37,6 @@ import co.kr.tnt.feature.roleselect.R import co.kr.tnt.roleselect.RoleSelectionContract.RoleSelectionEffect import co.kr.tnt.roleselect.RoleSelectionContract.RoleSelectionUiEvent import co.kr.tnt.roleselect.model.RoleState -import co.kr.tnt.core.ui.R as uiResource @Composable internal fun RoleSelectionRoute( @@ -67,7 +67,7 @@ fun RoleSelectionScreen( Scaffold( bottomBar = { TnTBottomButton( - text = stringResource(uiResource.string.next), + text = stringResource(core_next), enabled = true, onClick = { onClickNext(selectedRole) }, modifier = Modifier.navigationBarsPadding(), diff --git a/feature/roleselect/src/main/java/co/kr/tnt/roleselect/model/RoleState.kt b/feature/roleselect/src/main/java/co/kr/tnt/roleselect/model/RoleState.kt index 7ff90ab4..f15e77be 100644 --- a/feature/roleselect/src/main/java/co/kr/tnt/roleselect/model/RoleState.kt +++ b/feature/roleselect/src/main/java/co/kr/tnt/roleselect/model/RoleState.kt @@ -2,21 +2,22 @@ package co.kr.tnt.roleselect.model import androidx.annotation.DrawableRes import androidx.annotation.StringRes +import co.kr.tnt.core.ui.R.string.core_trainee +import co.kr.tnt.core.ui.R.string.core_trainer import co.kr.tnt.domain.model.UserType import co.kr.tnt.feature.roleselect.R -import co.kr.tnt.core.ui.R as uiResource sealed class RoleState( @StringRes val textResId: Int, @DrawableRes val imageResId: Int, ) { data object Trainer : RoleState( - textResId = uiResource.string.trainer, + textResId = core_trainer, imageResId = R.drawable.img_select_role_trainer, ) data object Trainee : RoleState( - textResId = uiResource.string.trainee, + textResId = core_trainee, imageResId = R.drawable.img_select_role_trainee, ) diff --git a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/CodeEntryPage.kt b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/CodeEntryPage.kt index 4d53d829..23342d38 100644 --- a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/CodeEntryPage.kt +++ b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/CodeEntryPage.kt @@ -18,6 +18,11 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import co.kr.tnt.core.ui.R.string.core_cancel +import co.kr.tnt.core.ui.R.string.core_connect +import co.kr.tnt.core.ui.R.string.core_next +import co.kr.tnt.core.ui.R.string.core_ok +import co.kr.tnt.core.ui.R.string.core_skip import co.kr.tnt.designsystem.component.TnTIconPopupDialog import co.kr.tnt.designsystem.component.TnTTopBar import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton @@ -31,7 +36,6 @@ import co.kr.tnt.trainee.connect.component.CodeTextField import co.kr.tnt.trainee.connect.model.InputState import co.kr.tnt.ui.extensions.clearFocusOnTap import co.kr.tnt.core.designsystem.R as uiResource -import co.kr.tnt.core.ui.R as coreR @Composable internal fun CodeEntryPage( @@ -60,16 +64,16 @@ internal fun CodeEntryPage( when (screenMode) { ScreenMode.BACK -> { TnTTopBarWithBackButton( - title = stringResource(coreR.string.connect), + title = stringResource(core_connect), onBackClick = onClickBack, ) } ScreenMode.SKIP -> { TnTTopBar( - title = stringResource(coreR.string.connect), + title = stringResource(core_connect), trailingComponent = { Text( - text = stringResource(coreR.string.skip), + text = stringResource(core_skip), color = TnTTheme.colors.neutralColors.Neutral400, style = TnTTheme.typography.body2Medium, modifier = Modifier.clickable { onClickSkip() }, @@ -79,7 +83,7 @@ internal fun CodeEntryPage( } ScreenMode.CLOSE -> { TnTTopBar( - title = stringResource(coreR.string.connect), + title = stringResource(core_connect), trailingComponent = { IconButton( onClick = onClickBack, @@ -123,7 +127,7 @@ internal fun CodeEntryPage( ) } TnTBottomButton( - text = stringResource(coreR.string.next), + text = stringResource(core_next), enabled = inputState.isValid, onClick = onClickNext, modifier = Modifier.align(Alignment.BottomCenter), @@ -135,8 +139,8 @@ internal fun CodeEntryPage( TnTIconPopupDialog( title = stringResource(R.string.stop_connecting_trainer), content = stringResource(R.string.warning_reconnect_needed), - leftButtonText = stringResource(coreR.string.cancel), - rightButtonText = stringResource(coreR.string.ok), + leftButtonText = stringResource(core_cancel), + rightButtonText = stringResource(core_ok), onLeftButtonClick = onClickCancel, onRightButtonClick = onDismissDialog, onDismiss = onDismissDialog, diff --git a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/PTSessionFormPage.kt b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/PTSessionFormPage.kt index 2501041d..72bd1b57 100644 --- a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/PTSessionFormPage.kt +++ b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/PTSessionFormPage.kt @@ -26,6 +26,8 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import co.kr.tnt.core.ui.R.string.core_entered_wrong_text +import co.kr.tnt.core.ui.R.string.core_next import co.kr.tnt.designsystem.component.TnTLabeledTextField import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton import co.kr.tnt.designsystem.component.button.TnTBottomButton @@ -37,7 +39,6 @@ import co.kr.tnt.ui.utils.throttled import java.time.LocalDate import java.time.ZoneId import java.time.format.DateTimeFormatter -import co.kr.tnt.core.ui.R as uiResource private const val MAX_COUNT = 99 @@ -159,7 +160,7 @@ internal fun PTSessionFormPage( ) Text( text = if (showCompletedSessionWarning || showTotalSessionWarning) { - stringResource(uiResource.string.entered_wrong_text) + stringResource(core_entered_wrong_text) } else { "" }, @@ -195,7 +196,7 @@ internal fun PTSessionFormPage( ) Text( text = if (showTotalSessionWarning || showCompletedSessionWarning) { - stringResource(uiResource.string.entered_wrong_text) + stringResource(core_entered_wrong_text) } else { "" }, @@ -207,7 +208,7 @@ internal fun PTSessionFormPage( } } TnTBottomButton( - text = stringResource(uiResource.string.next), + text = stringResource(core_next), modifier = Modifier.align(Alignment.BottomCenter), enabled = isFormValid, onClick = throttled { onClickNext() }, diff --git a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectCompletePage.kt b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectCompletePage.kt index 96c82bc9..77b36441 100644 --- a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectCompletePage.kt +++ b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectCompletePage.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import co.kr.tnt.core.ui.R.string.core_next import co.kr.tnt.designsystem.component.TnTProfileImage import co.kr.tnt.designsystem.component.button.TnTBottomButton import co.kr.tnt.designsystem.theme.TnTTheme @@ -107,7 +108,7 @@ internal fun TraineeConnectCompletePage( } } TnTBottomButton( - text = stringResource(uiResource.string.next), + text = stringResource(core_next), onClick = onClickNext, modifier = Modifier.align(Alignment.BottomCenter), ) diff --git a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectContract.kt b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectContract.kt index 1e25adbf..4b369fe4 100644 --- a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectContract.kt +++ b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectContract.kt @@ -4,6 +4,7 @@ import co.kr.tnt.trainee.connect.model.InputState import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.resource.DisplayText import java.time.LocalDate internal class TraineeConnectContract { @@ -37,7 +38,7 @@ internal class TraineeConnectContract { sealed interface TraineeConnectSideEffect : UiSideEffect { data object NavigateToBack : TraineeConnectSideEffect data object NavigateToHome : TraineeConnectSideEffect - data class ShowToast(val message: String) : TraineeConnectSideEffect + data class ShowToast(val message: DisplayText) : TraineeConnectSideEffect } enum class TraineeConnectPage { diff --git a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectScreen.kt b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectScreen.kt index e73b4a17..13d2f520 100644 --- a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectScreen.kt +++ b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectScreen.kt @@ -3,6 +3,7 @@ package co.kr.tnt.trainee.connect 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 @@ -20,6 +21,7 @@ internal fun TraineeConnectRoute( navigateToHome: (Boolean) -> Unit, viewModel: TraineeConnectViewModel = hiltViewModel(), ) { + val context = LocalContext.current val snackbar = LocalSnackbar.current val state by viewModel.uiState.collectAsStateWithLifecycle() @@ -53,7 +55,7 @@ internal fun TraineeConnectRoute( when (effect) { TraineeConnectSideEffect.NavigateToBack -> navigateToPrevious() TraineeConnectSideEffect.NavigateToHome -> navigateToHome(false) - is TraineeConnectSideEffect.ShowToast -> snackbar.show(effect.message) + is TraineeConnectSideEffect.ShowToast -> snackbar.show(effect.message.asString(context)) } } } diff --git a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectViewModel.kt b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectViewModel.kt index d09bdf20..d09deac5 100644 --- a/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectViewModel.kt +++ b/feature/trainee/connect/src/main/java/co/kr/tnt/trainee/connect/TraineeConnectViewModel.kt @@ -1,6 +1,7 @@ package co.kr.tnt.trainee.connect import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.repository.ConnectRepository import co.kr.tnt.trainee.connect.TraineeConnectContract.TraineeConnectPage import co.kr.tnt.trainee.connect.TraineeConnectContract.TraineeConnectSideEffect @@ -10,6 +11,7 @@ import co.kr.tnt.trainee.connect.model.InputState.FOCUS import co.kr.tnt.trainee.connect.model.InputState.INVALID import co.kr.tnt.trainee.connect.model.InputState.VALID import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import java.time.LocalDate @@ -53,7 +55,11 @@ internal class TraineeConnectViewModel @Inject constructor( updateState { copy(inviteCodeInputState = INVALID) } } }.onFailure { - sendEffect(TraineeConnectSideEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect( + TraineeConnectSideEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } } } @@ -96,7 +102,11 @@ internal class TraineeConnectViewModel @Inject constructor( } navigateToNext() }.onFailure { - sendEffect(TraineeConnectSideEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect( + TraineeConnectSideEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) }.also { updateState { copy(isLoading = false) } } diff --git a/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeContract.kt b/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeContract.kt index 2884d91f..03109280 100644 --- a/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeContract.kt +++ b/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeContract.kt @@ -6,6 +6,7 @@ import co.kr.tnt.domain.model.trainee.TraineePtSession import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.resource.DisplayText import java.time.LocalDate import java.time.YearMonth @@ -36,6 +37,6 @@ internal class TraineeHomeContract { data object NavigateToConnect : TraineeHomeEffect data object NavigateToExerciseRecord : TraineeHomeEffect data object NavigateToMealRecord : TraineeHomeEffect - data class ShowToast(val message: String) : TraineeHomeEffect + data class ShowToast(val message: DisplayText) : TraineeHomeEffect } } diff --git a/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeScreen.kt b/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeScreen.kt index e5989a6d..f677dc52 100644 --- a/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeScreen.kt +++ b/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeScreen.kt @@ -41,6 +41,9 @@ 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 co.kr.tnt.core.ui.R.string.core_connect +import co.kr.tnt.core.ui.R.string.core_do_not_see_for_three_days +import co.kr.tnt.core.ui.R.string.core_next_time import co.kr.tnt.designsystem.component.TnTModalBottomSheet import co.kr.tnt.designsystem.component.calendar.TnTIndicatorWeekCalendar import co.kr.tnt.designsystem.component.calendar.model.DayIndicatorState @@ -75,7 +78,6 @@ import java.time.DayOfWeek import java.time.LocalDate import java.time.LocalDateTime import java.time.YearMonth -import co.kr.tnt.core.ui.R as coreR @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -132,9 +134,9 @@ internal fun TraineeHomeRoute( title = stringResource(R.string.please_connect_trainer), content = stringResource(R.string.connect_dialog_warning), isChecked = uiState.isDialogHiddenForThreeDays, - checkToggleText = stringResource(coreR.string.do_not_see_for_three_days), - leftButtonText = stringResource(coreR.string.next_time), - rightButtonText = stringResource(coreR.string.connect), + checkToggleText = stringResource(core_do_not_see_for_three_days), + leftButtonText = stringResource(core_next_time), + rightButtonText = stringResource(core_connect), onLeftButtonClick = { viewModel.setEvent(TraineeHomeUiEvent.OnDismissDialog) }, onRightButtonClick = { viewModel.setEvent(TraineeHomeUiEvent.OnConfirmConnectDialog) }, onClickCheck = { viewModel.setEvent(TraineeHomeUiEvent.OnChangeHideDialogOption) }, @@ -156,7 +158,7 @@ internal fun TraineeHomeRoute( } TraineeHomeEffect.NavigateToConnect -> navigateToConnect() - is TraineeHomeEffect.ShowToast -> snackbar.show(effect.message) + is TraineeHomeEffect.ShowToast -> snackbar.show(effect.message.asString(context)) } } } diff --git a/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeViewModel.kt b/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeViewModel.kt index ff1dd2e7..08a082ab 100644 --- a/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeViewModel.kt +++ b/feature/trainee/home/src/main/java/co/kr/tnt/trainee/home/TraineeHomeViewModel.kt @@ -1,6 +1,7 @@ package co.kr.tnt.trainee.home import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.model.trainee.TraineeDailyRecordStatus import co.kr.tnt.domain.repository.ConnectRepository import co.kr.tnt.domain.repository.TraineeRepository @@ -8,6 +9,7 @@ import co.kr.tnt.trainee.home.TraineeHomeContract.TraineeHomeEffect import co.kr.tnt.trainee.home.TraineeHomeContract.TraineeHomeUiEvent import co.kr.tnt.trainee.home.TraineeHomeContract.TraineeHomeUiState import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.resource.DisplayText import com.kizitonwose.calendar.core.yearMonth import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.firstOrNull @@ -64,7 +66,11 @@ internal class TraineeHomeViewModel @Inject constructor( updateMonthlyRecordStatus(mergedData) } }.onFailure { - sendEffect(TraineeHomeEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”.")) + sendEffect( + TraineeHomeEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } } } @@ -106,7 +112,11 @@ internal class TraineeHomeViewModel @Inject constructor( ) } }.onFailure { - sendEffect(TraineeHomeEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”.")) + sendEffect( + TraineeHomeEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } } } @@ -166,7 +176,11 @@ internal class TraineeHomeViewModel @Inject constructor( return@launch } }.onFailure { - sendEffect(TraineeHomeEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”.")) + sendEffect( + TraineeHomeEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } val lastHiddenDate = connectRepository.getExplicitDeniedConnectDate().firstOrNull() diff --git a/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailContract.kt b/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailContract.kt index c8c98e67..153debbf 100644 --- a/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailContract.kt +++ b/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailContract.kt @@ -4,6 +4,7 @@ import co.kr.tnt.domain.model.RecordType.MealType import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.resource.DisplayText import java.time.LocalDateTime internal class TraineeMealDetailContract { @@ -22,6 +23,6 @@ internal class TraineeMealDetailContract { sealed interface TraineeMealDetailSideEffect : UiSideEffect { data object NavigateToHome : TraineeMealDetailSideEffect - data class ShowToast(val message: String) : TraineeMealDetailSideEffect + data class ShowToast(val message: DisplayText) : TraineeMealDetailSideEffect } } diff --git a/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailScreen.kt b/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailScreen.kt index c51a6976..c8c68bcf 100644 --- a/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailScreen.kt +++ b/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailScreen.kt @@ -1,7 +1,6 @@ package co.kr.tnt.trainee.mealdetail import android.content.Context -import android.widget.Toast import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -36,6 +35,7 @@ import co.kr.tnt.core.designsystem.R import co.kr.tnt.designsystem.component.TnTDivider import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton import co.kr.tnt.designsystem.component.chip.TnTChip +import co.kr.tnt.designsystem.snackbar.LocalSnackbar import co.kr.tnt.designsystem.theme.TnTTheme import co.kr.tnt.domain.IMAGE_MAX_SIZE import co.kr.tnt.domain.model.RecordType.MealType @@ -56,6 +56,7 @@ internal fun TraineeMealDetailRoute( ) { val state by viewModel.uiState.collectAsStateWithLifecycle() val context = LocalContext.current + val snackbar = LocalSnackbar.current val dateFormatter = remember { DateFormatter() } TraineeMealDetailScreen( @@ -73,10 +74,7 @@ internal fun TraineeMealDetailRoute( LaunchedEffect(viewModel.effect) { viewModel.effect.collect { effect -> when (effect) { - is TraineeMealDetailSideEffect.ShowToast -> { - Toast.makeText(context, effect.message, Toast.LENGTH_SHORT).show() - } - + is TraineeMealDetailSideEffect.ShowToast -> snackbar.show(effect.message.asString(context)) TraineeMealDetailSideEffect.NavigateToHome -> navigateToPrevious() } } diff --git a/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailViewModel.kt b/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailViewModel.kt index 0ffa54f1..12736033 100644 --- a/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailViewModel.kt +++ b/feature/trainee/mealdetail/src/main/java/co/kr/tnt/trainee/mealdetail/TraineeMealDetailViewModel.kt @@ -1,12 +1,14 @@ package co.kr.tnt.trainee.mealdetail import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.model.RecordType.MealType import co.kr.tnt.domain.repository.TraineeRepository import co.kr.tnt.trainee.mealdetail.TraineeMealDetailContract.TraineeMealDetailSideEffect import co.kr.tnt.trainee.mealdetail.TraineeMealDetailContract.TraineeMealDetailUiEvent import co.kr.tnt.trainee.mealdetail.TraineeMealDetailContract.TraineeMealDetailUiState import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @@ -39,7 +41,11 @@ internal class TraineeMealDetailViewModel @Inject constructor( ) } }.onFailure { - sendEffect(TraineeMealDetailSideEffect.ShowToast("데이터 λΆˆλŸ¬μ˜€κΈ°μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect( + TraineeMealDetailSideEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } } } 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 7e2f70f5..68bcc477 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 @@ -4,6 +4,7 @@ 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 co.kr.tnt.ui.resource.DisplayText import java.io.File import java.time.LocalDate import java.time.LocalDateTime @@ -60,6 +61,6 @@ internal class TraineeMealRecordContract { sealed interface TraineeMealRecordSideEffect : UiSideEffect { data object NavigateToHome : TraineeMealRecordSideEffect - data class ShowToast(val message: String) : TraineeMealRecordSideEffect + data class ShowToast(val message: DisplayText) : TraineeMealRecordSideEffect } } 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 e59060e4..f84a08bd 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 @@ -49,7 +49,12 @@ 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 co.kr.tnt.core.designsystem.R +import co.kr.tnt.core.designsystem.R.drawable.ic_close +import co.kr.tnt.core.designsystem.R.drawable.ic_image +import co.kr.tnt.core.designsystem.R.drawable.ic_overlay_close +import co.kr.tnt.core.ui.R.string.core_cancel +import co.kr.tnt.core.ui.R.string.core_length_warning +import co.kr.tnt.core.ui.R.string.core_ok import co.kr.tnt.designsystem.component.TnTBottomSheetDialog import co.kr.tnt.designsystem.component.TnTDivider import co.kr.tnt.designsystem.component.TnTIconPopupDialog @@ -70,6 +75,7 @@ import co.kr.tnt.designsystem.theme.TnTTheme import co.kr.tnt.domain.IMAGE_MAX_SIZE import co.kr.tnt.domain.model.RecordType.MealType import co.kr.tnt.domain.utils.DateFormatter +import co.kr.tnt.feature.trainee.mealrecord.R import co.kr.tnt.trainee.mealrecord.TraineeMealRecordContract.TraineeMealRecordUiEvent import co.kr.tnt.trainee.mealrecord.TraineeMealRecordContract.TraineeMealRecordUiState import co.kr.tnt.trainee.mealrecord.TraineeMealRecordContract.TraineeMealRecordUiState.DialogState @@ -89,7 +95,6 @@ import java.time.DayOfWeek import java.time.LocalDate import java.time.LocalTime import java.time.YearMonth -import co.kr.tnt.core.ui.R as coreR @Composable internal fun TraineeMealRecordRoute( @@ -199,7 +204,7 @@ internal fun TraineeMealRecordRoute( when (effect) { TraineeMealRecordContract.TraineeMealRecordSideEffect.NavigateToHome -> navigateToPrevious() is TraineeMealRecordContract.TraineeMealRecordSideEffect.ShowToast -> snackbar.show( - effect.message, + effect.message.asString(context), ) } } @@ -231,7 +236,7 @@ private fun TraineeMealRecordScreen( containerColor = TnTTheme.colors.commonColors.Common0, topBar = { TnTTopBarWithBackButton( - title = "식단 기둝", + title = stringResource(R.string.meal_record), onBackClick = onClickBack, showStoke = true, ) @@ -321,9 +326,9 @@ private fun Dialog( DialogState.NONE -> Unit DialogState.COMPLETED -> { TnTSingleButtonPopupDialog( - title = "식단을 κΈ°λ‘ν–ˆμ–΄μš”!", - content = "내일도 기둝해 μ£Όμ‹€ κ±°μ£ ?", - buttonText = stringResource(coreR.string.ok), + title = stringResource(R.string.recorded_meal), + content = stringResource(R.string.will_you_record_tomorrow_too), + buttonText = stringResource(core_ok), cancelable = false, onButtonClick = onClickConfirm, onDismiss = onDismissDialog, @@ -332,12 +337,12 @@ private fun Dialog( DialogState.EXIT -> { TnTIconPopupDialog( - title = "식단 기둝을 μ’…λ£Œν• κΉŒμš”?", - content = "기둝이 μ €μž₯λ˜μ§€ μ•Šμ•„μš”!", - leftButtonText = "μ·¨μ†Œ", - rightButtonText = "확인", - onLeftButtonClick = onDismissDialog, - onRightButtonClick = onClickExit, + title = stringResource(R.string.exit_meal_recording), + content = stringResource(R.string.record_will_not_be_saved), + leftButtonText = stringResource(core_cancel), + rightButtonText = stringResource(core_ok), + onLeftButtonClick = onClickExit, + onRightButtonClick = onDismissDialog, onDismiss = onDismissDialog, ) } @@ -374,11 +379,11 @@ private fun MealImageSelector( ) { if (imageUri == null) { Image( - painter = painterResource(R.drawable.ic_image), + painter = painterResource(ic_image), contentDescription = null, ) Text( - text = "였늘 먹은 식단을 μΆ”κ°€ν•΄λ³΄μ„Έμš”", + text = stringResource(R.string.add_todays_meal), color = TnTTheme.colors.neutralColors.Neutral400, style = TnTTheme.typography.body2Medium, ) @@ -395,7 +400,7 @@ private fun MealImageSelector( modifier = Modifier.align(Alignment.TopEnd), ) { Icon( - painter = painterResource(R.drawable.ic_overlay_close), + painter = painterResource(ic_overlay_close), contentDescription = null, tint = Color.Unspecified, ) @@ -414,7 +419,7 @@ private fun MealDate( onClick: () -> Unit, ) { TnTSelectableTextField( - title = "식사 λ‚ μ§œ", + title = stringResource(R.string.meal_date), value = dateFormatter.format(date, "yyyy/MM/dd"), onValueChange = { }, isRequired = true, @@ -432,7 +437,7 @@ private fun MealTime( ) { val now = LocalTime.now() TnTSelectableTextField( - title = "식사 μ‹œκ°„", + title = stringResource(R.string.meal_time), value = time?.let { dateFormatter.format(it, "HH:mm") } ?: "", onValueChange = { }, isRequired = true, @@ -459,7 +464,7 @@ private fun MealTypes( modifier = Modifier.fillMaxWidth(), ) { Text( - text = "λΆ„λ₯˜", + text = stringResource(R.string.category), style = TnTTheme.typography.body1Bold, color = TnTTheme.colors.neutralColors.Neutral900, ) @@ -500,7 +505,7 @@ private fun MealMemo( modifier = Modifier.fillMaxWidth(), ) { Text( - text = "λ©”λͺ¨ν•˜κΈ°", + text = stringResource(R.string.wirte_memo), style = TnTTheme.typography.body1Bold, color = TnTTheme.colors.neutralColors.Neutral900, ) @@ -516,10 +521,10 @@ private fun MealMemo( onValueChange = { newValue -> onValueChange(newValue) }, - placeholder = "식단에 λŒ€ν•œ 정보λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”!", + placeholder = stringResource(R.string.enter_meal_info), maxLength = 100, isError = state.showWarning, - warningMessage = "100자 미만으둜 μž…λ ₯ν•΄μ£Όμ„Έμš”", + warningMessage = stringResource(core_length_warning, 100), ) } } @@ -542,13 +547,13 @@ private fun CalendarBottomSheetContent( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = "식단 λ‚ μ§œ μ„ νƒν•˜κΈ°", + text = stringResource(R.string.select_meal_date), color = TnTTheme.colors.neutralColors.Neutral900, style = TnTTheme.typography.h3, modifier = Modifier.weight(1f), ) Icon( - painter = painterResource(R.drawable.ic_close), + painter = painterResource(ic_close), contentDescription = null, modifier = Modifier.clickable(onClick = onClickClose), ) @@ -559,7 +564,7 @@ private fun CalendarBottomSheetContent( onClickDay = { newDate -> selectedDate = newDate }, ) TnTTextButton( - text = stringResource(coreR.string.ok), + text = stringResource(core_ok), modifier = Modifier .fillMaxWidth() .padding(horizontal = 20.dp), @@ -633,13 +638,13 @@ private fun TimePickerBottomSheetContent( modifier = Modifier.padding(20.dp), ) { Text( - text = "식단 μ‹œκ°„ μ„ νƒν•˜κΈ°", + text = stringResource(R.string.select_meal_time), color = TnTTheme.colors.neutralColors.Neutral900, style = TnTTheme.typography.h3, modifier = Modifier.weight(1f), ) Icon( - painter = painterResource(R.drawable.ic_close), + painter = painterResource(ic_close), contentDescription = null, modifier = Modifier.clickable(onClick = onClickClose), ) @@ -656,7 +661,7 @@ private fun TimePickerBottomSheetContent( ) Spacer(Modifier.height(40.dp)) TnTTextButton( - text = stringResource(coreR.string.ok), + text = stringResource(core_ok), modifier = Modifier .fillMaxWidth() .padding(horizontal = 20.dp), 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 cc228deb..b99c9acc 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 @@ -3,11 +3,13 @@ package co.kr.tnt.trainee.mealrecord import androidx.lifecycle.viewModelScope import co.kr.tnt.domain.repository.TraineeRepository import co.kr.tnt.domain.utils.DateFormatter +import co.kr.tnt.feature.trainee.mealrecord.R import co.kr.tnt.trainee.mealrecord.TraineeMealRecordContract.TraineeMealRecordSideEffect import co.kr.tnt.trainee.mealrecord.TraineeMealRecordContract.TraineeMealRecordUiEvent 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.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import java.io.File @@ -106,7 +108,11 @@ internal class TraineeMealRecordViewModel @Inject constructor( }.onSuccess { updateState { copy(dialogState = DialogState.COMPLETED) } }.onFailure { - sendEffect(TraineeMealRecordSideEffect.ShowToast("식단 기둝에 μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect( + TraineeMealRecordSideEffect.ShowToast( + DisplayText.Resource(R.string.failed_meal_record), + ), + ) }.also { updateState { copy(isLoading = false) } } diff --git a/feature/trainee/mealrecord/src/main/res/values/strings.xml b/feature/trainee/mealrecord/src/main/res/values/strings.xml new file mode 100644 index 00000000..7af49819 --- /dev/null +++ b/feature/trainee/mealrecord/src/main/res/values/strings.xml @@ -0,0 +1,17 @@ + + + 식단 기둝에 μ‹€νŒ¨ν–ˆμ–΄μš” + 식단 기둝 + 식단을 κΈ°λ‘ν–ˆμ–΄μš”! + 내일도 기둝해 μ£Όμ‹€ κ±°μ£ ? + 식단 기둝을 μ’…λ£Œν• κΉŒμš”? + 기둝이 μ €μž₯λ˜μ§€ μ•Šμ•„μš”! + 였늘 먹은 식단을 μΆ”κ°€ν•΄λ³΄μ„Έμš” + 식사 λ‚ μ§œ + 식사 μ‹œκ°„ + λΆ„λ₯˜ + λ©”λͺ¨ν•˜κΈ° + 식단에 λŒ€ν•œ 정보λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”! + 식단 λ‚ μ§œ μ„ νƒν•˜κΈ° + 식단 μ‹œκ°„ μ„ νƒν•˜κΈ° + diff --git a/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageContract.kt b/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageContract.kt index 862828af..20364dfc 100644 --- a/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageContract.kt +++ b/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageContract.kt @@ -4,6 +4,7 @@ import co.kr.tnt.domain.model.User import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.resource.DisplayText internal class TraineeMyPageContract { data class TraineeMyPageUiState( @@ -40,7 +41,7 @@ internal class TraineeMyPageContract { } sealed interface TraineeMyPageEffect : UiSideEffect { - data class ShowToast(val message: String) : TraineeMyPageEffect + data class ShowToast(val message: DisplayText) : TraineeMyPageEffect data object NavigateToConnect : TraineeMyPageEffect data object NavigateToLogin : TraineeMyPageEffect data class NavigateToWebView(val url: String) : TraineeMyPageEffect diff --git a/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageScreen.kt b/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageScreen.kt index 4b1cdc40..989e70b3 100644 --- a/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageScreen.kt +++ b/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageScreen.kt @@ -27,6 +27,18 @@ 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 co.kr.tnt.core.ui.R.string.core_app_push_notification +import co.kr.tnt.core.ui.R.string.core_app_version +import co.kr.tnt.core.ui.R.string.core_cancel +import co.kr.tnt.core.ui.R.string.core_delete_account +import co.kr.tnt.core.ui.R.string.core_logout +import co.kr.tnt.core.ui.R.string.core_logout_complete_title +import co.kr.tnt.core.ui.R.string.core_logout_content +import co.kr.tnt.core.ui.R.string.core_logout_title +import co.kr.tnt.core.ui.R.string.core_ok +import co.kr.tnt.core.ui.R.string.core_open_source_license +import co.kr.tnt.core.ui.R.string.core_privacy_policy +import co.kr.tnt.core.ui.R.string.core_terms_of_service import co.kr.tnt.designsystem.component.TnTIconPopupDialog import co.kr.tnt.designsystem.component.TnTProfileImage import co.kr.tnt.designsystem.component.TnTSingleButtonPopupDialog @@ -54,7 +66,6 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.rememberMultiplePermissionsState import com.google.android.gms.oss.licenses.OssLicensesMenuActivity import java.time.LocalDate -import co.kr.tnt.core.ui.R as coreR @OptIn(ExperimentalPermissionsApi::class) @Composable @@ -106,7 +117,7 @@ internal fun TraineeMyPageRoute( when (effect) { TraineeMyPageEffect.NavigateToConnect -> navigateToConnect(ScreenMode.BACK) TraineeMyPageEffect.NavigateToLogin -> navigateToLogin() - is TraineeMyPageEffect.ShowToast -> snackbar.show(effect.message) + is TraineeMyPageEffect.ShowToast -> snackbar.show(effect.message.asString(context)) is TraineeMyPageEffect.NavigateToWebView -> navigateToWebView(effect.url) is TraineeMyPageEffect.RequestPermission -> { if (effect.isExplicitlyDenied) { @@ -182,7 +193,7 @@ private fun TraineeMyPageScreen( ) } TnTMyPageButton( - text = stringResource(coreR.string.app_push_notification), + text = stringResource(core_app_push_notification), verticalPadding = 12.dp, enabled = false, trailingComponent = { @@ -199,17 +210,17 @@ private fun TraineeMyPageScreen( .padding(vertical = 12.dp), ) { TnTMyPageButton( - text = stringResource(coreR.string.terms_of_service), + text = stringResource(core_terms_of_service), onClick = onClickTermsOfService, verticalPadding = 8.dp, ) TnTMyPageButton( - text = stringResource(coreR.string.privacy_policy), + text = stringResource(core_privacy_policy), onClick = onClickPrivacy, verticalPadding = 8.dp, ) TnTMyPageButton( - text = stringResource(coreR.string.app_version), + text = stringResource(core_app_version), verticalPadding = 12.dp, enabled = false, trailingComponent = { @@ -221,7 +232,7 @@ private fun TraineeMyPageScreen( }, ) TnTMyPageButton( - text = stringResource(coreR.string.open_source_license), + text = stringResource(core_open_source_license), onClick = onClickOpenSource, verticalPadding = 8.dp, ) @@ -234,12 +245,12 @@ private fun TraineeMyPageScreen( .padding(vertical = 12.dp), ) { TnTMyPageButton( - text = stringResource(coreR.string.logout), + text = stringResource(core_logout), onClick = onClickLogout, verticalPadding = 8.dp, ) TnTMyPageButton( - text = stringResource(coreR.string.delete_account), + text = stringResource(core_delete_account), onClick = onClickDeleteAccount, verticalPadding = 8.dp, ) @@ -258,10 +269,10 @@ private fun Dialog( DialogState.NONE -> Unit DialogState.LOGOUT_CONFIRM -> { TnTIconPopupDialog( - title = stringResource(coreR.string.logout_title), - content = stringResource(coreR.string.logout_content), - leftButtonText = stringResource(coreR.string.cancel), - rightButtonText = stringResource(coreR.string.ok), + title = stringResource(core_logout_title), + content = stringResource(core_logout_content), + leftButtonText = stringResource(core_cancel), + rightButtonText = stringResource(core_ok), onLeftButtonClick = onDismissDialog, onRightButtonClick = onClickConfirm, onDismiss = onDismissDialog, @@ -270,9 +281,9 @@ private fun Dialog( DialogState.LOGOUT -> { TnTSingleButtonPopupDialog( - title = stringResource(coreR.string.logout_complete_title), - content = stringResource(coreR.string.logout_content), - buttonText = stringResource(coreR.string.ok), + title = stringResource(core_logout_complete_title), + content = stringResource(core_logout_content), + buttonText = stringResource(core_ok), cancelable = false, onButtonClick = onClickConfirm, onDismiss = onDismissDialog, @@ -283,8 +294,8 @@ private fun Dialog( TnTIconPopupDialog( title = stringResource(R.string.delete_account_title), content = stringResource(R.string.delete_account_content), - leftButtonText = stringResource(coreR.string.cancel), - rightButtonText = stringResource(coreR.string.ok), + leftButtonText = stringResource(core_cancel), + rightButtonText = stringResource(core_ok), onLeftButtonClick = onDismissDialog, onRightButtonClick = onClickConfirm, onDismiss = onDismissDialog, @@ -295,7 +306,7 @@ private fun Dialog( TnTSingleButtonPopupDialog( title = stringResource(R.string.delete_account_complete_title), content = stringResource(R.string.delete_account_complete_content), - buttonText = stringResource(coreR.string.ok), + buttonText = stringResource(core_ok), cancelable = false, onButtonClick = onClickConfirm, onDismiss = onDismissDialog, diff --git a/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageViewModel.kt b/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageViewModel.kt index efadcd8f..67a4f272 100644 --- a/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageViewModel.kt +++ b/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageViewModel.kt @@ -1,16 +1,19 @@ package co.kr.tnt.trainee.mypage import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.repository.LoginRepository import co.kr.tnt.domain.repository.SettingRepository import co.kr.tnt.domain.repository.TraineeRepository import co.kr.tnt.domain.utils.AppUrls +import co.kr.tnt.feature.trainee.mypage.R import co.kr.tnt.login.kakao.KakaoLoginSdk import co.kr.tnt.trainee.mypage.TraineeMyPageContract.TraineeMyPageEffect import co.kr.tnt.trainee.mypage.TraineeMyPageContract.TraineeMyPageUiEvent import co.kr.tnt.trainee.mypage.TraineeMyPageContract.TraineeMyPageUiState import co.kr.tnt.trainee.mypage.TraineeMyPageContract.TraineeMyPageUiState.DialogState import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -39,6 +42,7 @@ internal class TraineeMyPageViewModel @Inject constructor( isGrantedPermission = event.isGrantedPermission, shouldShowRationale = event.shouldShowRationale, ) + TraineeMyPageUiEvent.OnClickTermsOfService -> sendEffect( TraineeMyPageEffect.NavigateToWebView(AppUrls.TERMS_OF_SERVICE_URL), ) @@ -70,7 +74,11 @@ internal class TraineeMyPageViewModel @Inject constructor( }.onSuccess { user -> updateState { copy(user = user) } }.onFailure { - sendEffect(TraineeMyPageEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”.")) + sendEffect( + TraineeMyPageEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } settingRepository.isEnablePushNotification() @@ -142,7 +150,7 @@ internal class TraineeMyPageViewModel @Inject constructor( }.onSuccess { updateState { copy(dialogState = DialogState.LOGOUT) } }.onFailure { - sendEffect(TraineeMyPageEffect.ShowToast("λ‘œκ·Έμ•„μ›ƒμ— μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€.")) + sendEffect(TraineeMyPageEffect.ShowToast(DisplayText.Resource(R.string.failed_login))) }.also { updateState { copy(isLoading = false) } } @@ -158,7 +166,11 @@ internal class TraineeMyPageViewModel @Inject constructor( }.onSuccess { updateState { copy(dialogState = DialogState.DELETE_ACCOUNT) } }.onFailure { - sendEffect(TraineeMyPageEffect.ShowToast("νƒˆν‡΄μ— μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€.")) + sendEffect( + TraineeMyPageEffect.ShowToast( + DisplayText.Resource(R.string.failed_delete_account), + ), + ) }.also { updateState { copy(isLoading = false) } } diff --git a/feature/trainee/mypage/src/main/res/values/strings.xml b/feature/trainee/mypage/src/main/res/values/strings.xml index 4083b04b..a5221b2e 100644 --- a/feature/trainee/mypage/src/main/res/values/strings.xml +++ b/feature/trainee/mypage/src/main/res/values/strings.xml @@ -12,4 +12,7 @@ μš΄λ™ 및 식단 기둝에 λŒ€ν•œ 데이터가 μ‚¬λΌμ Έμš”! 계정 νƒˆν‡΄κ°€ μ™„λ£Œλ˜μ—ˆμ–΄μš” λ‹€μŒμ— 더 폭발적인 μΌ€λ―Έλ‘œ λ‹€μ‹œ λ§Œλ‚˜μš”! πŸ’£ + + λ‘œκ·Έμ•„μ›ƒμ— μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€. + νƒˆν‡΄μ— μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€. diff --git a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationContract.kt b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationContract.kt index cb59f419..2e05df1e 100644 --- a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationContract.kt +++ b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationContract.kt @@ -4,6 +4,7 @@ import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState import co.kr.tnt.ui.model.NotificationState +import co.kr.tnt.ui.resource.DisplayText internal class TraineeNotificationContract { data class TraineeNotificationUiState( @@ -15,7 +16,7 @@ internal class TraineeNotificationContract { } sealed interface TraineeNotificationEffect : UiSideEffect { - data class ShowToast(val message: String) : TraineeNotificationEffect + data class ShowToast(val message: DisplayText) : TraineeNotificationEffect data object NavigateToPrevious : TraineeNotificationEffect } } diff --git a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt index a0e0b883..32ee6827 100644 --- a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt +++ b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt @@ -13,10 +13,13 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext 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 co.kr.tnt.core.ui.R.string.core_no_recent_notifications +import co.kr.tnt.core.ui.R.string.core_notification import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton import co.kr.tnt.designsystem.component.notification.TnTNotification import co.kr.tnt.designsystem.component.notification.model.NotificationIcon @@ -25,13 +28,13 @@ import co.kr.tnt.designsystem.theme.TnTTheme import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotificationUiEvent import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotificationUiState import co.kr.tnt.ui.model.NotificationState -import co.kr.tnt.core.ui.R as uiResource @Composable internal fun TraineeNotificationRoute( navigateToPrevious: () -> Unit, viewModel: TraineeNotificationViewModel = hiltViewModel(), ) { + val context = LocalContext.current val snackbar = LocalSnackbar.current val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -44,7 +47,9 @@ internal fun TraineeNotificationRoute( viewModel.effect.collect { effect -> when (effect) { TraineeNotificationContract.TraineeNotificationEffect.NavigateToPrevious -> navigateToPrevious() - is TraineeNotificationContract.TraineeNotificationEffect.ShowToast -> snackbar.show(effect.message) + is TraineeNotificationContract.TraineeNotificationEffect.ShowToast -> snackbar.show( + effect.message.asString(context), + ) } } } @@ -58,7 +63,7 @@ private fun TraineeNotificationScreen( Scaffold( topBar = { TnTTopBarWithBackButton( - title = stringResource(uiResource.string.notification), + title = stringResource(core_notification), onBackClick = onClickBack, showStoke = true, ) @@ -72,7 +77,7 @@ private fun TraineeNotificationScreen( contentAlignment = Alignment.Center, ) { Text( - text = stringResource(uiResource.string.no_recent_notifications), + text = stringResource(core_no_recent_notifications), style = TnTTheme.typography.label1Medium, color = TnTTheme.colors.neutralColors.Neutral400, ) diff --git a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeBasicInfoPage.kt b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeBasicInfoPage.kt index 66ac6573..fef4399e 100644 --- a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeBasicInfoPage.kt +++ b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeBasicInfoPage.kt @@ -28,6 +28,12 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import co.kr.tnt.core.ui.R.string.core_entered_wrong_text +import co.kr.tnt.core.ui.R.string.core_height_label +import co.kr.tnt.core.ui.R.string.core_height_unit +import co.kr.tnt.core.ui.R.string.core_next +import co.kr.tnt.core.ui.R.string.core_weight_label +import co.kr.tnt.core.ui.R.string.core_weight_unit import co.kr.tnt.designsystem.component.TnTLabeledTextField import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton import co.kr.tnt.designsystem.component.button.TnTBottomButton @@ -39,7 +45,6 @@ import co.kr.tnt.ui.extensions.clearFocusOnTap import java.time.LocalDate import java.time.ZoneId import java.time.format.DateTimeFormatter -import co.kr.tnt.core.ui.R as uiResource @Composable internal fun TraineeBasicInfoPage( @@ -101,29 +106,29 @@ internal fun TraineeBasicInfoPage( .padding(horizontal = 20.dp), ) { TnTLabeledTextField( - title = stringResource(uiResource.string.height_label), + title = stringResource(core_height_label), value = state.height ?: "", placeholder = "0", isSingleLine = true, showWarning = state.isHeightValid.not(), - warningMessage = stringResource(uiResource.string.entered_wrong_text), + warningMessage = stringResource(core_entered_wrong_text), keyboardType = KeyboardType.Number, trailingComponent = { - UnitLabel(uiResource.string.height_unit) + UnitLabel(core_height_unit) }, onValueChange = onChangeHeight, modifier = Modifier.weight(1f), ) TnTLabeledTextField( - title = stringResource(uiResource.string.weight_label), + title = stringResource(core_weight_label), value = state.weight ?: "", placeholder = "00.0", isSingleLine = true, showWarning = state.isWeightValid.not(), - warningMessage = stringResource(uiResource.string.entered_wrong_text), + warningMessage = stringResource(core_entered_wrong_text), keyboardType = KeyboardType.Number, trailingComponent = { - UnitLabel(uiResource.string.weight_unit) + UnitLabel(core_weight_unit) }, onValueChange = onChangeWeight, modifier = Modifier.weight(1f), @@ -131,7 +136,7 @@ internal fun TraineeBasicInfoPage( } } TnTBottomButton( - text = stringResource(uiResource.string.next), + text = stringResource(core_next), modifier = Modifier.align(Alignment.BottomCenter), enabled = state.isBasicInfoValid, onClick = onClickNext, diff --git a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeNoteForTrainerPage.kt b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeNoteForTrainerPage.kt index a2844679..329a4978 100644 --- a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeNoteForTrainerPage.kt +++ b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeNoteForTrainerPage.kt @@ -17,6 +17,7 @@ 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 co.kr.tnt.core.ui.R.string.core_next import co.kr.tnt.designsystem.component.TnTOutlinedTextField import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton import co.kr.tnt.designsystem.component.button.TnTBottomButton @@ -24,7 +25,6 @@ import co.kr.tnt.designsystem.theme.TnTTheme import co.kr.tnt.feature.trainee.signup.R import co.kr.tnt.trainee.signup.component.ProgressSteps import co.kr.tnt.ui.extensions.clearFocusOnTap -import co.kr.tnt.core.ui.R as uiResource private const val MAX_LENGTH = 100 @@ -69,7 +69,7 @@ internal fun TraineeNoteForTrainerPage( ) } TnTBottomButton( - text = stringResource(uiResource.string.next), + text = stringResource(core_next), modifier = Modifier.align(Alignment.BottomCenter), enabled = (caution?.length ?: 0) < MAX_LENGTH, onClick = onClickNext, diff --git a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineePTPurposePage.kt b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineePTPurposePage.kt index 6e53c001..d6241011 100644 --- a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineePTPurposePage.kt +++ b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineePTPurposePage.kt @@ -17,6 +17,7 @@ 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 co.kr.tnt.core.ui.R.string.core_next import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton import co.kr.tnt.designsystem.component.button.TnTBottomButton import co.kr.tnt.designsystem.component.button.TnTTextButton @@ -27,7 +28,6 @@ import co.kr.tnt.feature.trainee.signup.R import co.kr.tnt.trainee.signup.TraineeSignUpContract.TraineeSignUpUiState import co.kr.tnt.trainee.signup.component.ProgressSteps import co.kr.tnt.trainee.signup.model.PTPurpose -import co.kr.tnt.core.ui.R as uiResource private const val ROW_NUM = 3 private const val COLUMNS_NUM = 2 @@ -76,7 +76,7 @@ internal fun TraineePTPurposePage( } } TnTBottomButton( - text = stringResource(uiResource.string.next), + text = stringResource(core_next), onClick = onClickNext, modifier = Modifier.align(Alignment.BottomCenter), ) diff --git a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeProfileSetupPage.kt b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeProfileSetupPage.kt index b4df61fc..99c7a1f8 100644 --- a/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeProfileSetupPage.kt +++ b/feature/trainee/signup/src/main/java/co/kr/tnt/trainee/signup/TraineeProfileSetupPage.kt @@ -24,6 +24,9 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import co.kr.tnt.core.ui.R.string.core_name +import co.kr.tnt.core.ui.R.string.core_next +import co.kr.tnt.core.ui.R.string.core_text_length_and_format_warning import co.kr.tnt.designsystem.component.TnTLabeledTextFieldWithCounter import co.kr.tnt.designsystem.component.TnTProfileImage import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton @@ -38,7 +41,6 @@ import co.kr.tnt.ui.extensions.clearFocusOnTap import co.kr.tnt.ui.model.DefaultUserProfile import coil.compose.rememberAsyncImagePainter import coil.request.ImageRequest -import co.kr.tnt.core.ui.R as coreR private const val MAX_LENGTH = 15 @@ -100,7 +102,7 @@ internal fun TraineeProfileSetupPage( ) Spacer(Modifier.padding(top = 60.dp)) TnTLabeledTextFieldWithCounter( - title = stringResource(coreR.string.name), + title = stringResource(core_name), value = state.name, onValueChange = { newValue -> onChangeName(newValue) @@ -111,11 +113,11 @@ internal fun TraineeProfileSetupPage( isSingleLine = true, showWarning = !state.isNameValid, isRequired = true, - warningMessage = stringResource(coreR.string.text_length_and_format_warning, MAX_LENGTH), + warningMessage = stringResource(core_text_length_and_format_warning, MAX_LENGTH), ) } TnTBottomButton( - text = stringResource(coreR.string.next), + text = stringResource(core_next), enabled = state.name.isNotBlank() && state.isNameValid, onClick = onClickNext, modifier = Modifier.align(Alignment.BottomCenter), 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 8881204b..ce78b158 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 @@ -22,6 +22,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign.Companion.Center import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import co.kr.tnt.core.ui.R.string.core_start import co.kr.tnt.designsystem.component.TnTProfileImage import co.kr.tnt.designsystem.component.button.TnTBottomButton import co.kr.tnt.designsystem.theme.TnTTheme @@ -35,7 +36,6 @@ 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 @Composable internal fun TraineeSignUpCompletePage( @@ -98,7 +98,7 @@ internal fun TraineeSignUpCompletePage( ) } TnTBottomButton( - text = stringResource(uiResource.string.start), + text = stringResource(core_start), onClick = throttled { completeState.value = true }, 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 46f678bf..e13d115f 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 @@ -4,6 +4,7 @@ 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 co.kr.tnt.ui.resource.DisplayText import java.io.File import java.time.LocalDate @@ -76,7 +77,7 @@ internal class TraineeSignUpContract { } sealed interface TraineeSignUpEffect : UiSideEffect { - data class ShowToast(val message: String) : TraineeSignUpEffect + data class ShowToast(val message: DisplayText) : TraineeSignUpEffect data object NavigateToBack : TraineeSignUpEffect data object NavigateToConnect : TraineeSignUpEffect } 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 e600c8f4..702e64d7 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,6 +4,7 @@ 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 @@ -24,6 +25,7 @@ internal fun TraineeSignUpRoute( navigateToConnect: () -> Unit, viewModel: TraineeSignUpViewModel = hiltViewModel(), ) { + val context = LocalContext.current val snackbar = LocalSnackbar.current val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -56,7 +58,7 @@ internal fun TraineeSignUpRoute( when (effect) { TraineeSignUpEffect.NavigateToBack -> navigateToPrevious() TraineeSignUpEffect.NavigateToConnect -> navigateToConnect() - is TraineeSignUpEffect.ShowToast -> snackbar.show(effect.message) + is TraineeSignUpEffect.ShowToast -> snackbar.show(effect.message.asString(context)) } } } 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 84655ef4..05f41f8e 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 @@ -2,6 +2,7 @@ package co.kr.tnt.trainee.signup import android.net.Uri import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.model.User import co.kr.tnt.domain.repository.SignUpRepository import co.kr.tnt.trainee.signup.TraineeSignUpContract.TraineeSignUpEffect @@ -9,6 +10,7 @@ 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.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import java.io.File @@ -75,7 +77,11 @@ internal class TraineeSignUpViewModel @Inject constructor( }.onSuccess { sendEffect(TraineeSignUpEffect.NavigateToConnect) }.onFailure { - sendEffect(TraineeSignUpEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”.")) + sendEffect( + TraineeSignUpEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) }.also { updateState { copy(isLoading = false) } } diff --git a/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionContract.kt b/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionContract.kt index d0f02780..b408cedd 100644 --- a/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionContract.kt +++ b/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionContract.kt @@ -4,6 +4,7 @@ import co.kr.tnt.domain.model.MemberInfo import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.resource.DisplayText import java.time.LocalDate import java.time.LocalTime import java.time.temporal.ChronoUnit @@ -82,7 +83,7 @@ internal class AddPtSessionContract { sealed interface AddPtSessionSideEffect : UiSideEffect { data object ShowBottomSheet : AddPtSessionSideEffect data object HideBottomSheet : AddPtSessionSideEffect - data class ShowToast(val message: String) : AddPtSessionSideEffect + data class ShowToast(val message: DisplayText) : AddPtSessionSideEffect data object NavigateToPrevious : AddPtSessionSideEffect } } diff --git a/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionScreen.kt b/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionScreen.kt index cb661879..c9aeadd5 100644 --- a/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionScreen.kt +++ b/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionScreen.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -48,7 +49,13 @@ 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 co.kr.tnt.core.designsystem.R +import co.kr.tnt.core.designsystem.R.drawable.ic_arrow_down +import co.kr.tnt.core.designsystem.R.drawable.ic_check_true +import co.kr.tnt.core.designsystem.R.drawable.ic_delete +import co.kr.tnt.core.designsystem.R.drawable.ic_red_clock +import co.kr.tnt.core.ui.R.string.core_cancel +import co.kr.tnt.core.ui.R.string.core_length_warning +import co.kr.tnt.core.ui.R.string.core_ok import co.kr.tnt.designsystem.component.TnTBottomSheetDialog import co.kr.tnt.designsystem.component.TnTDivider import co.kr.tnt.designsystem.component.TnTIconPopupDialog @@ -69,6 +76,7 @@ import co.kr.tnt.designsystem.snackbar.LocalSnackbar import co.kr.tnt.designsystem.theme.TnTTheme import co.kr.tnt.domain.model.MemberInfo import co.kr.tnt.domain.utils.DateFormatter +import co.kr.tnt.feature.trainer.addptsession.R import co.kr.tnt.trainer.addptsession.AddPtSessionContract.AddPtSessionSideEffect import co.kr.tnt.trainer.addptsession.AddPtSessionContract.AddPtSessionUiEvent import co.kr.tnt.trainer.addptsession.AddPtSessionContract.AddPtSessionUiState @@ -83,7 +91,6 @@ import kotlinx.coroutines.launch import java.time.DayOfWeek import java.time.LocalDate import java.time.LocalTime -import co.kr.tnt.core.ui.R as coreR @Composable internal fun AddPtSessionRoute( @@ -91,6 +98,7 @@ internal fun AddPtSessionRoute( viewModel: AddPtSessionViewModel = hiltViewModel(), navigateToPrevious: () -> Unit, ) { + val context = LocalContext.current val snackbar = LocalSnackbar.current val state by viewModel.uiState.collectAsStateWithLifecycle() @@ -139,7 +147,7 @@ internal fun AddPtSessionRoute( ) AddPtSessionUiState.BottomSheetType.SELECT_START_TIME -> TimePickerBottomSheetContent( - title = "μ‹œμž‘ μ‹œκ°„ μ„ νƒν•˜κΈ°", + title = stringResource(R.string.select_start_time), selectedTime = state.selectedStartTime, onDismissRequest = { showBottomSheet = false }, onClickConfirm = { selectTime -> @@ -148,7 +156,7 @@ internal fun AddPtSessionRoute( ) AddPtSessionUiState.BottomSheetType.SELECT_END_TIME -> TimePickerBottomSheetContent( - title = "μ’…λ£Œ μ‹œκ°„ μ„ νƒν•˜κΈ°", + title = stringResource(R.string.select_end_time), selectedTime = state.selectedEndTime, onDismissRequest = { showBottomSheet = false }, onClickConfirm = { selectTime -> @@ -181,7 +189,7 @@ internal fun AddPtSessionRoute( showBottomSheet = false } - is AddPtSessionSideEffect.ShowToast -> snackbar.show(effect.message) + is AddPtSessionSideEffect.ShowToast -> snackbar.show(effect.message.asString(context)) AddPtSessionSideEffect.NavigateToPrevious -> navigateToPrevious() } } @@ -206,7 +214,7 @@ private fun AddPtSessionScreen( topBar = { TnTTopBarWithBackButton( modifier = Modifier.fillMaxWidth(), - title = "μˆ˜μ—… μΆ”κ°€ν•˜κΈ°", + title = stringResource(R.string.add_pt_session), onBackClick = onClickBack, showStoke = true, ) @@ -236,18 +244,18 @@ private fun AddPtSessionScreen( Description() Spacer(modifier = Modifier.height(48.dp)) Selector( - title = "νšŒμ› 선택", + title = stringResource(R.string.select_member), value = state.selectedMember?.traineeName ?: "", - placeholder = "νšŒμ›μ„ μž…λ ₯ν•΄μ£Όμ„Έμš”", + placeholder = stringResource(R.string.insert_memeber), onClick = onClickMember, ) Spacer(modifier = Modifier.height(48.dp)) Selector( - title = "PT λ‚ μ§œ", + title = stringResource(R.string.pt_date), value = state.selectedDate?.let { selectedDate -> dateFormatter.format(selectedDate, "yyyy/MM/dd") } ?: "", - placeholder = "λ‚ μ§œλ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”", + placeholder = stringResource(R.string.insert_date), onClick = onClickDate, ) Spacer(modifier = Modifier.height(48.dp)) @@ -295,13 +303,13 @@ private fun AddPtSessionScreen( @Composable private fun Description() { Text( - text = "μ–Έμ œ μˆ˜μ—…ν• κΉŒμš”?", + text = stringResource(R.string.when_to_have_pt), style = TnTTheme.typography.h2, color = TnTTheme.colors.neutralColors.Neutral950, ) Spacer(modifier = Modifier.height(8.dp)) Text( - text = "일정을 λ“±λ‘ν•˜λ©΄ νšŒμ›μ—κ²Œλ„ 일정이 λ“±λ‘λΌμš”", + text = stringResource(R.string.schedule_registered_for_member), style = TnTTheme.typography.body2Medium, color = TnTTheme.colors.neutralColors.Neutral500, ) @@ -346,7 +354,7 @@ private fun Selector( }, trailingComponent = { Icon( - painter = painterResource(R.drawable.ic_arrow_down), + painter = painterResource(ic_arrow_down), contentDescription = null, tint = TnTTheme.colors.neutralColors.Neutral400, ) @@ -368,7 +376,7 @@ private fun TimeSelector( ) { Row(modifier = modifier.fillMaxWidth()) { Selector( - title = "μ‹œμž‘ μ‹œκ°„", + title = stringResource(R.string.start_time), value = startTime?.let { dateFormatter.format(it, "HH:mm") } ?: "", @@ -390,7 +398,7 @@ private fun TimeSelector( .align(Alignment.Bottom), ) Selector( - title = "μ’…λ£Œ μ‹œκ°„", + title = stringResource(R.string.end_time), value = endTime?.let { dateFormatter.format(it, "HH:mm") } ?: "", @@ -408,7 +416,7 @@ private fun MinuteChips( onClickChip: (minute: Int) -> Unit, ) { Text( - text = "μˆ˜μ—… μ‹œκ°„", + text = stringResource(R.string.pt_time), style = TnTTheme.typography.body1Bold, color = TnTTheme.colors.neutralColors.Neutral900, ) @@ -444,7 +452,7 @@ private fun MinuteChip( onClick: (minute: Int) -> Unit, ) { TnTTextButton( - "+${minute}λΆ„", + stringResource(R.string.minute, minute), modifier = modifier, type = if (isSelected) ButtonType.RedOutline else ButtonType.GrayOutline, onClick = { onClick(minute) }, @@ -467,18 +475,18 @@ private fun TotalSessionMinute( ), ) { Icon( - painter = painterResource(R.drawable.ic_red_clock), + painter = painterResource(ic_red_clock), contentDescription = null, tint = Color.Unspecified, ) Spacer(modifier = Modifier.width(4.dp)) Text( text = buildAnnotatedString { - append("총 ") + append(stringResource(R.string.total_prefix)) withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append("${minute}λΆ„") } - append(" μˆ˜μ—…μ΄μ—μš”") + append(stringResource(R.string.minute_suffix)) }, style = TnTTheme.typography.body2Medium, color = TnTTheme.colors.neutralColors.Neutral900, @@ -493,7 +501,7 @@ private fun Memo( onValueChanged: (String) -> Unit, ) { Text( - text = "λ©”λͺ¨ν•˜κΈ°", + text = stringResource(R.string.write_memo), style = TnTTheme.typography.body1Bold, color = TnTTheme.colors.neutralColors.Neutral900, ) @@ -503,7 +511,7 @@ private fun Memo( onValueChange = onValueChanged, maxLength = 30, isError = isWarning, - warningMessage = "30자 미만으둜 μž…λ ₯ν•΄μ£Όμ„Έμš”", + warningMessage = stringResource(core_length_warning, 30), modifier = Modifier.fillMaxWidth(), ) } @@ -520,7 +528,7 @@ private fun MembersBottomSheetContent( modifier = modifier.heightIn(max = 708.dp), ) { SheetTopBar( - title = "νšŒμ› μ„ νƒν•˜κΈ°", + title = stringResource(R.string.select_member), onDismissRequest = onDismissRequest, ) LazyColumn { @@ -564,7 +572,7 @@ private fun MemberItem( ) if (isSelected) { Icon( - painter = painterResource(R.drawable.ic_check_true), + painter = painterResource(ic_check_true), contentDescription = null, tint = Color.Unspecified, ) @@ -596,7 +604,7 @@ private fun CalendarBottomSheetContent( verticalArrangement = Arrangement.Center, ) { SheetTopBar( - title = "PT λ‚ μ§œ μ„ νƒν•˜κΈ°", + title = stringResource(R.string.select_pt_date), onDismissRequest = onDismissRequest, ) Column( @@ -695,7 +703,7 @@ private fun SheetTopBar( .size(32.dp), ) { Icon( - painter = painterResource(R.drawable.ic_delete), + painter = painterResource(ic_delete), contentDescription = null, ) } @@ -709,7 +717,7 @@ private fun SheetConfirm( onClick: () -> Unit, ) { TnTTextButton( - text = stringResource(coreR.string.ok), + text = stringResource(core_ok), modifier = Modifier .fillMaxWidth() .padding(horizontal = 20.dp), @@ -729,10 +737,10 @@ private fun Dialog( DialogState.NONE -> Unit DialogState.CHECK_CANCEL_ADD -> { TnTIconPopupDialog( - title = "μˆ˜μ—… 등둝을 μ·¨μ†Œν• κΉŒμš”?", - content = "일정이 μ €μž₯λ˜μ§€ μ•Šμ•„μš”", - leftButtonText = stringResource(coreR.string.cancel), - rightButtonText = stringResource(coreR.string.ok), + title = stringResource(R.string.cancel_pt_registration), + content = stringResource(R.string.schedule_will_not_be_saved), + leftButtonText = stringResource(core_cancel), + rightButtonText = stringResource(core_ok), onLeftButtonClick = onDismissDialog, onRightButtonClick = onClickConfirm, onDismiss = onDismissDialog, @@ -741,9 +749,9 @@ private fun Dialog( DialogState.SUCCESS_ADD -> { TnTSingleButtonPopupDialog( - title = "μˆ˜μ—… 일정이 μΆ”κ°€λμ–΄μš”", - content = "λ“±λ‘λœ 일정은 νŠΈλ ˆμ΄λ‹ˆμ—κ²Œλ„ ν‘œμ‹œλΌμš”!", - buttonText = stringResource(coreR.string.ok), + title = stringResource(R.string.added_pt_schedule), + content = stringResource(R.string.schedule_shown_to_trainee), + buttonText = stringResource(core_ok), cancelable = false, onButtonClick = onClickConfirm, onDismiss = onDismissDialog, diff --git a/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionViewModel.kt b/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionViewModel.kt index 1f92b033..52a63de8 100644 --- a/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionViewModel.kt +++ b/feature/trainer/addptsession/src/main/java/co/kr/tnt/trainer/addptsession/AddPtSessionViewModel.kt @@ -1,13 +1,16 @@ package co.kr.tnt.trainer.addptsession import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.repository.TrainerRepository +import co.kr.tnt.feature.trainer.addptsession.R import co.kr.tnt.trainer.addptsession.AddPtSessionContract.AddPtSessionSideEffect import co.kr.tnt.trainer.addptsession.AddPtSessionContract.AddPtSessionUiEvent import co.kr.tnt.trainer.addptsession.AddPtSessionContract.AddPtSessionUiState import co.kr.tnt.trainer.addptsession.AddPtSessionContract.AddPtSessionUiState.BottomSheetType import co.kr.tnt.trainer.addptsession.AddPtSessionContract.AddPtSessionUiState.DialogState import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @@ -25,7 +28,11 @@ internal class AddPtSessionViewModel @Inject constructor( }.onSuccess { members -> updateState { copy(members = members) } }.onFailure { - sendEffect(AddPtSessionSideEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect( + AddPtSessionSideEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } } } @@ -95,7 +102,11 @@ internal class AddPtSessionViewModel @Inject constructor( private fun postPtSession() { if (currentState.isEnableComplete.not()) { - sendEffect(AddPtSessionSideEffect.ShowToast("ν•„μˆ˜ μž…λ ₯ ν•­λͺ©μ„ λͺ¨λ‘ μž…λ ₯ν•΄μ£Όμ„Έμš”")) + sendEffect( + AddPtSessionSideEffect.ShowToast( + DisplayText.Resource(R.string.fill_required_fields), + ), + ) return } @@ -114,7 +125,12 @@ internal class AddPtSessionViewModel @Inject constructor( }.onSuccess { updateState { copy(dialogState = DialogState.SUCCESS_ADD) } }.onFailure { throwable -> - sendEffect(AddPtSessionSideEffect.ShowToast(throwable.message ?: "μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect( + AddPtSessionSideEffect.ShowToast( + throwable.message?.let(DisplayText::Plain) + ?: DisplayText.Resource(core_failed_to_server_request), + ), + ) }.also { updateState { copy(isLoading = false) } } diff --git a/feature/trainer/addptsession/src/main/res/values/strings.xml b/feature/trainer/addptsession/src/main/res/values/strings.xml new file mode 100644 index 00000000..ea6d4ed2 --- /dev/null +++ b/feature/trainer/addptsession/src/main/res/values/strings.xml @@ -0,0 +1,26 @@ + + + ν•„μˆ˜ μž…λ ₯ ν•­λͺ©μ„ λͺ¨λ‘ μž…λ ₯ν•΄μ£Όμ„Έμš” + μ‹œμž‘ μ‹œκ°„ μ„ νƒν•˜κΈ° + μ’…λ£Œ μ‹œκ°„ μ„ νƒν•˜κΈ° + μˆ˜μ—… μΆ”κ°€ν•˜κΈ° + νšŒμ› 선택 + νšŒμ›μ„ μž…λ ₯ν•΄μ£Όμ„Έμš” + PT λ‚ μ§œ + λ‚ μ§œλ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš” + μ–Έμ œ μˆ˜μ—…ν• κΉŒμš”? + 일정을 λ“±λ‘ν•˜λ©΄ νšŒμ›μ—κ²Œλ„ 일정이 λ“±λ‘λΌμš” + μ‹œμž‘ μ‹œκ°„ + μ’…λ£Œ μ‹œκ°„ + μˆ˜μ—… μ‹œκ°„ + +%1$sλΆ„ + 총 %1$sλΆ„ μˆ˜μ—…μ΄μ—μš” + λ©”λͺ¨ν•˜κΈ° + PT λ‚ μ§œ μ„ νƒν•˜κΈ° + μˆ˜μ—… 등둝을 μ·¨μ†Œν• κΉŒμš”? + 일정이 μ €μž₯λ˜μ§€ μ•Šμ•„μš” + μˆ˜μ—… 일정이 μΆ”κ°€λμ–΄μš” + λ“±λ‘λœ 일정은 νŠΈλ ˆμ΄λ‹ˆμ—κ²Œλ„ ν‘œμ‹œλΌμš”! + "총 " + " μˆ˜μ—…μ΄μ—μš”" + diff --git a/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TraineeProfilePage.kt b/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TraineeProfilePage.kt index 9805a9f3..483ad47f 100644 --- a/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TraineeProfilePage.kt +++ b/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TraineeProfilePage.kt @@ -32,6 +32,13 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import co.kr.tnt.core.ui.R.string.core_age_label +import co.kr.tnt.core.ui.R.string.core_age_unit +import co.kr.tnt.core.ui.R.string.core_height_label +import co.kr.tnt.core.ui.R.string.core_height_unit +import co.kr.tnt.core.ui.R.string.core_start +import co.kr.tnt.core.ui.R.string.core_weight_label +import co.kr.tnt.core.ui.R.string.core_weight_unit import co.kr.tnt.designsystem.component.TnTProfileImage import co.kr.tnt.designsystem.component.button.TnTBottomButton import co.kr.tnt.designsystem.theme.TnTTheme @@ -115,17 +122,17 @@ internal fun TraineeProfilePage( Spacer(Modifier.height(32.dp)) val traineeInfo = listOfNotNull( trainee.age?.let { - stringResource(uiResource.string.age_label) to - it.toString() + stringResource(uiResource.string.age_unit) + stringResource(core_age_label) to + it.toString() + stringResource(core_age_unit) }, trainee.height?.let { - stringResource(uiResource.string.height_label) to - it.toString() + stringResource(uiResource.string.height_unit) + stringResource(core_height_label) to + it.toString() + stringResource(core_height_unit) }, trainee.weight?.let { - stringResource(uiResource.string.weight_label) to + stringResource(core_weight_label) to it.toString() - .removeSuffix(".0") + stringResource(uiResource.string.weight_unit) + .removeSuffix(".0") + stringResource(core_weight_unit) }, ) @@ -155,7 +162,7 @@ internal fun TraineeProfilePage( Spacer(Modifier.height(24.dp)) } TnTBottomButton( - text = stringResource(uiResource.string.start), + text = stringResource(core_start), onClick = onClickNext, modifier = Modifier.align(Alignment.BottomCenter), ) @@ -204,7 +211,7 @@ private fun TextWithBackground( .padding(horizontal = 16.dp, vertical = 12.dp), ) { Text( - text = text.ifEmpty { "λ―Έμž…λ ₯" }, + text = text.ifEmpty { stringResource(R.string.not_entered) }, style = TnTTheme.typography.label1Medium, color = if (text.isEmpty()) { diff --git a/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectCompletePage.kt b/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectCompletePage.kt index 0443e1c5..3129fb28 100644 --- a/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectCompletePage.kt +++ b/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectCompletePage.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import co.kr.tnt.core.ui.R.string.core_next import co.kr.tnt.designsystem.component.TnTProfileImage import co.kr.tnt.designsystem.component.button.TnTBottomButton import co.kr.tnt.designsystem.theme.TnTTheme @@ -96,7 +97,7 @@ internal fun TrainerConnectCompletePage( } } TnTBottomButton( - text = stringResource(uiResource.string.next), + text = stringResource(core_next), onClick = onClickNext, modifier = Modifier.align(Alignment.BottomCenter), ) diff --git a/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectContract.kt b/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectContract.kt index 80dbafea..58bb7cde 100644 --- a/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectContract.kt +++ b/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectContract.kt @@ -4,6 +4,7 @@ import co.kr.tnt.domain.model.User import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.resource.DisplayText internal class TrainerConnectContract { data class TrainerConnectUiState( @@ -24,7 +25,7 @@ internal class TrainerConnectContract { sealed interface TrainerConnectSideEffect : UiSideEffect { data object NavigateToBack : TrainerConnectSideEffect data object NavigateToHome : TrainerConnectSideEffect - data class ShowToast(val message: String) : TrainerConnectSideEffect + data class ShowToast(val message: DisplayText) : TrainerConnectSideEffect } enum class TrainerConnectPage { diff --git a/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectScreen.kt b/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectScreen.kt index 2398a86b..9c5b7f3e 100644 --- a/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectScreen.kt +++ b/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectScreen.kt @@ -3,6 +3,7 @@ package co.kr.tnt.trainer.connect 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 @@ -19,6 +20,7 @@ internal fun TrainerConnectRoute( navigateToHome: (Boolean) -> Unit, viewModel: TrainerConnectViewModel = hiltViewModel(), ) { + val context = LocalContext.current val snackbar = LocalSnackbar.current val state by viewModel.uiState.collectAsStateWithLifecycle() @@ -37,7 +39,7 @@ internal fun TrainerConnectRoute( when (effect) { TrainerConnectSideEffect.NavigateToBack -> navigateToPrevious() TrainerConnectSideEffect.NavigateToHome -> navigateToHome(true) - is TrainerConnectSideEffect.ShowToast -> snackbar.show(effect.message) + is TrainerConnectSideEffect.ShowToast -> snackbar.show(effect.message.asString(context)) } } } diff --git a/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectViewModel.kt b/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectViewModel.kt index 38172391..13ffb596 100644 --- a/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectViewModel.kt +++ b/feature/trainer/connect/src/main/java/co/kr/tnt/trainer/connect/TrainerConnectViewModel.kt @@ -1,6 +1,7 @@ package co.kr.tnt.trainer.connect import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.model.User import co.kr.tnt.domain.model.trainer.TrainerManagementMemberCount import co.kr.tnt.domain.repository.ConnectRepository @@ -9,6 +10,7 @@ import co.kr.tnt.trainer.connect.TrainerConnectContract.TrainerConnectSideEffect import co.kr.tnt.trainer.connect.TrainerConnectContract.TrainerConnectUiEvent import co.kr.tnt.trainer.connect.TrainerConnectContract.TrainerConnectUiState import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @@ -62,7 +64,7 @@ internal class TrainerConnectViewModel @Inject constructor( ) } }.onFailure { - sendEffect(TrainerConnectSideEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect(TrainerConnectSideEffect.ShowToast(DisplayText.Resource(core_failed_to_server_request))) } } } diff --git a/feature/trainer/connect/src/main/res/values/strings.xml b/feature/trainer/connect/src/main/res/values/strings.xml index a703db0f..8bb973ae 100644 --- a/feature/trainer/connect/src/main/res/values/strings.xml +++ b/feature/trainer/connect/src/main/res/values/strings.xml @@ -5,4 +5,5 @@ ν•¨κ»˜ν•  νŠΈλ ˆμ΄λ‹ˆλŠ” 이런 λΆ„μ΄μ—μš”! PT λͺ©ν‘œ μ£Όμ˜μ‚¬ν•­ + λ―Έμž…λ ₯ diff --git a/feature/trainer/feedback/src/main/java/co/kr/tnt/trainer/feedback/TrainerFeedbackScreen.kt b/feature/trainer/feedback/src/main/java/co/kr/tnt/trainer/feedback/TrainerFeedbackScreen.kt index b0eede23..8c4995c0 100644 --- a/feature/trainer/feedback/src/main/java/co/kr/tnt/trainer/feedback/TrainerFeedbackScreen.kt +++ b/feature/trainer/feedback/src/main/java/co/kr/tnt/trainer/feedback/TrainerFeedbackScreen.kt @@ -11,9 +11,12 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import co.kr.tnt.core.ui.R.string.core_no_records_yet import co.kr.tnt.designsystem.theme.TnTTheme +import co.kr.tnt.feature.trainer.feedback.R import co.kr.tnt.ui.component.TnTCountTopBar @Composable @@ -35,7 +38,7 @@ private fun TrainerFeedbackScreen( .padding(padding), ) { TnTCountTopBar( - title = "ν”Όλ“œλ°±", + title = stringResource(R.string.feedback), count = 0, ) EmptyFeedback() @@ -50,13 +53,13 @@ private fun EmptyFeedback() { horizontalAlignment = Alignment.CenterHorizontally, ) { Text( - text = "아직 λ“±λ‘λœ 기둝이 μ—†μ–΄μš”", + text = stringResource(core_no_records_yet), color = TnTTheme.colors.neutralColors.Neutral600, style = TnTTheme.typography.body2Bold, ) Spacer(modifier = Modifier.height(4.dp)) Text( - text = "νŠΈλ ˆμ΄λ‹ˆκ°€ 기둝을 μ „μ†‘ν•˜λ©΄ 여기에 ν‘œμ‹œλΌμš”!", + text = stringResource(R.string.records_shown_when_trainee_sends), color = TnTTheme.colors.neutralColors.Neutral400, style = TnTTheme.typography.label1Medium, ) diff --git a/feature/trainer/feedback/src/main/res/values/strings.xml b/feature/trainer/feedback/src/main/res/values/strings.xml new file mode 100644 index 00000000..3cea04b2 --- /dev/null +++ b/feature/trainer/feedback/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + + ν”Όλ“œλ°± + νŠΈλ ˆμ΄λ‹ˆκ°€ 기둝을 μ „μ†‘ν•˜λ©΄ 여기에 ν‘œμ‹œλΌμš”! + diff --git a/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeContract.kt b/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeContract.kt index 1dede40b..15de08cf 100644 --- a/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeContract.kt +++ b/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeContract.kt @@ -5,6 +5,7 @@ import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState import co.kr.tnt.ui.model.SnackbarType +import co.kr.tnt.ui.resource.DisplayText import java.time.LocalDate import java.time.YearMonth @@ -40,7 +41,7 @@ internal class TrainerHomeContract { data object NavigateToAddPtSession : TrainerHomeSideEffect data object NavigateToInvite : TrainerHomeSideEffect data class ShowToast( - val message: String, + val message: DisplayText, val type: SnackbarType = SnackbarType.WARNING, ) : TrainerHomeSideEffect } diff --git a/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeScreen.kt b/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeScreen.kt index 52a60206..2c6fa741 100644 --- a/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeScreen.kt +++ b/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeScreen.kt @@ -38,7 +38,13 @@ 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 co.kr.tnt.core.designsystem.R +import co.kr.tnt.core.designsystem.R.drawable.ic_add +import co.kr.tnt.core.designsystem.R.drawable.ic_fill_check_false +import co.kr.tnt.core.designsystem.R.drawable.ic_fill_check_true +import co.kr.tnt.core.designsystem.R.drawable.img_default +import co.kr.tnt.core.ui.R.string.core_connect +import co.kr.tnt.core.ui.R.string.core_do_not_see_for_three_days +import co.kr.tnt.core.ui.R.string.core_next_time import co.kr.tnt.designsystem.component.TnTPopupDialog import co.kr.tnt.designsystem.component.button.TnTFabButton import co.kr.tnt.designsystem.component.calendar.TnTIndicatorMonthCalendar @@ -50,6 +56,7 @@ import co.kr.tnt.designsystem.snackbar.LocalSnackbar import co.kr.tnt.designsystem.theme.TnTTheme import co.kr.tnt.domain.model.PtSession import co.kr.tnt.domain.utils.DateFormatter +import co.kr.tnt.feature.trainer.home.R import co.kr.tnt.navigation.model.ScreenMode import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeSideEffect import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeUiEvent @@ -65,7 +72,6 @@ import kotlinx.coroutines.launch import java.time.DayOfWeek import java.time.LocalDate import java.time.YearMonth -import co.kr.tnt.core.ui.R as coreR @Composable internal fun TrainerHomeRoute( @@ -76,6 +82,7 @@ internal fun TrainerHomeRoute( navigateToInvite: (ScreenMode) -> Unit, ) { val toast = LocalSnackbar.current + val context = LocalContext.current val state by viewModel.uiState.collectAsStateWithLifecycle() TrainerHomeScreen( @@ -95,7 +102,7 @@ internal fun TrainerHomeRoute( TrainerHomeSideEffect.NavigateToAddPtSession -> navigateToAddPtSession(state.selectedDay.toString()) TrainerHomeSideEffect.NavigateToInvite -> navigateToInvite(ScreenMode.CLOSE) is TrainerHomeSideEffect.ShowToast -> toast.show( - message = effect.message, + message = effect.message.asString(context), icon = effect.type.iconRes, ) } @@ -106,12 +113,12 @@ internal fun TrainerHomeRoute( TrainerHomeUiState.DialogState.NONE -> Unit TrainerHomeUiState.DialogState.HOME_CONNECT -> { TnTCheckToggleDialog( - title = "νšŒμ›μ„ μ—°κ²°ν•΄ μ£Όμ„Έμš”", - content = "μ—°κ²°ν•˜μ§€ μ•Šμ„ 경우 μˆ˜μ—…μ„ μΆ”κ°€ν•  수 μ—†μ–΄μš”\nμ΄ˆλŒ€ μ½”λ“œλ₯Ό 볡사해 μ—°κ²°ν•΄μ£Όμ‹œκ² μ–΄μš”?", + title = stringResource(R.string.please_connect_member), + content = stringResource(R.string.cannot_add_pt_without_connection), isChecked = state.isDialogHiddenForThreeDays, - checkToggleText = stringResource(coreR.string.do_not_see_for_three_days), - leftButtonText = stringResource(coreR.string.next_time), - rightButtonText = stringResource(coreR.string.connect), + checkToggleText = stringResource(core_do_not_see_for_three_days), + leftButtonText = stringResource(core_next_time), + rightButtonText = stringResource(core_connect), onLeftButtonClick = { viewModel.setEvent(TrainerHomeUiEvent.OnDismissDialog) }, onRightButtonClick = { viewModel.setEvent(TrainerHomeUiEvent.OnConfirmConnectDialog) }, onClickCheck = { viewModel.setEvent(TrainerHomeUiEvent.OnChangeHideDialogOption) }, @@ -121,10 +128,10 @@ internal fun TrainerHomeRoute( TrainerHomeUiState.DialogState.ADD_PT_CONNECT -> { TnTPopupDialog( - title = "νšŒμ›μ„ μ—°κ²°ν•΄ μ£Όμ„Έμš”", - content = "μ—°κ²°ν•˜μ§€ μ•Šμ„ 경우 μˆ˜μ—…μ„ μΆ”κ°€ν•  수 μ—†μ–΄μš”\nμ΄ˆλŒ€ μ½”λ“œλ₯Ό 볡사해 μ—°κ²°ν•΄μ£Όμ‹œκ² μ–΄μš”?", - leftButtonText = stringResource(coreR.string.next_time), - rightButtonText = stringResource(coreR.string.connect), + title = stringResource(R.string.please_connect_member), + content = stringResource(R.string.cannot_add_pt_without_connection), + leftButtonText = stringResource(core_next_time), + rightButtonText = stringResource(core_connect), onLeftButtonClick = { viewModel.setEvent(TrainerHomeUiEvent.OnDismissDialog) }, onRightButtonClick = { viewModel.setEvent(TrainerHomeUiEvent.OnConfirmConnectDialog) }, onDismiss = { viewModel.setEvent(TrainerHomeUiEvent.OnDismissDialog) }, @@ -227,11 +234,11 @@ private fun TrainerHomeScreen( bottom = 22.dp, end = 28.dp, ), - text = "μˆ˜μ—… μΆ”κ°€", + text = stringResource(R.string.add_pt_session), enabled = true, leadingComposable = { Icon( - painter = painterResource(R.drawable.ic_add), + painter = painterResource(ic_add), contentDescription = "add pt session", ) }, @@ -302,7 +309,7 @@ private fun DailyPtSessionTitle( ) { append(sessionCount.toString()) } - append("개의 μˆ˜μ—…μ΄ μžˆμ–΄μš”") + append(stringResource(R.string.pt_session_count_suffix)) }, style = TnTTheme.typography.label2Medium, color = TnTTheme.colors.neutralColors.Neutral800, @@ -320,13 +327,13 @@ private fun EmptyPtSessions(modifier: Modifier = Modifier) { horizontalAlignment = Alignment.CenterHorizontally, ) { Text( - text = "아직 λ“±λ‘λœ μˆ˜μ—…μ΄ μ—†μ–΄μš”.", + text = stringResource(R.string.no_pt_session_yet), style = TnTTheme.typography.body2Bold, color = TnTTheme.colors.neutralColors.Neutral600, ) Spacer(modifier = Modifier.height(4.dp)) Text( - text = "μΆ”κ°€ λ²„νŠΌμ„ 눌러 PT μˆ˜μ—… 일정을 μΆ”κ°€ν•΄ λ³΄μ„Έμš”", + text = stringResource(R.string.press_add_button_to_add_pt_session), style = TnTTheme.typography.label1Medium, color = TnTTheme.colors.neutralColors.Neutral400, ) @@ -343,8 +350,8 @@ private fun PtSessionCard( val painter = rememberAsyncImagePainter( model = ImageRequest.Builder(LocalContext.current) .data(ptSession.traineeProfileUrl) - .placeholder(R.drawable.img_default) - .error(R.drawable.img_default) + .placeholder(img_default) + .error(img_default) .build(), ) @@ -367,9 +374,9 @@ private fun PtSessionCard( .padding(4.dp), painter = painterResource( if (ptSession.isCompleted) { - R.drawable.ic_fill_check_true + ic_fill_check_true } else { - R.drawable.ic_fill_check_false + ic_fill_check_false }, ), contentDescription = null, @@ -382,10 +389,10 @@ private fun PtSessionCard( TnTSessionRecordCard( isTrainer = true, name = traineeName, - tagText = "${round}회차 μˆ˜μ—…", + tagText = stringResource(R.string.pt_session_count, round), startTime = dateFormatter.format(startTime, "a hh:mm"), endTime = dateFormatter.format(endTime, "a hh:mm"), - defaultImage = painterResource(R.drawable.img_default), + defaultImage = painterResource(img_default), profileImage = painter, leadingEmoji = "\uD83D\uDCAA", showSessionRecordCreation = false, diff --git a/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeViewModel.kt b/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeViewModel.kt index f540964f..86099954 100644 --- a/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeViewModel.kt +++ b/feature/trainer/home/src/main/java/co/kr/tnt/trainer/home/TrainerHomeViewModel.kt @@ -1,16 +1,19 @@ package co.kr.tnt.trainer.home import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.model.PtSession import co.kr.tnt.domain.model.trainer.TrainerDailyPtSessionCount import co.kr.tnt.domain.repository.ConnectRepository import co.kr.tnt.domain.repository.TrainerRepository +import co.kr.tnt.feature.trainer.home.R import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeSideEffect import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeUiEvent import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeUiState import co.kr.tnt.trainer.home.TrainerHomeContract.TrainerHomeUiState.DialogState import co.kr.tnt.ui.base.BaseViewModel import co.kr.tnt.ui.model.SnackbarType +import co.kr.tnt.ui.resource.DisplayText import com.kizitonwose.calendar.core.yearMonth import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.async @@ -77,7 +80,11 @@ internal class TrainerHomeViewModel @Inject constructor( results.forEach(::updateMonthlyPtSessionCounts) }.onFailure { - sendEffect(TrainerHomeSideEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect( + TrainerHomeSideEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } } } @@ -97,7 +104,11 @@ internal class TrainerHomeViewModel @Inject constructor( updateState { copy(selectedDayPtSessions = selectedDayPtSessions) } }.onFailure { updateState { copy(selectedDayPtSessions = null) } - sendEffect(TrainerHomeSideEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect( + TrainerHomeSideEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } } } @@ -120,12 +131,18 @@ internal class TrainerHomeViewModel @Inject constructor( getDailyPtSessions(currentState.selectedDay) sendEffect( TrainerHomeSideEffect.ShowToast( - message = "PT μˆ˜μ—…μ„ μ™„λ£Œν–ˆμ–΄μš”", + message = DisplayText.Resource(R.string.pt_completed), type = SnackbarType.SUCCESS, ), ) }.onFailure { throwable -> - sendEffect(TrainerHomeSideEffect.ShowToast(throwable.message ?: "μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect( + TrainerHomeSideEffect.ShowToast( + throwable.message?.let { message -> + DisplayText.Plain(message) + } ?: DisplayText.Resource(core_failed_to_server_request), + ), + ) } } } @@ -140,7 +157,7 @@ internal class TrainerHomeViewModel @Inject constructor( updateState { copy(selectedDayPtSessions = cachedDailyPtSession[day]) } } }.onFailure { - sendEffect(TrainerHomeSideEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect(TrainerHomeSideEffect.ShowToast(DisplayText.Resource(core_failed_to_server_request))) } } } diff --git a/feature/trainer/home/src/main/res/values/strings.xml b/feature/trainer/home/src/main/res/values/strings.xml new file mode 100644 index 00000000..f9c25c95 --- /dev/null +++ b/feature/trainer/home/src/main/res/values/strings.xml @@ -0,0 +1,11 @@ + + + PT μˆ˜μ—…μ„ μ™„λ£Œν–ˆμ–΄μš” + νšŒμ›μ„ μ—°κ²°ν•΄ μ£Όμ„Έμš” + μ—°κ²°ν•˜μ§€ μ•Šμ„ 경우 μˆ˜μ—…μ„ μΆ”κ°€ν•  수 μ—†μ–΄μš”\nμ΄ˆλŒ€ μ½”λ“œλ₯Ό 볡사해 μ—°κ²°ν•΄μ£Όμ‹œκ² μ–΄μš”? + μˆ˜μ—… μΆ”κ°€ + 개의 μˆ˜μ—…μ΄ μžˆμ–΄μš” + 아직 λ“±λ‘λœ μˆ˜μ—…μ΄ μ—†μ–΄μš”. + μΆ”κ°€ λ²„νŠΌμ„ 눌러 PT μˆ˜μ—… 일정을 μΆ”κ°€ν•΄ λ³΄μ„Έμš” + %1$s회차 μˆ˜μ—… + diff --git a/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteContract.kt b/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteContract.kt index e86e4cda..46b6793f 100644 --- a/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteContract.kt +++ b/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteContract.kt @@ -3,6 +3,7 @@ package co.kr.tnt.trainer.invite import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.resource.DisplayText internal class TrainerInviteContract { data class TrainerInviteUiState( @@ -19,7 +20,7 @@ internal class TrainerInviteContract { sealed interface TrainerInviteSideEffect : UiSideEffect { data object NavigateToBack : TrainerInviteSideEffect data object NavigateToHome : TrainerInviteSideEffect - data class ShowToast(val message: String) : TrainerInviteSideEffect + data class ShowToast(val message: DisplayText) : TrainerInviteSideEffect data class CopyToClipBoard(val value: String) : TrainerInviteSideEffect } } diff --git a/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteScreen.kt b/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteScreen.kt index 41965cd9..eafb4be9 100644 --- a/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteScreen.kt +++ b/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteScreen.kt @@ -21,6 +21,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString @@ -28,6 +29,8 @@ 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 co.kr.tnt.core.ui.R.string.core_connect +import co.kr.tnt.core.ui.R.string.core_skip import co.kr.tnt.designsystem.component.TnTTopBar import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton import co.kr.tnt.designsystem.component.button.TnTTextButton @@ -41,7 +44,6 @@ import co.kr.tnt.trainer.invite.TrainerInviteContract.TrainerInviteSideEffect import co.kr.tnt.trainer.invite.TrainerInviteContract.TrainerInviteUiEvent import co.kr.tnt.trainer.invite.TrainerInviteContract.TrainerInviteUiState import kotlinx.coroutines.flow.collectLatest -import co.kr.tnt.core.ui.R as coreR @Composable internal fun TrainerInviteRoute( @@ -50,6 +52,7 @@ internal fun TrainerInviteRoute( navigateToHome: (Boolean) -> Unit, viewModel: TrainerInviteViewModel = hiltViewModel(), ) { + val context = LocalContext.current val snackbar = LocalSnackbar.current val state by viewModel.uiState.collectAsStateWithLifecycle() val clipboardManager = LocalClipboardManager.current @@ -68,7 +71,7 @@ internal fun TrainerInviteRoute( when (effect) { TrainerInviteSideEffect.NavigateToBack -> navigateToPrevious() TrainerInviteSideEffect.NavigateToHome -> navigateToHome(true) - is TrainerInviteSideEffect.ShowToast -> snackbar.show(effect.message) + is TrainerInviteSideEffect.ShowToast -> snackbar.show(effect.message.asString(context)) is TrainerInviteSideEffect.CopyToClipBoard -> clipboardManager.setText(AnnotatedString(effect.value)) } @@ -105,10 +108,10 @@ internal fun TrainerInviteScreen( ScreenMode.SKIP -> { TnTTopBar( - title = stringResource(coreR.string.connect), + title = stringResource(core_connect), trailingComponent = { Text( - text = stringResource(coreR.string.skip), + text = stringResource(core_skip), color = TnTTheme.colors.neutralColors.Neutral400, style = TnTTheme.typography.body2Medium, modifier = Modifier.clickable { diff --git a/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteViewModel.kt b/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteViewModel.kt index 63e891c3..635f5806 100644 --- a/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteViewModel.kt +++ b/feature/trainer/invite/src/main/java/co/kr/tnt/trainer/invite/TrainerInviteViewModel.kt @@ -1,11 +1,14 @@ package co.kr.tnt.trainer.invite import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.repository.ConnectRepository +import co.kr.tnt.feature.trainer.invite.R import co.kr.tnt.trainer.invite.TrainerInviteContract.TrainerInviteSideEffect import co.kr.tnt.trainer.invite.TrainerInviteContract.TrainerInviteUiEvent import co.kr.tnt.trainer.invite.TrainerInviteContract.TrainerInviteUiState import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @@ -23,7 +26,11 @@ internal class TrainerInviteViewModel @Inject constructor( TrainerInviteUiEvent.OnClickSkip -> navigateToHome() is TrainerInviteUiEvent.OnClickCode -> { sendEffect(TrainerInviteSideEffect.CopyToClipBoard(event.code)) - sendEffect(TrainerInviteSideEffect.ShowToast("μ½”λ“œκ°€ λ³΅μ‚¬λ˜μ—ˆμ–΄μš”!")) + sendEffect( + TrainerInviteSideEffect.ShowToast( + DisplayText.Resource(R.string.code_is_copied), + ), + ) } } } @@ -39,7 +46,11 @@ internal class TrainerInviteViewModel @Inject constructor( }.onSuccess { result -> updateState { copy(inviteCode = result.invitationCode) } }.onFailure { - sendEffect(TrainerInviteSideEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect( + TrainerInviteSideEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } } } @@ -51,7 +62,11 @@ internal class TrainerInviteViewModel @Inject constructor( }.onSuccess { result -> updateState { copy(inviteCode = result.invitationCode) } }.onFailure { - sendEffect(TrainerInviteSideEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect( + TrainerInviteSideEffect.ShowToast( + DisplayText.Resource(core_failed_to_server_request), + ), + ) } } } diff --git a/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMemberContract.kt b/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMemberContract.kt index 09337727..4c200fa8 100644 --- a/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMemberContract.kt +++ b/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMemberContract.kt @@ -4,6 +4,7 @@ import co.kr.tnt.domain.model.MemberInfo import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.resource.DisplayText internal class TrainerMemberContract { data class TrainerMemberUiState( @@ -16,6 +17,6 @@ internal class TrainerMemberContract { sealed interface TrainerMemberSideEffect : UiSideEffect { data object NavigateToInvite : TrainerMemberSideEffect - data class ShowToast(val message: String) : TrainerMemberSideEffect + data class ShowToast(val message: DisplayText) : TrainerMemberSideEffect } } diff --git a/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMembersScreen.kt b/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMembersScreen.kt index 9298a7a3..21602fec 100644 --- a/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMembersScreen.kt +++ b/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMembersScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -27,10 +28,11 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import co.kr.tnt.core.designsystem.R +import co.kr.tnt.core.designsystem.R.drawable.img_default import co.kr.tnt.designsystem.component.card.TnTMemberProfileCard import co.kr.tnt.designsystem.theme.TnTTheme import co.kr.tnt.domain.model.MemberInfo +import co.kr.tnt.feature.trainer.members.R import co.kr.tnt.navigation.model.ScreenMode import co.kr.tnt.trainer.members.TrainerMemberContract.TrainerMemberUiState import co.kr.tnt.ui.component.TnTCountTopBar @@ -65,7 +67,7 @@ private fun TrainerMembersScreen( ) { Column(modifier = Modifier.fillMaxSize()) { TnTCountTopBar( - title = "λ‚΄ νšŒμ›", + title = stringResource(R.string.my_member), count = state.memberList.size, trailingComponent = { MemberInviteButton(onClickInviteButton) @@ -104,7 +106,7 @@ private fun MemberInviteButton( ), ) { Text( - text = "νšŒμ› μ΄ˆλŒ€ν•˜κΈ°", + text = stringResource(R.string.invite_member), color = TnTTheme.colors.neutralColors.Neutral600, style = TnTTheme.typography.label2Medium, overflow = TextOverflow.Ellipsis, @@ -121,14 +123,14 @@ private fun EmptyMemberList(modifier: Modifier = Modifier) { horizontalAlignment = Alignment.CenterHorizontally, ) { Text( - text = "아직 μ—°κ²°λœ νšŒμ›μ΄ μ—†μ–΄μš”", + text = stringResource(R.string.no_connected_member_yet), color = TnTTheme.colors.neutralColors.Neutral600, style = TnTTheme.typography.body2Bold, textAlign = TextAlign.Center, ) Spacer(Modifier.height(4.dp)) Text( - text = "μΆ”κ°€ λ²„νŠΌμ„ 눌러 νšŒμ›μ„ μΆ”κ°€ν•΄ λ³΄μ„Έμš”", + text = stringResource(R.string.press_add_button_to_add_member), color = TnTTheme.colors.neutralColors.Neutral400, style = TnTTheme.typography.label1Medium, textAlign = TextAlign.Center, @@ -141,8 +143,8 @@ private fun MemberList(member: MemberInfo) { val painter = rememberAsyncImagePainter( model = ImageRequest.Builder(LocalContext.current) .data(member.profileUrl) - .placeholder(R.drawable.img_default) - .error(R.drawable.img_default) + .placeholder(img_default) + .error(img_default) .build(), ) // TODO : νšŒμ› 상세 νŽ˜μ΄μ§€ μ—°κ²° (배포 이후) diff --git a/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMembersViewModel.kt b/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMembersViewModel.kt index 49afdfd8..262d7d86 100644 --- a/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMembersViewModel.kt +++ b/feature/trainer/members/src/main/java/co/kr/tnt/trainer/members/TrainerMembersViewModel.kt @@ -1,11 +1,13 @@ package co.kr.tnt.trainer.members import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.repository.TrainerRepository import co.kr.tnt.trainer.members.TrainerMemberContract.TrainerMemberSideEffect import co.kr.tnt.trainer.members.TrainerMemberContract.TrainerMemberUiEvent import co.kr.tnt.trainer.members.TrainerMemberContract.TrainerMemberUiState import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @@ -32,7 +34,7 @@ internal class TrainerMembersViewModel @Inject constructor( }.onSuccess { members -> updateState { copy(memberList = members) } }.onFailure { - sendEffect(TrainerMemberSideEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect(TrainerMemberSideEffect.ShowToast(DisplayText.Resource(core_failed_to_server_request))) } } } diff --git a/feature/trainer/members/src/main/res/values/strings.xml b/feature/trainer/members/src/main/res/values/strings.xml new file mode 100644 index 00000000..7b516f9d --- /dev/null +++ b/feature/trainer/members/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + + λ‚΄ νšŒμ› + νšŒμ› μ΄ˆλŒ€ν•˜κΈ° + 아직 μ—°κ²°λœ νšŒμ›μ΄ μ—†μ–΄μš” + μΆ”κ°€ λ²„νŠΌμ„ 눌러 νšŒμ›μ„ μΆ”κ°€ν•΄ λ³΄μ„Έμš” + diff --git a/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageContract.kt b/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageContract.kt index 68521a35..767717b4 100644 --- a/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageContract.kt +++ b/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageContract.kt @@ -4,6 +4,7 @@ import co.kr.tnt.domain.model.User import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.resource.DisplayText internal class TrainerMyPageContract { data class TrainerMyPageUiState( @@ -42,6 +43,6 @@ internal class TrainerMyPageContract { data class NavigateToWebView(val url: String) : TrainerMyPageSideEffect data object NavigateToOpenSourceLicense : TrainerMyPageSideEffect data class RequestPermission(val isExplicitlyDenied: Boolean) : TrainerMyPageSideEffect - data class ShowToast(val message: String) : TrainerMyPageSideEffect + data class ShowToast(val message: DisplayText) : TrainerMyPageSideEffect } } diff --git a/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageScreen.kt b/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageScreen.kt index bd1c0b91..f7a43d1b 100644 --- a/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageScreen.kt +++ b/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageScreen.kt @@ -32,6 +32,18 @@ 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 co.kr.tnt.core.ui.R.string.core_app_push_notification +import co.kr.tnt.core.ui.R.string.core_app_version +import co.kr.tnt.core.ui.R.string.core_cancel +import co.kr.tnt.core.ui.R.string.core_delete_account +import co.kr.tnt.core.ui.R.string.core_logout +import co.kr.tnt.core.ui.R.string.core_logout_complete_title +import co.kr.tnt.core.ui.R.string.core_logout_content +import co.kr.tnt.core.ui.R.string.core_logout_title +import co.kr.tnt.core.ui.R.string.core_ok +import co.kr.tnt.core.ui.R.string.core_open_source_license +import co.kr.tnt.core.ui.R.string.core_privacy_policy +import co.kr.tnt.core.ui.R.string.core_terms_of_service import co.kr.tnt.designsystem.component.TnTIconPopupDialog import co.kr.tnt.designsystem.component.TnTProfileImage import co.kr.tnt.designsystem.component.TnTSingleButtonPopupDialog @@ -59,7 +71,6 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.rememberMultiplePermissionsState import com.google.android.gms.oss.licenses.OssLicensesMenuActivity import co.kr.tnt.core.designsystem.R as designSystemR -import co.kr.tnt.core.ui.R as coreR @OptIn(ExperimentalPermissionsApi::class) @Composable @@ -108,7 +119,7 @@ internal fun TrainerMyPageRoute( when (effect) { TrainerMyPageSideEffect.NavigateToLogin -> navigateToLogin() is TrainerMyPageSideEffect.NavigateToWebView -> navigateToWebView(effect.url) - is TrainerMyPageSideEffect.ShowToast -> toast.show(effect.message) + is TrainerMyPageSideEffect.ShowToast -> toast.show(effect.message.asString(context)) is TrainerMyPageSideEffect.RequestPermission -> { if (effect.isExplicitlyDenied) { @@ -175,12 +186,12 @@ private fun TrainerMyPageScreen( horizontalArrangement = Arrangement.Center, ) { ManagementMemberCount( - title = "관리 쀑인 νšŒμ›", + title = stringResource(R.string.managing_member), count = state.user.memberCounts.activeCount, ) Spacer(modifier = Modifier.width(8.dp)) ManagementMemberCount( - title = "ν•¨κ»˜ ν–ˆλ˜ νšŒμ›", + title = stringResource(R.string.worked_together_member), count = state.user.memberCounts.totalCount, ) } @@ -192,7 +203,7 @@ private fun TrainerMyPageScreen( .padding(20.dp), ) { TnTMyPageButton( - text = stringResource(coreR.string.app_push_notification), + text = stringResource(core_app_push_notification), verticalPadding = 12.dp, enabled = false, trailingComponent = { @@ -209,17 +220,17 @@ private fun TrainerMyPageScreen( .padding(vertical = 12.dp), ) { TnTMyPageButton( - text = stringResource(coreR.string.terms_of_service), + text = stringResource(core_terms_of_service), onClick = onClickTermsOfService, verticalPadding = 8.dp, ) TnTMyPageButton( - text = stringResource(coreR.string.privacy_policy), + text = stringResource(core_privacy_policy), onClick = onClickPrivacy, verticalPadding = 8.dp, ) TnTMyPageButton( - text = stringResource(coreR.string.app_version), + text = stringResource(core_app_version), verticalPadding = 12.dp, enabled = false, onClick = onTogglePushNotification, @@ -232,7 +243,7 @@ private fun TrainerMyPageScreen( }, ) TnTMyPageButton( - text = stringResource(coreR.string.open_source_license), + text = stringResource(core_open_source_license), onClick = onClickOpenSourceLicense, verticalPadding = 8.dp, ) @@ -245,12 +256,12 @@ private fun TrainerMyPageScreen( .padding(vertical = 12.dp), ) { TnTMyPageButton( - text = stringResource(coreR.string.logout), + text = stringResource(core_logout), onClick = onClickLogout, verticalPadding = 8.dp, ) TnTMyPageButton( - text = stringResource(coreR.string.delete_account), + text = stringResource(core_delete_account), onClick = onClickDeleteAccount, verticalPadding = 8.dp, ) @@ -308,10 +319,10 @@ private fun Dialog( DialogState.NONE -> Unit DialogState.LOGOUT_CONFIRM -> { TnTIconPopupDialog( - title = stringResource(coreR.string.logout_title), - content = stringResource(coreR.string.logout_content), - leftButtonText = stringResource(coreR.string.cancel), - rightButtonText = stringResource(coreR.string.ok), + title = stringResource(core_logout_title), + content = stringResource(core_logout_content), + leftButtonText = stringResource(core_cancel), + rightButtonText = stringResource(core_ok), onLeftButtonClick = onDismissDialog, onRightButtonClick = onClickConfirm, onDismiss = onDismissDialog, @@ -320,9 +331,9 @@ private fun Dialog( DialogState.LOGOUT -> { TnTSingleButtonPopupDialog( - title = stringResource(coreR.string.logout_complete_title), - content = stringResource(coreR.string.logout_content), - buttonText = stringResource(coreR.string.ok), + title = stringResource(core_logout_complete_title), + content = stringResource(core_logout_content), + buttonText = stringResource(core_ok), cancelable = false, onButtonClick = onClickConfirm, onDismiss = onDismissDialog, @@ -333,8 +344,8 @@ private fun Dialog( TnTIconPopupDialog( title = stringResource(R.string.delete_account_title), content = stringResource(R.string.delete_account_content), - leftButtonText = stringResource(coreR.string.cancel), - rightButtonText = stringResource(coreR.string.ok), + leftButtonText = stringResource(core_cancel), + rightButtonText = stringResource(core_ok), onLeftButtonClick = onDismissDialog, onRightButtonClick = onClickConfirm, onDismiss = onDismissDialog, @@ -345,7 +356,7 @@ private fun Dialog( TnTSingleButtonPopupDialog( title = stringResource(R.string.delete_account_complete_title), content = stringResource(R.string.delete_account_complete_content), - buttonText = stringResource(coreR.string.ok), + buttonText = stringResource(core_ok), cancelable = false, onButtonClick = onClickConfirm, onDismiss = onDismissDialog, diff --git a/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageViewModel.kt b/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageViewModel.kt index b8537ac7..eb859305 100644 --- a/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageViewModel.kt +++ b/feature/trainer/mypage/src/main/java/co/kr/tnt/trainer/mypage/TrainerMyPageViewModel.kt @@ -1,16 +1,19 @@ package co.kr.tnt.trainer.mypage import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.repository.LoginRepository import co.kr.tnt.domain.repository.SettingRepository import co.kr.tnt.domain.repository.TrainerRepository import co.kr.tnt.domain.utils.AppUrls +import co.kr.tnt.feature.trainer.mypage.R import co.kr.tnt.login.kakao.KakaoLoginSdk import co.kr.tnt.trainer.mypage.TrainerMyPageContract.TrainerMyPageSideEffect import co.kr.tnt.trainer.mypage.TrainerMyPageContract.TrainerMyPageUiEvent import co.kr.tnt.trainer.mypage.TrainerMyPageContract.TrainerMyPageUiState import co.kr.tnt.trainer.mypage.TrainerMyPageContract.TrainerMyPageUiState.DialogState import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -31,7 +34,7 @@ internal class TrainerMyPageViewModel @Inject constructor( }.onSuccess { user -> updateState { copy(user = user) } }.onFailure { - sendEffect(TrainerMyPageSideEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect(TrainerMyPageSideEffect.ShowToast(DisplayText.Resource(core_failed_to_server_request))) } settingRepository.isEnablePushNotification() @@ -128,7 +131,11 @@ internal class TrainerMyPageViewModel @Inject constructor( }.onSuccess { updateState { copy(dialogState = DialogState.LOGOUT) } }.onFailure { - sendEffect(TrainerMyPageSideEffect.ShowToast("λ‘œκ·Έμ•„μ›ƒμ— μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€.")) + sendEffect( + TrainerMyPageSideEffect.ShowToast( + DisplayText.Resource(R.string.failed_logout), + ), + ) }.also { updateState { copy(isLoading = false) } } @@ -144,7 +151,7 @@ internal class TrainerMyPageViewModel @Inject constructor( }.onSuccess { updateState { copy(dialogState = DialogState.DELETE_ACCOUNT) } }.onFailure { - sendEffect(TrainerMyPageSideEffect.ShowToast("νƒˆν‡΄μ— μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€.")) + sendEffect(TrainerMyPageSideEffect.ShowToast(DisplayText.Resource(R.string.failed_delete_account))) }.also { updateState { copy(isLoading = false) } } diff --git a/feature/trainer/mypage/src/main/res/values/strings.xml b/feature/trainer/mypage/src/main/res/values/strings.xml index 190d9935..63e2dff2 100644 --- a/feature/trainer/mypage/src/main/res/values/strings.xml +++ b/feature/trainer/mypage/src/main/res/values/strings.xml @@ -5,4 +5,8 @@ ν•¨κ»˜ ν–ˆλ˜ νšŒμ›λ“€μ— λŒ€ν•œ 데이터가 μ‚¬λΌμ Έμš”! 계정 νƒˆν‡΄κ°€ μ™„λ£Œλ˜μ—ˆμ–΄μš” λ‹€μŒμ— 더 폭발적인 μΌ€λ―Έλ‘œ λ‹€μ‹œ λ§Œλ‚˜μš”! πŸ’£ + νƒˆν‡΄μ— μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€. + λ‘œκ·Έμ•„μ›ƒμ— μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€. + 관리 쀑인 νšŒμ› + ν•¨κ»˜ ν–ˆλ˜ νšŒμ› diff --git a/feature/trainer/notification/src/main/java/co/kr/tnt/trainer/notification/TrainerNotificationContract.kt b/feature/trainer/notification/src/main/java/co/kr/tnt/trainer/notification/TrainerNotificationContract.kt index dbaf002f..8afe4443 100644 --- a/feature/trainer/notification/src/main/java/co/kr/tnt/trainer/notification/TrainerNotificationContract.kt +++ b/feature/trainer/notification/src/main/java/co/kr/tnt/trainer/notification/TrainerNotificationContract.kt @@ -4,6 +4,7 @@ import co.kr.tnt.ui.base.UiEvent import co.kr.tnt.ui.base.UiSideEffect import co.kr.tnt.ui.base.UiState import co.kr.tnt.ui.model.NotificationState +import co.kr.tnt.ui.resource.DisplayText internal class TrainerNotificationContract { data class TrainerNotificationUiState( @@ -18,7 +19,7 @@ internal class TrainerNotificationContract { } sealed interface TrainerNotificationEffect : UiSideEffect { - data class ShowToast(val message: String) : TrainerNotificationEffect + data class ShowToast(val message: DisplayText) : TrainerNotificationEffect data object NavigateToPrevious : TrainerNotificationEffect data object NavigateToConnect : TrainerNotificationEffect } diff --git a/feature/trainer/notification/src/main/java/co/kr/tnt/trainer/notification/TrainerNotificationScreen.kt b/feature/trainer/notification/src/main/java/co/kr/tnt/trainer/notification/TrainerNotificationScreen.kt index f146b236..53f11f85 100644 --- a/feature/trainer/notification/src/main/java/co/kr/tnt/trainer/notification/TrainerNotificationScreen.kt +++ b/feature/trainer/notification/src/main/java/co/kr/tnt/trainer/notification/TrainerNotificationScreen.kt @@ -13,10 +13,13 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext 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 co.kr.tnt.core.ui.R.string.core_no_recent_notifications +import co.kr.tnt.core.ui.R.string.core_notification import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton import co.kr.tnt.designsystem.component.notification.TnTNotification import co.kr.tnt.designsystem.component.notification.model.NotificationIcon @@ -26,7 +29,6 @@ import co.kr.tnt.trainer.notification.TrainerNotificationContract.TrainerNotific import co.kr.tnt.trainer.notification.TrainerNotificationContract.TrainerNotificationUiEvent import co.kr.tnt.trainer.notification.TrainerNotificationContract.TrainerNotificationUiState import co.kr.tnt.ui.model.NotificationState -import co.kr.tnt.core.ui.R as uiResource @Composable internal fun TrainerNotificationRoute( @@ -34,6 +36,7 @@ internal fun TrainerNotificationRoute( navigateToConnect: (trainerId: String, traineeId: String) -> Unit, viewModel: TrainerNotificationViewModel = hiltViewModel(), ) { + val context = LocalContext.current val snackbar = LocalSnackbar.current val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -52,7 +55,7 @@ internal fun TrainerNotificationRoute( uiState.traineeId, ) - is TrainerNotificationEffect.ShowToast -> snackbar.show(effect.message) + is TrainerNotificationEffect.ShowToast -> snackbar.show(effect.message.asString(context)) } } } @@ -67,7 +70,7 @@ private fun TrainerNotificationScreen( Scaffold( topBar = { TnTTopBarWithBackButton( - title = stringResource(uiResource.string.notification), + title = stringResource(core_notification), onBackClick = onClickBack, showStoke = true, ) @@ -85,7 +88,7 @@ private fun TrainerNotificationScreen( contentAlignment = Alignment.Center, ) { Text( - text = stringResource(uiResource.string.no_recent_notifications), + text = stringResource(core_no_recent_notifications), style = TnTTheme.typography.label1Medium, color = TnTTheme.colors.neutralColors.Neutral400, ) diff --git a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerProfileSetupPage.kt b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerProfileSetupPage.kt index 3744723d..abe5c358 100644 --- a/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerProfileSetupPage.kt +++ b/feature/trainer/signup/src/main/java/co/kr/tnt/trainer/signup/TrainerProfileSetupPage.kt @@ -25,6 +25,9 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import co.kr.tnt.core.ui.R.string.core_name +import co.kr.tnt.core.ui.R.string.core_next +import co.kr.tnt.core.ui.R.string.core_text_length_and_format_warning import co.kr.tnt.designsystem.component.TnTLabeledTextFieldWithCounter import co.kr.tnt.designsystem.component.TnTProfileImage import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton @@ -38,7 +41,6 @@ import co.kr.tnt.ui.extensions.clearFocusOnTap import co.kr.tnt.ui.model.DefaultUserProfile import coil.compose.rememberAsyncImagePainter import coil.request.ImageRequest -import co.kr.tnt.core.ui.R as coreR private const val MAX_LENGTH = 15 @@ -102,7 +104,7 @@ internal fun TrainerProfileSetupPage( ) Spacer(Modifier.padding(top = 60.dp)) TnTLabeledTextFieldWithCounter( - title = stringResource(coreR.string.name), + title = stringResource(core_name), value = state.name, onValueChange = { newValue -> onChangeName(newValue) @@ -113,11 +115,11 @@ internal fun TrainerProfileSetupPage( isSingleLine = true, showWarning = state.isNameValid.not(), isRequired = true, - warningMessage = stringResource(coreR.string.text_length_and_format_warning, MAX_LENGTH), + warningMessage = stringResource(core_text_length_and_format_warning, MAX_LENGTH), ) } TnTBottomButton( - text = stringResource(coreR.string.next), + text = stringResource(core_next), modifier = Modifier.align(Alignment.BottomCenter), enabled = state.name.isNotBlank() && state.isNameValid, onClick = onClickNext, 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 85a5fe12..a3746df7 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 @@ -20,6 +20,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign.Companion.Center import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import co.kr.tnt.core.ui.R.string.core_start import co.kr.tnt.designsystem.component.TnTProfileImage import co.kr.tnt.designsystem.component.button.TnTBottomButton import co.kr.tnt.designsystem.theme.TnTTheme @@ -34,7 +35,6 @@ 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 @Composable internal fun TrainerSignUpCompletePage( @@ -87,7 +87,7 @@ internal fun TrainerSignUpCompletePage( ) } TnTBottomButton( - text = stringResource(uiResource.string.start), + text = stringResource(core_start), onClick = throttled { coroutineScope.launch { val imageFile = withContext(Dispatchers.IO) { 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 200d650b..98c9702c 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 @@ -4,6 +4,7 @@ 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 co.kr.tnt.ui.resource.DisplayText import java.io.File private const val MAX_LENGTH = 15 @@ -37,7 +38,7 @@ internal class TrainerSignUpContract { } sealed interface TrainerSignUpEffect : UiSideEffect { - data class ShowToast(val message: String) : TrainerSignUpEffect + data class ShowToast(val message: DisplayText) : TrainerSignUpEffect data object NavigateToBack : TrainerSignUpEffect data object NavigateToConnect : TrainerSignUpEffect } 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 262e7dde..1183584a 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,6 +4,7 @@ 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 @@ -22,6 +23,7 @@ internal fun TrainerSignUpRoute( navigateToInvite: (ScreenMode) -> Unit, viewModel: TrainerSignUpViewModel = hiltViewModel(), ) { + val context = LocalContext.current val snackbar = LocalSnackbar.current val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -49,7 +51,9 @@ internal fun TrainerSignUpRoute( when (effect) { TrainerSignUpContract.TrainerSignUpEffect.NavigateToBack -> navigateToPrevious() TrainerSignUpContract.TrainerSignUpEffect.NavigateToConnect -> navigateToInvite(ScreenMode.SKIP) - is TrainerSignUpContract.TrainerSignUpEffect.ShowToast -> snackbar.show(effect.message) + is TrainerSignUpContract.TrainerSignUpEffect.ShowToast -> snackbar.show( + effect.message.asString(context), + ) } } } 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 7e76a7eb..5403de87 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 @@ -2,6 +2,7 @@ package co.kr.tnt.trainer.signup import android.net.Uri import androidx.lifecycle.viewModelScope +import co.kr.tnt.core.ui.R.string.core_failed_to_server_request import co.kr.tnt.domain.model.User import co.kr.tnt.domain.model.trainer.TrainerManagementMemberCount import co.kr.tnt.domain.repository.SignUpRepository @@ -10,6 +11,7 @@ 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.resource.DisplayText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -65,7 +67,7 @@ internal class TrainerSignUpViewModel @Inject constructor( }.onSuccess { sendEffect(TrainerSignUpEffect.NavigateToConnect) }.onFailure { - sendEffect(TrainerSignUpEffect.ShowToast("μ„œλ²„ μš”μ²­μ— μ‹€νŒ¨ν–ˆμ–΄μš”")) + sendEffect(TrainerSignUpEffect.ShowToast(DisplayText.Resource(core_failed_to_server_request))) }.also { updateState { copy(isLoading = false) } }