diff --git a/feature/build.gradle.kts b/feature/build.gradle.kts index ecb21af29..7212299fd 100644 --- a/feature/build.gradle.kts +++ b/feature/build.gradle.kts @@ -91,6 +91,8 @@ dependencies { implementation(libs.ossLicense) implementation(libs.lottie) implementation(libs.process.phoenix) + implementation(libs.accompanist.systemuicontroller) + implementation (libs.androidx.core.splashscreen) // Compose Preview debugImplementation(libs.compose.ui.tooling) diff --git a/feature/src/main/java/com/terning/feature/home/home/HomeRoute.kt b/feature/src/main/java/com/terning/feature/home/home/HomeRoute.kt index fe79143b1..bbf615a28 100644 --- a/feature/src/main/java/com/terning/feature/home/home/HomeRoute.kt +++ b/feature/src/main/java/com/terning/feature/home/home/HomeRoute.kt @@ -19,6 +19,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState +import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf @@ -33,6 +34,7 @@ import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.flowWithLifecycle import androidx.navigation.NavHostController +import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.terning.core.designsystem.component.bottomsheet.SortingBottomSheet import com.terning.core.designsystem.component.button.SortingButton import com.terning.core.designsystem.component.item.InternItem @@ -40,6 +42,7 @@ import com.terning.core.designsystem.component.topappbar.LogoTopAppBar import com.terning.core.designsystem.theme.Black import com.terning.core.designsystem.theme.Grey150 import com.terning.core.designsystem.theme.Grey200 +import com.terning.core.designsystem.theme.TerningMain import com.terning.core.designsystem.theme.TerningTheme import com.terning.core.designsystem.theme.White import com.terning.core.extension.customShadow @@ -64,6 +67,17 @@ fun HomeRoute( navController: NavHostController, viewModel: HomeViewModel = hiltViewModel(), ) { + + val systemUiController = rememberSystemUiController() + SideEffect { + systemUiController.setStatusBarColor( + color = White + ) + systemUiController.setNavigationBarColor( + color = White + ) + } + val currentSortBy: MutableState = remember { mutableIntStateOf(0) } diff --git a/feature/src/main/java/com/terning/feature/main/MainNavigator.kt b/feature/src/main/java/com/terning/feature/main/MainNavigator.kt index 838030522..901d0fed0 100644 --- a/feature/src/main/java/com/terning/feature/main/MainNavigator.kt +++ b/feature/src/main/java/com/terning/feature/main/MainNavigator.kt @@ -11,9 +11,8 @@ import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions import com.terning.feature.calendar.calendar.navigation.navigateCalendar import com.terning.feature.home.home.navigation.navigateHome -import com.terning.feature.mypage.navigation.MyPage import com.terning.feature.mypage.navigation.navigateMyPage -import com.terning.feature.onboarding.signin.navigation.SignIn +import com.terning.feature.onboarding.splash.navigation.Splash import com.terning.feature.search.search.navigation.navigateSearch class MainNavigator( @@ -23,7 +22,7 @@ class MainNavigator( @Composable get() = navController .currentBackStackEntryAsState().value?.destination - val startDestination = SignIn + val startDestination = Splash val currentTab: MainTab? @Composable get() = MainTab.find { tab -> diff --git a/feature/src/main/java/com/terning/feature/main/MainScreen.kt b/feature/src/main/java/com/terning/feature/main/MainScreen.kt index 8ef53be83..474a6caa6 100644 --- a/feature/src/main/java/com/terning/feature/main/MainScreen.kt +++ b/feature/src/main/java/com/terning/feature/main/MainScreen.kt @@ -21,17 +21,18 @@ import com.terning.core.designsystem.theme.TerningMain import com.terning.core.designsystem.theme.White import com.terning.core.util.NoRippleInteractionSource import com.terning.feature.calendar.calendar.navigation.calendarNavGraph +import com.terning.feature.filtering.filtering.navigation.filteringOneNavGraph +import com.terning.feature.filtering.filtering.navigation.filteringThreeNavGraph +import com.terning.feature.filtering.filtering.navigation.filteringTwoNavGraph +import com.terning.feature.filtering.startfiltering.navigation.startFilteringNavGraph +import com.terning.feature.filtering.starthome.navigation.startHomeNavGraph import com.terning.feature.home.changefilter.navigation.changeFilterNavGraph import com.terning.feature.home.home.navigation.homeNavGraph import com.terning.feature.intern.navigation.internNavGraph import com.terning.feature.mypage.navigation.myPageNavGraph -import com.terning.feature.filtering.filtering.navigation.filteringOneNavGraph -import com.terning.feature.filtering.filtering.navigation.filteringThreeNavGraph -import com.terning.feature.filtering.filtering.navigation.filteringTwoNavGraph import com.terning.feature.onboarding.signin.navigation.signInNavGraph import com.terning.feature.onboarding.signup.navigation.signUpNavGraph -import com.terning.feature.filtering.startfiltering.navigation.startFilteringNavGraph -import com.terning.feature.filtering.starthome.navigation.startHomeNavGraph +import com.terning.feature.onboarding.splash.navigation.splashNavGraph import com.terning.feature.search.search.navigation.searchNavGraph import com.terning.feature.search.searchprocess.navigation.searchProcessNavGraph @@ -58,6 +59,7 @@ fun MainScreen( navController = navigator.navController, startDestination = navigator.startDestination ) { + splashNavGraph(navHostController = navigator.navController) homeNavGraph(navHostController = navigator.navController) calendarNavGraph(navHostController = navigator.navController) searchNavGraph(navHostController = navigator.navController) diff --git a/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt index 976646e72..608f44ab4 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt +++ b/feature/src/main/java/com/terning/feature/onboarding/signin/SignInRoute.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.SideEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -19,7 +20,10 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.flowWithLifecycle import androidx.navigation.NavHostController +import com.google.accompanist.systemuicontroller.rememberSystemUiController +import com.terning.core.designsystem.theme.TerningMain import com.terning.core.designsystem.theme.TerningPointTheme +import com.terning.core.designsystem.theme.White import com.terning.core.extension.toast import com.terning.feature.R import com.terning.feature.home.home.navigation.navigateHome @@ -31,6 +35,16 @@ fun SignInRoute( viewModel: SignInViewModel = hiltViewModel(), navController: NavHostController, ) { + + val systemUiController = rememberSystemUiController() + SideEffect { + systemUiController.setStatusBarColor( + color = White + ) + systemUiController.setNavigationBarColor( + color = White + ) + } val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current diff --git a/feature/src/main/java/com/terning/feature/onboarding/splash/SplashScreen.kt b/feature/src/main/java/com/terning/feature/onboarding/splash/SplashScreen.kt index e966d29c6..8d95835d5 100644 --- a/feature/src/main/java/com/terning/feature/onboarding/splash/SplashScreen.kt +++ b/feature/src/main/java/com/terning/feature/onboarding/splash/SplashScreen.kt @@ -1,8 +1,67 @@ package com.terning.feature.onboarding.splash +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.Modifier +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.LocalLifecycleOwner +import androidx.lifecycle.flowWithLifecycle +import androidx.navigation.NavController +import com.google.accompanist.systemuicontroller.rememberSystemUiController +import com.terning.core.designsystem.component.image.TerningImage +import com.terning.core.designsystem.theme.TerningMain +import com.terning.feature.R +import com.terning.feature.home.home.navigation.navigateHome +import com.terning.feature.onboarding.signin.navigation.navigateSignIn @Composable -fun SplashScreen(){ +fun SplashScreen( + navController: NavController, + viewModel: SplashViewModel = hiltViewModel(), + modifier: Modifier = Modifier +) { + val systemUiController = rememberSystemUiController() + SideEffect { + systemUiController.setStatusBarColor( + color = TerningMain + ) + systemUiController.setNavigationBarColor( + color = TerningMain + ) + } -} \ No newline at end of file + val lifecycleOwner = LocalLifecycleOwner.current + + LaunchedEffect(key1 = true) { + viewModel.showSplash(lifecycleOwner) + } + + LaunchedEffect(viewModel.sideEffects, lifecycleOwner) { + viewModel.sideEffects.flowWithLifecycle(lifecycle = lifecycleOwner.lifecycle) + .collect { sideEffect -> + when (sideEffect) { + is SplashState.GetHasAccessToken -> { + if (sideEffect.hasAccessToken) navController.navigateHome() + else navController.navigateSignIn() + } + + } + } + } + + Column( + modifier = modifier + .fillMaxSize() + .background(TerningMain), + ) { + TerningImage( + painter = R.drawable.ic_splash, + modifier = Modifier.fillMaxSize() + ) + } + +} diff --git a/feature/src/main/java/com/terning/feature/onboarding/splash/SplashState.kt b/feature/src/main/java/com/terning/feature/onboarding/splash/SplashState.kt new file mode 100644 index 000000000..1ace71e67 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/onboarding/splash/SplashState.kt @@ -0,0 +1,5 @@ +package com.terning.feature.onboarding.splash + +sealed class SplashState { + data class GetHasAccessToken(val hasAccessToken: Boolean) : SplashState() +} diff --git a/feature/src/main/java/com/terning/feature/onboarding/splash/SplashViewModel.kt b/feature/src/main/java/com/terning/feature/onboarding/splash/SplashViewModel.kt new file mode 100644 index 000000000..c58795db3 --- /dev/null +++ b/feature/src/main/java/com/terning/feature/onboarding/splash/SplashViewModel.kt @@ -0,0 +1,35 @@ +package com.terning.feature.onboarding.splash + +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ViewModel +import androidx.lifecycle.lifecycleScope +import com.terning.domain.repository.TokenRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class SplashViewModel @Inject constructor( + private val tokenRepository: TokenRepository, +) : ViewModel() { + + private val _sideEffects = MutableSharedFlow() + val sideEffects: SharedFlow get() = _sideEffects.asSharedFlow() + + private fun getHasAccessToken(): Boolean = tokenRepository.getAccessToken().isNotBlank() + + fun showSplash(lifecycleOwner: LifecycleOwner) { + lifecycleOwner.lifecycleScope.launch { + delay(DELAY_TIME) + _sideEffects.emit(SplashState.GetHasAccessToken(getHasAccessToken())) + } + } + + companion object { + private const val DELAY_TIME = 2200L + } +} \ No newline at end of file diff --git a/feature/src/main/java/com/terning/feature/onboarding/splash/navigation/SplashNavigation.kt b/feature/src/main/java/com/terning/feature/onboarding/splash/navigation/SplashNavigation.kt new file mode 100644 index 000000000..db5c6759c --- /dev/null +++ b/feature/src/main/java/com/terning/feature/onboarding/splash/navigation/SplashNavigation.kt @@ -0,0 +1,32 @@ +package com.terning.feature.onboarding.splash.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.NavOptions +import androidx.navigation.compose.composable +import androidx.navigation.toRoute +import com.terning.core.navigation.Route +import com.terning.feature.onboarding.signup.SignUpRoute +import com.terning.feature.onboarding.splash.SplashScreen +import kotlinx.serialization.Serializable + +fun NavController.navigateSplash(navOptions: NavOptions? = null) { + navigate( + route = Splash, + navOptions = navOptions + ) +} + +fun NavGraphBuilder.splashNavGraph( + navHostController: NavHostController +) { + composable { + SplashScreen( + navController = navHostController, + ) + } +} + +@Serializable +data object Splash: Route \ No newline at end of file diff --git a/feature/src/main/res/drawable/ic_splash.xml b/feature/src/main/res/drawable/ic_splash.xml new file mode 100644 index 000000000..1c83cab18 --- /dev/null +++ b/feature/src/main/res/drawable/ic_splash.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 28bd2834a..a0ee229ef 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -61,8 +61,10 @@ coil = "2.4.0" ## Security securityVersion = "1.1.0-alpha06" -## Lottie +## Splash lottieVersion = "6.0.0" +accompanistSystemuicontroller = "0.28.0" +coreSplashscreen = "1.0.1" # ui uiTooling = "1.6.8" @@ -88,6 +90,7 @@ processPhoenix = "2.0.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidxCore" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidxAppCompat" } +androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" } junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidxActivity" } @@ -163,6 +166,8 @@ lottie = {group = "com.airbnb.android", name = "lottie-compose", version.ref = " kakao-user = {group = "com.kakao.sdk", name = "v2-user", version.ref = "kakaoVersion"} process-phoenix = {group = "com.jakewharton", name = "process-phoenix", version.ref = "processPhoenix"} +accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanistSystemuicontroller" } + [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }