Skip to content
This repository has been archived by the owner on Aug 7, 2024. It is now read-only.

Commit

Permalink
feat: support for predictive back animation
Browse files Browse the repository at this point in the history
  • Loading branch information
SuhasDissa committed May 3, 2024
1 parent 01689f9 commit 5799953
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 21 deletions.
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.VibeYou"
android:enableOnBackInvokedCallback="true"
tools:targetApi="31">
<activity
android:name=".MainActivity"
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/app/suhasdissa/vibeyou/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class MainActivity : ComponentActivity() {
val drawerState = rememberDrawerState(DrawerValue.Closed)
val scope = rememberCoroutineScope()
var currentDestination by remember {
mutableStateOf<Destination>(Destination.PipedMusic)
mutableStateOf<Destination>(Destination.Home)
}
ModalNavigationDrawer(
drawerState = drawerState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import kotlinx.serialization.Serializable
@Serializable
sealed class Destination {
@Serializable
object PipedMusic : Destination()
object Home : Destination()

@Serializable
object LocalMusic : Destination()
Expand Down
194 changes: 180 additions & 14 deletions app/src/main/java/app/suhasdissa/vibeyou/navigation/NavHost.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package app.suhasdissa.vibeyou.navigation

import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
Expand Down Expand Up @@ -36,17 +42,39 @@ fun AppNavHost(navHostController: NavHostController) {
val settingsModel: SettingsModel = viewModel(factory = SettingsModel.Factory)
NavHost(
navController = navHostController,
startDestination = Destination.PipedMusic
startDestination = Destination.Home
) {
composable<Destination.PipedMusic> {
composable<Destination.Home>(
enterTransition = {
scaleIn(initialScale = 3f / 4) + fadeIn()
},
exitTransition = {
if (listOf(Destination.OnlineSearch::class, Destination.LocalSearch::class)
.any { targetState.destination.hasRoute(it) }
) {
fadeOut()
} else {
scaleOut(targetScale = 0f) + fadeOut()
}
}
) {
CompositionLocalProvider(LocalViewModelStoreOwner provides viewModelStoreOwner) {
HomeScreen(onNavigate = { destination ->
navHostController.navigate(destination)
})
}
}

composable<Destination.OnlineSearch> {
composable<Destination.OnlineSearch>(
enterTransition = {
fadeIn()
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Down,
targetOffset = { it }) + fadeOut()
}
) {
val pipedSearchViewModel: PipedSearchViewModel =
viewModel(factory = PipedSearchViewModel.Factory)
CompositionLocalProvider(LocalViewModelStoreOwner provides viewModelStoreOwner) {
Expand All @@ -55,7 +83,16 @@ fun AppNavHost(navHostController: NavHostController) {
}, pipedSearchViewModel)
}
}
composable<Destination.LocalSearch> {
composable<Destination.LocalSearch>(
enterTransition = {
fadeIn()
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Down,
targetOffset = { it }) + fadeOut()
}
) {
val localSearchViewModel: LocalSearchViewModel =
viewModel(factory = LocalSearchViewModel.Factory)
CompositionLocalProvider(LocalViewModelStoreOwner provides viewModelStoreOwner) {
Expand All @@ -65,30 +102,119 @@ fun AppNavHost(navHostController: NavHostController) {
}
}

composable<Destination.Settings> {
composable<Destination.Settings>(
enterTransition = {
if (listOf(
Destination.About::class,
Destination.NetworkSettings::class,
Destination.DatabaseSettings::class,
Destination.AppearanceSettings::class
)
.any { initialState.destination.hasRoute(it) }
) {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Right,
initialOffset = { it }) + fadeIn()
} else {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Up,
initialOffset = { it / 4 }) + scaleIn(initialScale = 3f / 4) + fadeIn()
}
},
exitTransition = {
if (listOf(
Destination.About::class,
Destination.NetworkSettings::class,
Destination.DatabaseSettings::class,
Destination.AppearanceSettings::class
)
.any { targetState.destination.hasRoute(it) }
) {
slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Left,
targetOffset = { it / 4 }) + fadeOut()
} else {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Down,
targetOffset = { it / 4 }) + scaleOut(targetScale = 3f / 4) + fadeOut()
}
}) {
SettingsScreen(onNavigate = { route ->
navHostController.navigate(route)
})
}

composable<Destination.About> {
composable<Destination.About>(
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
initialOffset = { it }) + fadeIn()
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Right,
targetOffset = { it }) + fadeOut()
}
) {
AboutScreen()
}

composable<Destination.NetworkSettings> {
composable<Destination.NetworkSettings>(
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
initialOffset = { it }) + fadeIn()
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Right,
targetOffset = { it }) + fadeOut()
}
) {
NetworkSettingsScreen()
}

composable<Destination.DatabaseSettings> {
composable<Destination.DatabaseSettings>(
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
initialOffset = { it }) + fadeIn()
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Right,
targetOffset = { it }) + fadeOut()
}
) {
DatabaseSettingsScreen()
}

composable<Destination.AppearanceSettings> {
composable<Destination.AppearanceSettings>(
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Left,
initialOffset = { it }) + fadeIn()
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Right,
targetOffset = { it }) + fadeOut()
}
) {
AppearanceSettingsScreen(settingsModel)
}

composable<Destination.Playlists>(
typeMap = mapOf(typeOf<Album>() to AlbumType)
typeMap = mapOf(typeOf<Album>() to AlbumType),
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Up,
initialOffset = { it / 4 }) + scaleIn(initialScale = 3f / 4) + fadeIn()
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Down,
targetOffset = { it / 4 }) + scaleOut(targetScale = 3f / 4) + fadeOut()
}
) {
val onlinePlaylistViewModel: OnlinePlaylistViewModel =
viewModel(factory = OnlinePlaylistViewModel.Factory)
Expand All @@ -98,7 +224,17 @@ fun AppNavHost(navHostController: NavHostController) {
}

composable<Destination.LocalPlaylists>(
typeMap = mapOf(typeOf<Album>() to AlbumType)
typeMap = mapOf(typeOf<Album>() to AlbumType),
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Up,
initialOffset = { it / 4 }) + scaleIn(initialScale = 3f / 4) + fadeIn()
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Down,
targetOffset = { it / 4 }) + scaleOut(targetScale = 3f / 4) + fadeOut()
}
) {
val localPlaylistViewModel: LocalPlaylistViewModel =
viewModel(factory = LocalPlaylistViewModel.Factory)
Expand All @@ -108,7 +244,17 @@ fun AppNavHost(navHostController: NavHostController) {
}

composable<Destination.SavedPlaylists>(
typeMap = mapOf(typeOf<Album>() to AlbumType)
typeMap = mapOf(typeOf<Album>() to AlbumType),
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Up,
initialOffset = { it / 4 }) + scaleIn(initialScale = 3f / 4) + fadeIn()
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Down,
targetOffset = { it / 4 }) + scaleOut(targetScale = 3f / 4) + fadeOut()
}
) {
val playlistInfoViewModel: PlaylistInfoViewModel =
viewModel(factory = PlaylistInfoViewModel.Factory)
Expand All @@ -118,7 +264,17 @@ fun AppNavHost(navHostController: NavHostController) {
}

composable<Destination.OnlineArtist>(
typeMap = mapOf(typeOf<Artist>() to ArtistType)
typeMap = mapOf(typeOf<Artist>() to ArtistType),
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Up,
initialOffset = { it / 4 }) + scaleIn(initialScale = 3f / 4) + fadeIn()
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Down,
targetOffset = { it / 4 }) + scaleOut(targetScale = 3f / 4) + fadeOut()
}
) {
val onlineArtistViewModel: OnlineArtistViewModel =
viewModel(factory = OnlineArtistViewModel.Factory)
Expand All @@ -130,7 +286,17 @@ fun AppNavHost(navHostController: NavHostController) {
}

composable<Destination.LocalArtist>(
typeMap = mapOf(typeOf<Artist>() to ArtistType)
typeMap = mapOf(typeOf<Artist>() to ArtistType),
enterTransition = {
slideIntoContainer(
AnimatedContentTransitionScope.SlideDirection.Up,
initialOffset = { it / 4 }) + scaleIn(initialScale = 3f / 4) + fadeIn()
},
exitTransition = {
slideOutOfContainer(
AnimatedContentTransitionScope.SlideDirection.Down,
targetOffset = { it / 4 }) + scaleOut(targetScale = 3f / 4) + fadeOut()
}
) {
val localArtistViewModel: LocalArtistViewModel =
viewModel(factory = LocalArtistViewModel.Factory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ fun NavDrawerContent(
)
},
label = { Text(text = stringResource(id = R.string.piped_music)) },
selected = currentDestination == Destination.PipedMusic,
selected = currentDestination == Destination.Home,
onClick = {
view.playSoundEffect(SoundEffectConstants.CLICK)
onDestinationSelected(Destination.PipedMusic)
onDestinationSelected(Destination.Home)
}
)
Spacer(Modifier.height(16.dp))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ fun HomeScreen(
.padding(end = 8.dp)
.clickable {
view.playSoundEffect(SoundEffectConstants.CLICK)
if (currentDestination == Destination.PipedMusic) {
if (currentDestination == Destination.Home) {
onNavigate(Destination.OnlineSearch)
} else {
onNavigate(Destination.LocalSearch)
Expand Down Expand Up @@ -144,11 +144,11 @@ fun HomeScreen(
enterTransition = { EnterTransition.None },
exitTransition = { ExitTransition.None }
) {
composable<Destination.PipedMusic> {
composable<Destination.Home> {
CompositionLocalProvider(LocalViewModelStoreOwner provides viewModelStoreOwner) {
MusicScreen(onNavigate)
LaunchedEffect(Unit) {
currentDestination = Destination.PipedMusic
currentDestination = Destination.Home
}
}
}
Expand Down

0 comments on commit 5799953

Please sign in to comment.