diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ec5b3cf3..f465cf34 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -15,6 +15,7 @@ android { } manifestPlaceholders["MAPS_API_KEY"] = localProperties.getProperty("MAPS_API_KEY", "") + buildConfigField("String", "NDGL_TERMS_URL", "\"${localProperties.getProperty("NDGL_TERMS_URL", "")}\"") } buildFeatures { @@ -31,8 +32,8 @@ android { dependencies { implementation(project(":navigation")) + implementation(project(":feature:splash")) implementation(project(":feature:home")) - implementation(project(":feature:auth")) implementation(project(":feature:travel")) implementation(project(":feature:travel-helper")) @@ -41,4 +42,5 @@ dependencies { implementation(libs.androidx.navigation3.runtime) implementation(libs.androidx.navigation3.ui) implementation(libs.androidx.lifecycle.viewmodel.navigation3) + implementation(libs.androidx.core.splashscreen) } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2d178c9a..44a51cc3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,6 @@ android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" - android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.NDGL" @@ -24,7 +23,7 @@ android:name=".MainActivity" android:exported="true" android:label="@string/app_name" - android:theme="@style/Theme.NDGL"> + android:theme="@style/Theme.NDGL.Splash"> diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 00000000..3c63dc0f Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/yapp/ndgl/MainActivity.kt b/app/src/main/java/com/yapp/ndgl/MainActivity.kt index f97fffde..5f4a63c2 100644 --- a/app/src/main/java/com/yapp/ndgl/MainActivity.kt +++ b/app/src/main/java/com/yapp/ndgl/MainActivity.kt @@ -4,7 +4,17 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.compose.animation.AnimatedContent +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import com.yapp.ndgl.core.ui.designsystem.UserGuideModal import com.yapp.ndgl.core.ui.theme.NDGLTheme +import com.yapp.ndgl.core.ui.util.launchBrowser +import com.yapp.ndgl.feature.splash.SplashRoute +import com.yapp.ndgl.navigation.AppScreen import com.yapp.ndgl.ui.NDGLApp import dagger.hilt.android.AndroidEntryPoint @@ -12,10 +22,42 @@ import dagger.hilt.android.AndroidEntryPoint class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + installSplashScreen() enableEdgeToEdge() setContent { NDGLTheme { - NDGLApp() + var currentScreen by rememberSaveable { mutableStateOf(AppScreen.Splash) } + var showUserGuideModal by rememberSaveable { mutableStateOf(false) } + + AnimatedContent( + targetState = currentScreen, + ) { screen -> + when (screen) { + AppScreen.Splash -> { + SplashRoute( + navigateToHome = { isFirstUser -> + showUserGuideModal = isFirstUser + currentScreen = AppScreen.Main + }, + ) + } + + AppScreen.Main -> { + NDGLApp() + } + } + } + + if (showUserGuideModal) { + UserGuideModal( + onConfirmClick = { + showUserGuideModal = false + }, + onTermsClick = { + launchBrowser(BuildConfig.NDGL_TERMS_URL) + }, + ) + } } } } diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index 7706ab9e..4c4ee7d9 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -1,30 +1,33 @@ - - - - - - - - - + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 51% rename from app/src/main/res/mipmap-anydpi/ic_launcher.xml rename to app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index b3e26b4c..7353dbd1 100644 --- a/app/src/main/res/mipmap-anydpi/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,6 +1,5 @@ - - - - + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 51% rename from app/src/main/res/mipmap-anydpi/ic_launcher_round.xml rename to app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index b3e26b4c..7353dbd1 100644 --- a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,6 +1,5 @@ - - - - + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp index c209e78e..72ff7264 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp index b2dfe3d1..674f733e 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp index 4f0f1d64..6cc2eace 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp index 62b611da..4ada3c4c 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp index 948a3070..f34325d1 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp index 1b9a6956..ad139418 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp index 28d4b77f..95d2419e 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp index 9287f508..604ad1cb 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp index aa7d6427..26c67171 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp index 9126ae37..b0a6d403 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index ca1931bc..7ecc8b9c 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,4 +7,5 @@ #FF018786 #FF000000 #FFFFFFFF + #FF73D08B diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000..06999412 --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #2FED72 + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1b8ab60b..d86bd2b1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - NDGL - \ No newline at end of file + 나도갈래 + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index d08cf9a4..50bf98a5 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -2,4 +2,9 @@ diff --git a/core/ui/src/main/java/com/yapp/ndgl/core/ui/designsystem/NDGLUserGuideModal.kt b/core/ui/src/main/java/com/yapp/ndgl/core/ui/designsystem/NDGLUserGuideModal.kt new file mode 100644 index 00000000..bb0b47ed --- /dev/null +++ b/core/ui/src/main/java/com/yapp/ndgl/core/ui/designsystem/NDGLUserGuideModal.kt @@ -0,0 +1,112 @@ +package com.yapp.ndgl.core.ui.designsystem + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Surface +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.text.style.TextAlign +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import com.yapp.ndgl.core.ui.R +import com.yapp.ndgl.core.ui.theme.NDGLTheme + +@Composable +fun UserGuideModal( + onConfirmClick: () -> Unit, + onTermsClick: () -> Unit, + modifier: Modifier = Modifier, +) { + Dialog( + onDismissRequest = { /* 확인 버튼을 눌러야만 닫힘 */ }, + properties = DialogProperties( + dismissOnBackPress = false, + dismissOnClickOutside = false, + ), + ) { + Surface( + modifier = modifier.wrapContentHeight(), + shape = RoundedCornerShape(8.dp), + color = NDGLTheme.colors.white, + shadowElevation = 16.dp, + ) { + Column( + modifier = Modifier + .padding(horizontal = 28.dp) + .padding(top = 28.dp, bottom = 24.dp), + verticalArrangement = Arrangement.spacedBy(28.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + UserGuideContent( + onTermsClick = onTermsClick, + ) + NDGLCTAButton( + type = NDGLCTAButtonAttr.Type.PRIMARY, + size = NDGLCTAButtonAttr.Size.MEDIUM, + status = NDGLCTAButtonAttr.Status.ACTIVE, + label = stringResource(R.string.user_guide_modal_confirm), + onClick = onConfirmClick, + modifier = Modifier.fillMaxWidth(), + ) + } + } + } +} + +@Composable +private fun UserGuideContent( + onTermsClick: () -> Unit, +) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = stringResource(R.string.user_guide_modal_title), + modifier = Modifier.fillMaxWidth(), + color = NDGLTheme.colors.black900, + textAlign = TextAlign.Center, + style = NDGLTheme.typography.subtitleLgSemiBold, + ) + Text( + text = stringResource(R.string.user_guide_modal_body), + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp), + color = NDGLTheme.colors.black500, + textAlign = TextAlign.Center, + style = NDGLTheme.typography.bodyLgMedium, + ) + Text( + text = stringResource(R.string.user_guide_modal_terms), + modifier = Modifier + .padding(top = 12.dp) + .clickable(onClick = onTermsClick), + color = NDGLTheme.colors.black400, + textAlign = TextAlign.Center, + textDecoration = TextDecoration.Underline, + style = NDGLTheme.typography.bodyMdMedium, + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun UserGuideModalPreview() { + NDGLTheme { + UserGuideModal( + onConfirmClick = {}, + onTermsClick = {}, + ) + } +} diff --git a/core/ui/src/main/res/drawable/ic_splash.xml b/core/ui/src/main/res/drawable/ic_splash.xml new file mode 100644 index 00000000..553107c3 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_splash.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index 24051bc2..ba1e74ee 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -16,6 +16,12 @@ 다시 시도 전체 + + 서비스 이용 전\n반드시 확인해주세요. + 본 서비스는 AI 기술을 활용하여\n여행 정보를 분석 • 재구성하여 제공하는\n참고용 서비스입니다. 아래 내용을\n충분히 확인 후 이용해주세요. + 이용 약관 확인하기 + 확인했어요 + 약 %1$s • %2$s %skm diff --git a/data/auth/src/main/java/com/yapp/ndgl/data/auth/repository/AuthRepository.kt b/data/auth/src/main/java/com/yapp/ndgl/data/auth/repository/AuthRepository.kt index 76e1fd1f..8ddaa9fb 100644 --- a/data/auth/src/main/java/com/yapp/ndgl/data/auth/repository/AuthRepository.kt +++ b/data/auth/src/main/java/com/yapp/ndgl/data/auth/repository/AuthRepository.kt @@ -21,21 +21,25 @@ class AuthRepository @Inject constructor( private val api: AuthApi, private val localAuthDataSource: LocalAuthDataSource, ) { - suspend fun initSession() { + suspend fun initSession(): Boolean { val uuid = localAuthDataSource.getUuid() + var isFirstUser = false val response = if (uuid.isNotEmpty()) { suspendRunCatching { login(uuid) }.getOrElse { localAuthDataSource.clearSession() + isFirstUser = true createUser() } } else { + isFirstUser = true createUser() } localAuthDataSource.setAccessToken(response.accessToken) localAuthDataSource.setUuid(response.uuid) + return isFirstUser } private suspend fun createUser(): AuthResponse { diff --git a/feature/home/build.gradle.kts b/feature/home/build.gradle.kts index 1ee2137f..106213ee 100644 --- a/feature/home/build.gradle.kts +++ b/feature/home/build.gradle.kts @@ -8,5 +8,4 @@ android { dependencies { implementation(project(":data:travel")) - implementation(project(":data:auth")) } diff --git a/feature/home/src/main/java/com/yapp/ndgl/feature/home/main/HomeViewModel.kt b/feature/home/src/main/java/com/yapp/ndgl/feature/home/main/HomeViewModel.kt index f02ebe47..f691c159 100644 --- a/feature/home/src/main/java/com/yapp/ndgl/feature/home/main/HomeViewModel.kt +++ b/feature/home/src/main/java/com/yapp/ndgl/feature/home/main/HomeViewModel.kt @@ -3,7 +3,6 @@ package com.yapp.ndgl.feature.home.main import androidx.lifecycle.viewModelScope import com.yapp.ndgl.core.base.BaseViewModel import com.yapp.ndgl.core.util.suspendRunCatching -import com.yapp.ndgl.data.auth.repository.AuthRepository import com.yapp.ndgl.data.travel.model.TravelProgram import com.yapp.ndgl.data.travel.model.TravelTemplateSummary import com.yapp.ndgl.data.travel.repository.TravelProgramRepository @@ -22,7 +21,6 @@ import javax.inject.Inject @HiltViewModel class HomeViewModel @Inject constructor( - private val authRepository: AuthRepository, private val travelProgramRepository: TravelProgramRepository, private val travelTemplateRepository: TravelTemplateRepository, private val userTravelRepository: UserTravelRepository, @@ -30,17 +28,7 @@ class HomeViewModel @Inject constructor( initialState = HomeState(), ) { init { - initSession() - } - - private fun initSession() = viewModelScope.launch { - suspendRunCatching { - authRepository.initSession() - }.onSuccess { - loadHomeContents() - }.onFailure { - // FIXME: 에러 뷰 - } + loadHomeContents() } private fun loadHomeContents() { diff --git a/feature/splash/.gitignore b/feature/splash/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/feature/splash/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature/splash/build.gradle.kts b/feature/splash/build.gradle.kts new file mode 100644 index 00000000..0d5955a1 --- /dev/null +++ b/feature/splash/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("ndgl.feature") +} + +android { + namespace = "com.yapp.ndgl.feature.splash" +} + +dependencies { + implementation(projects.data.auth) +} diff --git a/feature/splash/src/main/AndroidManifest.xml b/feature/splash/src/main/AndroidManifest.xml new file mode 100644 index 00000000..8bdb7e14 --- /dev/null +++ b/feature/splash/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/feature/splash/src/main/java/com/yapp/ndgl/feature/splash/SplashContract.kt b/feature/splash/src/main/java/com/yapp/ndgl/feature/splash/SplashContract.kt new file mode 100644 index 00000000..f96584e8 --- /dev/null +++ b/feature/splash/src/main/java/com/yapp/ndgl/feature/splash/SplashContract.kt @@ -0,0 +1,10 @@ +package com.yapp.ndgl.feature.splash + +import com.yapp.ndgl.core.base.UiSideEffect +import com.yapp.ndgl.core.base.UiState + +class SplashState : UiState + +sealed interface SplashSideEffect : UiSideEffect { + data class NavigateToHome(val isFirstUser: Boolean) : SplashSideEffect +} diff --git a/feature/splash/src/main/java/com/yapp/ndgl/feature/splash/SplashScreen.kt b/feature/splash/src/main/java/com/yapp/ndgl/feature/splash/SplashScreen.kt new file mode 100644 index 00000000..c264a7bc --- /dev/null +++ b/feature/splash/src/main/java/com/yapp/ndgl/feature/splash/SplashScreen.kt @@ -0,0 +1,81 @@ +package com.yapp.ndgl.feature.splash + +import androidx.activity.ComponentActivity +import androidx.activity.SystemBarStyle +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import com.yapp.ndgl.core.ui.R +import com.yapp.ndgl.core.ui.theme.NDGLTheme + +@Composable +fun SplashRoute( + viewmodel: SplashViewModel = hiltViewModel(), + navigateToHome: (Boolean) -> Unit, +) { + val context = LocalContext.current + val activity = context as? ComponentActivity + + DisposableEffect(Unit) { + activity?.enableEdgeToEdge( + statusBarStyle = SystemBarStyle.dark(Color.Transparent.toArgb()), + navigationBarStyle = SystemBarStyle.dark(Color.Transparent.toArgb()), + ) + + onDispose { + activity?.enableEdgeToEdge( + statusBarStyle = SystemBarStyle.auto( + android.graphics.Color.TRANSPARENT, + android.graphics.Color.TRANSPARENT, + ), + navigationBarStyle = SystemBarStyle.auto( + android.graphics.Color.TRANSPARENT, + android.graphics.Color.TRANSPARENT, + ), + ) + } + } + + viewmodel.collectSideEffect { sideEffect -> + when (sideEffect) { + is SplashSideEffect.NavigateToHome -> { + navigateToHome(sideEffect.isFirstUser) + } + } + } + + SplashScreen() +} + +@Composable +private fun SplashScreen() { + Column( + modifier = Modifier + .fillMaxSize() + .background(NDGLTheme.colors.green300), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_splash), contentDescription = null, tint = Color.Unspecified) + } +} + +@Preview(showBackground = true) +@Composable +private fun SplashScreenPreview() { + SplashScreen() +} diff --git a/feature/splash/src/main/java/com/yapp/ndgl/feature/splash/SplashViewModel.kt b/feature/splash/src/main/java/com/yapp/ndgl/feature/splash/SplashViewModel.kt new file mode 100644 index 00000000..60218222 --- /dev/null +++ b/feature/splash/src/main/java/com/yapp/ndgl/feature/splash/SplashViewModel.kt @@ -0,0 +1,35 @@ +package com.yapp.ndgl.feature.splash + +import androidx.lifecycle.viewModelScope +import com.yapp.ndgl.core.base.BaseViewModel +import com.yapp.ndgl.core.base.UiIntent +import com.yapp.ndgl.core.util.suspendRunCatching +import com.yapp.ndgl.data.auth.repository.AuthRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class SplashViewModel @Inject constructor( + private val authRepository: AuthRepository, +) : BaseViewModel( + initialState = SplashState(), +) { + init { + initSession() + } + + private fun initSession() = viewModelScope.launch { + suspendRunCatching { + authRepository.initSession() + }.onSuccess { isFirstUser -> + postSideEffect(SplashSideEffect.NavigateToHome(isFirstUser = isFirstUser)) + }.onFailure { + // FIXME: 에러 뷰 + } + } + + override suspend fun handleIntent(intent: UiIntent) { + // Splash에 따로 intent 존재하지 않음 + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f5b7e916..0c13d455 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,11 +2,12 @@ agp = "8.13.2" kotlin = "2.0.21" ksp = "2.0.21-1.0.28" +jetbrainsKotlinJvm = "2.0.21" coreKtx = "1.17.0" lifecycleRuntimeKtx = "2.10.0" activityCompose = "1.12.2" composeBom = "2026.01.00" -jetbrainsKotlinJvm = "2.0.21" +androidxSplashscreen = "1.2.0" # Hilt hilt = "2.57.2" @@ -67,6 +68,7 @@ ktlint-source = "0.50.0" #https://github.com/pinterest/ktlint/releases androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidxSplashscreen" } # Compose androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } diff --git a/navigation/src/main/java/com/yapp/ndgl/navigation/AppScreen.kt b/navigation/src/main/java/com/yapp/ndgl/navigation/AppScreen.kt new file mode 100644 index 00000000..c7bfa4cd --- /dev/null +++ b/navigation/src/main/java/com/yapp/ndgl/navigation/AppScreen.kt @@ -0,0 +1,6 @@ +package com.yapp.ndgl.navigation + +enum class AppScreen { + Splash, + Main, +} diff --git a/navigation/src/main/java/com/yapp/ndgl/navigation/Route.kt b/navigation/src/main/java/com/yapp/ndgl/navigation/Route.kt index f03e6867..01a53bc4 100644 --- a/navigation/src/main/java/com/yapp/ndgl/navigation/Route.kt +++ b/navigation/src/main/java/com/yapp/ndgl/navigation/Route.kt @@ -8,7 +8,7 @@ import kotlinx.serialization.Serializable @Serializable sealed interface Route : NavKey { @Serializable - data object Auth : Route + data object Splash : Route @Serializable data object Home : Route diff --git a/settings.gradle.kts b/settings.gradle.kts index 9f8b8c87..4c7295e8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -29,9 +29,9 @@ include(":core:base") include(":core:ui") include(":core:util") include(":feature:home") -include(":feature:auth") include(":feature:travel") include(":feature:travel-helper") +include(":feature:splash") include(":data:core") include(":data:auth") include(":data:travel")