feat: refactor navigation structure by replacing AppNavigation with MainApp and updating ListDetailScreen and ListsScreen for improved functionality

This commit is contained in:
2025-11-11 19:54:47 +01:00
parent c53e234efe
commit 607a0c4fcb
4 changed files with 146 additions and 21 deletions
@@ -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()
}
}
}
@@ -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() })
}
}
}
}
}
@@ -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
@@ -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 =