Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,13 @@ data class OrbitTypography(
lineHeight = 18.sp,
letterSpacing = (-0.13).sp,
),
val label2Regular: TextStyle = TextStyle(
fontFamily = Pretendard,
fontWeight = FontWeight.Normal,
fontSize = 13.sp,
lineHeight = 18.sp,
letterSpacing = (-0.13).sp,
),
val caption1Regular: TextStyle = TextStyle(
fontFamily = Pretendard,
fontWeight = FontWeight.Normal,
Expand Down
10 changes: 6 additions & 4 deletions core/ui/src/main/java/com/yapp/ui/utils/ScreenPercentage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fun Modifier.widthForScreenPercentage(percentage: Float): Modifier {

@Composable
fun Modifier.paddingForScreenPercentage(
allPercentage: Float = 0f,
horizontalPercentage: Float = 0f,
verticalPercentage: Float = 0f,
topPercentage: Float = 0f,
Expand All @@ -31,10 +32,11 @@ fun Modifier.paddingForScreenPercentage(
val screenWidth = configuration.screenWidthDp.dp
val screenHeight = configuration.screenHeightDp.dp

val horizontalPadding = screenWidth * horizontalPercentage
val verticalPadding = screenHeight * verticalPercentage
val topPadding = screenHeight * topPercentage + verticalPadding
val bottomPadding = screenHeight * bottomPercentage + verticalPadding
val allPadding = screenHeight * allPercentage
val horizontalPadding = if (allPercentage > 0f) allPadding else screenWidth * horizontalPercentage
val verticalPadding = if (allPercentage > 0f) allPadding else screenHeight * verticalPercentage
val topPadding = if (allPercentage > 0f) allPadding else screenHeight * topPercentage + verticalPadding
val bottomPadding = if (allPercentage > 0f) allPadding else screenHeight * bottomPercentage + verticalPadding

return this.padding(
start = horizontalPadding,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ sealed class OnboardingContract {
val textFieldValue: String = "",
val showWarning: Boolean = false,
val isButtonEnabled: Boolean = false,
val selectedGender: String? = null,
) : UiState

sealed class Action {
Expand All @@ -17,6 +18,7 @@ sealed class OnboardingContract {
data class UpdateField(val value: String, val fieldType: FieldType) : Action()
data object Reset : Action()
data class Submit(val stepData: Map<String, String>) : Action()
data class UpdateGender(val gender: String) : Action()
}

enum class FieldType(val validationRegex: Regex) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.kms.onboarding

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import com.kms.onboarding.component.OnboardingGenderToggle
import com.yapp.designsystem.theme.OrbitTheme
import com.yapp.ui.utils.heightForScreenPercentage
import com.yapp.ui.utils.paddingForScreenPercentage
import com.yapp.ui.utils.widthForScreenPercentage
import feature.onboarding.R

@Composable
fun OnboardingGenderScreen(
state: OnboardingContract.State,
currentStep: Int,
totalSteps: Int,
onNextClick: () -> Unit,
onBackClick: () -> Unit,
onGenderSelect: (String) -> Unit,
) {
OnboardingScreen(
currentStep = currentStep,
totalSteps = totalSteps,
isButtonEnabled = state.selectedGender != null,
onNextClick = {},
onBackClick = onBackClick,
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Spacer(modifier = Modifier.heightForScreenPercentage(0.05f))
Text(
text = stringResource(id = R.string.onboarding_step6_text_title),
style = OrbitTheme.typography.heading1SemiBold,
color = OrbitTheme.colors.white,
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
)

Row(
modifier = Modifier
.fillMaxWidth()
.paddingForScreenPercentage(topPercentage = 0.11f),
horizontalArrangement = Arrangement.Center,
) {
OnboardingGenderToggle(
label = "남성",
isSelected = state.selectedGender == "남성",
onToggle = { onGenderSelect("남성") },
)
Spacer(modifier = Modifier.widthForScreenPercentage(0.04f))
OnboardingGenderToggle(
label = "여성",
isSelected = state.selectedGender == "여성",
onToggle = { onGenderSelect("여성") },
)
}
}
}
}

@Composable
@Preview
fun OnboardingGenderScreenPreview() {
OnboardingGenderScreen(
state = OnboardingContract.State(
isButtonEnabled = true,
),
currentStep = 0,
totalSteps = 0,
onNextClick = {},
onBackClick = {},
onGenderSelect = {},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class OnboardingViewModel @Inject constructor(
is OnboardingContract.Action.UpdateField -> updateField(action.value, action.fieldType)
is OnboardingContract.Action.Reset -> resetFields()
is OnboardingContract.Action.Submit -> handleSubmission(action.stepData)
is OnboardingContract.Action.UpdateGender -> updateGender(action.gender)
}
}

Expand Down Expand Up @@ -69,6 +70,10 @@ class OnboardingViewModel @Inject constructor(
}
}

private fun updateGender(gender: String) {
updateState { copy(selectedGender = gender, isButtonEnabled = true) }
}

private fun handleSubmission(stepData: Map<String, String>) {
emitSideEffect(OnboardingContract.SideEffect.OnboardingCompleted)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.kms.onboarding.component

import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.yapp.designsystem.theme.OrbitTheme
import com.yapp.ui.utils.paddingForScreenPercentage

@Composable
fun OnboardingGenderToggle(
label: String,
isSelected: Boolean,
onToggle: () -> Unit,
modifier: Modifier = Modifier,
) {
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()

val backgroundColor = when {
isPressed -> OrbitTheme.colors.gray_700
isSelected -> OrbitTheme.colors.main.copy(alpha = 0.1f)
else -> OrbitTheme.colors.gray_800
}
val borderColor = when {
isSelected -> OrbitTheme.colors.main.copy(alpha = 0.4f)
isPressed -> Color.Transparent
else -> OrbitTheme.colors.gray_600
}
val contentColor = when {
isPressed -> OrbitTheme.colors.white
isSelected -> OrbitTheme.colors.sub_main
else -> OrbitTheme.colors.white
}

val innerSizeScale by animateFloatAsState(
targetValue = if (isPressed) 0.95f else 1f,
animationSpec = tween(durationMillis = 100),
label = "SizeAnimation",
)

Box(
contentAlignment = Alignment.Center,
modifier = modifier
.wrapContentSize()
.border(
width = if (isPressed) 0.dp else 1.dp,
color = borderColor,
shape = RoundedCornerShape(16.dp),
)
.background(backgroundColor, shape = RoundedCornerShape(16.dp))
.clickable(
interactionSource = interactionSource,
indication = null,
enabled = !isSelected,
) {
onToggle()
},
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.paddingForScreenPercentage(verticalPercentage = 0.074f, horizontalPercentage = 0.144f)
.wrapContentSize()
.scale(innerSizeScale),
) {
Text(
text = label,
color = contentColor,
style = OrbitTheme.typography.heading2SemiBold,
)
}
}
}

@Preview
@Composable
fun PreviewSquareToggleButton() {
var isSelected by remember { mutableStateOf(false) }

OnboardingGenderToggle(
label = "남성",
isSelected = isSelected,
onToggle = { isSelected = !isSelected },
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ sealed class OnboardingDestination(val route: String) {
data object Birthday : OnboardingDestination(Routes.BIRTHDAY)
data object TimeOfBirth : OnboardingDestination(Routes.TIME_OF_BIRTH)
data object Name : OnboardingDestination(Routes.NAME)
data object Gender : OnboardingDestination(Routes.GENDER)

companion object {
private val routes = listOf(Explain, AlarmTimeSelection, Birthday, TimeOfBirth, Name)
private val routes = listOf(Explain, AlarmTimeSelection, Birthday, TimeOfBirth, Name, Gender)

fun nextRoute(currentStep: Int): String? {
return routes.getOrNull(currentStep)?.route
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.kms.onboarding.OnboardingAlarmTimeSelectionScreen
import com.kms.onboarding.OnboardingBirthdayScreen
import com.kms.onboarding.OnboardingContract
import com.kms.onboarding.OnboardingExplainScreen
import com.kms.onboarding.OnboardingGenderScreen
import com.kms.onboarding.OnboardingNameScreen
import com.kms.onboarding.OnboardingTimeOfBirthScreen

Expand All @@ -28,7 +29,7 @@ fun NavGraphBuilder.onboardingNavGraph(
OnboardingAlarmTimeSelectionScreen(
state = stateProvider(),
currentStep = 1,
totalSteps = 4,
totalSteps = 5,
onNextClick = {
eventDispatcher(OnboardingContract.Action.NextStep)
},
Expand All @@ -42,7 +43,7 @@ fun NavGraphBuilder.onboardingNavGraph(
OnboardingBirthdayScreen(
state = stateProvider(),
currentStep = 2,
totalSteps = 4,
totalSteps = 5,
onNextClick = {
eventDispatcher(OnboardingContract.Action.NextStep)
},
Expand All @@ -57,7 +58,7 @@ fun NavGraphBuilder.onboardingNavGraph(
OnboardingTimeOfBirthScreen(
state = stateProvider(),
currentStep = 3,
totalSteps = 4,
totalSteps = 5,
onNextClick = {
eventDispatcher(OnboardingContract.Action.NextStep)
eventDispatcher(OnboardingContract.Action.Reset)
Expand All @@ -75,7 +76,7 @@ fun NavGraphBuilder.onboardingNavGraph(
OnboardingNameScreen(
state = stateProvider(),
currentStep = 4,
totalSteps = 4,
totalSteps = 5,
onNextClick = {
eventDispatcher(OnboardingContract.Action.NextStep)
},
Expand All @@ -87,4 +88,19 @@ fun NavGraphBuilder.onboardingNavGraph(
},
)
}
composable(OnboardingDestination.Gender.route) {
OnboardingGenderScreen(
state = stateProvider(),
currentStep = 5,
totalSteps = 5,
onNextClick = {
},
onBackClick = {
eventDispatcher(OnboardingContract.Action.PreviousStep)
},
onGenderSelect = { gender ->
eventDispatcher(OnboardingContract.Action.UpdateGender(gender))
},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ object Routes {
const val BIRTHDAY = "onboarding_birthday"
const val TIME_OF_BIRTH = "onboarding_time_of_birth"
const val NAME = "onboarding_name"
const val GENDER = "onboarding_gender"
}
16 changes: 16 additions & 0 deletions feature/onboarding/src/main/res/values/values.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@
<string name="onboarding_step5_text_title">어떤 이름으로 불리길\n원하시나요?</string>
<string name="onboarding_step5_textfield_warning">입력한 내용을 확인해 주세요</string>

<string name="onboarding_step6_text_title">성별을 알려주세요</string>

<string name="onboarding_step6_bs_title">입력하신 정보가 맞나요?</string>
<string name="onboarding_step6_bs_name">이름</string>
<string name="onboarding_step6_bs_gender">성별</string>
<string name="onboarding_step6_bs_birth">생년월일</string>
<string name="onboarding_step6_bs_time">태어난 시간</string>
<string name="onboarding_step6_bs_btn_confirm">맞아요</string>
<string name="onboarding_step6_bs_btn_dismiss">아니에요</string>

<string name="onboarding_step7_text_title">알람을 받으려면 꼭 필요해요\n다음 화면에서 ‘허용’을 눌러주세요</string>
<string name="onboarding_step7_alert_title">‘오르비’에서 알림을 보내고자 합니다</string>
<string name="onboarding_step7_alert_message">알림 기능이 꺼져있으면\n알람이 울릴 때 확인에 어려움이 있어요</string>
<string name="onboarding_step7_alert_btn_confirm">허용</string>
<string name="onboarding_step7_alert_btn_dismiss">허용안함</string>


<!--<string name="onboarding_text_bottom_subtitle">서비스 시작 시 이용약관 및 개인정보처리방침에 동의하게 됩니다.</string>-->

Expand Down