package com.suno.android.ui.screens.root import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavOptions import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.toRoute import com.google.firebase.analytics.FirebaseAnalytics import com.suno.android.common_analytics.managers.AnalyticsManager import com.suno.android.common_ui.animations.NavigationFadeInAnimation import com.suno.android.common_ui.animations.NavigationFadeOutAnimation import com.suno.android.common_ui.effects.DialogEffect import com.suno.android.common_ui.theme.SunoTheme import com.suno.android.ui.screens.navigation.NavDestination import com.suno.android.ui.screens.navigation.NavDestination.SplashScreenDestination import com.suno.android.ui.screens.root.logged_in.LoggedInNavGraph import com.suno.android.ui.screens.root.logged_out.LoggedOutNavGraph import com.suno.android.ui.screens.splash.SplashScreen import kotlinx.coroutines.flow.distinctUntilChanged @Composable fun RootNavGraph( rootNavGraphVM: RootNavGraphVM = hiltViewModel(), onReadyToLoadBraze: () -> Unit, analyticsManager: AnalyticsManager, ) { val rootNavHostController = rememberNavController() val viewState by rootNavGraphVM.viewStateFlow().collectAsState() SunoTheme(themeMode = viewState.themeMode) { LaunchedEffect(rootNavHostController) { rootNavHostController.addOnDestinationChangedListener { controller, destination, arguments -> rootNavGraphVM.trackScreen( screenName = destination.route, ) } } DialogEffect(rootNavGraphVM.errorDialogFlow) LaunchedEffect(Unit) { rootNavGraphVM.effectFlow().distinctUntilChanged() // hacky fix to dedupe multiple events .collect { rootEffect -> when (rootEffect) { RootNavGraphVM.RootEffects.OnRouteToOnboarding -> { rootNavHostController.navigate( route = NavDestination.LoggedInNav.LoggedInNavGraphDestination( isOnboarding = true, ), navOptions = NavOptions.Builder() .setLaunchSingleTop(true) .setPopUpTo( destinationId = 0, inclusive = true, ) .build(), ) } is RootNavGraphVM.RootEffects.OnOauthDeeplinkSuccess -> { if (rootEffect.isOnboarding) { // new account created, log signup event analyticsManager.trackFirebaseEvent( FirebaseAnalytics.Event.SIGN_UP, null, ) } rootNavGraphVM.setFlagForOnboarding( isOnboarding = rootEffect.isOnboarding, ) } RootNavGraphVM.RootEffects.OnOauthDeeplinkFailure -> { // todo: what happens here tomdroid? } RootNavGraphVM.RootEffects.OnAppConfigurationLoadSuccess -> { } RootNavGraphVM.RootEffects.OnAppConfigurationLoadFailure -> { // todo: handle possible retry logic??? what should we do? } RootNavGraphVM.RootEffects.OnReadyToLoadBraze -> { onReadyToLoadBraze.invoke() } RootNavGraphVM.RootEffects.OnAuthenticationFailure -> { rootNavGraphVM.setAuthLoading(false) rootNavHostController.navigate( route = NavDestination.LoggedOutNav.LoggedOutNavGraphDestination, navOptions = NavOptions.Builder() .setLaunchSingleTop(true) .setPopUpTo( destinationId = 0, inclusive = true, ) .build(), ) } RootNavGraphVM.RootEffects.OnAuthenticationSuccess -> { rootNavGraphVM.loadAuthenticatedConfiguration() } RootNavGraphVM.RootEffects.OnAuthenticatedConfigurationLoaded -> { rootNavGraphVM.checkIfOnboarding() } RootNavGraphVM.RootEffects.OnRouteToHome -> { rootNavGraphVM.setAuthLoading(false) rootNavHostController.navigate( route = NavDestination.LoggedInNav.LoggedInNavGraphDestination( isOnboarding = false, ), navOptions = NavOptions.Builder() .setLaunchSingleTop(true) .setPopUpTo( destinationId = 0, inclusive = true, ) .build(), ) } } } } Box { NavHost( modifier = Modifier.fillMaxSize(), navController = rootNavHostController, startDestination = SplashScreenDestination, enterTransition = { NavigationFadeInAnimation }, exitTransition = { NavigationFadeOutAnimation }, ) { composable { SplashScreen( vm = hiltViewModel(), onAppConfigurationLoaded = { successfulLoad -> rootNavGraphVM.onAppConfigLoaded( isSuccessfulLoad = successfulLoad, ) }, ) } composable { LoggedOutNavGraph( authLoading = viewState.authLoading, setAuthLoading = { rootNavGraphVM.setAuthLoading(true) }, onRedirectToOnboarding = { rootNavGraphVM.setFlagForOnboarding( isOnboarding = true, ) }, onRedirectToHome = { rootNavGraphVM.setFlagForOnboarding( isOnboarding = false, ) }, ) } composable { route -> val isOnboarding = route.toRoute().isOnboarding LoggedInNavGraph( isOnboarding = isOnboarding, ) } } } rootNavGraphVM.tweaksEntryPoint.TweaksBottomSheet() } }