Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

double click 방지, 화면 전환 애니메이션 구현 #12

Merged
merged 13 commits into from
Aug 10, 2023
5 changes: 2 additions & 3 deletions app/src/main/java/com/jik/movie/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.core.view.WindowCompat
import com.jik.movie.splash.createSplashScreen
import com.jik.movie.splash.showSplashScreenWithDelay
import com.jik.movie.ui.MovieApp
import dagger.hilt.android.AndroidEntryPoint
import kotlin.time.Duration.Companion.seconds

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
createSplashScreen(delay = 1.2.seconds)
showSplashScreenWithDelay()

super.onCreate(savedInstanceState)

Expand Down
16 changes: 13 additions & 3 deletions app/src/main/java/com/jik/movie/navigation/MovieNavHost.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.jik.movie.navigation

import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import com.jik.feature.detail.navigation.DetailNavigation.installDetailScreen
import com.jik.feature.detail.navigation.DetailNavigation.navigateDetail
import com.jik.feature.home.navigation.HomeNavigation
import com.jik.feature.home.navigation.HomeNavigation.installHomeScreen
import com.jik.feature.popular.navigation.PopularNavigation.installPopularScreen
Expand All @@ -20,8 +23,15 @@ fun MovieNavHost(
startDestination = startDestination,
modifier = modifier
) {
installHomeScreen(navController)
installPopularScreen(navController)
installDetailScreen()
installHomeScreen(
onPosterClick = { movieId -> navController.navigateDetail(movieId) }
)
installPopularScreen(
onPosterClick = { movieId -> navController.navigateDetail(movieId) }
)
installDetailScreen(
enterTransition = slideInVertically { it },
exitTransition = slideOutVertically { it }
)
}
}
13 changes: 3 additions & 10 deletions app/src/main/java/com/jik/movie/navigation/TopLevelDestination.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.jik.movie.navigation

import androidx.compose.ui.graphics.vector.ImageVector
import com.jik.core.designsystem.icon.MovieIcons
import com.jik.core.ui.R
import com.jik.feature.home.navigation.HomeNavigation
import com.jik.feature.popular.navigation.PopularNavigation
import com.jik.feature.home.R as homeR
Expand All @@ -11,23 +10,17 @@ import com.jik.feature.popular.R as popularR

enum class TopLevelDestination(
val route: String,
val selectedIcon: ImageVector,
val unselectedIcon: ImageVector,
val icon: ImageVector,
val iconTextId: Int,
val titleTextId: Int,
) {
HOME(
route = HomeNavigation.route,
selectedIcon = MovieIcons.HomeRounded,
unselectedIcon = MovieIcons.HomeRounded,
icon = MovieIcons.HomeRounded,
iconTextId = homeR.string.home,
titleTextId = R.string.app_name
),
POPULAR(
route = PopularNavigation.route,
selectedIcon = MovieIcons.LocalFireDepartmentRounded,
unselectedIcon = MovieIcons.LocalFireDepartmentRounded,
icon = MovieIcons.LocalFireDepartmentRounded,
iconTextId = popularR.string.popular,
titleTextId = popularR.string.popular
)
}
19 changes: 13 additions & 6 deletions app/src/main/java/com/jik/movie/splash/SplashScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@ package com.jik.movie.splash

import android.app.Activity
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.launch
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

fun Activity.showSplashScreenWithDelay(delay: Duration = 1.2.seconds) {
var splashOut = true

CoroutineScope(Dispatchers.Main).launch {
delay(delay)
splashOut = false
}

fun Activity.createSplashScreen(delay: Duration) {
installSplashScreen().setKeepOnScreenCondition {
runBlocking {
delay(duration = delay)
}
false
splashOut
}
}
70 changes: 40 additions & 30 deletions app/src/main/java/com/jik/movie/ui/MovieApp.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.jik.movie.ui

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
Expand All @@ -10,26 +13,24 @@ import com.jik.core.designsystem.component.MovieNavigationBar
import com.jik.core.designsystem.component.MovieNavigationBarItem
import com.jik.core.designsystem.component.NavigationBarCornerSize
import com.jik.core.designsystem.theme.MovieTheme
import com.jik.core.ui.util.modifier.conditional
import com.jik.movie.navigation.MovieNavHost
import com.jik.movie.navigation.TopLevelDestination

@Composable
fun MovieApp() {
MovieTheme(
dynamicColor = false
) {
MovieTheme {
val appState = rememberMovieAppState()
val destination = appState.currentTopLevelDestination

Scaffold(
bottomBar = {
if (destination != null) {
MovieBottomBar(
topLevelDestination = appState.topLevelDestinations,
currentDestination = destination,
onNavigateToDestination = appState::navigateToDestination,
)
}
MovieBottomBar(
visible = destination != null,
topLevelDestination = appState.topLevelDestinations,
currentDestination = destination,
onNavigateToDestination = appState::navigateToDestination,
)
},
contentWindowInsets = WindowInsets(0.dp)
) {
Expand All @@ -38,36 +39,45 @@ fun MovieApp() {

MovieNavHost(
navController = appState.navController,
modifier = Modifier.padding(
top = topPadding,
bottom = if (destination != null && bottomPadding > 0.dp) bottomPadding - NavigationBarCornerSize
else bottomPadding
)
modifier = Modifier.conditional(destination != null) {
padding(
top = topPadding,
bottom = if (destination != null && bottomPadding > 0.dp) bottomPadding - NavigationBarCornerSize
else bottomPadding
)
}
)
}
}
}

@Composable
fun MovieBottomBar(
visible: Boolean,
topLevelDestination: List<TopLevelDestination>,
currentDestination: TopLevelDestination,
currentDestination: TopLevelDestination?,
modifier: Modifier = Modifier,
onNavigateToDestination: (TopLevelDestination) -> Unit,
) {
MovieNavigationBar(
modifier = modifier,
content = {
topLevelDestination.forEach { destination ->
val selected = destination.route == currentDestination.route
MovieNavigationBarItem(
selected = selected,
onClick = { onNavigateToDestination(destination) },
iconImageVector = destination.selectedIcon,
selectedIconImageVector = destination.selectedIcon,
labelTextId = destination.iconTextId,
)
AnimatedVisibility(
visible = visible,
enter = slideInVertically { it },
exit = slideOutVertically { it }
) {
MovieNavigationBar(
modifier = modifier,
content = {
topLevelDestination.forEach { destination ->
val selected = destination.route == currentDestination?.route
MovieNavigationBarItem(
selected = selected,
onClick = { onNavigateToDestination(destination) },
iconImageVector = destination.icon,
selectedIconImageVector = destination.icon,
labelTextId = destination.iconTextId,
)
}
}
}
)
)
}
}
6 changes: 0 additions & 6 deletions app/src/main/java/com/jik/movie/ui/MovieAppState.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.jik.movie.ui

import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
Expand Down Expand Up @@ -33,10 +31,6 @@ class MovieAppState(
val navController: NavHostController,
) {

@OptIn(ExperimentalMaterial3Api::class)
val topAppBarScrollBehavior
@Composable get() = TopAppBarDefaults.enterAlwaysScrollBehavior()

private val currentDestination: NavDestination?
@Composable get() = navController.currentBackStackEntryAsState().value?.destination

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.jik.core.designsystem.component

import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
Expand All @@ -24,6 +23,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import com.jik.core.designsystem.theme.MovieTheme
import com.jik.core.ui.util.modifier.clickableSingle

@Composable
fun PosterCard(
Expand All @@ -47,7 +47,7 @@ fun PosterCard(
contentDescription = contentDescription,
modifier = Modifier
.fillMaxSize()
.clickable(enabled = clickable) { onClick() },
.clickableSingle(enabled = clickable) { onClick() },
placeholder = placeholder,
alignment = alignment,
contentScale = contentScale
Expand Down Expand Up @@ -79,7 +79,7 @@ fun GradientPosterCard(
contentDescription = contentDescription,
modifier = Modifier
.fillMaxSize()
.clickable(enabled = clickable) { onClick() },
.clickableSingle(enabled = clickable) { onClick() },
placeholder = placeholder,
alignment = alignment,
contentScale = contentScale
Expand Down Expand Up @@ -128,9 +128,7 @@ enum class GradientArea {
@Preview
@Composable
fun PosterCardPreview() {
MovieTheme(
dynamicColor = false
) {
MovieTheme {
val context = LocalContext.current
PosterCard(
posterPath = "https://image.tmdb.org/t/p/w500/qNBAXBIQlnOThrVvA6mA2B5ggV6.jpg",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,18 @@ fun RowScope.MovieNavigationBarItem(
}
}

@Composable
private fun MovieNavigationBarItemIcon(
selected: Boolean,
iconImageVector: ImageVector,
selectedIconImageVector: ImageVector,
) {
Icon(
imageVector = if (selected) selectedIconImageVector else iconImageVector,
tint = if (selected) selectedIconColor() else unselectedIconColor(),
contentDescription = null
)
}

@Composable
private fun MovieNavigationBarItemLabelAndIcon(
Expand Down Expand Up @@ -128,19 +140,6 @@ private fun MovieNavigationBarItemLabelAndIcon(
}
}

@Composable
private fun MovieNavigationBarItemIcon(
selected: Boolean,
iconImageVector: ImageVector,
selectedIconImageVector: ImageVector,
) {
Icon(
imageVector = if (selected) selectedIconImageVector else iconImageVector,
tint = if (selected) selectedIconColor() else unselectedIconColor(),
contentDescription = null
)
}

private object MovieNavigationBarItemDefaults {
@Composable
fun selectedIconColor() = MaterialTheme.colorScheme.onSurface
Expand Down
Loading