diff --git a/3days/core/design-system/src/main/java/com/weave/design_system/component/DaysNextButton.kt b/3days/core/design-system/src/main/java/com/weave/design_system/component/DaysNextButton.kt
index 5b468aa..3535057 100644
--- a/3days/core/design-system/src/main/java/com/weave/design_system/component/DaysNextButton.kt
+++ b/3days/core/design-system/src/main/java/com/weave/design_system/component/DaysNextButton.kt
@@ -22,7 +22,8 @@ fun DaysNextButton(
message: String = "다음",
type: BtnType = BtnType.Tall,
isEnabled: Boolean = false,
- onClick: () -> Unit
+ onDisabledClick: () -> Unit = {},
+ onEnabledClick: () -> Unit
) {
val buttonHeight = when (type) {
BtnType.Tall -> 90.dp
@@ -30,12 +31,14 @@ fun DaysNextButton(
}
Button(
- onClick = onClick,
- enabled = isEnabled,
+ onClick = {
+ if (isEnabled) onEnabledClick() else onDisabledClick()
+ },
+ enabled = true,
shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp),
colors = ButtonColors(
- containerColor = DaysTheme.colors.grey500,
- contentColor = DaysTheme.colors.white,
+ containerColor = if (isEnabled) DaysTheme.colors.grey500 else DaysTheme.colors.grey100,
+ contentColor = if (isEnabled) DaysTheme.colors.white else DaysTheme.colors.white,
disabledContainerColor = DaysTheme.colors.grey100,
disabledContentColor = DaysTheme.colors.white,
),
diff --git a/3days/core/design-system/src/main/java/com/weave/design_system/component/DaysOnlyBackAppbar.kt b/3days/core/design-system/src/main/java/com/weave/design_system/component/DaysOnlyBackAppbar.kt
index 99e2890..779ada7 100644
--- a/3days/core/design-system/src/main/java/com/weave/design_system/component/DaysOnlyBackAppbar.kt
+++ b/3days/core/design-system/src/main/java/com/weave/design_system/component/DaysOnlyBackAppbar.kt
@@ -3,7 +3,7 @@ package com.weave.design_system.component
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -31,24 +31,20 @@ fun DaysOnlyBackAppbar(
TopAppBar(
modifier = Modifier
.fillMaxWidth()
- .height(54.dp),
+ .heightIn(min = 54.dp),
title = { Text(text = "") },
navigationIcon = {
- Box(modifier = Modifier.fillMaxSize(),
- contentAlignment = Alignment.CenterStart)
- {
- Box(
- modifier = Modifier
- .size(48.dp, 48.dp)
- .padding(start = 6.dp, top = 8.dp)
- .noRippleClickable(onBackPressed),
- ) {
- Icon(
- modifier = Modifier.size(24.dp, 24.dp),
- imageVector = ImageVector.vectorResource(id = R.drawable.ic_round_arrow_back),
- contentDescription = "Back"
- )
- }
+ Box(
+ modifier = Modifier
+ .size(48.dp, 48.dp)
+ .noRippleClickable(onBackPressed),
+ contentAlignment = Alignment.Center
+ ) {
+ Icon(
+ modifier = Modifier.size(24.dp, 24.dp),
+ imageVector = ImageVector.vectorResource(id = R.drawable.ic_round_arrow_back),
+ contentDescription = "Back"
+ )
}
},
colors = TopAppBarDefaults.topAppBarColors().copy(
diff --git a/3days/core/design-system/src/main/res/drawable/ic_question_mark.xml b/3days/core/design-system/src/main/res/drawable/ic_question_mark.xml
new file mode 100644
index 0000000..58b47a3
--- /dev/null
+++ b/3days/core/design-system/src/main/res/drawable/ic_question_mark.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/3days/core/design-system/src/main/res/drawable/ic_reading_glasses.png b/3days/core/design-system/src/main/res/drawable/ic_reading_glasses.png
new file mode 100644
index 0000000..c45028b
Binary files /dev/null and b/3days/core/design-system/src/main/res/drawable/ic_reading_glasses.png differ
diff --git a/3days/core/design-system/src/main/res/values/strings.xml b/3days/core/design-system/src/main/res/values/strings.xml
index 8d84561..ee76104 100644
--- a/3days/core/design-system/src/main/res/values/strings.xml
+++ b/3days/core/design-system/src/main/res/values/strings.xml
@@ -69,4 +69,13 @@
만나서 반가워요!
당신의 성별을 무엇인가요?
+ 성별을 선택해 주세요
+
+ 좋은 %s분 소개시켜 드릴께요!
+ 당신의 나이는 무엇인가요?
+ 년생
+ 가입 연령 확인하기
+ %s년 기준으로 %s년생(만 20살)부터 %s년생(만 35살)까지 가입할 수 있어요
+ 나이를 입력해 주세요
+ 가입이 불가한 연령이예요
diff --git a/3days/feat/intro/src/main/java/com/weave/intro/MobileSendAuthScreen.kt b/3days/feat/intro/src/main/java/com/weave/intro/MobileSendAuthScreen.kt
index e5936da..254d7e4 100644
--- a/3days/feat/intro/src/main/java/com/weave/intro/MobileSendAuthScreen.kt
+++ b/3days/feat/intro/src/main/java/com/weave/intro/MobileSendAuthScreen.kt
@@ -101,7 +101,7 @@ fun MobileSendAuthScreen(
message = stringResource(id = R.string.next_button_message),
type = if (isKeyboardVisible == Keyboard.Opened) BtnType.Short else BtnType.Tall,
isEnabled = isEnabled,
- onClick = { onNextBtnClicked(phoneNumber.text) },
+ onEnabledClick = { onNextBtnClicked(phoneNumber.text) },
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(
diff --git a/3days/feat/intro/src/main/java/com/weave/intro/TermsAgreementScreen.kt b/3days/feat/intro/src/main/java/com/weave/intro/TermsAgreementScreen.kt
index cf55147..6ad4d3c 100644
--- a/3days/feat/intro/src/main/java/com/weave/intro/TermsAgreementScreen.kt
+++ b/3days/feat/intro/src/main/java/com/weave/intro/TermsAgreementScreen.kt
@@ -73,7 +73,7 @@ fun TermsAgreementScreen(
message = stringResource(id = R.string.next_button_message),
type = if (isKeyboardVisible == Keyboard.Opened) BtnType.Short else BtnType.Tall,
isEnabled = true,
- onClick = { onNextBtnClicked() },
+ onEnabledClick = { onNextBtnClicked() },
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(
diff --git a/3days/feat/my-profile/src/androidTest/java/com/weave/my_profile/ExampleInstrumentedTest.kt b/3days/feat/my-profile/src/androidTest/java/com/weave/my_profile/ExampleInstrumentedTest.kt
index d33379f..4f09b2f 100644
--- a/3days/feat/my-profile/src/androidTest/java/com/weave/my_profile/ExampleInstrumentedTest.kt
+++ b/3days/feat/my-profile/src/androidTest/java/com/weave/my_profile/ExampleInstrumentedTest.kt
@@ -1,13 +1,11 @@
package com.weave.my_profile
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
-
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.Assert.*
-
/**
* Instrumented test, which will execute on an Android device.
*
diff --git a/3days/feat/my-profile/src/main/AndroidManifest.xml b/3days/feat/my-profile/src/main/AndroidManifest.xml
index a5918e6..44008a4 100644
--- a/3days/feat/my-profile/src/main/AndroidManifest.xml
+++ b/3days/feat/my-profile/src/main/AndroidManifest.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileBirthYearScreen.kt b/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileBirthYearScreen.kt
new file mode 100644
index 0000000..249a1ad
--- /dev/null
+++ b/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileBirthYearScreen.kt
@@ -0,0 +1,379 @@
+package com.weave.my_profile
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.imePadding
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.BasicTextField
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.SnackbarDuration
+import androidx.compose.material3.SnackbarHost
+import androidx.compose.material3.SnackbarHostState
+import androidx.compose.material3.Text
+import androidx.compose.material3.TooltipState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.SnapshotStateList
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusManager
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.focus.onFocusChanged
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.input.key.key
+import androidx.compose.ui.input.key.onKeyEvent
+import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.hilt.navigation.compose.hiltViewModel
+import com.weave.design_system.DaysTheme
+import com.weave.design_system.R
+import com.weave.design_system.component.BtnType
+import com.weave.design_system.component.DaysNextButton
+import com.weave.design_system.component.DaysOnlyBackAppbar
+import com.weave.design_system.component.DaysSnackBar
+import com.weave.design_system.component.DaysStepIndicator
+import com.weave.design_system.component.SnackBarType
+import com.weave.design_system.component.tooltip.DaysTooltip
+import com.weave.design_system.component.tooltip.TooltipDirection
+import com.weave.design_system.extension.addFocusCleaner
+import com.weave.design_system.extension.noRippleClickable
+import com.weave.utils.Keyboard
+import com.weave.utils.keyboardAsState
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import java.time.Year
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun MyProfileBirthYearScreen(
+ sharedViewModel: MyProfileSharedViewModel = hiltViewModel(),
+ onBackBtnClicked: () -> Unit,
+ onNextBtnClicked: () -> Unit
+) {
+ val focusManager = LocalFocusManager.current
+ val isKeyboardVisible by keyboardAsState()
+ var isEnabled by remember { mutableStateOf(sharedViewModel.birthYear.all { it.isNotEmpty() }) }
+ val snackState = remember { SnackbarHostState() }
+ val scope = rememberCoroutineScope()
+ val noInputMessage = stringResource(id = R.string.my_profile_birth_year_empty_input_message)
+ val tooltipState = remember { TooltipState() }
+
+ Scaffold(
+ modifier = Modifier.fillMaxSize(),
+ topBar = {
+ DaysOnlyBackAppbar(onBackPressed = onBackBtnClicked)
+ },
+ snackbarHost = {
+ SnackbarHost(
+ modifier = Modifier
+ .padding(bottom = 110.dp)
+ .imePadding(),
+ hostState = snackState,
+ ) { snackData ->
+ DaysSnackBar(
+ message = snackData.visuals.message,
+ type = if (snackData.visuals.actionLabel == SnackBarType.DEFAULT.toString()) SnackBarType.DEFAULT else SnackBarType.ERROR
+ )
+ }
+ }
+ ) { innerPadding ->
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .addFocusCleaner(focusManager)
+ .padding(
+ top = innerPadding.calculateTopPadding(),
+ )
+ ) {
+ Image(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(DaysTheme.colors.bgDefault),
+ painter = painterResource(id = R.drawable.texture_bg),
+ contentDescription = stringResource(id = R.string.background_description)
+ )
+
+ Column(
+ modifier = Modifier
+ .matchParentSize()
+ .padding(horizontal = 26.dp)
+ ) {
+ Spacer(modifier = Modifier.height(12.dp))
+
+ DaysStepIndicator(currentStep = 2, totalStep = 5)
+
+ Spacer(modifier = Modifier.height(20.dp))
+
+ Text(
+ text = stringResource(id = R.string.my_profile_birth_year_sub_title, if(sharedViewModel.genderState == "남성") "여성" else "남성"),
+ style = DaysTheme.typography.regular14.toTextStyle(),
+ color = DaysTheme.colors.grey200
+ )
+
+ Spacer(modifier = Modifier.height(4.dp))
+
+ Text(
+ text = stringResource(id = R.string.my_profile_birth_year_title),
+ style = DaysTheme.typography.semiBold24.toTextStyle(),
+ color = DaysTheme.colors.grey500
+ )
+
+ Spacer(modifier = Modifier.height(40.dp))
+
+ BirthYearInputRow(
+ focusManager = focusManager,
+ birthYear = sharedViewModel.birthYear,
+ onNumChanged = { index, newValue ->
+ sharedViewModel.birthYear[index] = newValue
+ isEnabled = sharedViewModel.birthYear.all { it.isNotEmpty() }
+ },
+ unSupportedYear = false
+ )
+
+ Spacer(modifier = Modifier.height(24.dp))
+
+ DaysTooltip(
+ tooltipState = tooltipState,
+ direction = TooltipDirection.Top,
+ tooltipText = boldBirthYearMessage(),
+ content = {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .noRippleClickable {
+ scope.launch { tooltipState.show() }
+ },
+ horizontalArrangement = Arrangement.Center,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(
+ modifier = Modifier.size(18.dp),
+ painter = painterResource(id = R.drawable.ic_question_mark),
+ tint = DaysTheme.colors.grey200,
+ contentDescription = ""
+ )
+
+ Spacer(modifier = Modifier.width(4.dp))
+
+ Text(
+ text = stringResource(id = R.string.my_profile_birth_year_description),
+ style = DaysTheme.typography.regular14.toTextStyle(),
+ color = DaysTheme.colors.grey200
+ )
+ }
+
+ }
+ )
+ }
+
+ DaysNextButton(
+ modifier = Modifier
+ .align(Alignment.BottomCenter)
+ .padding(
+ bottom = if (isKeyboardVisible == Keyboard.Closed) innerPadding.calculateBottomPadding() else 0.dp
+ ),
+ message = stringResource(id = R.string.next_button_message),
+ type = if (isKeyboardVisible == Keyboard.Opened) BtnType.Short else BtnType.Tall,
+ isEnabled = isEnabled,
+ onEnabledClick = onNextBtnClicked,
+ onDisabledClick = {
+ scope.launch {
+ val job = launch {
+ snackState.showSnackbar(
+ message = noInputMessage,
+ actionLabel = SnackBarType.ERROR.toString(),
+ duration = SnackbarDuration.Indefinite
+ )
+ }
+ delay(3000L)
+ job.cancel()
+ }
+ }
+ )
+ }
+ }
+}
+
+fun boldBirthYearMessage(): AnnotatedString {
+ val currentYear = Year.now().value
+ val twentyYearsOld = currentYear - 20
+ val thirtyFiveYearsOld = currentYear - 35
+
+ return buildAnnotatedString {
+ append("${currentYear}년 기준으로 ")
+ withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
+ append("${twentyYearsOld}년생(만 20살)부터 ${thirtyFiveYearsOld}년생(만 35살) ")
+ }
+ append("까지 가입할 수 있어요")
+ }
+}
+
+@Composable
+fun BirthYearInputRow(
+ modifier: Modifier = Modifier,
+ focusManager: FocusManager,
+ birthYear: SnapshotStateList,
+ onNumChanged: (Int, String) -> Unit,
+ unSupportedYear: Boolean
+) {
+ val focusRequesters = List(4) { FocusRequester() }
+ val isFocused = remember { mutableIntStateOf(-1) }
+ val showHint = birthYear.all { it.isEmpty() }
+
+ Row(
+ modifier = modifier
+ .fillMaxWidth()
+ .aspectRatio(314f / 92f),
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ verticalAlignment = Alignment.Bottom
+ ) {
+ birthYear.forEachIndexed { index, _ ->
+ BasicTextField(
+ modifier = Modifier
+ .weight(1f)
+ .fillMaxSize()
+ .background(
+ color = if (unSupportedYear) DaysTheme.colors.pink50 else DaysTheme.colors.yellow50,
+ shape = RoundedCornerShape(20.dp)
+ )
+ .border(
+ width = 4.dp,
+ color = if (unSupportedYear) {
+ DaysTheme.colors.red300
+ } else {
+ if (isFocused.intValue == index) Color(0xFFDFDBA5) else DaysTheme.colors.white
+ },
+ shape = RoundedCornerShape(20.dp)
+ )
+ .focusRequester(focusRequesters[index])
+ .onFocusChanged { focusState ->
+ if (focusState.isFocused) {
+ isFocused.intValue = index
+ onNumChanged(index, "")
+ } else if (isFocused.intValue == index) {
+ isFocused.intValue = -1
+ }
+ }
+ .onKeyEvent { event: KeyEvent ->
+ if (event.key == Key.Backspace) {
+ if (birthYear[index].isEmpty()) {
+ if (index > 0) {
+ focusRequesters[index - 1].requestFocus()
+ }
+ }
+ return@onKeyEvent true
+ }
+ false
+ },
+ value = birthYear[index],
+ onValueChange = { newValue ->
+ if (newValue.length == 1 && newValue.all { it.isDigit() }) {
+ onNumChanged(index, newValue)
+
+ val nextIdx = index + 1
+ if (nextIdx < birthYear.size) {
+ focusRequesters[nextIdx].requestFocus()
+ } else if (birthYear.all { it.isNotBlank() }) {
+ focusManager.clearFocus()
+ }
+ }
+ },
+ textStyle = DaysTheme.typography.semiBold28.copy(
+ fontSize = 40.dp, lineHeight = 60.dp, textAlign = TextAlign.Center
+ ).toTextStyle(),
+ singleLine = true,
+ maxLines = 1,
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
+ decorationBox = { innerTextField ->
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.Center
+ ) {
+ if (showHint) {
+ Text(
+ modifier = Modifier.fillMaxWidth(),
+ text = "2000"[index].toString(),
+ style = DaysTheme.typography.semiBold28.copy(
+ color = Color(0xFFF1EFCC),
+ fontSize = 40.dp,
+ lineHeight = 60.dp,
+ textAlign = TextAlign.Center
+ ).toTextStyle()
+ )
+ }
+ innerTextField()
+ }
+ }
+ )
+ }
+
+ Text(
+ modifier = Modifier.padding(bottom = 4.dp),
+ text = "년생",
+ style = DaysTheme.typography.semiBold18.toTextStyle(),
+ color = DaysTheme.colors.grey300
+ )
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+fun BirthYearInputRowPreview() {
+ val focusManager = LocalFocusManager.current
+ val birthYear = remember { mutableStateListOf("", "", "", "") }
+
+ val onNumChanged: (Int, String) -> Unit = { index, newValue ->
+ birthYear[index] = newValue
+ }
+
+ BirthYearInputRow(
+ focusManager = focusManager,
+ birthYear = birthYear,
+ onNumChanged = onNumChanged,
+ unSupportedYear = false
+ )
+}
+
+@Preview
+@Composable
+fun MyProfileBirthYearScreenPreview() {
+ MyProfileBirthYearScreen(
+ onNextBtnClicked = {},
+ onBackBtnClicked = {}
+ )
+}
\ No newline at end of file
diff --git a/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileGenderScreen.kt b/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileGenderScreen.kt
index acb17b3..139d4af 100644
--- a/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileGenderScreen.kt
+++ b/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileGenderScreen.kt
@@ -7,13 +7,18 @@ 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.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
+import androidx.compose.material3.SnackbarDuration
+import androidx.compose.material3.SnackbarHost
+import androidx.compose.material3.SnackbarHostState
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.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -21,31 +26,54 @@ 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 androidx.hilt.navigation.compose.hiltViewModel
import com.weave.design_system.DaysTheme
import com.weave.design_system.R
import com.weave.design_system.component.BtnType
import com.weave.design_system.component.DaysGenderSelector
import com.weave.design_system.component.DaysNextButton
import com.weave.design_system.component.DaysOnlyBackAppbar
+import com.weave.design_system.component.DaysSnackBar
import com.weave.design_system.component.DaysStepIndicator
+import com.weave.design_system.component.SnackBarType
import com.weave.utils.Keyboard
import com.weave.utils.keyboardAsState
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
@Composable
fun MyProfileGenderScreen(
+ sharedViewModel: MyProfileSharedViewModel = hiltViewModel(),
onBackBtnClicked: () -> Unit,
onNextBtnClicked: () -> Unit
) {
val isKeyboardVisible by keyboardAsState()
- var isEnabled by remember { mutableStateOf(false) }
- var genderState by remember { mutableStateOf("") }
+ var isEnabled by remember { mutableStateOf(sharedViewModel.genderState.isNotEmpty()) }
+ val snackState = remember { SnackbarHostState() }
+ val scope = rememberCoroutineScope()
+ val noSelectedMessage = stringResource(id = R.string.my_profile_gender_no_selected_message)
Scaffold(
- modifier = Modifier.fillMaxSize(),
+ modifier = Modifier
+ .fillMaxSize()
+ .imePadding(),
topBar = {
DaysOnlyBackAppbar(onBackPressed = onBackBtnClicked)
+ },
+ snackbarHost = {
+ SnackbarHost(
+ modifier = Modifier
+ .padding(bottom = 110.dp)
+ .imePadding(),
+ hostState = snackState,
+ ) { snackData ->
+ DaysSnackBar(
+ message = snackData.visuals.message,
+ type = if (snackData.visuals.actionLabel == SnackBarType.DEFAULT.toString()) SnackBarType.DEFAULT else SnackBarType.ERROR
+ )
+ }
}
- ) { innerPadding ->
+ ) { innerPadding ->
Box(
modifier = Modifier
.fillMaxSize()
@@ -89,24 +117,37 @@ fun MyProfileGenderScreen(
Spacer(modifier = Modifier.height(40.dp))
DaysGenderSelector(
- genderState = genderState,
+ genderState = sharedViewModel.genderState,
onChangedGender = { newValue ->
- genderState = newValue
- isEnabled = genderState.isNotEmpty()
+ sharedViewModel.genderState = newValue
+ isEnabled = sharedViewModel.genderState.isNotEmpty()
}
)
}
DaysNextButton(
- message = stringResource(id = R.string.next_button_message),
- type = if (isKeyboardVisible == Keyboard.Opened) BtnType.Short else BtnType.Tall,
- isEnabled = isEnabled,
- onClick = { onNextBtnClicked() },
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(
bottom = if (isKeyboardVisible == Keyboard.Closed) innerPadding.calculateBottomPadding() else 0.dp
- )
+ ),
+ message = stringResource(id = R.string.next_button_message),
+ type = if (isKeyboardVisible == Keyboard.Opened) BtnType.Short else BtnType.Tall,
+ isEnabled = isEnabled,
+ onEnabledClick = onNextBtnClicked,
+ onDisabledClick = {
+ scope.launch {
+ val job = launch {
+ snackState.showSnackbar(
+ message = noSelectedMessage,
+ actionLabel = SnackBarType.ERROR.toString(),
+ duration = SnackbarDuration.Indefinite
+ )
+ }
+ delay(3000L)
+ job.cancel()
+ }
+ }
)
}
}
@@ -114,7 +155,7 @@ fun MyProfileGenderScreen(
@Preview
@Composable
-fun MyProfileGenderScreenPreview(){
+fun MyProfileGenderScreenPreview() {
MyProfileGenderScreen(
onNextBtnClicked = {},
onBackBtnClicked = {}
diff --git a/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileInitScreen.kt b/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileInitScreen.kt
index 183fc93..8f50585 100644
--- a/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileInitScreen.kt
+++ b/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileInitScreen.kt
@@ -2,18 +2,24 @@ package com.weave.my_profile
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
@@ -21,31 +27,26 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.weave.design_system.DaysTheme
import com.weave.design_system.R
-import com.weave.design_system.component.BtnType
-import com.weave.design_system.component.DaysNextButton
-import com.weave.design_system.component.DaysOnlyBackAppbar
-import com.weave.utils.Keyboard
-import com.weave.utils.keyboardAsState
+import kotlinx.coroutines.delay
@Composable
fun MyProfileInitScreen(
- onBackBtnClicked: () -> Unit,
onNextBtnClicked: () -> Unit
) {
- val isKeyboardVisible by keyboardAsState()
+ val screenHeight =
+ LocalDensity.current.run { androidx.compose.ui.platform.LocalContext.current.resources.displayMetrics.heightPixels.toDp() }
+
+ LaunchedEffect(Unit) {
+ delay(3000)
+ onNextBtnClicked()
+ }
Scaffold(
modifier = Modifier.fillMaxSize(),
- topBar = {
- DaysOnlyBackAppbar(onBackPressed = onBackBtnClicked)
- }
) { innerPadding ->
Box(
modifier = Modifier
.fillMaxSize()
- .padding(
- top = innerPadding.calculateTopPadding(),
- )
) {
Image(
modifier = Modifier
@@ -55,30 +56,39 @@ fun MyProfileInitScreen(
contentDescription = stringResource(id = R.string.background_description)
)
+
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(screenHeight / 2)
+ .align(Alignment.BottomCenter)
+ .background(
+ brush = Brush.verticalGradient(
+ colors = listOf(Color(0x00F3DDE5), Color(0xFFF3DDE5))
+ )
+ )
+ )
+
Column(
- modifier = Modifier.matchParentSize(),
- horizontalAlignment = Alignment.CenterHorizontally
+ modifier = Modifier
+ .matchParentSize()
+ .padding(bottom = innerPadding.calculateBottomPadding()),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
) {
- Spacer(modifier = Modifier.height(54.dp))
+ Image(
+ modifier = Modifier.size(48.dp),
+ painter = painterResource(id = R.drawable.ic_reading_glasses),
+ contentDescription = ""
+ )
+ Spacer(modifier = Modifier.height(24.dp))
Text(
text = stringResource(id = R.string.my_profile_init_title),
- style = DaysTheme.typography.semiBold24.toTextStyle(),
+ style = DaysTheme.typography.semiBold20.toTextStyle(),
color = DaysTheme.colors.grey500,
textAlign = TextAlign.Center
)
}
-
- DaysNextButton(
- message = stringResource(id = R.string.next_button_message),
- type = if (isKeyboardVisible == Keyboard.Opened) BtnType.Short else BtnType.Tall,
- isEnabled = true,
- onClick = { onNextBtnClicked() },
- modifier = Modifier
- .align(Alignment.BottomCenter)
- .padding(
- bottom = if (isKeyboardVisible == Keyboard.Closed) innerPadding.calculateBottomPadding() else 0.dp
- )
- )
}
}
}
@@ -87,7 +97,6 @@ fun MyProfileInitScreen(
@Composable
fun MyProfileInitScreenPreview() {
MyProfileInitScreen(
- onBackBtnClicked = {},
onNextBtnClicked = {}
)
}
\ No newline at end of file
diff --git a/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileNavGraph.kt b/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileNavGraph.kt
index bba2e16..3ae67c5 100644
--- a/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileNavGraph.kt
+++ b/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileNavGraph.kt
@@ -1,5 +1,10 @@
package com.weave.my_profile
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.ViewModel
+import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
@@ -9,15 +14,35 @@ fun NavGraphBuilder.navGraphMyProfile(navController: NavController) {
navigation(startDestination = "my_profile_init", route = "my_profile") {
composable("my_profile_init") {
MyProfileInitScreen(
- onBackBtnClicked = { navController.popBackStack() },
onNextBtnClicked = { navController.navigate("my_profile_gender") },
)
}
composable("my_profile_gender") {
+ val sharedViewModel = it.sharedViewModel(navController = navController)
+
MyProfileGenderScreen(
+ sharedViewModel = sharedViewModel,
+ onBackBtnClicked = { navController.popBackStack() },
+ onNextBtnClicked = { navController.navigate("my_profile_birth") }
+ )
+ }
+ composable("my_profile_birth") {
+ val sharedViewModel = it.sharedViewModel(navController = navController)
+
+ MyProfileBirthYearScreen(
+ sharedViewModel = sharedViewModel,
onBackBtnClicked = { navController.popBackStack() },
- onNextBtnClicked = { navController.navigate("my_profile_age") }
+ onNextBtnClicked = { navController.navigate("next_screen") }
)
}
}
+}
+
+@Composable
+inline fun NavBackStackEntry.sharedViewModel(navController: NavController): T {
+ val navGraphRoute = destination.parent?.route ?: return hiltViewModel()
+ val parentEntry = remember(this) {
+ navController.getBackStackEntry(navGraphRoute)
+ }
+ return hiltViewModel(parentEntry)
}
\ No newline at end of file
diff --git a/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileSharedViewModel.kt b/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileSharedViewModel.kt
new file mode 100644
index 0000000..c5e7197
--- /dev/null
+++ b/3days/feat/my-profile/src/main/java/com/weave/my_profile/MyProfileSharedViewModel.kt
@@ -0,0 +1,18 @@
+package com.weave.my_profile
+
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.lifecycle.ViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class MyProfileSharedViewModel @Inject constructor(
+
+): ViewModel() {
+
+ var genderState by mutableStateOf("")
+ val birthYear = mutableStateListOf("", "", "", "")
+}
\ No newline at end of file
diff --git a/3days/feat/my-profile/src/test/java/com/weave/my_profile/ExampleUnitTest.kt b/3days/feat/my-profile/src/test/java/com/weave/my_profile/ExampleUnitTest.kt
index 07019af..d0b6243 100644
--- a/3days/feat/my-profile/src/test/java/com/weave/my_profile/ExampleUnitTest.kt
+++ b/3days/feat/my-profile/src/test/java/com/weave/my_profile/ExampleUnitTest.kt
@@ -1,9 +1,8 @@
package com.weave.my_profile
+import org.junit.Assert.assertEquals
import org.junit.Test
-import org.junit.Assert.*
-
/**
* Example local unit test, which will execute on the development machine (host).
*