package com.aiosman.ravenow.ui import ChangePasswordScreen import ImageViewer import ModificationListScreen import androidx.compose.animation.ExperimentalSharedTransitionApi import androidx.compose.animation.SharedTransitionLayout import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument import com.aiosman.ravenow.LocalAnimatedContentScope import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.LocalSharedTransitionScope import com.aiosman.ravenow.ui.about.AboutScreen import com.aiosman.ravenow.ui.account.AccountEditScreen2 import com.aiosman.ravenow.ui.account.AccountSetting import com.aiosman.ravenow.ui.account.ResetPasswordScreen import com.aiosman.ravenow.ui.agent.AddAgentScreen import com.aiosman.ravenow.ui.group.CreateGroupChatScreen import com.aiosman.ravenow.ui.chat.ChatAiScreen import com.aiosman.ravenow.ui.chat.ChatScreen import com.aiosman.ravenow.ui.comment.CommentsScreen import com.aiosman.ravenow.ui.comment.notice.CommentNoticeScreen import com.aiosman.ravenow.ui.crop.ImageCropScreen import com.aiosman.ravenow.ui.favourite.FavouriteListPage import com.aiosman.ravenow.ui.favourite.FavouriteNoticeScreen import com.aiosman.ravenow.ui.follower.FollowerListScreen import com.aiosman.ravenow.ui.follower.FollowerNoticeScreen import com.aiosman.ravenow.ui.follower.FollowingListScreen import com.aiosman.ravenow.ui.gallery.OfficialGalleryScreen import com.aiosman.ravenow.ui.gallery.OfficialPhotographerScreen import com.aiosman.ravenow.ui.gallery.ProfileTimelineScreen import com.aiosman.ravenow.ui.index.IndexScreen import com.aiosman.ravenow.ui.index.tabs.message.NotificationsScreen import com.aiosman.ravenow.ui.index.tabs.search.SearchScreen import com.aiosman.ravenow.ui.like.LikeNoticeScreen import com.aiosman.ravenow.ui.location.LocationDetailScreen import com.aiosman.ravenow.ui.login.EmailSignupScreen import com.aiosman.ravenow.ui.login.LoginPage import com.aiosman.ravenow.ui.login.SignupScreen import com.aiosman.ravenow.ui.login.UserAuthScreen import com.aiosman.ravenow.ui.modification.EditModificationScreen import com.aiosman.ravenow.ui.post.NewPostImageGridScreen import com.aiosman.ravenow.ui.post.NewPostScreen import com.aiosman.ravenow.ui.post.PostScreen import com.aiosman.ravenow.ui.profile.AccountProfileV2 sealed class NavigationRoute( val route: String, ) { data object Index : NavigationRoute("Index") data object ProfileTimeline : NavigationRoute("ProfileTimeline") data object LocationDetail : NavigationRoute("LocationDetail/{x}/{y}") data object OfficialPhoto : NavigationRoute("OfficialPhoto") data object OfficialPhotographer : NavigationRoute("OfficialPhotographer") data object Post : NavigationRoute("Post/{id}/{highlightCommentId}/{initImagePagerIndex}") data object ModificationList : NavigationRoute("ModificationList") data object MyMessage : NavigationRoute("MyMessage") data object Comments : NavigationRoute("Comments") data object Likes : NavigationRoute("Likes") data object Followers : NavigationRoute("Followers") data object NewPost : NavigationRoute("NewPost") data object EditModification : NavigationRoute("EditModification") data object Login : NavigationRoute("Login") data object AccountProfile : NavigationRoute("AccountProfile/{id}") data object SignUp : NavigationRoute("SignUp") data object UserAuth : NavigationRoute("UserAuth") data object EmailSignUp : NavigationRoute("EmailSignUp") data object AccountEdit : NavigationRoute("AccountEditScreen") data object ImageViewer : NavigationRoute("ImageViewer") data object ChangePasswordScreen : NavigationRoute("ChangePasswordScreen") data object FavouritesScreen : NavigationRoute("FavouritesScreen") data object NewPostImageGrid : NavigationRoute("NewPostImageGrid") data object Search : NavigationRoute("Search") data object FollowerList : NavigationRoute("FollowerList/{id}") data object FollowingList : NavigationRoute("FollowingList/{id}") data object ResetPassword : NavigationRoute("ResetPassword") data object FavouriteList : NavigationRoute("FavouriteList") data object Chat : NavigationRoute("Chat/{id}") data object ChatAi : NavigationRoute("ChatAi/{id}") data object CommentNoticeScreen : NavigationRoute("CommentNoticeScreen") data object ImageCrop : NavigationRoute("ImageCrop") data object AccountSetting : NavigationRoute("AccountSetting") data object AboutScreen : NavigationRoute("AboutScreen") data object AddAgent : NavigationRoute("AddAgent") data object CreateGroupChat : NavigationRoute("CreateGroupChat") } @Composable fun NavigationController( navController: NavHostController, startDestination: String = NavigationRoute.Login.route ) { val navigationBarHeight = with(LocalDensity.current) { WindowInsets.navigationBars.getBottom(this).toDp() } NavHost( navController = navController, startDestination = startDestination, ) { composable(route = NavigationRoute.Index.route) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { IndexScreen() } } composable(route = NavigationRoute.ProfileTimeline.route) { ProfileTimelineScreen() } composable( route = NavigationRoute.LocationDetail.route, arguments = listOf( navArgument("x") { type = NavType.FloatType }, navArgument("y") { type = NavType.FloatType } ) ) { Box( modifier = Modifier.padding(bottom = navigationBarHeight) ) { val x = it.arguments?.getFloat("x") ?: 0f val y = it.arguments?.getFloat("y") ?: 0f LocationDetailScreen( x, y ) } } composable(route = NavigationRoute.OfficialPhoto.route) { OfficialGalleryScreen() } composable(route = NavigationRoute.OfficialPhotographer.route) { OfficialPhotographerScreen() } composable( route = NavigationRoute.Post.route, arguments = listOf( navArgument("id") { type = NavType.StringType }, navArgument("highlightCommentId") { type = NavType.IntType }, navArgument("initImagePagerIndex") { type = NavType.IntType } ), enterTransition = { fadeIn(animationSpec = tween(durationMillis = 200)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 200)) }, popEnterTransition = { fadeIn(animationSpec = tween(durationMillis = 200)) }, popExitTransition = { fadeOut(animationSpec = tween(durationMillis = 200)) } ) { backStackEntry -> val id = backStackEntry.arguments?.getString("id") val highlightCommentId = backStackEntry.arguments?.getInt("highlightCommentId")?.let { if (it == 0) null else it } val initIndex = backStackEntry.arguments?.getInt("initImagePagerIndex") PostScreen( id!!, highlightCommentId, initImagePagerIndex = initIndex ) } composable(route = NavigationRoute.ModificationList.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { ModificationListScreen() } composable(route = NavigationRoute.MyMessage.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { NotificationsScreen() } composable(route = NavigationRoute.Comments.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { CommentsScreen() } composable(route = NavigationRoute.Likes.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { LikeNoticeScreen() } composable(route = NavigationRoute.Followers.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { FollowerNoticeScreen() } composable( route = NavigationRoute.NewPost.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { NewPostScreen() } composable(route = NavigationRoute.EditModification.route) { Box( modifier = Modifier.padding(top = 64.dp) ) { EditModificationScreen() } } composable(route = NavigationRoute.Login.route) { LoginPage() } composable( route = NavigationRoute.AccountProfile.route, arguments = listOf(navArgument("id") { type = NavType.StringType }) ) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { AccountProfileV2(it.arguments?.getString("id")!!) } } composable( route = NavigationRoute.SignUp.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { SignupScreen() } composable( route = NavigationRoute.UserAuth.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { UserAuthScreen() } composable( route = NavigationRoute.EmailSignUp.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { EmailSignupScreen() } composable( route = NavigationRoute.AccountEdit.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { AccountEditScreen2() } composable(route = NavigationRoute.ImageViewer.route) { ImageViewer() } composable(route = NavigationRoute.ChangePasswordScreen.route) { ChangePasswordScreen() } composable(route = NavigationRoute.FavouritesScreen.route) { FavouriteNoticeScreen() } composable(route = NavigationRoute.NewPostImageGrid.route) { NewPostImageGridScreen() } composable(route = NavigationRoute.Search.route) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { SearchScreen() } } composable( route = NavigationRoute.FollowerList.route, arguments = listOf(navArgument("id") { type = NavType.IntType }) ) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { FollowerListScreen(it.arguments?.getInt("id")!!) } } composable( route = NavigationRoute.FollowingList.route, arguments = listOf(navArgument("id") { type = NavType.IntType }) ) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { FollowingListScreen(it.arguments?.getInt("id")!!) } } composable(route = NavigationRoute.ResetPassword.route) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { ResetPasswordScreen() } } composable(route = NavigationRoute.FavouriteList.route) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { FavouriteListPage() } } composable( route = NavigationRoute.Chat.route, arguments = listOf(navArgument("id") { type = NavType.StringType }) ) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { ChatScreen(it.arguments?.getString("id")!!) } } composable( route = NavigationRoute.ChatAi.route, arguments = listOf(navArgument("id") { type = NavType.StringType }) ) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { ChatAiScreen(it.arguments?.getString("id")!!) } } composable(route = NavigationRoute.CommentNoticeScreen.route) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { CommentNoticeScreen() } } composable(route = NavigationRoute.ImageCrop.route) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { ImageCropScreen() } } composable(route = NavigationRoute.AccountSetting.route) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { AccountSetting() } } composable(route = NavigationRoute.AboutScreen.route) { CompositionLocalProvider( LocalAnimatedContentScope provides this, ) { AboutScreen() } } composable( route = NavigationRoute.AddAgent.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { AddAgentScreen() } composable( route = NavigationRoute.CreateGroupChat.route, enterTransition = { fadeIn(animationSpec = tween(durationMillis = 0)) }, exitTransition = { fadeOut(animationSpec = tween(durationMillis = 0)) } ) { CreateGroupChatScreen() } } } @OptIn(ExperimentalSharedTransitionApi::class) @Composable fun Navigation( startDestination: String = NavigationRoute.Login.route, onLaunch: (navController: NavHostController) -> Unit ) { val navController = rememberNavController() LaunchedEffect(Unit) { onLaunch(navController) } SharedTransitionLayout { CompositionLocalProvider( LocalNavController provides navController, LocalSharedTransitionScope provides this@SharedTransitionLayout, ) { Box { NavigationController( navController = navController, startDestination = startDestination ) } } } } fun NavHostController.navigateToPost( id: Int, highlightCommentId: Int? = 0, initImagePagerIndex: Int? = 0 ) { navigate( route = NavigationRoute.Post.route .replace("{id}", id.toString()) .replace("{highlightCommentId}", highlightCommentId.toString()) .replace("{initImagePagerIndex}", initImagePagerIndex.toString()) ) } fun NavHostController.navigateToChat(id: String) { navigate( route = NavigationRoute.Chat.route .replace("{id}", id) ) } fun NavHostController.navigateToChatAi(id: String) { navigate( route = NavigationRoute.ChatAi.route .replace("{id}", id) ) } fun NavHostController.goTo( route: NavigationRoute ) { navigate(route.route) }