diff --git a/.github/workflows/dokka.yml b/.github/workflows/dokka.yml index 252f3cd3d..33920026f 100644 --- a/.github/workflows/dokka.yml +++ b/.github/workflows/dokka.yml @@ -27,10 +27,12 @@ jobs: - name: Set Local Properties env: BASE_URL: ${{ secrets.BASE_URL }} + TEST_BASE_URL: ${{ secrets.TEST_BASE_URL }} NATIVE_APP_KEY: ${{ secrets.NATIVE_APP_KEY }} NATIVEAPPKEY: ${{ secrets.NATIVEAPPKEY }} run: | echo base.url=\"$BASE_URL\" >> local.properties + echo test.base.url=\"$TEST_BASE_URL\" >> local.properties echo native.app.key=\"$NATIVE_APP_KEY\" >> local.properties echo nativeAppKey=\"$NATIVEAPPKEY\" >> local.properties diff --git a/.github/workflows/pr_checker.yml b/.github/workflows/pr_checker.yml index e8548ccda..d08ddca5a 100644 --- a/.github/workflows/pr_checker.yml +++ b/.github/workflows/pr_checker.yml @@ -41,5 +41,11 @@ jobs: - name: Access Local Properties env: base_url: ${{ secrets.BASE_URL }} + TEST_BASE_URL: ${{ secrets.TEST_BASE_URL }} + NATIVE_APP_KEY: ${{ secrets.NATIVE_APP_KEY }} + NATIVEAPPKEY: ${{ secrets.NATIVEAPPKEY }} run: | - echo base.url=\"$base_url\" >> local.properties \ No newline at end of file + echo base.url=\"$base_url\" >> local.properties + echo test.base.url=\"$TEST_BASE_URL\" >> local.properties + echo native.app.key=\"$NATIVE_APP_KEY\" >> local.properties + echo nativeAppKey=\"$NATIVEAPPKEY\" >> local.properties \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e01b17572..e53028e48 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -38,7 +38,7 @@ android { buildConfigField( "String", "BASE_URL", - gradleLocalProperties(rootDir, providers).getProperty("base.url") + gradleLocalProperties(rootDir, providers).getProperty("test.base.url") ) } release { diff --git a/app/src/main/java/com/terning/point/di/AuthInterceptor.kt b/app/src/main/java/com/terning/point/di/AuthInterceptor.kt index cc8680022..43de4f28b 100644 --- a/app/src/main/java/com/terning/point/di/AuthInterceptor.kt +++ b/app/src/main/java/com/terning/point/di/AuthInterceptor.kt @@ -26,9 +26,9 @@ class AuthInterceptor @Inject constructor( override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() - Timber.d("GET REFRESH TOKEN : ${terningDataStore.refreshToken}") + Timber.d("GET ACCESS TOKEN : ${terningDataStore.accessToken}") - val authRequest = if (terningDataStore.refreshToken.isNotBlank()) { + val authRequest = if (terningDataStore.accessToken.isNotBlank()) { originalRequest.newBuilder().newAuthBuilder().build() } else { originalRequest @@ -45,7 +45,7 @@ class AuthInterceptor @Inject constructor( ) }.onSuccess { data -> terningDataStore.apply { - refreshToken = data.refreshToken + accessToken = data.accessToken } response.close() @@ -77,7 +77,7 @@ class AuthInterceptor @Inject constructor( } private fun Request.Builder.newAuthBuilder() = - this.addHeader(AUTHORIZATION, "$BEARER ${terningDataStore.refreshToken}") + this.addHeader(AUTHORIZATION, "$BEARER ${terningDataStore.accessToken}") companion object { private const val CODE_TOKEN_EXPIRED = 401 diff --git a/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/MyPageLogoutBottomSheet.kt b/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/MyPageLogoutBottomSheet.kt index ff3268983..9d7e9d318 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/MyPageLogoutBottomSheet.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/MyPageLogoutBottomSheet.kt @@ -1,6 +1,8 @@ package com.terning.core.designsystem.component.bottomsheet import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text @@ -41,18 +43,20 @@ fun MyPageLogoutBottomSheet( content = { Column( horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier ) { + Spacer(modifier = modifier.height(10.dp)) Text( text = stringResource(id = R.string.my_page_bottom_sheet_title), style = TerningTheme.typography.heading1, - modifier = modifier.padding(top = 35.dp) ) + Spacer(modifier = modifier.height(60.dp)) Text( text = stringResource(id = R.string.my_page_logout_sub), style = TerningTheme.typography.body4, color = Grey400, - modifier = modifier.padding(top = 54.dp) ) + Spacer(modifier = modifier.height(64.dp)) RoundButton( style = TerningTheme.typography.button2, paddingVertical = 15.dp, @@ -63,10 +67,10 @@ fun MyPageLogoutBottomSheet( }, modifier = modifier.padding( start = 24.dp, - top = 72.dp, end = 24.dp ), ) + Spacer(modifier = modifier.height(8.dp)) DeleteRoundButton( style = TerningTheme.typography.button2, paddingVertical = 15.dp, @@ -82,11 +86,10 @@ fun MyPageLogoutBottomSheet( }, modifier = modifier.padding( start = 24.dp, - top = 8.dp, end = 24.dp, - bottom = 100.dp ) ) + Spacer(modifier = modifier.height(32.dp)) } }, onDismissRequest = { onDismiss() }, diff --git a/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/MyPageQuitBottomSheet.kt b/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/MyPageQuitBottomSheet.kt index 42c1d597b..dd8717115 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/MyPageQuitBottomSheet.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/MyPageQuitBottomSheet.kt @@ -1,6 +1,8 @@ package com.terning.core.designsystem.component.bottomsheet import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text @@ -42,19 +44,21 @@ fun MyPageQuitBottomSheet( content = { Column( horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier ) { + Spacer(modifier = modifier.height(10.dp)) Text( text = stringResource(id = R.string.my_page_bottom_sheet_title), style = TerningTheme.typography.heading1, - modifier = modifier.padding(top = 14.dp) ) + Spacer(modifier = modifier.height(28.dp)) Text( text = stringResource(id = R.string.my_page_quit_sub), style = TerningTheme.typography.body3, - modifier = modifier.padding(top = 54.dp), textAlign = TextAlign.Center, color = Grey400 ) + Spacer(modifier = modifier.height(36.dp)) RoundButton( style = TerningTheme.typography.button2, paddingVertical = 15.dp, @@ -63,12 +67,12 @@ fun MyPageQuitBottomSheet( onButtonClick = { onQuitClick() }, - modifier = modifier.padding( + modifier = Modifier.padding( start = 24.dp, - top = 41.dp, end = 24.dp ) ) + Spacer(modifier = modifier.height(8.dp)) DeleteRoundButton( style = TerningTheme.typography.button2, paddingVertical = 15.dp, @@ -82,13 +86,12 @@ fun MyPageQuitBottomSheet( } } }, - modifier = modifier.padding( + modifier = Modifier.padding( start = 24.dp, - top = 8.dp, end = 24.dp, - bottom = 100.dp ) ) + Spacer(modifier = modifier.height(32.dp)) } }, onDismissRequest = { onDismiss() }, diff --git a/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/SignUpBottomSheet.kt b/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/ProfileBottomSheet.kt similarity index 76% rename from core/src/main/java/com/terning/core/designsystem/component/bottomsheet/SignUpBottomSheet.kt rename to core/src/main/java/com/terning/core/designsystem/component/bottomsheet/ProfileBottomSheet.kt index db86a1aba..9382ceb7a 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/SignUpBottomSheet.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/bottomsheet/ProfileBottomSheet.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.itemsIndexed @@ -17,7 +18,6 @@ import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue @@ -27,14 +27,13 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.terning.core.R -import com.terning.core.designsystem.component.button.RoundButton import com.terning.core.designsystem.theme.TerningMain import com.terning.core.designsystem.theme.TerningTheme import com.terning.core.extension.noRippleClickable import kotlinx.coroutines.launch /** - * 회원가입을 할 때 프로필 이미지를 선택할 수 있는 바텀시트입니다. + * 프로필 이미지를 선택할 수 있는 바텀시트입니다. * * @param modifier 바텀시트에 적용할 Modifier입니다. * @param onDismiss 바텀시트가 닫힐 때 호출되는 콜백 함수입니다. @@ -43,7 +42,7 @@ import kotlinx.coroutines.launch */ @OptIn(ExperimentalMaterial3Api::class) @Composable -fun SignUpBottomSheet( +fun ProfileBottomSheet( modifier: Modifier = Modifier, onDismiss: () -> Unit, onSaveClick: (Int) -> Unit, @@ -52,43 +51,30 @@ fun SignUpBottomSheet( val scope = rememberCoroutineScope() val sheetState = rememberModalBottomSheetState() - var selectedImageIndex by remember { mutableIntStateOf(initialSelectedOption) } - TerningBasicBottomSheet( content = { - Column { + Column(modifier = modifier) { Text( text = stringResource(id = R.string.sign_up_bottom_sheet_title), style = TerningTheme.typography.title2, - modifier = modifier + modifier = Modifier .padding( start = 28.dp, - bottom = 25.dp + bottom = 20.dp ), ) RadioButtonGroup( onOptionSelected = { index -> - selectedImageIndex = index - }, - initialSelectedOption = initialSelectedOption - ) - Spacer(modifier = modifier.padding(bottom = 24.dp)) - RoundButton( - style = TerningTheme.typography.button0, - paddingVertical = 19.dp, - cornerRadius = 10.dp, - text = R.string.sign_up_dialog_start, - onButtonClick = { scope.launch { sheetState.hide() } .invokeOnCompletion { if (!sheetState.isVisible) { - onSaveClick(selectedImageIndex) + onSaveClick(index) } } }, - modifier = modifier.padding(horizontal = 24.dp) + initialSelectedOption = initialSelectedOption ) - Spacer(modifier = modifier.padding(bottom = 15.dp)) + Spacer(modifier = modifier.padding(bottom = 26.dp)) } }, onDismissRequest = { onDismiss() }, @@ -99,15 +85,15 @@ fun SignUpBottomSheet( /** * 6개의 프로필 이미지 중, 하나의 이미지만 선택할 수 있는 라디오 버튼입니다. * - * @param modifier 라디오 버튼에 적용할 Modifier입니다. * @param onOptionSelected 선택된 이미지의 인덱스 값을 나타내는 콜백 함수입니다. * @param initialSelectedOption 초기에 선택된 이미지를 나타내는 인덱스 값입니다. + * @param modifier 라디오 버튼에 적용할 Modifier입니다. */ @Composable fun RadioButtonGroup( - modifier: Modifier = Modifier, onOptionSelected: (Int) -> Unit, - initialSelectedOption: Int + initialSelectedOption: Int, + modifier: Modifier = Modifier, ) { val options = listOf( R.drawable.ic_terning_profile_00, @@ -122,35 +108,36 @@ fun RadioButtonGroup( LazyVerticalGrid( columns = GridCells.Fixed(3), - verticalArrangement = Arrangement.spacedBy(20.dp), - horizontalArrangement = Arrangement.spacedBy(24.dp), - modifier = modifier - .padding(horizontal = 42.dp) + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(20.dp), + modifier = modifier.padding(horizontal = 34.dp) ) { itemsIndexed(options) { index, option -> val imageModifier = if (selectedOption == options[index]) { - modifier + Modifier .border( color = TerningMain, width = 2.dp, shape = CircleShape ) + .aspectRatio(1f) } else { - modifier + Modifier.aspectRatio(1f) } Image( painter = painterResource( id = option ), - contentDescription = stringResource(id = R.string.sign_up_bottom_sheet_description), + contentDescription = "profile image", modifier = imageModifier - .aspectRatio(1f) .noRippleClickable { onOptionSelected(index) selectedOption = option } .clip(shape = CircleShape) + .size(76.dp) + .aspectRatio(1f) ) } } diff --git a/feature/src/main/java/com/terning/feature/onboarding/signup/component/SignUpProfile.kt b/core/src/main/java/com/terning/core/designsystem/component/item/ProfileWithPlusButton.kt similarity index 57% rename from feature/src/main/java/com/terning/feature/onboarding/signup/component/SignUpProfile.kt rename to core/src/main/java/com/terning/core/designsystem/component/item/ProfileWithPlusButton.kt index 86786ed45..659f27b03 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/signup/component/SignUpProfile.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/item/ProfileWithPlusButton.kt @@ -1,29 +1,26 @@ -package com.terning.feature.onboarding.signup.component +package com.terning.core.designsystem.component.item import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentWidth -import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale 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 com.terning.core.designsystem.component.image.TerningImage -import com.terning.feature.R +import com.terning.core.R @Composable -fun SignUpProfile( +fun ProfileWithPlusButton( index: Int, modifier: Modifier = Modifier, ) { - val profile = when (index) { + val grade = when (index) { 0 -> R.drawable.ic_terning_profile_00 1 -> R.drawable.ic_terning_profile_01 2 -> R.drawable.ic_terning_profile_02 @@ -36,24 +33,23 @@ fun SignUpProfile( modifier = modifier.wrapContentWidth() ) { Image( - painterResource(id = profile), - contentDescription = stringResource(id = R.string.sign_up_profile_image), + painterResource(id = grade), + contentDescription = "profile image", modifier = modifier - .clip(shape = RoundedCornerShape(76.dp)) - .size(80.dp) - .aspectRatio(1f), + .clip(shape = CircleShape) + .size(80.dp), contentScale = ContentScale.Crop ) - Box( - modifier = modifier.align(Alignment.BottomEnd) - ) { - TerningImage(painter = R.drawable.ic_sign_up_button) - } + Image( + painter = painterResource(id = R.drawable.ic_sign_up_button), + contentDescription = "plus button", + modifier = Modifier.align(Alignment.BottomEnd) + ) } } @Preview(showBackground = true) @Composable -fun SignUpProfilePreview() { - SignUpProfile(index = 1) +fun ProfileWithPlusButtonPreview() { + ProfileWithPlusButton(index = 1) } \ No newline at end of file diff --git a/core/src/main/java/com/terning/core/designsystem/component/textfield/NameTextField.kt b/core/src/main/java/com/terning/core/designsystem/component/textfield/NameTextField.kt index 7f92022bf..9620bde6c 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/textfield/NameTextField.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/textfield/NameTextField.kt @@ -1,8 +1,6 @@ package com.terning.core.designsystem.component.textfield -import androidx.annotation.StringRes import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor @@ -10,39 +8,122 @@ import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction +import com.terning.core.R import com.terning.core.designsystem.theme.Black import com.terning.core.designsystem.theme.Grey300 import com.terning.core.designsystem.theme.Grey400 +import com.terning.core.designsystem.theme.Grey500 +import com.terning.core.designsystem.theme.TerningMain import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.WarningRed +import com.terning.core.designsystem.theme.White +import com.terning.core.util.NAME_ERROR_REGEX + +data class NameFieldState( + val name: String, + val lineColor: Color, + val helperMessage: Int, + val helperIcon: Int?, + val helperColor: Color, + val isValid: Boolean +) @Composable fun NameTextField( value: String, onValueChange: (String) -> Unit, hint: String, - drawLineColor: Color, - @StringRes helperMessage: Int, - helperColor: Color, - helperIcon: Int? = null, + modifier: Modifier = Modifier, + onValidationChanged: (Boolean) -> Unit, + initialView: Boolean = false ) { val focusManager = LocalFocusManager.current val keyboardController = LocalSoftwareKeyboardController.current + val nameErrorRegex = NAME_ERROR_REGEX + val trimmedName: String + var isNameOutOfBounds = false + if (value.length > MAX_LENGTH) { + trimmedName = value.substring(0, MAX_LENGTH) + isNameOutOfBounds = true + } else { + trimmedName = value + } + + val state = when { + initialView -> { + NameFieldState( + name = trimmedName, + lineColor = Grey500, + helperMessage = R.string.sign_up_helper, + helperIcon = R.drawable.ic_name_text_field_check, + helperColor = White, + isValid = false + ) + } + + nameErrorRegex.matcher(trimmedName).find() -> { + NameFieldState( + name = trimmedName, + lineColor = WarningRed, + helperMessage = R.string.sign_up_helper_error, + helperIcon = R.drawable.ic_name_text_field_error, + helperColor = WarningRed, + isValid = false + ) + } + + trimmedName.isEmpty() || trimmedName.isBlank() -> { + NameFieldState( + name = trimmedName, + lineColor = Grey500, + helperMessage = R.string.sign_up_helper, + helperIcon = null, + helperColor = Grey400, + isValid = false + ) + } + + isNameOutOfBounds -> { + NameFieldState( + name = trimmedName, + lineColor = WarningRed, + helperMessage = R.string.sign_up_helper_out, + helperIcon = R.drawable.ic_name_text_field_error, + helperColor = WarningRed, + isValid = false + ) + } + + else -> { + NameFieldState( + name = trimmedName, + lineColor = TerningMain, + helperMessage = R.string.sign_up_helper_available, + helperIcon = R.drawable.ic_name_text_field_check, + helperColor = TerningMain, + isValid = true + ) + } + } + + onValidationChanged(state.isValid) + TerningBasicTextField( - value = value, + value = state.name, onValueChange = onValueChange, - modifier = Modifier, + modifier = modifier, textStyle = TerningTheme.typography.detail1, textColor = Black, - drawLineColor = drawLineColor, + drawLineColor = state.lineColor, cursorBrush = SolidColor(Grey400), hint = hint, hintColor = Grey300, showTextLength = true, - maxTextLength = 12, - helperMessage = stringResource(id = helperMessage), - helperIcon = helperIcon, - helperColor = helperColor, + maxTextLength = MAX_LENGTH, + helperMessage = stringResource(id = state.helperMessage), + helperIcon = state.helperIcon, + helperColor = state.helperColor, imeAction = ImeAction.Done, onDoneAction = { focusManager.clearFocus() @@ -50,3 +131,5 @@ fun NameTextField( } ) } + +private const val MAX_LENGTH = 12 diff --git a/core/src/main/java/com/terning/core/designsystem/component/textfield/TerningBasicTextField.kt b/core/src/main/java/com/terning/core/designsystem/component/textfield/TerningBasicTextField.kt index 67c799550..0e8bd9667 100644 --- a/core/src/main/java/com/terning/core/designsystem/component/textfield/TerningBasicTextField.kt +++ b/core/src/main/java/com/terning/core/designsystem/component/textfield/TerningBasicTextField.kt @@ -41,6 +41,7 @@ fun TerningBasicTextField( hintColor: Color, drawLineColor: Color, cursorBrush: Brush, + helperColor: Color, strokeWidth: Float = 1f, leftIcon: Int? = null, leftIconColor: Color = TerningMain, @@ -51,7 +52,6 @@ fun TerningBasicTextField( helperMessage: String = "", helperIcon: Int? = null, enabled: Boolean = true, - helperColor: Color, readOnly: Boolean = false, onDoneAction: () -> Unit? = {}, onSearchAction: () -> Unit? = {}, @@ -139,7 +139,7 @@ fun TerningBasicTextField( ) { helperIcon?.let { Icon( - painter = painterResource(id = it), + painter = painterResource(id = helperIcon), contentDescription = null, tint = helperColor, ) diff --git a/core/src/main/java/com/terning/core/designsystem/theme/Color.kt b/core/src/main/java/com/terning/core/designsystem/theme/Color.kt index 1ea24c8b6..38e375622 100644 --- a/core/src/main/java/com/terning/core/designsystem/theme/Color.kt +++ b/core/src/main/java/com/terning/core/designsystem/theme/Color.kt @@ -9,6 +9,7 @@ val Grey150 = Color(0xFFE9E9E9) val Grey200 = Color(0xFFDDDDDD) val Grey300 = Color(0xFFBCBCBC) val Grey350 = Color(0xFFADADAD) +val Grey375 = Color(0xFF898989) val Grey400 = Color(0xFF666666) val Grey500 = Color(0xFF373737) val Black = Color(0xFF171717) diff --git a/core/src/main/java/com/terning/core/util/Regex.kt b/core/src/main/java/com/terning/core/util/Regex.kt new file mode 100644 index 000000000..4fd047690 --- /dev/null +++ b/core/src/main/java/com/terning/core/util/Regex.kt @@ -0,0 +1,8 @@ +package com.terning.core.util + +import java.util.regex.Pattern + +private const val NAME_ERROR_PATTERN = + "[!@#\$%^&*(),.?\":{}|<>\\[\\]\\\\/\\-=+~`\\p{S}\\p{P}]" +val NAME_ERROR_REGEX: Pattern = + Pattern.compile(NAME_ERROR_PATTERN) diff --git a/feature/src/main/res/drawable/ic_check.xml b/core/src/main/res/drawable/ic_name_text_field_check.xml similarity index 100% rename from feature/src/main/res/drawable/ic_check.xml rename to core/src/main/res/drawable/ic_name_text_field_check.xml diff --git a/feature/src/main/res/drawable/ic_sign_up_error.xml b/core/src/main/res/drawable/ic_name_text_field_error.xml similarity index 100% rename from feature/src/main/res/drawable/ic_sign_up_error.xml rename to core/src/main/res/drawable/ic_name_text_field_error.xml diff --git a/feature/src/main/res/drawable/ic_sign_up_button.xml b/core/src/main/res/drawable/ic_sign_up_button.xml similarity index 100% rename from feature/src/main/res/drawable/ic_sign_up_button.xml rename to core/src/main/res/drawable/ic_sign_up_button.xml diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index ad3c916f7..2a3dd454b 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -33,7 +33,6 @@ 프로필 이미지 선택 - 회원가입 바텀시트 저장하기 잠깐만요! 정말 로그아웃 하시겠어요? @@ -62,4 +61,10 @@ TerningBasicImage + + 12자리 이내, 문자/숫자 가능, 특수문자/기호 입력불가 + 이름에 특수문자는 입력할 수 없어요 + 사용 가능한 이름이에요 + 이름은 12자리 이내로 설정해 주세요 + \ No newline at end of file diff --git a/data/src/main/java/com/terning/data/dto/response/TokenReissueResponseDto.kt b/data/src/main/java/com/terning/data/dto/response/TokenReissueResponseDto.kt index 56647b905..91cca0810 100644 --- a/data/src/main/java/com/terning/data/dto/response/TokenReissueResponseDto.kt +++ b/data/src/main/java/com/terning/data/dto/response/TokenReissueResponseDto.kt @@ -5,6 +5,6 @@ import kotlinx.serialization.Serializable @Serializable data class TokenReissueResponseDto( - @SerialName("refreshToken") - val refreshToken: String + @SerialName("accessToken") + val accessToken: String ) \ No newline at end of file diff --git a/data/src/main/java/com/terning/data/mapper/auth/TokenReissueMapper.kt b/data/src/main/java/com/terning/data/mapper/auth/TokenReissueMapper.kt index 90e2e964f..176698aa6 100644 --- a/data/src/main/java/com/terning/data/mapper/auth/TokenReissueMapper.kt +++ b/data/src/main/java/com/terning/data/mapper/auth/TokenReissueMapper.kt @@ -4,4 +4,4 @@ import com.terning.data.dto.response.TokenReissueResponseDto import com.terning.domain.entity.auth.TokenReissue fun TokenReissueResponseDto.toTokenReissue(): TokenReissue = - TokenReissue(refreshToken = refreshToken) + TokenReissue(accessToken = accessToken) diff --git a/domain/src/main/java/com/terning/domain/entity/auth/TokenReissue.kt b/domain/src/main/java/com/terning/domain/entity/auth/TokenReissue.kt index 9841acf59..933015dfc 100644 --- a/domain/src/main/java/com/terning/domain/entity/auth/TokenReissue.kt +++ b/domain/src/main/java/com/terning/domain/entity/auth/TokenReissue.kt @@ -1,5 +1,5 @@ package com.terning.domain.entity.auth data class TokenReissue ( - val refreshToken : String + val accessToken : String ) \ No newline at end of file diff --git a/feature/build.gradle.kts b/feature/build.gradle.kts index 6b56a6904..781cf168f 100644 --- a/feature/build.gradle.kts +++ b/feature/build.gradle.kts @@ -100,5 +100,4 @@ dependencies { // KakaoDependencies implementation(libs.kakao.user) - } \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringOneScreen.kt b/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringOneScreen.kt index 3f4a28c8c..17ba94a8c 100644 --- a/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringOneScreen.kt +++ b/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringOneScreen.kt @@ -1,6 +1,8 @@ package com.terning.feature.filtering.filtering +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -21,6 +23,7 @@ import com.terning.core.designsystem.component.topappbar.BackButtonTopAppBar import com.terning.core.designsystem.theme.Grey300 import com.terning.core.designsystem.theme.TerningPointTheme import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White import com.terning.feature.R import com.terning.feature.filtering.filtering.component.StatusOneRadioGroup @@ -30,6 +33,7 @@ fun FilteringOneScreen( onNextClick: (Int) -> Unit, navigateUp: () -> Unit, modifier: Modifier = Modifier, + paddingValues: PaddingValues = PaddingValues(), onButtonClick: (Int) -> Unit = {}, ) { val isButtonValid = remember { mutableStateOf(false) } @@ -38,6 +42,8 @@ fun FilteringOneScreen( Column( modifier = modifier + .padding(paddingValues) + .background(White) ) { BackButtonTopAppBar( onBackButtonClick = { navigateUp() } diff --git a/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringThreeRoute.kt b/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringThreeRoute.kt index b51640a80..3eb6a89db 100644 --- a/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringThreeRoute.kt +++ b/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringThreeRoute.kt @@ -1,6 +1,8 @@ package com.terning.feature.filtering.filtering +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -26,6 +28,7 @@ import com.terning.core.designsystem.component.topappbar.BackButtonTopAppBar import com.terning.core.designsystem.theme.Grey300 import com.terning.core.designsystem.theme.TerningPointTheme import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White import com.terning.core.extension.toast import com.terning.feature.R import java.util.Calendar @@ -37,6 +40,7 @@ fun FilteringThreeRoute( navigateUp: () -> Unit, navigateToStartHome: () -> Unit, viewModel: FilteringViewModel = hiltViewModel(), + paddingValues: PaddingValues ) { val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current @@ -68,6 +72,7 @@ fun FilteringThreeRoute( } FilteringThreeScreen( + paddingValues = paddingValues, navigateUp = { navigateUp() }, chosenYear = chosenYear, chosenMonth = chosenMonth, @@ -80,6 +85,7 @@ fun FilteringThreeRoute( @Composable fun FilteringThreeScreen( modifier: Modifier = Modifier, + paddingValues: PaddingValues = PaddingValues(), navigateUp: () -> Unit, chosenYear: Int, chosenMonth: Int, @@ -88,7 +94,9 @@ fun FilteringThreeScreen( onNextClick: () -> Unit, ) { Column( - modifier = modifier, + modifier = modifier + .padding(paddingValues) + .background(White), ) { BackButtonTopAppBar( onBackButtonClick = { navigateUp() } diff --git a/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringTwoScreen.kt b/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringTwoScreen.kt index e66df12e8..c35eec330 100644 --- a/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringTwoScreen.kt +++ b/feature/src/main/java/com/terning/feature/filtering/filtering/FilteringTwoScreen.kt @@ -1,6 +1,8 @@ package com.terning.feature.filtering.filtering +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -21,6 +23,7 @@ import com.terning.core.designsystem.component.topappbar.BackButtonTopAppBar import com.terning.core.designsystem.theme.Grey300 import com.terning.core.designsystem.theme.TerningPointTheme import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White import com.terning.feature.R import com.terning.feature.filtering.filtering.component.StatusTwoRadioGroup @@ -30,6 +33,7 @@ fun FilteringTwoScreen( onNextClick: (Int, Int) -> Unit, navigateUp: () -> Unit, modifier: Modifier = Modifier, + paddingValues: PaddingValues = PaddingValues(), onButtonClick: (Int) -> Unit = {}, ) { val isButtonValid = remember { mutableStateOf(false) } @@ -38,6 +42,8 @@ fun FilteringTwoScreen( Column( modifier = modifier + .padding(paddingValues) + .background(White) ) { BackButtonTopAppBar( onBackButtonClick = { navigateUp() } diff --git a/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringOneNavigation.kt b/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringOneNavigation.kt index 266137688..3ac282c44 100644 --- a/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringOneNavigation.kt +++ b/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringOneNavigation.kt @@ -1,5 +1,6 @@ package com.terning.feature.filtering.filtering.navigation +import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController @@ -21,11 +22,13 @@ fun NavController.navigateFilteringOne( } fun NavGraphBuilder.filteringOneNavGraph( + paddingValues: PaddingValues, navHostController: NavHostController ) { composable { val args = it.toRoute() FilteringOneScreen( + paddingValues = paddingValues, name = args.name, onNextClick = { grade -> navHostController.navigateFilteringTwo(grade) }, navigateUp = { navHostController.navigateUp() } diff --git a/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringThreeNavigation.kt b/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringThreeNavigation.kt index 759c65c4d..97f95beae 100644 --- a/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringThreeNavigation.kt +++ b/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringThreeNavigation.kt @@ -1,5 +1,6 @@ package com.terning.feature.filtering.filtering.navigation +import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController @@ -23,11 +24,13 @@ fun NavController.navigateFilteringThree( } fun NavGraphBuilder.filteringThreeNavGraph( + paddingValues: PaddingValues, navHostController: NavHostController ) { composable { val args = it.toRoute() FilteringThreeRoute( + paddingValues = paddingValues, grade = args.grade, workingPeriod = args.workingPeriod, navigateUp = { navHostController.navigateUp() }, diff --git a/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringTwoNavigation.kt b/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringTwoNavigation.kt index 0bde2ac5e..ff9f1286d 100644 --- a/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringTwoNavigation.kt +++ b/feature/src/main/java/com/terning/feature/filtering/filtering/navigation/FilteringTwoNavigation.kt @@ -1,5 +1,6 @@ package com.terning.feature.filtering.filtering.navigation +import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController @@ -21,11 +22,13 @@ fun NavController.navigateFilteringTwo( } fun NavGraphBuilder.filteringTwoNavGraph( + paddingValues: PaddingValues, navHostController: NavHostController ) { composable { val args = it.toRoute() FilteringTwoScreen( + paddingValues = paddingValues, grade = args.grade, onNextClick = { _, workingPeriod -> navHostController.navigateFilteringThree( diff --git a/feature/src/main/java/com/terning/feature/filtering/startfiltering/StartFilteringScreen.kt b/feature/src/main/java/com/terning/feature/filtering/startfiltering/StartFilteringScreen.kt index e8e1128b2..2429947ce 100644 --- a/feature/src/main/java/com/terning/feature/filtering/startfiltering/StartFilteringScreen.kt +++ b/feature/src/main/java/com/terning/feature/filtering/startfiltering/StartFilteringScreen.kt @@ -2,8 +2,10 @@ package com.terning.feature.filtering.startfiltering import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -27,12 +29,14 @@ import com.terning.core.designsystem.component.button.RectangleButton import com.terning.core.designsystem.component.image.TerningImage import com.terning.core.designsystem.theme.TerningPointTheme import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White import com.terning.feature.R import kotlinx.coroutines.delay @Composable fun StartFilteringScreen( modifier: Modifier = Modifier, + paddingValues: PaddingValues = PaddingValues(), onNextClick: () -> Unit ) { var isVisible by remember { mutableStateOf(false) } @@ -46,7 +50,10 @@ fun StartFilteringScreen( } Box( - modifier = modifier.fillMaxSize() + modifier = modifier + .fillMaxSize() + .padding(paddingValues) + .background(White) ) { Column( modifier = Modifier.fillMaxSize(), diff --git a/feature/src/main/java/com/terning/feature/filtering/startfiltering/navigation/StartFilteringNavigation.kt b/feature/src/main/java/com/terning/feature/filtering/startfiltering/navigation/StartFilteringNavigation.kt index e70d98afa..17280736b 100644 --- a/feature/src/main/java/com/terning/feature/filtering/startfiltering/navigation/StartFilteringNavigation.kt +++ b/feature/src/main/java/com/terning/feature/filtering/startfiltering/navigation/StartFilteringNavigation.kt @@ -1,5 +1,6 @@ package com.terning.feature.filtering.startfiltering.navigation +import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController @@ -22,11 +23,13 @@ fun NavController.navigateStartFiltering( } fun NavGraphBuilder.startFilteringNavGraph( + paddingValues: PaddingValues, navHostController: NavHostController ) { composable { val args = it.toRoute() StartFilteringScreen( + paddingValues = paddingValues, onNextClick = { navHostController.navigateFilteringOne(args.name) } diff --git a/feature/src/main/java/com/terning/feature/filtering/starthome/StartHomeScreen.kt b/feature/src/main/java/com/terning/feature/filtering/starthome/StartHomeScreen.kt index 63b92593f..29cdba837 100644 --- a/feature/src/main/java/com/terning/feature/filtering/starthome/StartHomeScreen.kt +++ b/feature/src/main/java/com/terning/feature/filtering/starthome/StartHomeScreen.kt @@ -2,8 +2,10 @@ package com.terning.feature.filtering.starthome import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize @@ -24,9 +26,6 @@ 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 androidx.navigation.NavController -import androidx.navigation.NavOptions -import androidx.navigation.compose.rememberNavController import com.airbnb.lottie.compose.LottieAnimation import com.airbnb.lottie.compose.LottieCompositionSpec import com.airbnb.lottie.compose.LottieConstants @@ -34,16 +33,14 @@ import com.airbnb.lottie.compose.rememberLottieComposition import com.terning.core.designsystem.component.button.RectangleButton import com.terning.core.designsystem.theme.TerningPointTheme import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White import com.terning.feature.R -import com.terning.feature.home.home.navigation.navigateHome -import com.terning.feature.main.MainNavigator -import com.terning.feature.main.rememberMainNavigator -import com.terning.feature.onboarding.signin.navigation.SignIn import kotlinx.coroutines.delay @Composable fun StartHomeScreen( modifier: Modifier = Modifier, + paddingValues: PaddingValues = PaddingValues(), navigateToHome: () -> Unit ) { var isVisible by remember { mutableStateOf(false) } @@ -57,7 +54,10 @@ fun StartHomeScreen( } Box( - modifier = modifier.fillMaxSize() + modifier = modifier + .fillMaxSize() + .padding(paddingValues) + .background(White) ) { Column( modifier = Modifier.fillMaxSize(), @@ -95,7 +95,7 @@ fun StartHomeScreen( } } -private const val DELAY : Long = 1000 +private const val DELAY: Long = 1000 @Composable fun StartHomeLottieAnimation( diff --git a/feature/src/main/java/com/terning/feature/filtering/starthome/navigation/StartHomeNavigation.kt b/feature/src/main/java/com/terning/feature/filtering/starthome/navigation/StartHomeNavigation.kt index ed29bcf97..9f493d51a 100644 --- a/feature/src/main/java/com/terning/feature/filtering/starthome/navigation/StartHomeNavigation.kt +++ b/feature/src/main/java/com/terning/feature/filtering/starthome/navigation/StartHomeNavigation.kt @@ -1,7 +1,6 @@ package com.terning.feature.filtering.starthome.navigation -import androidx.compose.animation.EnterTransition -import androidx.compose.animation.ExitTransition +import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController @@ -21,30 +20,20 @@ fun NavController.navigateStartHome(navOptions: NavOptions? = null) { } fun NavGraphBuilder.startHomeNavGraph( + paddingValues: PaddingValues, navHostController: NavHostController ) { - composable( - exitTransition = { - ExitTransition.None - }, - popEnterTransition = { - EnterTransition.None - }, - enterTransition = { - EnterTransition.None - }, - popExitTransition = { - ExitTransition.None - } - ) { - StartHomeScreen(navigateToHome = { - navHostController.navigateHome( - navOptions = NavOptions.Builder().setPopUpTo( - route = SignIn, - inclusive = true - ).build() - ) - } + composable { + StartHomeScreen( + paddingValues = paddingValues, + navigateToHome = { + navHostController.navigateHome( + navOptions = NavOptions.Builder().setPopUpTo( + route = SignIn, + inclusive = true + ).build() + ) + } ) } } diff --git a/feature/src/main/java/com/terning/feature/home/changefilter/ChangeFilterRoute.kt b/feature/src/main/java/com/terning/feature/home/changefilter/ChangeFilterRoute.kt index ec13a8e4e..dfc3a938a 100644 --- a/feature/src/main/java/com/terning/feature/home/changefilter/ChangeFilterRoute.kt +++ b/feature/src/main/java/com/terning/feature/home/changefilter/ChangeFilterRoute.kt @@ -2,7 +2,9 @@ package com.terning.feature.home.changefilter import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -100,7 +102,10 @@ fun ChangeFilterScreen( modifier = Modifier .shadow(elevation = 2.dp) ) - } + }, + modifier = Modifier + .statusBarsPadding() + .navigationBarsPadding() ) { paddingValues -> Column( modifier = Modifier diff --git a/feature/src/main/java/com/terning/feature/home/home/HomeRoute.kt b/feature/src/main/java/com/terning/feature/home/home/HomeRoute.kt index cc92f3bdf..2e9793e17 100644 --- a/feature/src/main/java/com/terning/feature/home/home/HomeRoute.kt +++ b/feature/src/main/java/com/terning/feature/home/home/HomeRoute.kt @@ -75,6 +75,7 @@ const val NAME_END_LENGTH = 12 @Composable fun HomeRoute( + paddingValues: PaddingValues, navController: NavHostController, viewModel: HomeViewModel = hiltViewModel(), ) { @@ -109,6 +110,7 @@ fun HomeRoute( } HomeScreen( + paddingValues = paddingValues, homeDialogState = homeDialogState, onChangeFilterClick = { navController.navigateChangeFilter() }, navigateToIntern = { navController.navigateIntern(announcementId = it) }, @@ -119,6 +121,7 @@ fun HomeRoute( @OptIn(ExperimentalFoundationApi::class) @Composable fun HomeScreen( + paddingValues: PaddingValues, homeDialogState: HomeDialogState, onChangeFilterClick: () -> Unit, navigateToIntern: (Long) -> Unit, @@ -162,6 +165,9 @@ fun HomeScreen( Column( horizontalAlignment = Alignment.Start, + modifier = Modifier + .background(White) + .padding(paddingValues) ) { TerningImage( painter = R.drawable.ic_terning_logo_typo, diff --git a/feature/src/main/java/com/terning/feature/home/home/navigation/HometNavigation.kt b/feature/src/main/java/com/terning/feature/home/home/navigation/HometNavigation.kt index 6343c1df4..307d4ed93 100644 --- a/feature/src/main/java/com/terning/feature/home/home/navigation/HometNavigation.kt +++ b/feature/src/main/java/com/terning/feature/home/home/navigation/HometNavigation.kt @@ -5,6 +5,7 @@ import androidx.compose.animation.ExitTransition import androidx.compose.animation.core.LinearOutSlowInEasing import androidx.compose.animation.core.tween import androidx.compose.animation.slideIn +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.ui.unit.IntOffset import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder @@ -22,7 +23,9 @@ fun NavController.navigateHome(navOptions: NavOptions? = null) { ) } -fun NavGraphBuilder.homeNavGraph(navHostController: NavHostController) { +fun NavGraphBuilder.homeNavGraph( + paddingValues : PaddingValues, + navHostController: NavHostController) { composable( exitTransition = { ExitTransition.None @@ -37,7 +40,9 @@ fun NavGraphBuilder.homeNavGraph(navHostController: NavHostController) { ExitTransition.None } ) { - HomeRoute(navController = navHostController) + HomeRoute( + paddingValues= paddingValues, + navController = navHostController) } } diff --git a/feature/src/main/java/com/terning/feature/intern/InternRoute.kt b/feature/src/main/java/com/terning/feature/intern/InternRoute.kt index 2249e3e68..bcab1d50e 100644 --- a/feature/src/main/java/com/terning/feature/intern/InternRoute.kt +++ b/feature/src/main/java/com/terning/feature/intern/InternRoute.kt @@ -2,24 +2,18 @@ package com.terning.feature.intern import android.view.ViewGroup import android.webkit.WebView -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Icon +import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable 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.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView @@ -30,10 +24,8 @@ import androidx.lifecycle.flowWithLifecycle import androidx.navigation.NavHostController import com.terning.core.designsystem.component.dialog.TerningBasicDialog import com.terning.core.designsystem.component.topappbar.BackButtonTopAppBar -import com.terning.core.designsystem.theme.Black import com.terning.core.designsystem.theme.Grey200 import com.terning.core.designsystem.theme.Grey400 -import com.terning.core.designsystem.theme.TerningMain import com.terning.core.designsystem.theme.TerningTheme import com.terning.core.extension.customShadow import com.terning.core.extension.toast @@ -41,24 +33,24 @@ import com.terning.core.state.UiState import com.terning.domain.entity.response.InternInfoModel import com.terning.feature.R import com.terning.feature.intern.component.InternBottomBar -import com.terning.feature.intern.component.InternCancelDialog import com.terning.feature.intern.component.InternCompanyInfo import com.terning.feature.intern.component.InternInfoRow import com.terning.feature.intern.component.InternPageTitle -import com.terning.feature.intern.component.ScrapDialogContent +import com.terning.feature.intern.component.InternTitle +import com.terning.feature.intern.model.InternUiState import java.text.DecimalFormat @Composable fun InternRoute( - navController: NavHostController, announcementId: Long = 0, viewModel: InternViewModel = hiltViewModel(), + navController: NavHostController, ) { + val internState by viewModel.internUiState.collectAsStateWithLifecycle() + val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current - val state by viewModel.internState.collectAsStateWithLifecycle(lifecycleOwner = lifecycleOwner) - LaunchedEffect(key1 = true) { viewModel.getInternInfo(announcementId) } @@ -72,15 +64,15 @@ fun InternRoute( } } - when (state.internInfo) { - is UiState.Loading -> {} - is UiState.Empty -> {} + when (internState.loadState) { + UiState.Loading -> {} + UiState.Empty -> {} is UiState.Failure -> {} is UiState.Success -> { InternScreen( - navController = navController, - internInfoModel = (state.internInfo as UiState.Success).data, - announcementId = announcementId + internUiState = internState, + internInfoModel = (internState.loadState as UiState.Success).data, + navController = navController ) } } @@ -91,10 +83,9 @@ fun InternScreen( modifier: Modifier = Modifier, navController: NavHostController, viewModel: InternViewModel = hiltViewModel(), + internUiState: InternUiState, internInfoModel: InternInfoModel, - announcementId: Long, ) { - val internState by viewModel.internState.collectAsStateWithLifecycle() val decimal = DecimalFormat("#,###") val internInfoList = listOf( @@ -103,10 +94,12 @@ fun InternScreen( stringResource(id = R.string.intern_info_start_date) to internInfoModel.startDate, ) - val qualificationList = internInfoModel.qualification.split(",").map { it.trim() } - val jobTypeList = internInfoModel.jobType.split(",").map { it.trim() } + val qualificationList = listOf( + stringResource(id = R.string.intern_recruitment_target) to internInfoModel.qualification, + stringResource(id = R.string.intern_info_work) to internInfoModel.jobType, + ) - if (internState.showWeb) { + if (internUiState.showWeb) { AndroidView( factory = { WebView(it).apply { @@ -130,7 +123,7 @@ fun InternScreen( offsetY = 2.dp ), onBackButtonClick = { - navController.navigateUp() + navController.popBackStack() }, ) }, @@ -157,244 +150,94 @@ fun InternScreen( end = 24.dp ) ) { - Row( - modifier = modifier - .border( - width = 1.dp, - color = TerningMain, - shape = RoundedCornerShape(size = 12.dp) - ), - horizontalArrangement = Arrangement.spacedBy( - 0.dp, - Alignment.CenterHorizontally - ), - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = internInfoModel.dDay, - style = TerningTheme.typography.title5, - color = TerningMain, - modifier = Modifier.padding( - horizontal = 12.dp, - vertical = 2.dp - ) - ) - } + Spacer(modifier = modifier.padding(top = 16.dp)) - Text( - text = internInfoModel.title, - style = TerningTheme.typography.title2, - color = Black, - modifier = modifier.padding( - top = 4.dp, - bottom = 16.dp - ) - ) - - Column( - modifier = modifier - .border( - width = 1.dp, - color = TerningMain, - shape = RoundedCornerShape(size = 5.dp) - ) - .fillMaxWidth() - .padding(start = 16.dp, top = 16.dp, bottom = 16.dp), - verticalArrangement = Arrangement.spacedBy( - 6.dp, - Alignment.CenterVertically - ), - horizontalAlignment = Alignment.Start, - ) { - internInfoList.forEach { (title, value) -> - InternInfoRow(title, value) - } - } - Row( - horizontalArrangement = Arrangement.spacedBy(3.dp, Alignment.End), - verticalAlignment = Alignment.CenterVertically, - modifier = modifier - .fillMaxWidth() - .padding( - top = 9.dp, - ) - ) { - Text( - text = stringResource(id = R.string.intern_view_count), - style = TerningTheme.typography.detail3, - color = Grey400 - ) - Text( - text = "${decimal.format(internInfoModel.viewCount)}회", - style = TerningTheme.typography.button4, - color = Grey400, - ) - } - } - - Column( - verticalArrangement = Arrangement.Top, - ) { - InternPageTitle( - modifier = modifier, - text = stringResource(id = R.string.intern_sub_title_intern_info) - ) InternCompanyInfo( modifier = modifier, companyImage = internInfoModel.companyImage, company = internInfoModel.company, companyCategory = internInfoModel.companyCategory ) + + Spacer(modifier = modifier.padding(top = 20.dp)) + + InternTitle( + modifier = modifier, + dDay = internInfoModel.dDay, + title = internInfoModel.title, + viewCount = decimal.format(internInfoModel.viewCount) + ) + + Spacer(modifier = modifier.padding(top = 16.dp)) + InternPageTitle( modifier = modifier, text = stringResource(id = R.string.intern_sub_title_intern_summary) ) + Column( - modifier = modifier - .padding( - start = 24.dp, - bottom = 16.dp, - end = 24.dp - ) - .fillMaxWidth(), - verticalArrangement = Arrangement.Top, - horizontalAlignment = Alignment.Start, + modifier = modifier.padding( + top = 4.dp, + bottom = 4.dp, + start = 10.dp + ) ) { - Row( - modifier = modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy( - 3.dp, - Alignment.Start - ), - verticalAlignment = Alignment.Top - ) { - Row( - modifier = modifier - .weight(2f), - verticalAlignment = Alignment.Top, - ) { - Icon( - painter = painterResource(id = R.drawable.ic_first_info_20), - contentDescription = null - ) - Text( - text = stringResource(id = R.string.intern_info_request), - style = TerningTheme.typography.button2, - color = Black - ) - } - - Column( - modifier = modifier - .weight(5f) - .padding(start = 8.dp), - verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.Top), - ) { - qualificationList.forEach { qualification -> - Text( - text = qualification, - style = TerningTheme.typography.body4, - color = Grey400, - ) - } - } + internInfoList.forEach { (title, value) -> + InternInfoRow(title, value) } } + + Spacer(modifier = modifier.padding(top = 16.dp)) + + InternPageTitle( + modifier = modifier, + text = stringResource(id = R.string.intern_info_request) + ) + Column( - modifier = modifier - .padding(horizontal = 24.dp) - .fillMaxWidth(), - verticalArrangement = Arrangement.Top, - horizontalAlignment = Alignment.Start, + modifier = modifier.padding( + top = 4.dp, + bottom = 4.dp, + start = 10.dp + ) ) { - Row( - modifier = modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy( - 3.dp, - Alignment.Start - ), - verticalAlignment = Alignment.Top - ) { - Row( - modifier = modifier - .weight(2f), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Start - ) { - Icon( - painter = painterResource(id = R.drawable.ic_second_info_20), - contentDescription = null, - ) - Text( - text = stringResource(id = R.string.intern_info_work), - style = TerningTheme.typography.button2, - color = Black - ) - } - - Column( - modifier = modifier - .weight(5f) - .padding(start = 8.dp), - verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.Top), - ) { - jobTypeList.forEach { jobType -> - Text( - text = jobType, - style = TerningTheme.typography.body4, - color = Grey400, - ) - } - } + qualificationList.forEach { (title, value) -> + InternInfoRow(title, value) } } + + Spacer(modifier = modifier.padding(top = 16.dp)) + InternPageTitle( modifier = modifier, text = stringResource(id = R.string.intern_sub_title_intern_detail) ) + Column( modifier = modifier.padding( - start = 24.dp, - end = 24.dp, + start = 10.dp, + top = 5.dp, bottom = 20.dp ) ) { - Text( - text = internInfoModel.detail.trimIndent(), - style = TerningTheme.typography.detail1, - color = Grey400 - ) + SelectionContainer { + Text( + text = internInfoModel.detail.trimIndent(), + style = TerningTheme.typography.body3, + color = Grey400 + ) + } } } } } - if (internState.isScrapDialogVisible) { + + if (internUiState.isScrapDialogVisible) { TerningBasicDialog( onDismissRequest = { viewModel.updateScrapDialogVisible(false) }, - content = { - when (internInfoModel.scrapId != null) { - true -> InternCancelDialog( - onDismissRequest = { viewModel.updateScrapDialogVisible(false) }, - onClickScrapCancel = { - viewModel.deleteScrap( - internInfoModel.scrapId, - announcementId - ) - } - ) - - else -> ScrapDialogContent( - internInfoList = internInfoList, - dDay = internInfoModel.dDay, - title = internInfoModel.title, - companyImage = internInfoModel.companyImage, - announcementId = announcementId, - type = 0 - ) - } - }, + content = {}, ) } } diff --git a/feature/src/main/java/com/terning/feature/intern/InternViewModel.kt b/feature/src/main/java/com/terning/feature/intern/InternViewModel.kt index 13e71a697..7322223a9 100644 --- a/feature/src/main/java/com/terning/feature/intern/InternViewModel.kt +++ b/feature/src/main/java/com/terning/feature/intern/InternViewModel.kt @@ -9,11 +9,10 @@ import com.terning.domain.repository.InternRepository import com.terning.domain.repository.ScrapRepository import com.terning.feature.R import com.terning.feature.intern.model.InternScrapState -import com.terning.feature.intern.model.InternViewState +import com.terning.feature.intern.model.InternUiState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update @@ -25,9 +24,8 @@ class InternViewModel @Inject constructor( private val internRepository: InternRepository, private val scrapRepository: ScrapRepository, ) : ViewModel() { - private val _internState: MutableStateFlow = - MutableStateFlow(InternViewState()) - val internState: StateFlow = _internState.asStateFlow() + private val _internUiState = MutableStateFlow(InternUiState()) + val internUiState get() = _internUiState.asStateFlow() private val _scrapState: MutableStateFlow = MutableStateFlow(InternScrapState()) @@ -37,20 +35,19 @@ class InternViewModel @Inject constructor( fun getInternInfo(id: Long) { viewModelScope.launch { - internRepository.getInternInfo( - id - ).onSuccess { internInfo -> - _internState.update { - it.copy(internInfo = UiState.Success(internInfo)) + internRepository.getInternInfo(id) + .onSuccess { internInfoModel -> + _internUiState.update { currentState -> + currentState.copy(loadState = UiState.Success(internInfoModel)) + } + } + .onFailure { + _sideEffect.emit(InternViewSideEffect.Toast(R.string.server_failure)) } - }.onFailure { - _sideEffect.emit( - InternViewSideEffect.Toast(R.string.server_failure) - ) - } } } + fun postScrap( id: Long, color: Int, @@ -100,31 +97,31 @@ class InternViewModel @Inject constructor( } fun updateSelectColor(newColor: Color) { - _internState.update { + _internUiState.update { it.copy(selectedColor = newColor) } } fun updateScrapDialogVisible(visible: Boolean) { - _internState.update { + _internUiState.update { it.copy(isScrapDialogVisible = visible) } } fun updatePaletteOpen(open: Boolean) { - _internState.update { + _internUiState.update { it.copy(isPaletteOpen = open) } } fun updateColorChange(change: Boolean) { - _internState.update { + _internUiState.update { it.copy(isColorChange = change) } } fun updateShowWeb(show: Boolean) { - _internState.update { + _internUiState.update { it.copy(showWeb = show) } } diff --git a/feature/src/main/java/com/terning/feature/intern/component/InternCompanyInfo.kt b/feature/src/main/java/com/terning/feature/intern/component/InternCompanyInfo.kt index afee51466..39d31b248 100644 --- a/feature/src/main/java/com/terning/feature/intern/component/InternCompanyInfo.kt +++ b/feature/src/main/java/com/terning/feature/intern/component/InternCompanyInfo.kt @@ -22,8 +22,8 @@ import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import coil.request.ImageRequest import com.terning.core.designsystem.theme.Black -import com.terning.core.designsystem.theme.Grey300 -import com.terning.core.designsystem.theme.TerningMain +import com.terning.core.designsystem.theme.Grey150 +import com.terning.core.designsystem.theme.Grey350 import com.terning.core.designsystem.theme.TerningTheme import com.terning.feature.R @@ -36,70 +36,55 @@ fun InternCompanyInfo( company: String, companyCategory: String, ) { - Row( - modifier = modifier.padding( - start = 20.dp, - ) + Column( + modifier = Modifier + .fillMaxWidth(), + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.CenterHorizontally, ) { Row( verticalAlignment = Alignment.CenterVertically, - ) { - Column( - verticalArrangement = Arrangement.spacedBy( - 2.dp, - Alignment.CenterVertically - ), - horizontalAlignment = Alignment.Start, - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .size(60.dp) - .border( - width = 1.dp, - color = TerningMain, - shape = RoundedCornerShape(size = 30.dp) - ) - ) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(companyImage) - .crossfade(true) - .build(), - contentDescription = stringResource(id = R.string.search_image), - contentScale = ContentScale.Fit, - modifier = modifier - .fillMaxWidth() - .clip(CircleShape), - ) - } - } - Column( - verticalArrangement = Arrangement.spacedBy( - 3.dp, - Alignment.Bottom - ), - horizontalAlignment = Alignment.Start, - modifier = modifier - .padding( - horizontal = 12.dp - ) - ) { - Text( - text = company, - style = TerningTheme.typography.title4, - color = Black, - modifier = modifier.padding(top = 11.dp), - maxLines = MAX_LINES, - overflow = TextOverflow.Ellipsis - ) - Text( - text = companyCategory, - style = TerningTheme.typography.body4, - color = Grey300, - modifier = modifier.padding(bottom = 6.dp) + modifier = Modifier + .size(128.dp) + .border( + width = 1.dp, + color = Grey150, + shape = RoundedCornerShape(size = 20.dp) ) - } + ) { + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .crossfade(true) + .data(companyImage) + .build(), + contentDescription = stringResource(id = R.string.search_image), + contentScale = ContentScale.Fit, + modifier = Modifier + .fillMaxWidth() + .clip(CircleShape), + ) + } + Column( + verticalArrangement = Arrangement.spacedBy( + 4.dp, + Alignment.Bottom + ), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = company, + style = TerningTheme.typography.title4, + color = Black, + modifier = modifier.padding(top = 20.dp), + maxLines = MAX_LINES, + overflow = TextOverflow.Ellipsis + ) + Text( + text = companyCategory, + style = TerningTheme.typography.body4, + color = Grey350, + modifier = modifier.padding(bottom = 8.dp) + ) } } } \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/intern/component/InternInfoRow.kt b/feature/src/main/java/com/terning/feature/intern/component/InternInfoRow.kt index 073e4ae7b..756b4c097 100644 --- a/feature/src/main/java/com/terning/feature/intern/component/InternInfoRow.kt +++ b/feature/src/main/java/com/terning/feature/intern/component/InternInfoRow.kt @@ -13,13 +13,13 @@ import com.terning.core.designsystem.theme.TerningTheme @Composable fun InternInfoRow(title: String, value: String) { Row( - horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.Start), + horizontalArrangement = Arrangement.spacedBy(23.dp, Alignment.Start), verticalAlignment = Alignment.Top, ) { Text( text = title, style = TerningTheme.typography.body2, - color = Grey400, + color = Grey500, ) Text( text = value, diff --git a/feature/src/main/java/com/terning/feature/intern/component/InternPageTitle.kt b/feature/src/main/java/com/terning/feature/intern/component/InternPageTitle.kt index 011191a5a..79aa47b82 100644 --- a/feature/src/main/java/com/terning/feature/intern/component/InternPageTitle.kt +++ b/feature/src/main/java/com/terning/feature/intern/component/InternPageTitle.kt @@ -1,39 +1,43 @@ package com.terning.feature.intern.component -import androidx.compose.foundation.background +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text +import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import com.terning.core.designsystem.theme.Black import com.terning.core.designsystem.theme.TerningMain -import com.terning.core.designsystem.theme.TerningSub4 import com.terning.core.designsystem.theme.TerningTheme @Composable fun InternPageTitle( modifier: Modifier, - text: String + text: String, ) { Row( modifier = modifier + .height(IntrinsicSize.Min) .fillMaxWidth() .padding( - top = 16.dp, - bottom = 16.dp + top = 7.dp, + bottom = 6.dp, ) - .background(TerningSub4) ) { + VerticalDivider( + color = TerningMain, + thickness = 2.dp, + ) Text( text = text, style = TerningTheme.typography.title4, - color = TerningMain, + color = Black, modifier = modifier.padding( - top = 7.dp, - bottom = 6.dp, - start = 20.dp + start = 8.dp ) ) } diff --git a/feature/src/main/java/com/terning/feature/intern/component/InternTitle.kt b/feature/src/main/java/com/terning/feature/intern/component/InternTitle.kt new file mode 100644 index 000000000..0d6a34e7c --- /dev/null +++ b/feature/src/main/java/com/terning/feature/intern/component/InternTitle.kt @@ -0,0 +1,82 @@ +package com.terning.feature.intern.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +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 com.terning.core.designsystem.component.image.TerningImage +import com.terning.core.designsystem.theme.Black +import com.terning.core.designsystem.theme.Grey375 +import com.terning.core.designsystem.theme.TerningMain +import com.terning.core.designsystem.theme.TerningSub3 +import com.terning.core.designsystem.theme.TerningTheme +import com.terning.feature.R + + +@Composable +fun InternTitle( + modifier: Modifier, + dDay: String, + title: String, + viewCount: String, +) { + Column( + modifier = modifier + .fillMaxWidth(), + ) { + Row( + modifier = Modifier + .background( + color = TerningSub3, + shape = RoundedCornerShape(size = 5.dp) + ), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = dDay, + style = TerningTheme.typography.title3, + color = TerningMain, + modifier = Modifier.padding( + horizontal = 19.5.dp, + vertical = 1.5.dp + ) + ) + } + + Text( + text = title, + style = TerningTheme.typography.heading2, + color = Black, + modifier = modifier.padding( + top = 8.dp, + bottom = 4.dp + ) + ) + + Row( + horizontalArrangement = Arrangement.spacedBy(3.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + ) { + TerningImage( + painter = R.drawable.ic_view_count_14 + ) + Text( + text = stringResource(id = R.string.intern_view_count_detail, viewCount), + style = TerningTheme.typography.detail2, + color = Grey375, + ) + } + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/intern/component/ScrapDialogContent.kt b/feature/src/main/java/com/terning/feature/intern/component/ScrapDialogContent.kt index 49f107b0b..3746f5f13 100644 --- a/feature/src/main/java/com/terning/feature/intern/component/ScrapDialogContent.kt +++ b/feature/src/main/java/com/terning/feature/intern/component/ScrapDialogContent.kt @@ -65,7 +65,7 @@ fun ScrapDialogContent( announcementId: Long, type: Int, ) { - val state by viewModel.internState.collectAsStateWithLifecycle() + val state by viewModel.internUiState.collectAsStateWithLifecycle() val colorList = listOf( CalRed, diff --git a/feature/src/main/java/com/terning/feature/intern/model/InternViewState.kt b/feature/src/main/java/com/terning/feature/intern/model/InternUiState.kt similarity index 83% rename from feature/src/main/java/com/terning/feature/intern/model/InternViewState.kt rename to feature/src/main/java/com/terning/feature/intern/model/InternUiState.kt index 499fe2c6f..16f8afcc3 100644 --- a/feature/src/main/java/com/terning/feature/intern/model/InternViewState.kt +++ b/feature/src/main/java/com/terning/feature/intern/model/InternUiState.kt @@ -5,8 +5,8 @@ import com.terning.core.designsystem.theme.CalRed import com.terning.core.state.UiState import com.terning.domain.entity.response.InternInfoModel -data class InternViewState( - var internInfo: UiState = UiState.Loading, +data class InternUiState( + val loadState: UiState = UiState.Loading, val isColorChange: Boolean = false, val isPaletteOpen: Boolean = false, val selectedColor: Color = CalRed, diff --git a/feature/src/main/java/com/terning/feature/intern/navigation/InternNavigation.kt b/feature/src/main/java/com/terning/feature/intern/navigation/InternNavigation.kt index 486134573..7bc5c14c3 100644 --- a/feature/src/main/java/com/terning/feature/intern/navigation/InternNavigation.kt +++ b/feature/src/main/java/com/terning/feature/intern/navigation/InternNavigation.kt @@ -41,8 +41,8 @@ fun NavGraphBuilder.internNavGraph( ) { val args = it.toRoute() InternRoute( - navController = navHostController, announcementId = args.announcementId, + navController = navHostController ) } } diff --git a/feature/src/main/java/com/terning/feature/main/MainNavigator.kt b/feature/src/main/java/com/terning/feature/main/MainNavigator.kt index 901d0fed0..f0598bf1f 100644 --- a/feature/src/main/java/com/terning/feature/main/MainNavigator.kt +++ b/feature/src/main/java/com/terning/feature/main/MainNavigator.kt @@ -11,7 +11,7 @@ import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions import com.terning.feature.calendar.calendar.navigation.navigateCalendar import com.terning.feature.home.home.navigation.navigateHome -import com.terning.feature.mypage.navigation.navigateMyPage +import com.terning.feature.mypage.mypage.navigation.navigateMyPage import com.terning.feature.onboarding.splash.navigation.Splash import com.terning.feature.search.search.navigation.navigateSearch diff --git a/feature/src/main/java/com/terning/feature/main/MainScreen.kt b/feature/src/main/java/com/terning/feature/main/MainScreen.kt index e5fbb5d02..d78934eba 100644 --- a/feature/src/main/java/com/terning/feature/main/MainScreen.kt +++ b/feature/src/main/java/com/terning/feature/main/MainScreen.kt @@ -1,23 +1,24 @@ package com.terning.feature.main import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.tween -import androidx.compose.animation.expandVertically -import androidx.compose.animation.shrinkVertically -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideIn +import androidx.compose.animation.slideOut import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Icon import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.Scaffold 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.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.sp import androidx.navigation.compose.NavHost import com.terning.core.designsystem.theme.Grey300 @@ -33,7 +34,8 @@ import com.terning.feature.filtering.starthome.navigation.startHomeNavGraph import com.terning.feature.home.changefilter.navigation.changeFilterNavGraph import com.terning.feature.home.home.navigation.homeNavGraph import com.terning.feature.intern.navigation.internNavGraph -import com.terning.feature.mypage.navigation.myPageNavGraph +import com.terning.feature.mypage.mypage.navigation.myPageNavGraph +import com.terning.feature.mypage.profileedit.navigation.profileEditNavGraph import com.terning.feature.onboarding.signin.navigation.signInNavGraph import com.terning.feature.onboarding.signup.navigation.signUpNavGraph import com.terning.feature.onboarding.splash.navigation.splashNavGraph @@ -53,31 +55,72 @@ fun MainScreen( onTabSelected = navigator::navigate ) }, - ) { innerPadding -> + ) { paddingValues -> Column( - modifier = Modifier - .padding(innerPadding), - verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.fillMaxSize() ) { NavHost( + enterTransition = { + EnterTransition.None + }, + exitTransition = { + ExitTransition.None + }, + popEnterTransition = { + EnterTransition.None + }, + popExitTransition = { + ExitTransition.None + }, navController = navigator.navController, startDestination = navigator.startDestination ) { - splashNavGraph(navHostController = navigator.navController) - homeNavGraph(navHostController = navigator.navController) + splashNavGraph( + paddingValues = paddingValues, + navHostController = navigator.navController + ) + homeNavGraph( + paddingValues = paddingValues, + navHostController = navigator.navController + ) calendarNavGraph(navHostController = navigator.navController) searchNavGraph(navHostController = navigator.navController) - myPageNavGraph(navHostController = navigator.navController) - signInNavGraph(navHostController = navigator.navController) - signUpNavGraph(navHostController = navigator.navController) - filteringOneNavGraph(navHostController = navigator.navController) - filteringTwoNavGraph(navHostController = navigator.navController) - filteringThreeNavGraph(navHostController = navigator.navController) + signInNavGraph( + paddingValues = paddingValues, + navHostController = navigator.navController + ) + signUpNavGraph( + paddingValues = paddingValues, + navHostController = navigator.navController + ) + startFilteringNavGraph( + paddingValues = paddingValues, + navHostController = navigator.navController + ) + startHomeNavGraph( + paddingValues = paddingValues, + navHostController = navigator.navController + ) + filteringOneNavGraph( + paddingValues = paddingValues, + navHostController = navigator.navController + ) + filteringTwoNavGraph( + paddingValues = paddingValues, + navHostController = navigator.navController + ) + filteringThreeNavGraph( + paddingValues = paddingValues, + navHostController = navigator.navController + ) searchProcessNavGraph(navHostController = navigator.navController) changeFilterNavGraph(navHostController = navigator.navController) - startFilteringNavGraph(navHostController = navigator.navController) - startHomeNavGraph(navHostController = navigator.navController) internNavGraph(navHostController = navigator.navController) + myPageNavGraph( + paddingValues = paddingValues, + navHostController = navigator.navController + ) + profileEditNavGraph(navHostController = navigator.navController) } } } @@ -92,10 +135,8 @@ private fun MainBottomBar( ) { AnimatedVisibility( visible = isVisible, - enter = expandVertically(expandFrom = Alignment.Top) { 20 }, - exit = shrinkVertically(animationSpec = tween()) { fullHeight -> - fullHeight / 2 - }, + enter = fadeIn() + slideIn { IntOffset(0, 0) }, + exit = fadeOut() + slideOut { IntOffset(0, 0) } ) { NavigationBar(containerColor = White) { tabs.forEach { itemType -> diff --git a/feature/src/main/java/com/terning/feature/main/MainTab.kt b/feature/src/main/java/com/terning/feature/main/MainTab.kt index 179669c64..993a7c47a 100644 --- a/feature/src/main/java/com/terning/feature/main/MainTab.kt +++ b/feature/src/main/java/com/terning/feature/main/MainTab.kt @@ -8,7 +8,7 @@ import com.terning.core.navigation.Route import com.terning.feature.R import com.terning.feature.calendar.calendar.navigation.Calendar import com.terning.feature.home.home.navigation.Home -import com.terning.feature.mypage.navigation.MyPage +import com.terning.feature.mypage.mypage.navigation.MyPage import com.terning.feature.search.search.navigation.Search enum class MainTab( diff --git a/feature/src/main/java/com/terning/feature/mypage/MyPageRoute.kt b/feature/src/main/java/com/terning/feature/mypage/mypage/MyPageRoute.kt similarity index 77% rename from feature/src/main/java/com/terning/feature/mypage/MyPageRoute.kt rename to feature/src/main/java/com/terning/feature/mypage/mypage/MyPageRoute.kt index bf41f671d..e520d3504 100644 --- a/feature/src/main/java/com/terning/feature/mypage/MyPageRoute.kt +++ b/feature/src/main/java/com/terning/feature/mypage/mypage/MyPageRoute.kt @@ -1,9 +1,10 @@ -package com.terning.feature.mypage +package com.terning.feature.mypage.mypage import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -14,11 +15,9 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -26,7 +25,9 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.flowWithLifecycle import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.terning.core.designsystem.component.bottomsheet.MyPageLogoutBottomSheet import com.terning.core.designsystem.component.bottomsheet.MyPageQuitBottomSheet @@ -41,19 +42,18 @@ import com.terning.core.designsystem.theme.White import com.terning.core.extension.noRippleClickable import com.terning.core.state.UiState import com.terning.feature.R -import com.terning.feature.mypage.component.MyPageItem import com.terning.feature.mypage.component.MyPageProfile +import com.terning.feature.mypage.mypage.component.MyPageItem @Composable fun MyPageRoute( + paddingValues: PaddingValues, + navigateToProfileEdit: (String, Int) -> Unit, viewModel: MyPageViewModel = hiltViewModel(), ) { val state by viewModel.state.collectAsStateWithLifecycle() val context = LocalContext.current - - var name by remember { mutableStateOf(state.name) } - // TODO: 프로필로 바꾸기 - var profile by remember { mutableStateOf(state.authType) } + val lifecycleOwner = LocalLifecycleOwner.current val systemUiController = rememberSystemUiController() @@ -63,6 +63,18 @@ fun MyPageRoute( ) } + LaunchedEffect(viewModel.sideEffects, lifecycleOwner) { + viewModel.sideEffects.flowWithLifecycle(lifecycle = lifecycleOwner.lifecycle) + .collect { sideEffect -> + when (sideEffect) { + is MyPageSideEffect.NavigateToProfileEdit -> navigateToProfileEdit( + state.name, + state.profile + ) + } + } + } + if (state.showLogoutBottomSheet) { MyPageLogoutBottomSheet( onDismiss = { viewModel.fetchShowLogoutBottomSheet(false) }, @@ -93,9 +105,18 @@ fun MyPageRoute( when (state.isGetSuccess) { is UiState.Success -> { - name = state.name - // TODO: 프로필로 바꾸기 - profile = state.authType + MyPageScreen( + paddingValues = paddingValues, + onEditClick = { viewModel.navigateToProfileEdit() }, + onLogoutClick = { viewModel.fetchShowLogoutBottomSheet(true) }, + onQuitClick = { viewModel.fetchShowQuitBottomSheet(true) }, + onNoticeClick = { viewModel.fetchShowNotice(true) }, + onOpinionClick = { viewModel.fetchShowOpinion(true) }, + onServiceClick = {}, + onPersonalClick = {}, + name = state.name, + profile = state.profile + ) } is UiState.Loading -> {} @@ -112,33 +133,26 @@ fun MyPageRoute( viewModel.navigateToOpinionWebView(context) viewModel.fetchShowOpinion(false) } - - MyPageScreen( - onLogoutClick = { viewModel.fetchShowLogoutBottomSheet(true) }, - onQuitClick = { viewModel.fetchShowQuitBottomSheet(true) }, - onNoticeClick = { viewModel.fetchShowNotice(true) }, - onOpinionClick = { viewModel.fetchShowOpinion(true) }, - onEditClick = { /*TODO: 프로필 수정으로 이동*/ }, - name = name, - profile = profile - ) } @Composable fun MyPageScreen( + onEditClick: () -> Unit, onLogoutClick: () -> Unit, onQuitClick: () -> Unit, onNoticeClick: () -> Unit, onOpinionClick: () -> Unit, - onEditClick: () -> Unit, - modifier: Modifier = Modifier, + onServiceClick: () -> Unit, + onPersonalClick: () -> Unit, + paddingValues: PaddingValues = PaddingValues(), name: String = "", - profile: String = "" + profile: Int = 0 ) { Column( - modifier = modifier + modifier = Modifier .fillMaxSize() .background(Back) + .padding(paddingValues) ) { UserProfile( name = name, @@ -146,12 +160,12 @@ fun MyPageScreen( onEditClick = onEditClick ) TerningCommunity( - onNoticeClick = onNoticeClick, + onNoticeClick = onNoticeClick, onOpinionClick = onOpinionClick ) ServiceInfo( - onNoticeClick = onNoticeClick, - onOpinionClick = onOpinionClick + onServiceClick = onServiceClick, + onPersonalClick = onPersonalClick ) Row( modifier = Modifier @@ -195,7 +209,7 @@ fun UserProfile( name: String, onEditClick: () -> Unit, modifier: Modifier = Modifier, - profile: String = "PROFILE_00", + profile: Int = 0, ) { Row( modifier = modifier.padding( @@ -215,10 +229,12 @@ fun UserProfile( bottom = 7.dp ) ) - Row(verticalAlignment = Alignment.CenterVertically, + Row( + verticalAlignment = Alignment.CenterVertically, modifier = Modifier.noRippleClickable { onEditClick() - }) { + } + ) { Text( text = stringResource(id = R.string.my_page_edit_profile), modifier = Modifier.padding(start = 16.dp, end = 7.dp), @@ -267,20 +283,19 @@ fun TerningCommunity( modifier = Modifier.padding(bottom = 20.dp) ) MyPageItem( - text = stringResource(id = R.string.my_page_information), + text = stringResource(id = R.string.my_page_notice), icon = R.drawable.ic_my_page_notice, - onButtonClick = { onNoticeClick() } + onButtonClick = onNoticeClick ) HorizontalDivider( - modifier = Modifier - .padding(vertical = 20.dp), + modifier = Modifier.padding(vertical = 20.dp), thickness = 1.dp, color = Grey150 ) MyPageItem( text = stringResource(id = R.string.my_page_opinion), icon = R.drawable.ic_my_page_opinion, - onButtonClick = { onOpinionClick() } + onButtonClick = onOpinionClick ) } } @@ -289,8 +304,8 @@ fun TerningCommunity( @Composable fun ServiceInfo( modifier: Modifier = Modifier, - onNoticeClick: () -> Unit, - onOpinionClick: () -> Unit + onServiceClick: () -> Unit, + onPersonalClick: () -> Unit ) { Column( modifier = modifier @@ -321,24 +336,22 @@ fun ServiceInfo( modifier = Modifier.padding(bottom = 20.dp) ) MyPageItem( - text = stringResource(id = R.string.my_page_notice), - icon = R.drawable.ic_my_page_notice, - onButtonClick = { onNoticeClick() } + text = stringResource(id = R.string.my_page_service), + icon = R.drawable.ic_my_page_service, + onButtonClick = onServiceClick ) HorizontalDivider( - modifier = Modifier - .padding(vertical = 20.dp), + modifier = Modifier.padding(vertical = 20.dp), thickness = 1.dp, color = Grey150 ) MyPageItem( - text = stringResource(id = R.string.my_page_private_information), - icon = R.drawable.ic_my_page_opinion, - onButtonClick = { onOpinionClick() } + text = stringResource(id = R.string.my_page_personal), + icon = R.drawable.ic_my_page_personal, + onButtonClick = onPersonalClick ) HorizontalDivider( - modifier = Modifier - .padding(vertical = 20.dp), + modifier = Modifier.padding(vertical = 20.dp), thickness = 1.dp, color = Grey150 ) @@ -363,7 +376,9 @@ fun MyPageScreenPreview() { onOpinionClick = {}, onLogoutClick = {}, onQuitClick = {}, - onEditClick = {} + onEditClick = {}, + onServiceClick = {}, + onPersonalClick = {}, ) } } \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/mypage/mypage/MyPageSideEffect.kt b/feature/src/main/java/com/terning/feature/mypage/mypage/MyPageSideEffect.kt new file mode 100644 index 000000000..26d1e5856 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/mypage/mypage/MyPageSideEffect.kt @@ -0,0 +1,5 @@ +package com.terning.feature.mypage.mypage + +sealed class MyPageSideEffect { + data object NavigateToProfileEdit : MyPageSideEffect() +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/mypage/MyPageState.kt b/feature/src/main/java/com/terning/feature/mypage/mypage/MyPageState.kt similarity index 79% rename from feature/src/main/java/com/terning/feature/mypage/MyPageState.kt rename to feature/src/main/java/com/terning/feature/mypage/mypage/MyPageState.kt index e74a16fe8..bf072cb13 100644 --- a/feature/src/main/java/com/terning/feature/mypage/MyPageState.kt +++ b/feature/src/main/java/com/terning/feature/mypage/mypage/MyPageState.kt @@ -1,4 +1,4 @@ -package com.terning.feature.mypage +package com.terning.feature.mypage.mypage import com.terning.core.state.UiState @@ -6,7 +6,8 @@ data class MyPageState( val isLogoutAndQuitSuccess: UiState = UiState.Loading, val isGetSuccess: UiState = UiState.Loading, val name: String = "", - val authType: String = "", + val profile: Int = 0, + val authType : String ="", val showNotice: Boolean = false, val showOpinion: Boolean = false, val showLogoutBottomSheet : Boolean = false, diff --git a/feature/src/main/java/com/terning/feature/mypage/MyPageViewModel.kt b/feature/src/main/java/com/terning/feature/mypage/mypage/MyPageViewModel.kt similarity index 83% rename from feature/src/main/java/com/terning/feature/mypage/MyPageViewModel.kt rename to feature/src/main/java/com/terning/feature/mypage/mypage/MyPageViewModel.kt index d5e87497b..b4f39bb61 100644 --- a/feature/src/main/java/com/terning/feature/mypage/MyPageViewModel.kt +++ b/feature/src/main/java/com/terning/feature/mypage/mypage/MyPageViewModel.kt @@ -1,4 +1,4 @@ -package com.terning.feature.mypage +package com.terning.feature.mypage.mypage import android.content.Context import android.content.Intent @@ -15,8 +15,11 @@ import com.terning.domain.repository.MyPageRepository import com.terning.domain.repository.TokenRepository import com.terning.feature.main.MainActivity import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import javax.inject.Inject @@ -34,6 +37,9 @@ class MyPageViewModel @Inject constructor( private val _state: MutableStateFlow = MutableStateFlow(MyPageState()) val state: StateFlow get() = _state.asStateFlow() + private val _sideEffects = MutableSharedFlow() + val sideEffects: SharedFlow get() = _sideEffects.asSharedFlow() + fun logoutKakao() { UserApiClient.instance.logout { error -> if (error == null) { @@ -95,14 +101,14 @@ class MyPageViewModel @Inject constructor( viewModelScope.launch { myPageRepository.getProfile() .onSuccess { response -> - _state.value = _state.value.copy( - isGetSuccess = UiState.Success(true), - name = response.name, - authType = response.authType - ) - }.onFailure { - _state.value = _state.value.copy(isGetSuccess = UiState.Failure(it.toString())) - } + _state.value = _state.value.copy( + isGetSuccess = UiState.Success(true), + name = response.name, + authType = response.authType + ) + }.onFailure { + _state.value = _state.value.copy(isGetSuccess = UiState.Failure(it.toString())) + } } } @@ -134,6 +140,9 @@ class MyPageViewModel @Inject constructor( customTabsIntent.launchUrl(context, url) } + fun navigateToProfileEdit() = + viewModelScope.launch { _sideEffects.emit(MyPageSideEffect.NavigateToProfileEdit) } + companion object { private const val NOTICE_URL = "https://abundant-quiver-13f.notion.site/69109213e7db4873be6b9600f2f5163a" diff --git a/feature/src/main/java/com/terning/feature/mypage/component/MyPageItem.kt b/feature/src/main/java/com/terning/feature/mypage/mypage/component/MyPageItem.kt similarity index 97% rename from feature/src/main/java/com/terning/feature/mypage/component/MyPageItem.kt rename to feature/src/main/java/com/terning/feature/mypage/mypage/component/MyPageItem.kt index 10346d75d..ca15cd033 100644 --- a/feature/src/main/java/com/terning/feature/mypage/component/MyPageItem.kt +++ b/feature/src/main/java/com/terning/feature/mypage/mypage/component/MyPageItem.kt @@ -1,4 +1,4 @@ -package com.terning.feature.mypage.component +package com.terning.feature.mypage.mypage.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row diff --git a/feature/src/main/java/com/terning/feature/mypage/component/MyPageProfile.kt b/feature/src/main/java/com/terning/feature/mypage/mypage/component/MyPageProfile.kt similarity index 67% rename from feature/src/main/java/com/terning/feature/mypage/component/MyPageProfile.kt rename to feature/src/main/java/com/terning/feature/mypage/mypage/component/MyPageProfile.kt index c57969e3c..cd12d2623 100644 --- a/feature/src/main/java/com/terning/feature/mypage/component/MyPageProfile.kt +++ b/feature/src/main/java/com/terning/feature/mypage/mypage/component/MyPageProfile.kt @@ -1,18 +1,20 @@ package com.terning.feature.mypage.component +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.terning.core.R -import com.terning.core.designsystem.component.image.TerningImage @Composable fun MyPageProfile( modifier: Modifier = Modifier, - profile: String + profile: Int ) { val options = listOf( R.drawable.ic_terning_profile_00, @@ -24,18 +26,20 @@ fun MyPageProfile( ) val option = when (profile) { - "PROFILE_00" -> options[0] - "PROFILE_01" -> options[1] - "PROFILE_02" -> options[2] - "PROFILE_03" -> options[3] - "PROFILE_04" -> options[4] + 0 -> options[0] + 1 -> options[1] + 2 -> options[2] + 3 -> options[3] + 4 -> options[4] else -> options[5] } - TerningImage( - painter = option, + Image( + painter = painterResource(id = option), modifier = modifier .size(72.dp) .clip(shape = CircleShape) + .aspectRatio(1f), + contentDescription = "profile image" ) } diff --git a/feature/src/main/java/com/terning/feature/mypage/navigation/MyPageNavigation.kt b/feature/src/main/java/com/terning/feature/mypage/mypage/navigation/MyPageNavigation.kt similarity index 50% rename from feature/src/main/java/com/terning/feature/mypage/navigation/MyPageNavigation.kt rename to feature/src/main/java/com/terning/feature/mypage/mypage/navigation/MyPageNavigation.kt index c028d5967..7248c8a2a 100644 --- a/feature/src/main/java/com/terning/feature/mypage/navigation/MyPageNavigation.kt +++ b/feature/src/main/java/com/terning/feature/mypage/mypage/navigation/MyPageNavigation.kt @@ -1,14 +1,14 @@ -package com.terning.feature.mypage.navigation +package com.terning.feature.mypage.mypage.navigation -import androidx.compose.animation.EnterTransition -import androidx.compose.animation.ExitTransition +import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.terning.core.navigation.MainTabRoute -import com.terning.feature.mypage.MyPageRoute +import com.terning.feature.mypage.mypage.MyPageRoute +import com.terning.feature.mypage.profileedit.navigation.navigateProfileEdit import kotlinx.serialization.Serializable fun NavController.navigateMyPage(navOptions: NavOptions? = null) { @@ -19,23 +19,19 @@ fun NavController.navigateMyPage(navOptions: NavOptions? = null) { } fun NavGraphBuilder.myPageNavGraph( + paddingValues: PaddingValues, navHostController: NavHostController, ) { - composable( - exitTransition = { - ExitTransition.None - }, - popEnterTransition = { - EnterTransition.None - }, - enterTransition = { - EnterTransition.None - }, - popExitTransition = { - ExitTransition.None - } - ) { - MyPageRoute() + composable { + MyPageRoute( + paddingValues = paddingValues, + navigateToProfileEdit = { name, profile -> + navHostController.navigateProfileEdit( + name, + profile + ) + } + ) } } diff --git a/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditRoute.kt b/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditRoute.kt new file mode 100644 index 000000000..577c5689b --- /dev/null +++ b/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditRoute.kt @@ -0,0 +1,197 @@ +package com.terning.feature.mypage.profileedit + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.LocalLifecycleOwner +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.flowWithLifecycle +import com.google.accompanist.systemuicontroller.rememberSystemUiController +import com.terning.core.designsystem.component.bottomsheet.ProfileBottomSheet +import com.terning.core.designsystem.component.button.RectangleButton +import com.terning.core.designsystem.component.item.ProfileWithPlusButton +import com.terning.core.designsystem.component.textfield.NameTextField +import com.terning.core.designsystem.component.topappbar.BackButtonTopAppBar +import com.terning.core.designsystem.theme.Grey500 +import com.terning.core.designsystem.theme.TerningPointTheme +import com.terning.core.designsystem.theme.TerningTheme +import com.terning.core.designsystem.theme.White +import com.terning.core.extension.addFocusCleaner +import com.terning.core.extension.noRippleClickable +import com.terning.feature.R + +@Composable +fun ProfileEditRoute( + navigateUp: () -> Unit, + initialName: String, + initialProfile: Int, + viewModel: ProfileEditViewModel = hiltViewModel(), +) { + val state by viewModel.state.collectAsStateWithLifecycle() + + val lifecycleOwner = LocalLifecycleOwner.current + + val systemUiController = rememberSystemUiController() + + SideEffect { + systemUiController.setStatusBarColor( + color = White + ) + } + + LaunchedEffect(key1 = true) { + viewModel.updateInitialInfo(initialName = initialName, initialProfile = initialProfile) + } + + LaunchedEffect(viewModel.sideEffects, lifecycleOwner) { + viewModel.sideEffects.flowWithLifecycle(lifecycle = lifecycleOwner.lifecycle) + .collect { sideEffect -> + when (sideEffect) { + is ProfileEditSideEffect.NavigateUp -> navigateUp() + } + } + } + + if (state.showBottomSheet) { + ProfileBottomSheet( + onDismiss = { viewModel.updateBottomSheet(false) }, + onSaveClick = { index -> + viewModel.updateBottomSheet(false) + viewModel.updateProfile(index) + }, + initialSelectedOption = state.profile + ) + } + + ProfileEditScreen( + profileEditState = state, + onProfileEditClick = { isVisible -> + viewModel.updateBottomSheet(isVisible) + }, + onInputChange = { editName -> + viewModel.updateName(editName) + }, + onSaveClick = { viewModel.navigateUp() }, + name = state.name, + onBackButtonClick = { viewModel.navigateUp() }, + onValidationChanged = { isValid -> + viewModel.updateButtonValidation(isValid) + } + ) +} + +@Composable +fun ProfileEditScreen( + profileEditState: ProfileEditState, + onProfileEditClick: (Boolean) -> Unit, + onInputChange: (String) -> Unit, + onSaveClick: () -> Unit, + name: String, + onBackButtonClick: () -> Unit, + onValidationChanged: (Boolean) -> Unit, +) { + val focusManager = LocalFocusManager.current + + Column( + modifier = Modifier + .statusBarsPadding() + .navigationBarsPadding() + .fillMaxSize() + .addFocusCleaner(focusManager) + .background(White) + ) { + BackButtonTopAppBar( + onBackButtonClick = { onBackButtonClick() }, + title = stringResource(id = R.string.profile_edit_title), + ) + Spacer(modifier = Modifier.height(24.dp)) + Column( + modifier = Modifier.padding(horizontal = 24.dp) + ) { + Text( + text = stringResource(id = R.string.sign_up_profile_image), + style = TerningTheme.typography.body2, + color = Grey500 + ) + Spacer(modifier = Modifier.height(20.dp)) + ProfileWithPlusButton( + modifier = Modifier + .noRippleClickable { + onProfileEditClick(true) + } + .align(Alignment.CenterHorizontally), + index = profileEditState.profile + ) + Spacer(modifier = Modifier.height(48.dp)) + Text( + text = stringResource(id = R.string.sign_up_name), + color = Grey500 + ) + Spacer(modifier = Modifier.height(20.dp)) + NameTextField( + value = name, + onValueChange = { editName -> + onInputChange(editName) + }, + hint = stringResource(id = R.string.sign_up_hint), + onValidationChanged = { isValid -> + onValidationChanged(isValid) + }, + initialView = profileEditState.initialView + ) + Spacer(modifier = Modifier.height(48.dp)) + Text( + text = stringResource(id = R.string.profile_edit_auth_type), + style = TerningTheme.typography.body2, + color = Grey500, + ) + Spacer(modifier = Modifier.height(11.dp)) + Text( + text = profileEditState.authType, + style = TerningTheme.typography.detail0 + ) + } + Spacer(modifier = Modifier.weight(1f)) + RectangleButton( + style = TerningTheme.typography.button1, + paddingVertical = 20.dp, + text = R.string.profile_edit_save, + onButtonClick = onSaveClick, + isEnabled = profileEditState.isButtonValid, + ) + Spacer(modifier = Modifier.height(12.dp)) + } +} + +@Preview(showBackground = true) +@Composable +fun ProfileEditScreenPreview() { + TerningPointTheme { + ProfileEditScreen( + profileEditState = ProfileEditState(), + onProfileEditClick = {}, + onInputChange = {}, + onSaveClick = {}, + name = "터닝이", + onBackButtonClick = {}, + onValidationChanged = {} + ) + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditSideEffect.kt b/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditSideEffect.kt new file mode 100644 index 000000000..6fd2f3668 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditSideEffect.kt @@ -0,0 +1,5 @@ +package com.terning.feature.mypage.profileedit + +sealed class ProfileEditSideEffect { + data object NavigateUp : ProfileEditSideEffect() +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditState.kt b/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditState.kt new file mode 100644 index 000000000..eb34b9548 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditState.kt @@ -0,0 +1,11 @@ +package com.terning.feature.mypage.profileedit + +data class ProfileEditState( + val name: String = "", + val initialName: String = "", + val profile: Int = 0, + val initialView: Boolean = true, + val isButtonValid: Boolean = false, + val authType: String = "", + val showBottomSheet: Boolean = false +) \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditViewModel.kt b/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditViewModel.kt new file mode 100644 index 000000000..58bf6349f --- /dev/null +++ b/feature/src/main/java/com/terning/feature/mypage/profileedit/ProfileEditViewModel.kt @@ -0,0 +1,50 @@ +package com.terning.feature.mypage.profileedit + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class ProfileEditViewModel @Inject constructor() : ViewModel() { + + private val _state: MutableStateFlow = MutableStateFlow(ProfileEditState()) + val state: StateFlow get() = _state.asStateFlow() + + private val _sideEffects = MutableSharedFlow() + val sideEffects: SharedFlow get() = _sideEffects.asSharedFlow() + + fun navigateUp() = viewModelScope.launch { _sideEffects.emit(ProfileEditSideEffect.NavigateUp) } + + fun updateBottomSheet(isVisible: Boolean) { + _state.value = _state.value.copy(showBottomSheet = isVisible) + } + + fun updateInitialInfo(initialName: String, initialProfile: Int) { + _state.value = _state.value.copy( + name = initialName, + initialName = initialName, + profile = initialProfile, + ) + } + + fun updateName(name: String) { + _state.value = _state.value.copy(name = name, initialView = false) + } + + fun updateProfile(profile: Int) { + _state.value = _state.value.copy(profile = profile, initialView = false) + } + + fun updateButtonValidation(isValid: Boolean) { + _state.value = _state.value.copy(isButtonValid = isValid) + } + +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/mypage/profileedit/navigation/ProfileEditNavigation.kt b/feature/src/main/java/com/terning/feature/mypage/profileedit/navigation/ProfileEditNavigation.kt new file mode 100644 index 000000000..71ef7f910 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/mypage/profileedit/navigation/ProfileEditNavigation.kt @@ -0,0 +1,58 @@ +package com.terning.feature.mypage.profileedit.navigation + +import androidx.compose.animation.core.LinearOutSlowInEasing +import androidx.compose.animation.core.tween +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.NavOptions +import androidx.navigation.compose.composable +import androidx.navigation.toRoute +import com.terning.core.navigation.Route +import com.terning.feature.mypage.profileedit.ProfileEditRoute +import kotlinx.serialization.Serializable + +fun NavController.navigateProfileEdit( + name: String, + profile: Int, + navOptions: NavOptions? = null +) { + navigate( + route = ProfileEdit(name = name, profile = profile), + navOptions = navOptions + ) +} + +fun NavGraphBuilder.profileEditNavGraph( + navHostController: NavHostController, +) { + composable( + enterTransition = { + slideInHorizontally( + initialOffsetX = { it }, + animationSpec = tween(durationMillis = 700, easing = LinearOutSlowInEasing) + ) + }, + popExitTransition = { + slideOutHorizontally( + targetOffsetX = { it }, + animationSpec = tween(durationMillis = 700, easing = LinearOutSlowInEasing) + ) + }, + ) { + val args = it.toRoute() + ProfileEditRoute( + initialName = args.name, + initialProfile = args.profile, + navigateUp = { navHostController.navigateUp() } + ) + } +} + +@Serializable +data class ProfileEdit( + val name: String, + val profile: Int +) : Route \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt index 43b79c8c6..9b946f9f5 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt +++ b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt @@ -3,6 +3,7 @@ package com.terning.feature.onboarding.signin import android.content.Context import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -31,6 +32,7 @@ import com.terning.feature.onboarding.signin.component.KakaoButton @Composable fun SignInRoute( + paddingValues: PaddingValues, navigateToHome: () -> Unit, navigateToSignUp: (String) -> Unit, viewModel: SignInViewModel = hiltViewModel(), @@ -79,6 +81,7 @@ fun SignInRoute( } SignInScreen( + paddingValues = paddingValues, onSignInClick = { viewModel.startKakaoLogIn( isKakaoAvailable = UserApiClient.instance.isKakaoTalkLoginAvailable( @@ -91,29 +94,28 @@ fun SignInRoute( @Composable fun SignInScreen( - modifier: Modifier = Modifier, - onSignInClick: () -> Unit = {}, + onSignInClick: () -> Unit, + paddingValues: PaddingValues = PaddingValues(), ) { Column( - modifier = modifier + modifier = Modifier .fillMaxSize() .background(color = White) + .padding(paddingValues) .padding(horizontal = 20.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - Spacer(modifier = modifier.weight(1f)) + Spacer(modifier = Modifier.weight(1f)) TerningImage( painter = R.drawable.ic_terning_login, modifier = Modifier.fillMaxWidth() ) - Spacer(modifier = modifier.weight(1f)) + Spacer(modifier = Modifier.weight(1f)) KakaoButton( title = stringResource(id = R.string.sign_in_kakao_button), - onSignInClick = { - onSignInClick() - } + onSignInClick = onSignInClick ) - Spacer(modifier = modifier.weight(1f)) + Spacer(modifier = Modifier.weight(1f)) } } @@ -154,6 +156,8 @@ private const val KAKAO_NOT_LOGGED_IN = "statusCode=302" @Composable fun SignInScreenPreview() { TerningPointTheme { - SignInScreen() + SignInScreen( + onSignInClick = {} + ) } } \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/onboarding/signin/navigation/SignInNavigation.kt b/feature/src/main/java/com/terning/feature/onboarding/signin/navigation/SignInNavigation.kt index f9ee42532..49f367ab3 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/signin/navigation/SignInNavigation.kt +++ b/feature/src/main/java/com/terning/feature/onboarding/signin/navigation/SignInNavigation.kt @@ -1,5 +1,6 @@ package com.terning.feature.onboarding.signin.navigation +import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController @@ -19,10 +20,12 @@ fun NavController.navigateSignIn(navOptions: NavOptions? = null) { } fun NavGraphBuilder.signInNavGraph( + paddingValues: PaddingValues, navHostController: NavHostController, ) { composable { SignInRoute( + paddingValues = paddingValues, navigateToHome = { navHostController.navigateHome() }, navigateToSignUp = { authId -> navHostController.navigateSignUp(authId) } ) diff --git a/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpRoute.kt b/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpRoute.kt index 61dce1b1d..9a963fe57 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpRoute.kt +++ b/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpRoute.kt @@ -1,16 +1,15 @@ package com.terning.feature.onboarding.signup import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -22,30 +21,32 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.flowWithLifecycle -import com.terning.core.designsystem.component.bottomsheet.SignUpBottomSheet +import com.terning.core.designsystem.component.bottomsheet.ProfileBottomSheet import com.terning.core.designsystem.component.button.RectangleButton +import com.terning.core.designsystem.component.item.ProfileWithPlusButton import com.terning.core.designsystem.component.textfield.NameTextField +import com.terning.core.designsystem.theme.Grey500 import com.terning.core.designsystem.theme.TerningPointTheme import com.terning.core.designsystem.theme.TerningTheme import com.terning.core.extension.addFocusCleaner import com.terning.core.extension.noRippleClickable import com.terning.core.extension.toast import com.terning.feature.R -import com.terning.feature.onboarding.signup.component.SignUpProfile @Composable fun SignUpRoute( + paddingValues: PaddingValues, authId: String, navigateToStartFiltering: (String) -> Unit, viewModel: SignUpViewModel = hiltViewModel(), ) { - val signUpState by viewModel.state.collectAsStateWithLifecycle() + val state by viewModel.state.collectAsStateWithLifecycle() val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current LaunchedEffect(key1 = true) { - viewModel.fetchAuthId(authId) + viewModel.updateAuthId(authId) } LaunchedEffect(viewModel.sideEffects, lifecycleOwner) { @@ -54,110 +55,106 @@ fun SignUpRoute( when (sideEffect) { is SignUpSideEffect.ShowToast -> context.toast(sideEffect.message) is SignUpSideEffect.NavigateToStartFiltering -> - navigateToStartFiltering(signUpState.name) + navigateToStartFiltering(state.name) } } } + if (state.showBottomSheet) { + ProfileBottomSheet( + onDismiss = { viewModel.updateBottomSheet(false) }, + onSaveClick = { index -> + viewModel.updateBottomSheet(false) + viewModel.updateProfileImage(index) + }, + initialSelectedOption = state.profileImage + ) + } + SignUpScreen( - signUpState = signUpState, + paddingValues = paddingValues, + state = state, onSignUpClick = { viewModel.postSignUpWithServer() }, onInputChange = { name -> - viewModel.isInputValid(name) + viewModel.updateName(name) }, - onFetchCharacter = { index -> - viewModel.fetchCharacter(index) + onProfileEditClick = { isVisible -> + viewModel.updateBottomSheet(isVisible) + }, + onValidationChanged = { isVisible -> + viewModel.updateButtonValidation(isVisible) } ) } @Composable fun SignUpScreen( - signUpState: SignUpState, + state: SignUpState, onSignUpClick: () -> Unit, onInputChange: (String) -> Unit, - onFetchCharacter: (Int) -> Unit, - modifier: Modifier = Modifier, + onProfileEditClick: (Boolean) -> Unit, + onValidationChanged: (Boolean) -> Unit, + paddingValues: PaddingValues = PaddingValues(), ) { val focusManager = LocalFocusManager.current - var showBottomSheet by remember { mutableStateOf(false) } Column( - modifier = modifier + modifier = Modifier .fillMaxSize() .addFocusCleaner(focusManager) + .padding(paddingValues) ) { - Spacer(modifier = modifier.weight(1f)) + Spacer(modifier = Modifier.height(56.dp)) Text( text = stringResource(id = R.string.sign_up_title), style = TerningTheme.typography.heading2, - modifier = modifier.padding( - bottom = 42.dp, - start = 24.dp - ) + modifier = Modifier.padding(start = 24.dp) ) - if (showBottomSheet) { - SignUpBottomSheet( - onDismiss = { showBottomSheet = false }, - onSaveClick = { index -> - showBottomSheet = false - onFetchCharacter(index) - }, - initialSelectedOption = signUpState.character - ) - } + Spacer(modifier = Modifier.height(36.dp)) Text( text = stringResource(id = R.string.sign_up_profile_image), style = TerningTheme.typography.body2, - modifier = modifier - .padding( - start = 24.dp, - bottom = 20.dp - ) + modifier = Modifier.padding(start = 24.dp), + color = Grey500 ) + Spacer(modifier = Modifier.height(20.dp)) Column( - modifier = modifier - .align(Alignment.CenterHorizontally) - .padding(bottom = 52.dp) + modifier = Modifier.align(Alignment.CenterHorizontally) ) { - SignUpProfile( - modifier = modifier.noRippleClickable { - showBottomSheet = true + Spacer(modifier = Modifier.height(48.dp)) + ProfileWithPlusButton( + modifier = Modifier.noRippleClickable { + onProfileEditClick(true) }, - index = signUpState.character + index = state.profileImage ) } Column( - modifier = modifier + modifier = Modifier .align(Alignment.CenterHorizontally) .padding(horizontal = 24.dp) ) { - Text( - text = stringResource(id = R.string.sign_up_name), - modifier = modifier.padding(bottom = 20.dp) - ) + Text(text = stringResource(id = R.string.sign_up_name)) + Spacer(modifier = Modifier.height(20.dp)) NameTextField( - value = signUpState.name, + value = state.name, onValueChange = { name -> onInputChange(name) }, hint = stringResource(id = R.string.sign_up_hint), - drawLineColor = signUpState.drawLineColor, - helperMessage = signUpState.helper, - helperIcon = signUpState.helperIcon, - helperColor = signUpState.helperColor + onValidationChanged = { isValid -> onValidationChanged(isValid) } ) } - Spacer(modifier = modifier.weight(5f)) + Spacer(modifier = Modifier.weight(1f)) RectangleButton( style = TerningTheme.typography.button1, paddingVertical = 20.dp, text = R.string.sign_up_next_button, onButtonClick = { onSignUpClick() }, - modifier = modifier.padding(bottom = 12.dp), - isEnabled = signUpState.isButtonValid + modifier = Modifier.padding(bottom = 12.dp), + isEnabled = state.isButtonValid ) } } @@ -167,10 +164,11 @@ fun SignUpScreen( fun SignUpScreenPreview() { TerningPointTheme { SignUpScreen( - signUpState = SignUpState(), + state = SignUpState(), onSignUpClick = {}, onInputChange = {}, - onFetchCharacter = {} + onProfileEditClick = {}, + onValidationChanged = {} ) } } \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpState.kt b/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpState.kt index 9874f996d..5a3f8b253 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpState.kt +++ b/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpState.kt @@ -1,18 +1,9 @@ package com.terning.feature.onboarding.signup -import androidx.annotation.StringRes -import androidx.compose.ui.graphics.Color -import com.terning.core.designsystem.theme.Grey400 -import com.terning.core.designsystem.theme.Grey500 -import com.terning.feature.R - data class SignUpState( val name: String = "", - val character: Int = 0, - val drawLineColor: Color = Grey500, - @StringRes val helper: Int = R.string.sign_up_helper, - val helperIcon: Int? = null, - val helperColor: Color = Grey400, + val profileImage: Int = 0, val isButtonValid: Boolean = false, - val authId: String = "" + val authId: String = "", + val showBottomSheet: Boolean = false ) \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpViewModel.kt b/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpViewModel.kt index 52f46f86f..504bf3ada 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpViewModel.kt +++ b/feature/src/main/java/com/terning/feature/onboarding/signup/SignUpViewModel.kt @@ -2,10 +2,6 @@ package com.terning.feature.onboarding.signup import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.terning.core.designsystem.theme.Grey400 -import com.terning.core.designsystem.theme.Grey500 -import com.terning.core.designsystem.theme.TerningMain -import com.terning.core.designsystem.theme.WarningRed import com.terning.domain.entity.onboarding.SignUpRequest import com.terning.domain.repository.AuthRepository import com.terning.domain.repository.TokenRepository @@ -32,59 +28,19 @@ class SignUpViewModel @Inject constructor( private val _sideEffects = MutableSharedFlow() val sideEffects: SharedFlow get() = _sideEffects.asSharedFlow() - fun isInputValid(name: String) { - val nameErrorRegex = Regex(NAME_ERROR) - var trimmedName = "" - var outOfBoundName = false - if (name.length > MAX_LENGTH) { - trimmedName = name.substring(0, MAX_LENGTH) - outOfBoundName = true - } else trimmedName = name - - when { - nameErrorRegex.containsMatchIn(trimmedName) -> _state.value = _state.value.copy( - name = trimmedName, - drawLineColor = WarningRed, - helper = R.string.sign_up_helper_error, - helperIcon = R.drawable.ic_sign_up_error, - helperColor = WarningRed, - isButtonValid = false - ) - - trimmedName.isEmpty() || trimmedName.isBlank() -> _state.value = _state.value.copy( - name = trimmedName, - drawLineColor = Grey500, - helper = R.string.sign_up_helper, - helperIcon = null, - helperColor = Grey400, - isButtonValid = false - ) - - outOfBoundName -> _state.value = _state.value.copy( - name = trimmedName, - drawLineColor =WarningRed, - helper = R.string.sign_up_helper_out, - helperIcon = R.drawable.ic_sign_up_error, - helperColor = WarningRed, - isButtonValid = false - ) + fun updateButtonValidation(isValid: Boolean) { + _state.value = _state.value.copy(isButtonValid = isValid) + } - else -> _state.value = _state.value.copy( - name = trimmedName, - drawLineColor = TerningMain, - helper = R.string.sign_up_helper_available, - helperIcon = R.drawable.ic_check, - helperColor = TerningMain, - isButtonValid = true - ) - } + fun updateName(name: String) { + _state.value = _state.value.copy(name = name) } - fun fetchCharacter(character: Int) { - _state.value = _state.value.copy(character = character) + fun updateProfileImage(profileImage: Int) { + _state.value = _state.value.copy(profileImage = profileImage) } - fun fetchAuthId(authId: String) { + fun updateAuthId(authId: String) { _state.value = _state.value.copy(authId = authId) } @@ -95,7 +51,7 @@ class SignUpViewModel @Inject constructor( state.value.run { SignUpRequest( name = name, - profileImage = character, + profileImage = profileImage, authType = KAKA0 ) } @@ -113,9 +69,11 @@ class SignUpViewModel @Inject constructor( } } + fun updateBottomSheet(isVisible: Boolean) { + _state.value = _state.value.copy(showBottomSheet = isVisible) + } + companion object { - const val NAME_ERROR = "[!@#\$%^&*(),.?\":{}|<>\\[\\]\\\\/\\-=+~`\\p{S}\\p{P}]" - private const val MAX_LENGTH = 12 private const val KAKA0 = "KAKAO" } } \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/onboarding/signup/navigation/SignUpNavigation.kt b/feature/src/main/java/com/terning/feature/onboarding/signup/navigation/SignUpNavigation.kt index 479e02eda..34308cc81 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/signup/navigation/SignUpNavigation.kt +++ b/feature/src/main/java/com/terning/feature/onboarding/signup/navigation/SignUpNavigation.kt @@ -1,5 +1,6 @@ package com.terning.feature.onboarding.signup.navigation +import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController @@ -22,14 +23,15 @@ fun NavController.navigateSignUp( } fun NavGraphBuilder.signUpNavGraph( + paddingValues: PaddingValues, navHostController: NavHostController ) { composable { val args = it.toRoute() SignUpRoute( + paddingValues = paddingValues, authId = args.authId, navigateToStartFiltering = { name -> navHostController.navigateFilteringOne(name) } - ) } } diff --git a/feature/src/main/java/com/terning/feature/onboarding/splash/SplashRoute.kt b/feature/src/main/java/com/terning/feature/onboarding/splash/SplashRoute.kt index da523a392..ba79374e2 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/splash/SplashRoute.kt +++ b/feature/src/main/java/com/terning/feature/onboarding/splash/SplashRoute.kt @@ -1,24 +1,28 @@ package com.terning.feature.onboarding.splash +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.flowWithLifecycle import com.google.accompanist.systemuicontroller.rememberSystemUiController -import com.terning.core.designsystem.component.image.TerningImage import com.terning.core.designsystem.theme.TerningMain import com.terning.core.designsystem.theme.TerningPointTheme import com.terning.feature.R @Composable fun SplashRoute( + paddingValues: PaddingValues, navigateToHome: () -> Unit, navigateToSignIn: () -> Unit, viewModel: SplashViewModel = hiltViewModel(), @@ -52,21 +56,23 @@ fun SplashRoute( } } - SplashScreen() + SplashScreen(paddingValues = paddingValues) } @Composable fun SplashScreen( - modifier: Modifier = Modifier, + paddingValues: PaddingValues = PaddingValues(), ) { Column( - modifier = modifier + modifier = Modifier + .padding(paddingValues) .fillMaxSize() .background(TerningMain), ) { - TerningImage( - painter = R.drawable.ic_splash, - modifier = Modifier.fillMaxSize() + Image( + painter = painterResource(id = R.drawable.ic_splash), + modifier = Modifier.fillMaxSize(), + contentDescription = "splash screen" ) } } diff --git a/feature/src/main/java/com/terning/feature/onboarding/splash/navigation/SplashNavigation.kt b/feature/src/main/java/com/terning/feature/onboarding/splash/navigation/SplashNavigation.kt index fa1610589..37dfeca9c 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/splash/navigation/SplashNavigation.kt +++ b/feature/src/main/java/com/terning/feature/onboarding/splash/navigation/SplashNavigation.kt @@ -1,7 +1,6 @@ package com.terning.feature.onboarding.splash.navigation -import androidx.compose.animation.EnterTransition -import androidx.compose.animation.ExitTransition +import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController @@ -21,23 +20,12 @@ fun NavController.navigateSplash(navOptions: NavOptions? = null) { } fun NavGraphBuilder.splashNavGraph( + paddingValues: PaddingValues, navHostController: NavHostController, ) { - composable( - popExitTransition = { - ExitTransition.None - }, - exitTransition = { - ExitTransition.None - }, - enterTransition = { - EnterTransition.None - }, - popEnterTransition = { - EnterTransition.None - } - ) { + composable { SplashRoute( + paddingValues = paddingValues, navigateToHome = { navHostController.navigateHome( navOptions = NavOptions.Builder().setPopUpTo( diff --git a/feature/src/main/res/drawable/ic_my_page_notice.xml b/feature/src/main/res/drawable/ic_my_page_notice.xml index 6f049a9e3..3e56590a0 100644 --- a/feature/src/main/res/drawable/ic_my_page_notice.xml +++ b/feature/src/main/res/drawable/ic_my_page_notice.xml @@ -1,26 +1,21 @@ + android:width="22dp" + android:height="22dp" + android:viewportWidth="22" + android:viewportHeight="22"> + android:pathData="M2.17,6.609H3.44V10.929H2.17C1.5,10.929 0.96,10.389 0.96,9.719V7.819C0.96,7.149 1.5,6.609 2.17,6.609Z" + android:fillColor="#1EAC61"/> + android:pathData="M12.76,20.279H11.23C10.87,20.279 10.56,19.989 10.45,19.569L7.77,8.449H10.99L13.54,18.999C13.69,19.639 13.31,20.289 12.76,20.289V20.279Z" + android:fillColor="#1EAC61"/> + android:pathData="M5.84,4.641H15.44V12.911H5.84C4.38,12.911 3.2,11.731 3.2,10.271V7.271C3.2,5.811 4.38,4.631 5.84,4.631V4.641Z" + android:fillColor="#65DB9B"/> + android:pathData="M19.75,10.291H18.78V7.261H19.75C20.59,7.261 21.27,7.941 21.27,8.781C21.27,9.621 20.59,10.301 19.75,10.301V10.291Z" + android:fillColor="#0D8443"/> + android:pathData="M13.27,4.7V12.85L19.03,15.79C19.33,15.94 19.65,15.67 19.65,15.27V2.29C19.65,1.89 19.32,1.61 19.03,1.77L13.27,4.71V4.7Z" + android:fillColor="#1EAC61"/> diff --git a/feature/src/main/res/drawable/ic_my_page_opinion.xml b/feature/src/main/res/drawable/ic_my_page_opinion.xml index 41512f23e..848db9d9a 100644 --- a/feature/src/main/res/drawable/ic_my_page_opinion.xml +++ b/feature/src/main/res/drawable/ic_my_page_opinion.xml @@ -1,26 +1,21 @@ + android:width="22dp" + android:height="22dp" + android:viewportWidth="22" + android:viewportHeight="22"> + android:pathData="M21.1,14.81V11.63C21.1,10 19.78,8.68 18.15,8.68H10.3C8.67,8.68 7.35,10 7.35,11.63V14.81C7.35,16.44 8.67,17.76 10.3,17.76H16.75C18.67,19.74 20.97,19.93 20.97,19.93C20.09,19.11 19.58,18.25 19.28,17.54C20.35,17.1 21.11,16.05 21.11,14.81H21.1Z" + android:fillColor="#1EAC61"/> + android:pathData="M0.9,9.26V5.53C0.9,3.62 2.57,2.07 4.62,2.07H14.52C16.57,2.07 18.24,3.62 18.24,5.53V9.26C18.24,11.17 16.57,12.72 14.52,12.72H6.4C3.98,15.04 1.08,15.27 1.08,15.27C2.19,14.31 2.83,13.3 3.21,12.46C1.86,11.94 0.9,10.71 0.9,9.26Z" + android:fillColor="#65DB9B"/> + android:pathData="M9.63,8.379C10.072,8.379 10.43,8.021 10.43,7.579C10.43,7.137 10.072,6.779 9.63,6.779C9.188,6.779 8.83,7.137 8.83,7.579C8.83,8.021 9.188,8.379 9.63,8.379Z" + android:fillColor="#1EAC61"/> + android:pathData="M12.71,8.379C13.152,8.379 13.51,8.021 13.51,7.579C13.51,7.137 13.152,6.779 12.71,6.779C12.268,6.779 11.91,7.137 11.91,7.579C11.91,8.021 12.268,8.379 12.71,8.379Z" + android:fillColor="#1EAC61"/> + android:pathData="M6.55,8.379C6.992,8.379 7.35,8.021 7.35,7.579C7.35,7.137 6.992,6.779 6.55,6.779C6.108,6.779 5.75,7.137 5.75,7.579C5.75,8.021 6.108,8.379 6.55,8.379Z" + android:fillColor="#1EAC61"/> diff --git a/feature/src/main/res/drawable/ic_my_page_personal.xml b/feature/src/main/res/drawable/ic_my_page_personal.xml new file mode 100644 index 000000000..62f540bf0 --- /dev/null +++ b/feature/src/main/res/drawable/ic_my_page_personal.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/feature/src/main/res/drawable/ic_my_page_service.xml b/feature/src/main/res/drawable/ic_my_page_service.xml new file mode 100644 index 000000000..ea3583ef0 --- /dev/null +++ b/feature/src/main/res/drawable/ic_my_page_service.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/feature/src/main/res/drawable/ic_my_page_version.xml b/feature/src/main/res/drawable/ic_my_page_version.xml index f264846fb..1d70ec4c2 100644 --- a/feature/src/main/res/drawable/ic_my_page_version.xml +++ b/feature/src/main/res/drawable/ic_my_page_version.xml @@ -1,34 +1,21 @@ + android:width="22dp" + android:height="22dp" + android:viewportWidth="22" + android:viewportHeight="22"> + android:pathData="M15.21,0.711H6.79C5.244,0.711 3.99,1.965 3.99,3.511V18.491C3.99,20.037 5.244,21.291 6.79,21.291H15.21C16.756,21.291 18.01,20.037 18.01,18.491V3.511C18.01,1.965 16.756,0.711 15.21,0.711Z" + android:fillColor="#1EAC61"/> + android:pathData="M15.73,3.85H6.28C5.855,3.85 5.51,4.194 5.51,4.62V16.19C5.51,16.615 5.855,16.96 6.28,16.96H15.73C16.155,16.96 16.5,16.615 16.5,16.19V4.62C16.5,4.194 16.155,3.85 15.73,3.85Z" + android:fillColor="#65DB9B"/> + android:pathData="M8.38,2.6C8.656,2.6 8.88,2.376 8.88,2.1C8.88,1.823 8.656,1.6 8.38,1.6C8.104,1.6 7.88,1.823 7.88,2.1C7.88,2.376 8.104,2.6 8.38,2.6Z" + android:fillColor="#0D8443"/> + android:pathData="M13.62,1.6H9.97C9.694,1.6 9.47,1.823 9.47,2.1C9.47,2.376 9.694,2.6 9.97,2.6H13.62C13.896,2.6 14.12,2.376 14.12,2.1C14.12,1.823 13.896,1.6 13.62,1.6Z" + android:fillColor="#0D8443"/> - - + android:pathData="M11,20.511C11.635,20.511 12.15,19.996 12.15,19.361C12.15,18.726 11.635,18.211 11,18.211C10.365,18.211 9.85,18.726 9.85,19.361C9.85,19.996 10.365,20.511 11,20.511Z" + android:fillColor="#0D8443"/> diff --git a/feature/src/main/res/drawable/ic_terning_profile_00.xml b/feature/src/main/res/drawable/ic_terning_profile_00.xml index f34f8769c..99edfdf96 100644 --- a/feature/src/main/res/drawable/ic_terning_profile_00.xml +++ b/feature/src/main/res/drawable/ic_terning_profile_00.xml @@ -1,137 +1,60 @@ - - - - - - - + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + android:pathData="M38,0L38,0A38,38 0,0 1,76 38L76,38A38,38 0,0 1,38 76L38,76A38,38 0,0 1,0 38L0,38A38,38 0,0 1,38 0z"/> - - - - - - - - - - - - - - - - + android:pathData="M76,0H0V76H76V0Z" + android:fillColor="#FBF8CB"/> - - - - + android:pathData="M57.95,77.966L67.64,49.542C68.314,47.472 67.574,45.192 65.807,43.909L41.971,26.59C40.204,25.308 37.819,25.308 36.053,26.59L12.217,43.909C10.45,45.192 9.718,47.462 10.384,49.542L19.494,77.567C20.169,79.638 22.097,81.045 24.282,81.045H53.751" + android:fillColor="#ffffff"/> - - - - - - + android:pathData="M57.95,77.966L67.64,49.542C68.314,47.472 67.574,45.192 65.807,43.909L41.971,26.59C40.204,25.308 37.819,25.308 36.053,26.59L12.217,43.909C10.45,45.192 9.718,47.462 10.384,49.542L19.494,77.567C20.169,79.638 22.097,81.045 24.282,81.045H53.751" + android:strokeWidth="1.425" + android:fillColor="#00000000" + android:strokeColor="#171717" + android:strokeLineCap="round"/> + + + + + + + + + android:pathData="M35.444,53.884C35.444,53.884 36.243,55.613 38.114,55.613C39.986,55.613 40.565,53.884 40.565,53.884" + android:strokeWidth="1.425" + android:fillColor="#00000000" + android:strokeColor="#171717" + android:strokeLineCap="round"/> - diff --git a/feature/src/main/res/drawable/ic_terning_profile_01.xml b/feature/src/main/res/drawable/ic_terning_profile_01.xml index 557c169b6..0bfcc7b29 100644 --- a/feature/src/main/res/drawable/ic_terning_profile_01.xml +++ b/feature/src/main/res/drawable/ic_terning_profile_01.xml @@ -1,132 +1,80 @@ - - - - - - + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + android:pathData="M38,0L38,0A38,38 0,0 1,76 38L76,38A38,38 0,0 1,38 76L38,76A38,38 0,0 1,0 38L0,38A38,38 0,0 1,38 0z"/> + android:pathData="M76,0H0V76H76V0Z" + android:fillColor="#ECF9CA"/> + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - diff --git a/feature/src/main/res/drawable/ic_terning_profile_02.xml b/feature/src/main/res/drawable/ic_terning_profile_02.xml index 1ad3e5dd8..8ba5ffc15 100644 --- a/feature/src/main/res/drawable/ic_terning_profile_02.xml +++ b/feature/src/main/res/drawable/ic_terning_profile_02.xml @@ -1,98 +1,75 @@ - - - - - - + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + android:pathData="M38,0L38,0A38,38 0,0 1,76 38L76,38A38,38 0,0 1,38 76L38,76A38,38 0,0 1,0 38L0,38A38,38 0,0 1,38 0z"/> + android:pathData="M76,0H0V76H76V0Z" + android:fillColor="#D4F9DE"/> + + + + + + + + + + + + + - - - - - - - - - - - - - - diff --git a/feature/src/main/res/drawable/ic_terning_profile_03.xml b/feature/src/main/res/drawable/ic_terning_profile_03.xml index fc45cad6a..25e878efb 100644 --- a/feature/src/main/res/drawable/ic_terning_profile_03.xml +++ b/feature/src/main/res/drawable/ic_terning_profile_03.xml @@ -1,131 +1,76 @@ - - - - - + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + android:pathData="M38,0L38,0A38,38 0,0 1,76 38L76,38A38,38 0,0 1,38 76L38,76A38,38 0,0 1,0 38L0,38A38,38 0,0 1,38 0z"/> + android:pathData="M76.209,0H0.209V76H76.209V0Z" + android:fillColor="#C5DEF2"/> + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - diff --git a/feature/src/main/res/drawable/ic_terning_profile_04.xml b/feature/src/main/res/drawable/ic_terning_profile_04.xml index 228909ea8..8b27c5c6c 100644 --- a/feature/src/main/res/drawable/ic_terning_profile_04.xml +++ b/feature/src/main/res/drawable/ic_terning_profile_04.xml @@ -1,150 +1,74 @@ + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + android:pathData="M76,0H0V76H76V0Z" + android:fillColor="#E9F1E4"/> - - - - - - - - - - - - - - - - - - - - - - + android:pathData="M64.676,32.956H11.324V85.035H64.676V32.956Z" + android:strokeLineJoin="round" + android:strokeWidth="1.425" + android:fillColor="#ffffff" + android:strokeColor="#171717" + android:strokeLineCap="round"/> + android:pathData="M31.663,53.447C31.663,53.779 31.616,54.131 31.502,54.416C31.388,54.701 31.036,54.872 30.808,55.1C30.58,55.328 30.409,55.623 30.105,55.746C29.801,55.869 29.488,55.841 29.155,55.841C28.823,55.841 28.509,55.822 28.224,55.699C27.939,55.575 27.654,55.395 27.426,55.167C27.198,54.938 26.999,54.682 26.875,54.378C26.752,54.074 26.638,53.761 26.638,53.438C26.638,53.114 26.837,52.811 26.961,52.526C27.084,52.241 27.274,52.003 27.502,51.775C27.73,51.547 27.939,51.319 28.234,51.195C28.528,51.072 28.832,51.072 29.165,51.072C29.497,51.072 29.801,51.082 30.086,51.205C30.371,51.328 30.647,51.509 30.875,51.728C31.103,51.946 31.293,52.212 31.416,52.507C31.54,52.801 31.682,53.105 31.682,53.438L31.663,53.447Z" + android:fillColor="#F9DBDE"/> + android:pathData="M31.663,53.447C31.663,53.779 31.616,54.131 31.502,54.416C31.388,54.701 31.036,54.872 30.808,55.1C30.58,55.328 30.409,55.623 30.105,55.746C29.801,55.869 29.488,55.841 29.155,55.841C28.823,55.841 28.509,55.822 28.224,55.699C27.939,55.575 27.654,55.395 27.426,55.167C27.198,54.938 26.999,54.682 26.875,54.378C26.752,54.074 26.638,53.761 26.638,53.438C26.638,53.114 26.837,52.811 26.961,52.526C27.084,52.241 27.274,52.003 27.502,51.775C27.73,51.547 27.939,51.319 28.234,51.195C28.528,51.072 28.832,51.072 29.165,51.072C29.497,51.072 29.801,51.082 30.086,51.205C30.371,51.328 30.647,51.509 30.875,51.728C31.103,51.946 31.293,52.212 31.416,52.507C31.54,52.801 31.682,53.105 31.682,53.438L31.663,53.447Z" + android:strokeWidth="0.7315" + android:fillColor="#00000000" + android:strokeColor="#F9DBDE"/> + android:pathData="M49.343,53.267C49.343,53.599 49.267,53.932 49.143,54.226C49.02,54.521 48.839,54.825 48.611,55.043C48.383,55.262 48.079,55.433 47.785,55.556C47.49,55.68 47.167,55.651 46.835,55.651C46.502,55.651 46.217,55.585 45.923,55.461C45.628,55.338 45.267,55.281 45.049,55.053C44.83,54.825 44.669,54.511 44.545,54.217C44.422,53.922 44.422,53.599 44.422,53.267C44.422,52.934 44.45,52.611 44.564,52.326C44.678,52.041 44.897,51.775 45.125,51.557C45.353,51.338 45.638,51.215 45.932,51.091C46.227,50.968 46.502,50.92 46.835,50.92C47.167,50.92 47.49,50.863 47.785,50.987C48.079,51.11 48.355,51.3 48.583,51.528C48.811,51.756 49.01,52.022 49.134,52.326C49.257,52.63 49.343,52.944 49.343,53.276V53.267Z" + android:fillColor="#F9DBDE"/> + android:strokeColor="#F9DBDE"/> + android:pathData="M37.506,63.441H38.598C38.988,63.441 39.32,63.707 39.396,64.077L41.762,75.8C41.828,76.199 41.705,76.608 41.42,76.902L39.016,79.372C38.503,79.895 37.648,79.914 37.126,79.401L34.618,76.978C34.314,76.684 34.171,76.256 34.247,75.838L36.717,64.077C36.793,63.707 37.126,63.441 37.515,63.441H37.506Z" + android:strokeWidth="1.425" + android:fillColor="#A6B7FF" + android:strokeColor="#171717"/> + android:pathData="M39.168,63.907H36.955C36.518,63.907 36.147,63.603 36.053,63.185L35.54,60.952C35.407,60.373 35.853,59.812 36.442,59.812H39.701C40.299,59.812 40.745,60.373 40.603,60.952L40.071,63.185C39.976,63.603 39.596,63.897 39.168,63.897V63.907Z" + android:strokeWidth="1.425" + android:fillColor="#A6B7FF" + android:strokeColor="#171717"/> + android:pathData="M34.818,52.497C35.384,52.497 35.843,51.791 35.843,50.92C35.843,50.049 35.384,49.343 34.818,49.343C34.251,49.343 33.792,50.049 33.792,50.92C33.792,51.791 34.251,52.497 34.818,52.497Z" + android:fillColor="#171717"/> + android:pathData="M41.182,52.497C41.749,52.497 42.208,51.791 42.208,50.92C42.208,50.049 41.749,49.343 41.182,49.343C40.616,49.343 40.157,50.049 40.157,50.92C40.157,51.791 40.616,52.497 41.182,52.497Z" + android:fillColor="#171717"/> + diff --git a/feature/src/main/res/drawable/ic_terning_profile_05.xml b/feature/src/main/res/drawable/ic_terning_profile_05.xml index 2d21f7990..9a32c789e 100644 --- a/feature/src/main/res/drawable/ic_terning_profile_05.xml +++ b/feature/src/main/res/drawable/ic_terning_profile_05.xml @@ -1,111 +1,73 @@ - - - - + android:width="76dp" + android:height="76dp" + android:viewportWidth="76" + android:viewportHeight="76"> + android:pathData="M38,0L38,0A38,38 0,0 1,76 38L76,38A38,38 0,0 1,38 76L38,76A38,38 0,0 1,0 38L0,38A38,38 0,0 1,38 0z"/> + android:pathData="M76,0H0V76H76V0Z" + android:fillColor="#E6FFF6"/> + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - diff --git a/feature/src/main/res/drawable/ic_view_count_14.xml b/feature/src/main/res/drawable/ic_view_count_14.xml new file mode 100644 index 000000000..3f6e68ef5 --- /dev/null +++ b/feature/src/main/res/drawable/ic_view_count_14.xml @@ -0,0 +1,20 @@ + + + + diff --git a/feature/src/main/res/values/strings.xml b/feature/src/main/res/values/strings.xml index 9f970dce3..e258ad031 100644 --- a/feature/src/main/res/values/strings.xml +++ b/feature/src/main/res/values/strings.xml @@ -23,10 +23,6 @@ 이름 이름을 입력해 주세요 다음으로 - 12자리 이내, 문자/숫자 가능, 특수문자/기호 입력불가 - 이름에 특수문자는 입력할 수 없어요 - 사용 가능한 이름이에요 - 이름은 12자리 이내로 설정해 주세요 관심있는 인턴 공고 키워드를 검색해 보세요 @@ -137,16 +133,15 @@ 공유 아이콘 지원 사이트로 이동하기 공고 정보 - 조회수 %s회 서류 마감 근무 기간 근무 시작 - 공고 정보 공고 요약 + 자격 요건 상세 정보 - 자격요건 - 직무 + 모집대상 + 모집직무 관심 공고가 캘린더에 스크랩되었어요! 관심 공고가 캘린더에서 사라졌어요! @@ -155,12 +150,17 @@ 탈퇴하기 프로필 수정 터닝 커뮤니티 - 공지사항 + 공지사항 의견보내기 서비스 정보 - 서비스 이용약관 - 개인정보 처리방침 + 서비스 이용약관 + 개인정보 처리방침 버전정보 + + 프로필 수정 + 저장하기 + 연동 계정 +