Files
forkmessager/client-mobile/navigation/AppNavigation.kt
2026-04-14 01:41:51 +03:00

211 lines
9.3 KiB
Kotlin

package navigation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import auth.presentation.LoginScreen
import auth.presentation.RegisterScreen
import auth.presentation.AuthViewModel
import core.presentation.settings.SettingsScreen
import core.presentation.settings.SettingsViewModel
import chats.presentation.chat_list.ChatListScreen
import chats.presentation.chat_list.ChatListViewModel
import chats.presentation.chat_detail.ChatDetailScreen
import chats.presentation.chat_detail.ChatDetailViewModel
import contacts.presentation.ContactListScreen
import contacts.presentation.ContactListViewModel
import core.presentation.components.GlassNavigationBar
import profiles.presentation.ProfileScreen
import profiles.presentation.EditProfileScreen
import profiles.presentation.viewmodel.ProfileViewModel
import stories.presentation.StoryViewModel
sealed class Screen(val route: String) {
object Login : Screen("login")
object Register : Screen("register")
object ChatList : Screen("chat_list")
object ChatDetail : Screen("chat_detail/{chatId}/{chatName}") {
fun createRoute(chatId: String, chatName: String) = "chat_detail/$chatId/$chatName"
}
object Profile : Screen("profile?profileId={profileId}") {
fun createRoute(profileId: String? = null) = if (profileId != null) "profile?profileId=$profileId" else "profile"
}
object EditProfile : Screen("edit_profile")
object Settings : Screen("settings")
object Contacts : Screen("contacts")
}
@Composable
fun AppNavigation(
navController: NavHostController = rememberNavController()
) {
val authViewModel: AuthViewModel = hiltViewModel()
val authState by authViewModel.state.collectAsState()
val startDestination = if (authState.isAuthenticated) Screen.ChatList.route else Screen.Login.route
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
// Определяем, нужно ли показывать нижнюю панель
val showBottomBar = currentRoute in listOf(
Screen.ChatList.route,
Screen.Contacts.route,
Screen.Settings.route,
Screen.Profile.route
)
Scaffold(
bottomBar = {
if (showBottomBar) {
GlassNavigationBar(
currentRoute = currentRoute ?: "",
onNavigate = { route ->
navController.navigate(route) {
popUpTo(Screen.ChatList.route) { saveState = true }
launchSingleTop = true
restoreState = true
}
},
userAvatarUrl = null,
username = "Me"
)
}
}
) { paddingValues ->
Box(modifier = Modifier.padding(if (showBottomBar) paddingValues else PaddingValues(0.dp))) {
NavHost(
navController = navController,
startDestination = startDestination
) {
composable(Screen.Login.route) {
val viewModel: AuthViewModel = hiltViewModel()
LoginScreen(
viewModel = viewModel,
onNavigateToRegister = { navController.navigate(Screen.Register.route) },
onNavigateToSettings = { navController.navigate(Screen.Settings.route) },
onLoginSuccess = {
navController.navigate(Screen.ChatList.route) {
popUpTo(Screen.Login.route) { inclusive = true }
}
}
)
}
composable(Screen.Register.route) {
val viewModel: AuthViewModel = hiltViewModel()
RegisterScreen(
viewModel = viewModel,
onNavigateToLogin = { navController.popBackStack() },
onRegisterSuccess = {
navController.navigate(Screen.ChatList.route) {
popUpTo(Screen.Login.route) { inclusive = true }
}
}
)
}
composable(Screen.ChatList.route) {
val viewModel: ChatListViewModel = hiltViewModel()
val storyViewModel: StoryViewModel = hiltViewModel()
ChatListScreen(
viewModel = viewModel,
storyViewModel = storyViewModel,
onChatClick = { chatId ->
navController.navigate(Screen.ChatDetail.createRoute(chatId, "Chat"))
},
onStoryClick = { /* Story click logic */ }
)
}
composable(
route = Screen.ChatDetail.route,
arguments = listOf(
navArgument("chatId") { type = NavType.StringType },
navArgument("chatName") { type = NavType.StringType }
)
) { backStackEntry ->
val chatId = backStackEntry.arguments?.getString("chatId") ?: ""
val chatName = backStackEntry.arguments?.getString("chatName") ?: "Chat"
val viewModel: ChatDetailViewModel = hiltViewModel()
ChatDetailScreen(
chatId = chatId,
chatName = chatName,
viewModel = viewModel,
onBack = { navController.popBackStack() }
)
}
composable(Screen.Contacts.route) {
val viewModel: ContactListViewModel = hiltViewModel()
val state by viewModel.state.collectAsState()
ContactListScreen(
contacts = state.contacts,
isLoading = state.isLoading,
onContactClick = { id -> navController.navigate(Screen.Profile.createRoute(id)) },
onSearchChange = { viewModel.onSearchChange(it) }
)
}
composable(
route = Screen.Profile.route,
arguments = listOf(
navArgument("profileId") {
type = NavType.StringType
nullable = true
}
)
) { backStackEntry ->
val profileId = backStackEntry.arguments?.getString("profileId")
val viewModel: ProfileViewModel = hiltViewModel()
ProfileScreen(
profileId = profileId,
viewModel = viewModel,
onEditProfile = { navController.navigate(Screen.EditProfile.route) },
onBack = { navController.popBackStack() },
onSendMessage = { id -> navController.navigate(Screen.ChatDetail.createRoute(id, "Chat")) }
)
}
composable(Screen.EditProfile.route) {
val viewModel: ProfileViewModel = hiltViewModel()
val state by viewModel.state.collectAsState()
EditProfileScreen(
currentDisplayName = state.profile?.displayName,
currentUsername = state.profile?.username ?: "",
currentBio = state.profile?.bio,
currentAvatarUrl = state.profile?.avatarUrl,
onSave = { name, bio, uri ->
viewModel.updateProfile(name, bio, uri)
navController.popBackStack()
},
onBack = { navController.popBackStack() }
)
}
composable(Screen.Settings.route) {
val viewModel: SettingsViewModel = hiltViewModel()
SettingsScreen(
viewModel = viewModel,
onBack = { navController.popBackStack() },
onLogout = {
navController.navigate(Screen.Login.route) {
popUpTo(0) { inclusive = true }
}
}
)
}
}
}
}
}