diff --git a/Near/app/build.gradle.kts b/Near/app/build.gradle.kts
index 1e85f397..0284dce0 100644
--- a/Near/app/build.gradle.kts
+++ b/Near/app/build.gradle.kts
@@ -99,6 +99,9 @@ dependencies {
// Kakao Module
implementation(libs.v2.all)
+
+ // Splash Screen API
+ implementation(libs.androidx.core.splashscreen)
}
fun getProperty(propertyKey: String): String = gradleLocalProperties(rootDir, providers).getProperty(propertyKey)
diff --git a/Near/app/src/main/AndroidManifest.xml b/Near/app/src/main/AndroidManifest.xml
index b0ae0a68..09d49b30 100644
--- a/Near/app/src/main/AndroidManifest.xml
+++ b/Near/app/src/main/AndroidManifest.xml
@@ -9,7 +9,7 @@
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
- android:icon="@mipmap/ic_launcher"
+ android:icon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
@@ -20,25 +20,28 @@
-
+
+
-
+
+
-
+
+ android:theme="@style/Theme.Near.Splash">
diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/login/LoginScreen.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/login/LoginScreen.kt
index 10990fba..c231a9c3 100644
--- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/login/LoginScreen.kt
+++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/login/LoginScreen.kt
@@ -89,7 +89,7 @@ private fun LoginIntroductionSection(modifier: Modifier = Modifier) {
Image(
modifier = modifier.wrapContentSize(Alignment.Center),
alignment = Alignment.Center,
- painter = painterResource(R.drawable.ic_near_logo_title),
+ painter = painterResource(R.drawable.ic_near_logo_title_primary),
contentDescription = stringResource(R.string.near_logo_title),
)
diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/MainActivity.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/MainActivity.kt
index 35f00fdc..92fd46ef 100644
--- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/MainActivity.kt
+++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/MainActivity.kt
@@ -4,17 +4,47 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
+import androidx.activity.viewModels
+import androidx.compose.runtime.getValue
+import androidx.core.splashscreen.SplashScreen
+import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.lifecycle.lifecycleScope
import com.alarmy.near.presentation.ui.theme.NearTheme
import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
+ private val mainViewModel: MainViewModel by viewModels()
+
override fun onCreate(savedInstanceState: Bundle?) {
+ val splashScreen = installSplashScreen()
+
super.onCreate(savedInstanceState)
enableEdgeToEdge()
+ setupSplashScreen(splashScreen)
+
setContent {
NearTheme {
- NearApp()
+ val uiState by mainViewModel.uiState.collectAsStateWithLifecycle()
+ if (!uiState.isLoading) {
+ NearApp(
+ isLoggedIn = uiState.isLoggedIn
+ )
+ }
+ }
+ }
+ }
+
+ /**
+ * 스플래시 스크린을 설정하고 MainViewModel의 상태를 관찰합니다.
+ * API 스플래시가 표시되는 동안 백그라운드에서 검증을 수행합니다.
+ */
+ private fun setupSplashScreen(splashScreen: SplashScreen) {
+ lifecycleScope.launch {
+ mainViewModel.uiState.collect { uiState ->
+ splashScreen.setKeepOnScreenCondition { uiState.isLoading }
}
}
}
diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/MainViewModel.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/MainViewModel.kt
new file mode 100644
index 00000000..3c97b6fb
--- /dev/null
+++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/MainViewModel.kt
@@ -0,0 +1,53 @@
+package com.alarmy.near.presentation.feature.main
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.alarmy.near.data.repository.AuthRepository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class MainViewModel @Inject constructor(
+ private val authRepository: AuthRepository,
+) : ViewModel() {
+
+ // UI 상태 관리
+ private val _uiState = MutableStateFlow(MainUiState())
+ val uiState: StateFlow = _uiState.asStateFlow()
+
+ init {
+ checkLoginStatus()
+ }
+
+ /**
+ * 로그인 상태를 확인하고 스플래시 스크린을 제어합니다.
+ * API 스플래시가 표시되는 동안 백그라운드에서 검증을 수행합니다.
+ */
+ private fun checkLoginStatus() {
+ viewModelScope.launch {
+
+ // 로그인 상태 검증
+ val isLoggedIn = runCatching {
+ authRepository.isLoggedIn()
+ }.getOrElse { false }
+
+ // UI 상태 업데이트
+ _uiState.value = _uiState.value.copy(
+ isLoading = false,
+ isLoggedIn = isLoggedIn
+ )
+ }
+ }
+}
+
+/**
+ * MainActivity의 UI 상태를 관리하는 데이터 클래스
+ */
+data class MainUiState(
+ val isLoading: Boolean = true,
+ val isLoggedIn: Boolean = false,
+)
diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearApp.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearApp.kt
index 106f00b5..3e739250 100644
--- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearApp.kt
+++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearApp.kt
@@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.exclude
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.ime
-import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.Scaffold
@@ -26,6 +25,7 @@ import kotlinx.coroutines.launch
internal fun NearApp(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
+ isLoggedIn: Boolean = false,
) {
val snackBarState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
@@ -48,6 +48,7 @@ internal fun NearApp(
NearNavHost(
modifier = Modifier.consumeWindowInsets(innerPadding), // 하위 뷰에 Padding을 소비한 것으로 알립니다.
navController = navController,
+ isLoggedIn = isLoggedIn,
onShowSnackbar = {
scope.launch {
snackBarState.showSnackbar(
diff --git a/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearNavHost.kt b/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearNavHost.kt
index adf33e39..8c0cdb19 100644
--- a/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearNavHost.kt
+++ b/Near/app/src/main/java/com/alarmy/near/presentation/feature/main/NearNavHost.kt
@@ -7,6 +7,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.core.net.toUri
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
+import androidx.navigation.navOptions
import com.alarmy.near.presentation.feature.friendprofile.navigation.friendProfileNavGraph
import com.alarmy.near.presentation.feature.friendprofile.navigation.navigateToFriendProfile
import com.alarmy.near.presentation.feature.friendprofileedittor.navigation.FRIEND_PROFILE_EDIT_COMPLETE_KEY
@@ -14,26 +15,29 @@ import com.alarmy.near.presentation.feature.friendprofileedittor.navigation.frie
import com.alarmy.near.presentation.feature.friendprofileedittor.navigation.navigateToFriendProfileEditor
import com.alarmy.near.presentation.feature.home.navigation.RouteHome
import com.alarmy.near.presentation.feature.home.navigation.homeNavGraph
-import java.net.URLEncoder
-import java.nio.charset.StandardCharsets
import com.alarmy.near.presentation.feature.home.navigation.navigateToHome
import com.alarmy.near.presentation.feature.login.navigation.RouteLogin
import com.alarmy.near.presentation.feature.login.navigation.loginNavGraph
+import java.net.URLEncoder
+import java.nio.charset.StandardCharsets
@Composable
internal fun NearNavHost(
modifier: Modifier = Modifier,
navController: NavHostController,
+ isLoggedIn: Boolean = false,
onShowSnackbar: (Throwable?) -> Unit = { _ -> },
) {
val context = LocalContext.current
+
/*
* 화면 이동 및 구성을 위한 컴포저블 함수입니다.
+ * 로그인 상태에 따라 즉시 적절한 화면으로 시작합니다.
* */
NavHost(
modifier = modifier,
navController = navController,
- startDestination = RouteHome,
+ startDestination = if (isLoggedIn) RouteHome else RouteLogin,
) {
friendProfileNavGraph(onShowErrorSnackBar = onShowSnackbar, onClickBackButton = {
navController.popBackStack()
@@ -72,12 +76,14 @@ internal fun NearNavHost(
)
navController.popBackStack()
})
+
+
// 로그인 화면 NavGraph
loginNavGraph(
onShowErrorSnackBar = onShowSnackbar,
onNavigateToHome = {
navController.navigateToHome(
- navOptions = androidx.navigation.navOptions {
+ navOptions = navOptions {
popUpTo(RouteLogin) { inclusive = true }
}
)
@@ -94,5 +100,21 @@ internal fun NearNavHost(
onAlarmClick = {},
onAddContactClick = {},
)
+
+ // 친구 프로필 화면 NavGraph
+ friendProfileNavGraph(
+ onShowErrorSnackBar = onShowSnackbar,
+ onClickBackButton = {
+ navController.popBackStack()
+ }
+ )
+
+ // 친구 프로필 편집 화면 NavGraph
+ friendProfileEditorNavGraph(
+ onShowErrorSnackBar = onShowSnackbar,
+ onClickBackButton = {
+ navController.popBackStack()
+ }
+ )
}
}
diff --git a/Near/app/src/main/res/drawable-hdpi/img_bg.png b/Near/app/src/main/res/drawable-hdpi/img_bg.png
new file mode 100644
index 00000000..7ad84255
Binary files /dev/null and b/Near/app/src/main/res/drawable-hdpi/img_bg.png differ
diff --git a/Near/app/src/main/res/drawable/img_bg.png b/Near/app/src/main/res/drawable-mdpi/img_bg.png
similarity index 100%
rename from Near/app/src/main/res/drawable/img_bg.png
rename to Near/app/src/main/res/drawable-mdpi/img_bg.png
diff --git a/Near/app/src/main/res/drawable-xhdpi/img_bg.png b/Near/app/src/main/res/drawable-xhdpi/img_bg.png
new file mode 100644
index 00000000..eca43ad9
Binary files /dev/null and b/Near/app/src/main/res/drawable-xhdpi/img_bg.png differ
diff --git a/Near/app/src/main/res/drawable-xxhdpi/img_bg.png b/Near/app/src/main/res/drawable-xxhdpi/img_bg.png
new file mode 100644
index 00000000..bb6e965a
Binary files /dev/null and b/Near/app/src/main/res/drawable-xxhdpi/img_bg.png differ
diff --git a/Near/app/src/main/res/drawable-xxxhdpi/img_bg.png b/Near/app/src/main/res/drawable-xxxhdpi/img_bg.png
new file mode 100644
index 00000000..bc5e2345
Binary files /dev/null and b/Near/app/src/main/res/drawable-xxxhdpi/img_bg.png differ
diff --git a/Near/app/src/main/res/drawable/ic_launcher_foreground.xml b/Near/app/src/main/res/drawable/ic_launcher_foreground.xml
index 2b068d11..db210bef 100644
--- a/Near/app/src/main/res/drawable/ic_launcher_foreground.xml
+++ b/Near/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -1,30 +1,33 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+ android:width="100dp"
+ android:height="101dp"
+ android:viewportWidth="100"
+ android:viewportHeight="101">
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Near/app/src/main/res/drawable/ic_near_logo_title.xml b/Near/app/src/main/res/drawable/ic_near_logo_title_primary.xml
similarity index 100%
rename from Near/app/src/main/res/drawable/ic_near_logo_title.xml
rename to Near/app/src/main/res/drawable/ic_near_logo_title_primary.xml
diff --git a/Near/app/src/main/res/drawable/ic_near_logo_title_white.xml b/Near/app/src/main/res/drawable/ic_near_logo_title_white.xml
new file mode 100644
index 00000000..68cda581
--- /dev/null
+++ b/Near/app/src/main/res/drawable/ic_near_logo_title_white.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/Near/app/src/main/res/drawable/img_splash_logo.xml b/Near/app/src/main/res/drawable/img_splash_logo.xml
new file mode 100644
index 00000000..3ea2c402
--- /dev/null
+++ b/Near/app/src/main/res/drawable/img_splash_logo.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/Near/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Near/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
deleted file mode 100644
index 6f3b755b..00000000
--- a/Near/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Near/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Near/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index 6f3b755b..e61cccae 100644
--- a/Near/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/Near/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,6 +1,4 @@
-
-
-
-
\ No newline at end of file
+
+
diff --git a/Near/app/src/main/res/mipmap-hdpi/ic_launcher.png b/Near/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..f1fae059
Binary files /dev/null and b/Near/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/Near/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/Near/app/src/main/res/mipmap-hdpi/ic_launcher.webp
deleted file mode 100644
index c209e78e..00000000
Binary files a/Near/app/src/main/res/mipmap-hdpi/ic_launcher.webp and /dev/null differ
diff --git a/Near/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Near/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..cff35eaa
Binary files /dev/null and b/Near/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/Near/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/Near/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
deleted file mode 100644
index b2dfe3d1..00000000
Binary files a/Near/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/Near/app/src/main/res/mipmap-mdpi/ic_launcher.png b/Near/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..1d716579
Binary files /dev/null and b/Near/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/Near/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/Near/app/src/main/res/mipmap-mdpi/ic_launcher.webp
deleted file mode 100644
index 4f0f1d64..00000000
Binary files a/Near/app/src/main/res/mipmap-mdpi/ic_launcher.webp and /dev/null differ
diff --git a/Near/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Near/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..55dad60a
Binary files /dev/null and b/Near/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/Near/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/Near/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
deleted file mode 100644
index 62b611da..00000000
Binary files a/Near/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/Near/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/Near/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..4bdeb0d0
Binary files /dev/null and b/Near/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/Near/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/Near/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
deleted file mode 100644
index 948a3070..00000000
Binary files a/Near/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and /dev/null differ
diff --git a/Near/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Near/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..c57d22ed
Binary files /dev/null and b/Near/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/Near/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/Near/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
deleted file mode 100644
index 1b9a6956..00000000
Binary files a/Near/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..10430089
Binary files /dev/null and b/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
deleted file mode 100644
index 28d4b77f..00000000
Binary files a/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and /dev/null differ
diff --git a/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..afc978cf
Binary files /dev/null and b/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
deleted file mode 100644
index 9287f508..00000000
Binary files a/Near/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..b24a89ed
Binary files /dev/null and b/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
deleted file mode 100644
index aa7d6427..00000000
Binary files a/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and /dev/null differ
diff --git a/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..2010a26f
Binary files /dev/null and b/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
deleted file mode 100644
index 9126ae37..00000000
Binary files a/Near/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/Near/app/src/main/res/values/strings.xml b/Near/app/src/main/res/values/strings.xml
index 173ad5c1..8ec92e67 100644
--- a/Near/app/src/main/res/values/strings.xml
+++ b/Near/app/src/main/res/values/strings.xml
@@ -8,6 +8,9 @@
메뉴
네트워크 에러가 발생했습니다.
+
+ 스플래쉬 배경
+
Near 로고
Near 타이틀
diff --git a/Near/app/src/main/res/values/themes.xml b/Near/app/src/main/res/values/themes.xml
index dbbeb9df..abc32d05 100644
--- a/Near/app/src/main/res/values/themes.xml
+++ b/Near/app/src/main/res/values/themes.xml
@@ -1,5 +1,14 @@
+
-
\ No newline at end of file
+
+
+
+
diff --git a/Near/gradle/libs.versions.toml b/Near/gradle/libs.versions.toml
index d3aa3673..0c32d4ea 100644
--- a/Near/gradle/libs.versions.toml
+++ b/Near/gradle/libs.versions.toml
@@ -30,6 +30,8 @@ datastorePreferences = "1.1.7"
datastoreCore = "1.1.7"
#Kakao
v2All = "2.21.7"
+# Splash Screen
+splashScreen = "1.0.1"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -63,6 +65,7 @@ logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-intercep
retrofit-kotlin-serialization-converter = { group = "com.squareup.retrofit2", name = "converter-kotlinx-serialization", version.ref = "retrofitVersion" }
androidx-datastore-core = { group = "androidx.datastore", name = "datastore-core", version.ref = "datastoreCore" }
v2-all = { module = "com.kakao.sdk:v2-all", version.ref = "v2All" }
+androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "splashScreen" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }