From 607a0c4fcbed3a35ca2d90acafe6474b7befc62b Mon Sep 17 00:00:00 2001 From: gabriel20xx Date: Tue, 11 Nov 2025 19:54:47 +0100 Subject: [PATCH] feat: refactor navigation structure by replacing AppNavigation with MainApp and updating ListDetailScreen and ListsScreen for improved functionality --- .../java/com/collabtable/app/MainActivity.kt | 4 +- .../collabtable/app/ui/navigation/MainApp.kt | 131 ++++++++++++++++++ .../app/ui/screens/ListDetailScreen.kt | 18 ++- .../collabtable/app/ui/screens/ListsScreen.kt | 14 +- 4 files changed, 146 insertions(+), 21 deletions(-) create mode 100644 CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/navigation/MainApp.kt diff --git a/CollabTableAndroid/app/src/main/java/com/collabtable/app/MainActivity.kt b/CollabTableAndroid/app/src/main/java/com/collabtable/app/MainActivity.kt index fe37e66..9f56b65 100644 --- a/CollabTableAndroid/app/src/main/java/com/collabtable/app/MainActivity.kt +++ b/CollabTableAndroid/app/src/main/java/com/collabtable/app/MainActivity.kt @@ -10,7 +10,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import com.collabtable.app.data.preferences.PreferencesManager -import com.collabtable.app.ui.navigation.AppNavigation +import com.collabtable.app.ui.navigation.MainApp import com.collabtable.app.ui.theme.CollabTableTheme class MainActivity : ComponentActivity() { @@ -34,7 +34,7 @@ class MainActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background, ) { - AppNavigation() + MainApp() } } } diff --git a/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/navigation/MainApp.kt b/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/navigation/MainApp.kt new file mode 100644 index 0000000..034306c --- /dev/null +++ b/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/navigation/MainApp.kt @@ -0,0 +1,131 @@ +package com.collabtable.app.ui.navigation + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Home +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.navigation.NavGraph.Companion.findStartDestination +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 androidx.navigation.NavType +import com.collabtable.app.data.preferences.PreferencesManager +import com.collabtable.app.ui.screens.ListDetailScreen +import com.collabtable.app.ui.screens.ListsScreen +import com.collabtable.app.ui.screens.LogsScreen +import com.collabtable.app.ui.screens.ServerSetupScreen +import com.collabtable.app.ui.screens.SettingsScreen + +private object Routes { + const val Setup = "server_setup" + const val MainRoot = "main_root" + const val Tables = "tables" + const val Settings = "settings" + const val ListDetail = "list/{listId}" + const val Logs = "logs" +} + +@Composable +fun MainApp() { + val context = LocalContext.current + val prefs = remember { PreferencesManager.getInstance(context) } + + // Show setup flow until completed; then show main app with bottom nav + if (prefs.isFirstRun()) { + val navController = rememberNavController() + NavHost(navController, startDestination = Routes.Setup) { + composable(Routes.Setup) { + ServerSetupScreen( + onSetupComplete = { + // Mark not first run and trigger recomposition to show main UI + prefs.setIsFirstRun(false) + }, + ) + } + } + return + } + + val navController = rememberNavController() + val backStackEntry by navController.currentBackStackEntryAsState() + val currentRoute = backStackEntry?.destination?.route + + Scaffold( + bottomBar = { + NavigationBar { + NavigationBarItem( + selected = currentRoute == Routes.Tables || currentRoute?.startsWith("list/") == true, + onClick = { + navController.navigate(Routes.Tables) { + popUpTo(navController.graph.findStartDestination().id) { saveState = true } + launchSingleTop = true + restoreState = true + } + }, + icon = { androidx.compose.material3.Icon(Icons.Default.Home, contentDescription = null) }, + label = { Text("Tables") }, + ) + NavigationBarItem( + selected = currentRoute == Routes.Settings, + onClick = { + navController.navigate(Routes.Settings) { + popUpTo(navController.graph.findStartDestination().id) { saveState = true } + launchSingleTop = true + restoreState = true + } + }, + icon = { androidx.compose.material3.Icon(Icons.Default.Settings, contentDescription = null) }, + label = { Text("Settings") }, + ) + } + }, + ) { innerPadding -> + Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { + NavHost( + navController = navController, + startDestination = Routes.Tables, + ) { + composable(Routes.Tables) { + ListsScreen( + onNavigateToList = { listId -> navController.navigate("list/$listId") }, + onNavigateToSettings = { navController.navigate(Routes.Settings) }, + onNavigateToLogs = { navController.navigate(Routes.Logs) }, + ) + } + composable(Routes.Settings) { + SettingsScreen( + onNavigateBack = { navController.popBackStack() }, + onNavigateToLogs = { navController.navigate(Routes.Logs) }, + onLeaveServer = { + // Reset to setup flow by toggling the flag and rebuilding graph via recomposition + prefs.setIsFirstRun(true) + }, + ) + } + composable(Routes.Logs) { + LogsScreen(onNavigateBack = { navController.popBackStack() }) + } + composable( + route = Routes.ListDetail, + arguments = listOf(navArgument("listId") { type = NavType.StringType }), + ) { backStackEntry -> + val listId = backStackEntry.arguments?.getString("listId") ?: return@composable + ListDetailScreen(listId = listId, onNavigateBack = { navController.popBackStack() }) + } + } + } + } +} diff --git a/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListDetailScreen.kt b/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListDetailScreen.kt index 21687f5..6c44bb1 100644 --- a/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListDetailScreen.kt +++ b/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListDetailScreen.kt @@ -188,8 +188,8 @@ fun ListDetailScreen( val localCtx = LocalContext.current val localPrefs = remember { PreferencesManager.getInstance(localCtx) } ConnectionStatusAction(prefs = localPrefs) - IconButton(onClick = { showManageColumnsDialog = true }) { - Icon(Icons.Default.Settings, contentDescription = "Manage Columns") + IconButton(onClick = { showAddItemDialog = true }) { + Icon(Icons.Default.Add, contentDescription = stringResource(R.string.add_item)) } }, colors = TopAppBarDefaults.topAppBarColors( @@ -198,13 +198,7 @@ fun ListDetailScreen( ), ) }, - floatingActionButton = { - FloatingActionButton( - onClick = { showAddItemDialog = true }, - ) { - Icon(Icons.Default.Add, contentDescription = stringResource(R.string.add_item)) - } - }, + floatingActionButton = {}, ) { padding -> // Apply filtering, sorting, and grouping to items fun valueFor(item: ItemWithValues, field: Field?): String { @@ -527,6 +521,7 @@ fun ListDetailScreen( }, scrollState = horizontalScrollState, isLast = (field.id == stableFields.lastOrNull()?.id), + onHeaderClick = { showManageColumnsDialog = true }, ) } } @@ -741,6 +736,7 @@ fun FieldHeader( onWidthChange: (Float) -> Unit, scrollState: androidx.compose.foundation.ScrollState, isLast: Boolean, + onHeaderClick: () -> Unit, ) { val density = LocalDensity.current val scope = rememberCoroutineScope() @@ -767,7 +763,9 @@ fun FieldHeader( Text( text = field.name, style = MaterialTheme.typography.labelLarge, - modifier = Modifier.weight(1f), + modifier = Modifier + .weight(1f) + .clickable { onHeaderClick() }, ) // Resize handle diff --git a/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListsScreen.kt b/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListsScreen.kt index 9712b01..7f0aa48 100644 --- a/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListsScreen.kt +++ b/CollabTableAndroid/app/src/main/java/com/collabtable/app/ui/screens/ListsScreen.kt @@ -23,7 +23,6 @@ import androidx.compose.material.icons.filled.DragHandle import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.Refresh -import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.Sort import androidx.compose.material3.AlertDialog import androidx.compose.material3.CircularProgressIndicator @@ -69,6 +68,7 @@ import org.burnoutcrew.reorderable.reorderable @Composable fun ListsScreen( onNavigateToList: (String) -> Unit, + // Settings now accessed via bottom navigation; keep param for backward compat (unused) onNavigateToSettings: () -> Unit, onNavigateToLogs: () -> Unit = {}, ) { @@ -108,10 +108,10 @@ fun ListsScreen( val context = LocalContext.current val prefsLocal = remember { PreferencesManager.getInstance(context) } ConnectionStatusAction(prefs = prefsLocal) - IconButton(onClick = onNavigateToSettings) { + IconButton(onClick = { showCreateDialog = true }) { Icon( - Icons.Default.Settings, - contentDescription = stringResource(R.string.settings), + Icons.Default.Add, + contentDescription = stringResource(R.string.create_list), ) } }, @@ -122,11 +122,7 @@ fun ListsScreen( ), ) }, - floatingActionButton = { - FloatingActionButton(onClick = { showCreateDialog = true }) { - Icon(Icons.Default.Add, contentDescription = stringResource(R.string.create_list)) - } - }, + floatingActionButton = {}, ) { padding -> Box( modifier =