diff --git a/app/src/main/java/com/paw/key/presentation/ui/onboard/OnboardingScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/onboard/OnboardingScreen.kt index b2beac2d..8def8e11 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/onboard/OnboardingScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/onboard/OnboardingScreen.kt @@ -2,24 +2,23 @@ package com.paw.key.presentation.ui.onboard 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.PaddingValues -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.withStyle -import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.paw.key.R import com.paw.key.core.designsystem.component.PawkeyButton import com.paw.key.core.designsystem.theme.PawKeyTheme +import com.paw.key.presentation.ui.onboard.component.OnboardPager +import com.paw.key.presentation.ui.onboard.component.OnboardingPosting @Composable fun OnboardingRoute( @@ -66,48 +65,61 @@ fun OnboardingScreen( snackBarHostState: SnackbarHostState, modifier: Modifier = Modifier, ) { - Column( + + val jobList = listOf( + OnboardingPosting( + title = "우리의 강아지를 위한 산책,\nPAWKEY와 함께해요!", // 원본 텍스트로 변경 + subtitle = "", + backImg = R.drawable.onboard1 + ), + OnboardingPosting( + title = "새로운 산책의 시작", + subtitle = "최적화된 산책 환경에서 더 즐겁고 의미있는 산책을\n우리 강아지와 함께 시작해보세요.", + backImg = R.drawable.onboard2 + ), + OnboardingPosting( + title = "매일매일 새로운 루트로!\n우리 강아지와 나만의 산책.", + subtitle = "", + backImg = R.drawable.onboard3 + ), + OnboardingPosting( + title = "산책을 기록하고 공유하고\n수정해보세요.", + subtitle = "", + backImg = R.drawable.onboard4 + ) + ) + + Box( modifier = modifier .fillMaxSize() - .background(color = PawKeyTheme.colors.white1) + .background(color = PawKeyTheme.colors.green500) ) { + OnboardPager( + jobList = jobList + ) + Column( + verticalArrangement = Arrangement.spacedBy(12.dp), modifier = Modifier - .fillMaxSize() - .padding(horizontal = 16.dp, vertical = 60.dp) + .align(Alignment.BottomCenter) + .padding(horizontal = 16.dp, vertical = 64.dp) + .fillMaxWidth() ) { - - Text( - text = buildAnnotatedString { - append("안녕하세요\n우리 강아지를 위한 산책,\n") - withStyle(style = SpanStyle(color = PawKeyTheme.colors.green500)) { - append("PAWKEY") - } - append("와 함께해요! ") - }, - color = PawKeyTheme.colors.black, - style = PawKeyTheme.typography.head22B + PawkeyButton( + text = "신규 계정으로 회원가입", + enabled = true, + onClick = { }, + isBackGround = true, + isBorder = false ) - Spacer(modifier = Modifier.weight(1F)) - - Column( - verticalArrangement = Arrangement.spacedBy(10.dp) - ) { - PawkeyButton( - text = "신규 계정으로 회원가입", - enabled = true, - onClick = { }, - ) - - PawkeyButton( - text = "기존 계정으로 로그인", - enabled = true, - isBackGround = true, - isBorder = false, - onClick = { navigateSignUp() }, - ) - } + PawkeyButton( + text = "기존 계정으로 로그인", + enabled = true, + isBorder = false, + onClick = { navigateSignUp() }, + ) } } -} \ No newline at end of file +} + diff --git a/app/src/main/java/com/paw/key/presentation/ui/onboard/component/OnboardPager.kt b/app/src/main/java/com/paw/key/presentation/ui/onboard/component/OnboardPager.kt new file mode 100644 index 00000000..aeef3996 --- /dev/null +++ b/app/src/main/java/com/paw/key/presentation/ui/onboard/component/OnboardPager.kt @@ -0,0 +1,226 @@ +package com.paw.key.presentation.ui.onboard.component + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +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.width +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.PagerState +import androidx.compose.foundation.pager.rememberPagerState +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.draw.clip +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.zIndex +import com.paw.key.R +import com.paw.key.core.designsystem.theme.PawKeyTheme + +@Preview(showBackground = true) +@Composable +private fun PreviewOnboardPager() { + PawKeyTheme { + OnboardPager( + jobList = listOf( + OnboardingPosting( + title = "우리의 강아지를 위한 산책,\nPAWKEY와 함께해요!", // 원본 텍스트로 변경 + subtitle = "", + backImg = R.drawable.onboard1 + ), + ) + + ) + } +} + +@Composable +fun OnboardPager( + jobList: List, +) { + val pageCount = jobList.size + val pagerState = rememberPagerState(pageCount = { pageCount }) + + Box( + modifier = Modifier + .fillMaxWidth() + .height(620.dp) + .background( + color = PawKeyTheme.colors.white1, + shape = RoundedCornerShape(bottomStart = 16.dp, bottomEnd = 16.dp)) + .clip(RoundedCornerShape(bottomStart = 16.dp, bottomEnd = 16.dp)) + ) { + HorizontalPager( + state = pagerState, + modifier = Modifier + .fillMaxSize() + ) { page -> + val job = jobList[page] + OnboardingListItem( + title = job.title, + subtitle = job.subtitle, + backImg = job.backImg + ) + } + + AnimatedPagerIndicator( + pagerState = pagerState, + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = 20.dp), + activeColor = PawKeyTheme.colors.green500, + inactiveColor = PawKeyTheme.colors.green200 + ) + } +} + +@Composable +fun OnboardingListItem( + title: String, + subtitle: String, + backImg: Int, +) { + Box( + modifier = Modifier + .fillMaxSize() + .background( + color = PawKeyTheme.colors.white1, + shape = RoundedCornerShape(bottomStart = 24.dp, bottomEnd = 24.dp) + ) + .clip( + shape = RoundedCornerShape(bottomStart = 24.dp, bottomEnd = 24.dp) + ) + ) { + + Image( + painter = painterResource(id = backImg), + contentDescription = "sibal", + modifier = Modifier + .fillMaxSize() + .height(596.dp) + .align(Alignment.Center), + contentScale = ContentScale.FillBounds + ) + Column( + modifier = Modifier + .padding(top = 80.dp, start = 24.dp, end = 24.dp) + .zIndex(2F) + ) { + val annotatedTitle = if (title.contains("PAWKEY")) { + buildAnnotatedString { + val pawkeyStart = title.indexOf("PAWKEY") + val pawkeyEnd = pawkeyStart + "PAWKEY".length + + withStyle(style = SpanStyle(color = PawKeyTheme.colors.black)) { + append(title.substring(0, pawkeyStart)) + } + + withStyle(style = SpanStyle(color = PawKeyTheme.colors.green500)) { + append("PAWKEY") + } + + withStyle(style = SpanStyle(color = PawKeyTheme.colors.black)) { + append(title.substring(pawkeyEnd)) + } + } + } else { + buildAnnotatedString { + withStyle(style = SpanStyle(color = PawKeyTheme.colors.green500)) { + append(title) + } + } + } + Text( + text = annotatedTitle, + style = PawKeyTheme.typography.head24B.copy(lineHeight = 36.sp), + color = PawKeyTheme.colors.green500, + modifier = Modifier + ) + + if (subtitle.isNotEmpty()) { + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = subtitle, + style = PawKeyTheme.typography.body16M, + color = PawKeyTheme.colors.gray400, + ) + } + } + + } +} + +@Composable +fun AnimatedPagerIndicator( + pagerState: PagerState, + modifier: Modifier = Modifier, + activeColor: Color = Color.Blue, + inactiveColor: Color = Color.Gray, + indicatorWidth: Dp = 12.dp, + indicatorHeight: Dp = 12.dp, + spacing: Dp = 12.dp, +) { + val density = LocalDensity.current + val activeIndicatorWidth = 24.dp + + Canvas( + modifier = modifier + .height(indicatorHeight) + .width( + activeIndicatorWidth + (indicatorWidth * (pagerState.pageCount - 1)) + + spacing * (pagerState.pageCount - 1) + ) + ) { + val canvasWidth = size.width + val canvasHeight = size.height + + val indicatorWidthPx = with(density) { indicatorWidth.toPx() } + val activeIndicatorWidthPx = with(density) { activeIndicatorWidth.toPx() } + val indicatorHeightPx = with(density) { indicatorHeight.toPx() } + val spacingPx = with(density) { spacing.toPx() } + + var startX = 0f + + for (i in 0 until pagerState.pageCount) { + val isActive = i == pagerState.currentPage + val currentWidth = if (isActive) activeIndicatorWidthPx else indicatorWidthPx + + drawRoundRect( + color = if (isActive) activeColor else inactiveColor, + topLeft = Offset(startX, (canvasHeight - indicatorHeightPx) / 2), + size = Size(currentWidth, indicatorHeightPx), + cornerRadius = CornerRadius(indicatorHeightPx / 2) + ) + + startX += currentWidth + spacingPx + } + } +} + +data class OnboardingPosting( + val title: String, + val subtitle: String, + val backImg: Int, +) \ No newline at end of file diff --git a/app/src/main/java/com/paw/key/presentation/ui/splash/SplashScreen.kt b/app/src/main/java/com/paw/key/presentation/ui/splash/SplashScreen.kt index 85da1217..36e80d72 100644 --- a/app/src/main/java/com/paw/key/presentation/ui/splash/SplashScreen.kt +++ b/app/src/main/java/com/paw/key/presentation/ui/splash/SplashScreen.kt @@ -75,22 +75,12 @@ fun SplashScreen( .background(color = PawKeyTheme.colors.green500), contentAlignment = Alignment.Center ) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { Icon( - imageVector = ImageVector.vectorResource(id = R.drawable.ic_logo_draft), + imageVector = ImageVector.vectorResource(id = R.drawable.ic_splash_logo), contentDescription = stringResource(id = R.string.ic_logo), tint = Color.Unspecified, modifier = Modifier.size(154.dp) ) - - Spacer(modifier = Modifier.height(16.dp)) - - Text( - text = stringResource(id = R.string.ic_logo), - color = PawKeyTheme.colors.white1, - style = PawKeyTheme.typography.head22B - ) - } } } diff --git a/app/src/main/res/drawable/ic_onboard_1.xml b/app/src/main/res/drawable/ic_onboard_1.xml new file mode 100644 index 00000000..b5188e7a --- /dev/null +++ b/app/src/main/res/drawable/ic_onboard_1.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_onboard_2.xml b/app/src/main/res/drawable/ic_onboard_2.xml new file mode 100644 index 00000000..bd984f2b --- /dev/null +++ b/app/src/main/res/drawable/ic_onboard_2.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_onboard_3.xml b/app/src/main/res/drawable/ic_onboard_3.xml new file mode 100644 index 00000000..35b67e90 --- /dev/null +++ b/app/src/main/res/drawable/ic_onboard_3.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_onboard_4.xml b/app/src/main/res/drawable/ic_onboard_4.xml new file mode 100644 index 00000000..f7091571 --- /dev/null +++ b/app/src/main/res/drawable/ic_onboard_4.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_splash_logo.xml b/app/src/main/res/drawable/ic_splash_logo.xml new file mode 100644 index 00000000..a516cd88 --- /dev/null +++ b/app/src/main/res/drawable/ic_splash_logo.xml @@ -0,0 +1,30 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/onboard1.png b/app/src/main/res/drawable/onboard1.png new file mode 100644 index 00000000..6b2d60b3 Binary files /dev/null and b/app/src/main/res/drawable/onboard1.png differ diff --git a/app/src/main/res/drawable/onboard2.png b/app/src/main/res/drawable/onboard2.png new file mode 100644 index 00000000..5dc4d3b4 Binary files /dev/null and b/app/src/main/res/drawable/onboard2.png differ diff --git a/app/src/main/res/drawable/onboard3.png b/app/src/main/res/drawable/onboard3.png new file mode 100644 index 00000000..d0bae60b Binary files /dev/null and b/app/src/main/res/drawable/onboard3.png differ diff --git a/app/src/main/res/drawable/onboard4.png b/app/src/main/res/drawable/onboard4.png new file mode 100644 index 00000000..e42992ca Binary files /dev/null and b/app/src/main/res/drawable/onboard4.png differ