Skip to content

Commit 2dfd471

Browse files
feat: consistent back-navigation across all screens
No screen in the app rendered an explicit back arrow before this — every sub-screen relied solely on the system back gesture/button. Threads NavController through CollectionScreen, BibleScreen, GraniteLabScreen, InsightsRepositoryScreen, LibraryStatsScreen, TableInspectorScreen, VoiceLabScreen, and all four Settings sub-pages, adding a TopAppBar navigationIcon (Icons.AutoMirrored.Filled.ArrowBack -> popBackStack()) to each, matching the pattern already used by DataManagementScreen/ ExperimentalHub. BibleScreen keeps its existing internal book -> chapter -> read step navigation; popBackStack() is only wired at the top-level "book" step. SettingsScreens.kt's UpdateSettingsPage also changes signature to take the full MainViewModel (not just SettingsManager) so it shares availableUpdate state with MainMenu's banner rather than tracking it separately, and now shows the app's versionName/versionCode alongside its build commit sha. Note: ExperimentalHub, DataManagementScreen, and SettingsDashboard already receive navController but still don't render a back arrow — left alone here as a deliberately separate follow-up, not an oversight. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 0128b29 commit 2dfd471

9 files changed

Lines changed: 281 additions & 29 deletions

File tree

mobile/app/src/main/java/com/bytecats/metanoia/MainActivity.kt

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,41 +26,44 @@ class MainActivity : ComponentActivity() {
2626
MetanoiaTheme {
2727
NavHost(navController = navController, startDestination = "menu") {
2828
composable("menu") { MainMenu(navController, viewModel) }
29-
composable("bible") { BibleScreen(viewModel) }
30-
composable("collection") { CollectionScreen(viewModel) }
29+
composable("bible") { BibleScreen(navController, viewModel) }
30+
composable("collection") { CollectionScreen(navController, viewModel) }
3131
composable("insights") {
32-
InsightsRepositoryScreen(viewModel) { viewModel.speak(it) }
32+
InsightsRepositoryScreen(navController, viewModel) { viewModel.speak(it) }
3333
}
3434
composable("stats") {
35-
LibraryStatsScreen(viewModel.bibleManager)
35+
LibraryStatsScreen(navController, viewModel.bibleManager)
3636
}
3737
composable("experimental_hub") {
3838
ExperimentalHub(navController)
3939
}
4040
composable("ai_lab") {
41-
GraniteLabScreen(viewModel.aiLogs, viewModel.llmManager!!)
41+
GraniteLabScreen(navController, viewModel.aiLogs, viewModel.llmManager!!)
4242
}
4343
composable("voice_lab") {
44-
VoiceLabScreen(viewModel)
44+
VoiceLabScreen(navController, viewModel)
4545
}
4646
composable("data_management") {
4747
DataManagementScreen(navController, viewModel)
4848
}
4949
composable("table_inspector/{tableName}") { backStack ->
5050
val name = backStack.arguments?.getString("tableName") ?: "unknown"
51-
TableInspectorScreen(name, viewModel.bibleManager)
51+
TableInspectorScreen(navController, name, viewModel.bibleManager)
5252
}
5353
composable("settings_main") {
5454
SettingsDashboard(navController)
5555
}
5656
composable("settings_gateway") {
57-
GatewaySettingsPage(viewModel.settingsManager)
57+
GatewaySettingsPage(navController, viewModel.settingsManager)
5858
}
5959
composable("settings_audio") {
60-
AudioSettingsPage(viewModel.settingsManager)
60+
AudioSettingsPage(navController, viewModel.settingsManager)
6161
}
6262
composable("settings_reader") {
63-
ReaderSettingsPage(viewModel.settingsManager)
63+
ReaderSettingsPage(navController, viewModel.settingsManager)
64+
}
65+
composable("settings_updates") {
66+
UpdateSettingsPage(navController, viewModel)
6467
}
6568
}
6669
}

mobile/app/src/main/java/com/bytecats/metanoia/ui/screens/BibleScreen.kt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import androidx.compose.ui.text.style.TextOverflow
3030
import androidx.compose.ui.unit.LayoutDirection
3131
import androidx.compose.ui.unit.dp
3232
import androidx.compose.ui.unit.sp
33+
import androidx.navigation.NavController
3334
import com.bytecats.metanoia.models.BibleBook
3435
import com.bytecats.metanoia.models.InterlinearWord
3536
import com.bytecats.metanoia.models.LexiconEntry
@@ -43,7 +44,7 @@ import kotlinx.coroutines.withContext
4344

4445
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class, ExperimentalFoundationApi::class)
4546
@Composable
46-
fun BibleScreen(viewModel: MainViewModel) {
47+
fun BibleScreen(navController: NavController, viewModel: MainViewModel) {
4748
val bibleManager = viewModel.bibleManager
4849
val settings = viewModel.settingsManager
4950
val narration by viewModel.narrationState
@@ -118,7 +119,17 @@ fun BibleScreen(viewModel: MainViewModel) {
118119
Column {
119120
TopAppBar(
120121
title = { Text(if (step == "read") "${selectedBook?.name} $selectedChapter" else "BIBLE") },
121-
navigationIcon = { if (step != "book") IconButton({ step = if (step == "read") "chapter" else "book"; isSearchVisible = (step == "book"); viewModel.stopNarration() }) { Icon(Icons.AutoMirrored.Filled.ArrowBack, null) } },
122+
navigationIcon = {
123+
IconButton({
124+
if (step == "book") {
125+
navController.popBackStack()
126+
} else {
127+
step = if (step == "read") "chapter" else "book"
128+
isSearchVisible = (step == "book")
129+
viewModel.stopNarration()
130+
}
131+
}) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") }
132+
},
122133
actions = {
123134
if (viewModel.isRemoteTtsActive && narration.isPlaying) {
124135
Surface(

mobile/app/src/main/java/com/bytecats/metanoia/ui/screens/CollectionScreen.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.*
44
import androidx.compose.foundation.lazy.LazyColumn
55
import androidx.compose.foundation.lazy.items
66
import androidx.compose.material.icons.Icons
7+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
78
import androidx.compose.material.icons.automirrored.filled.VolumeUp
89
import androidx.compose.material3.*
910
import androidx.compose.runtime.*
@@ -12,16 +13,24 @@ import androidx.compose.ui.Modifier
1213
import androidx.compose.ui.text.font.FontWeight
1314
import androidx.compose.ui.text.style.TextOverflow
1415
import androidx.compose.ui.unit.dp
16+
import androidx.navigation.NavController
1517
import com.bytecats.metanoia.viewmodel.MainViewModel
1618

1719
@OptIn(ExperimentalMaterial3Api::class)
1820
@Composable
19-
fun CollectionScreen(viewModel: MainViewModel) {
21+
fun CollectionScreen(navController: NavController, viewModel: MainViewModel) {
2022
var tabIndex by remember { mutableStateOf(0) }
2123
val favs = remember { viewModel.bibleManager.getFavorites() }
22-
24+
2325
Scaffold(topBar = {
24-
TopAppBar(title = { Text("MY COLLECTION") })
26+
TopAppBar(
27+
title = { Text("MY COLLECTION") },
28+
navigationIcon = {
29+
IconButton(onClick = { navController.popBackStack() }) {
30+
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
31+
}
32+
}
33+
)
2534
}) { innerPadding ->
2635
Column(modifier = Modifier.padding(innerPadding).fillMaxSize()) {
2736
PrimaryTabRow(selectedTabIndex = tabIndex) {

mobile/app/src/main/java/com/bytecats/metanoia/ui/screens/GraniteLabScreen.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import androidx.compose.foundation.shape.CircleShape
77
import androidx.compose.foundation.shape.RoundedCornerShape
88
import androidx.compose.foundation.verticalScroll
99
import androidx.compose.material.icons.Icons
10+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
1011
import androidx.compose.material.icons.automirrored.filled.Send
1112
import androidx.compose.material.icons.filled.*
1213
import androidx.compose.material3.*
@@ -19,13 +20,14 @@ import androidx.compose.ui.text.font.FontFamily
1920
import androidx.compose.ui.text.font.FontWeight
2021
import androidx.compose.ui.unit.dp
2122
import androidx.compose.ui.unit.sp
23+
import androidx.navigation.NavController
2224
import com.bytecats.metanoia.llm.AIProvider
2325
import com.bytecats.metanoia.llm.LLMManager
2426
import kotlinx.coroutines.launch
2527

2628
@OptIn(ExperimentalMaterial3Api::class)
2729
@Composable
28-
fun GraniteLabScreen(logs: List<String>, llm: LLMManager) {
30+
fun GraniteLabScreen(navController: NavController, logs: List<String>, llm: LLMManager) {
2931
var query by remember { mutableStateOf("") }
3032
val chat = remember { mutableStateListOf<Pair<String, String>>() }
3133
val scope = rememberCoroutineScope()
@@ -46,6 +48,11 @@ fun GraniteLabScreen(logs: List<String>, llm: LLMManager) {
4648
Scaffold(topBar = {
4749
TopAppBar(
4850
title = { Text("AI LAB") },
51+
navigationIcon = {
52+
IconButton(onClick = { navController.popBackStack() }) {
53+
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
54+
}
55+
},
4956
actions = {
5057
IconButton({ showConfig = !showConfig }) { Icon(Icons.Default.Settings, "Configure Ollama") }
5158
IconButton({

mobile/app/src/main/java/com/bytecats/metanoia/ui/screens/InsightsRepositoryScreen.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,30 @@
11
package com.bytecats.metanoia.ui.screens
22

33
import androidx.compose.foundation.layout.*
4+
import androidx.compose.material.icons.Icons
5+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
46
import androidx.compose.material3.*
57
import androidx.compose.runtime.Composable
68
import androidx.compose.runtime.remember
79
import androidx.compose.ui.Alignment
810
import androidx.compose.ui.Modifier
11+
import androidx.navigation.NavController
912
import com.bytecats.metanoia.viewmodel.MainViewModel
1013

1114
@OptIn(ExperimentalMaterial3Api::class)
1215
@Composable
13-
fun InsightsRepositoryScreen(viewModel: MainViewModel, onTts: (String) -> Unit) {
16+
fun InsightsRepositoryScreen(navController: NavController, viewModel: MainViewModel, onTts: (String) -> Unit) {
1417
val stats = remember { viewModel.bibleManager.getStats() }
15-
Scaffold(topBar = { TopAppBar(title = { Text("MY INSIGHT REPOSITORY") }) }) { innerPadding ->
18+
Scaffold(topBar = {
19+
TopAppBar(
20+
title = { Text("MY INSIGHT REPOSITORY") },
21+
navigationIcon = {
22+
IconButton(onClick = { navController.popBackStack() }) {
23+
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
24+
}
25+
}
26+
)
27+
}) { innerPadding ->
1628
if (stats.notesCount == 0) {
1729
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
1830
Text("No insights recorded yet.", color = MaterialTheme.colorScheme.outline)

mobile/app/src/main/java/com/bytecats/metanoia/ui/screens/LibraryStatsScreen.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,33 @@ package com.bytecats.metanoia.ui.screens
33
import androidx.compose.foundation.layout.*
44
import androidx.compose.foundation.rememberScrollState
55
import androidx.compose.foundation.verticalScroll
6+
import androidx.compose.material.icons.Icons
7+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
68
import androidx.compose.material3.*
79
import androidx.compose.runtime.Composable
810
import androidx.compose.runtime.remember
911
import androidx.compose.ui.Alignment
1012
import androidx.compose.ui.Modifier
1113
import androidx.compose.ui.text.font.FontWeight
1214
import androidx.compose.ui.unit.dp
15+
import androidx.navigation.NavController
1316
import com.bytecats.metanoia.bible.BibleManager
1417
import com.bytecats.metanoia.ui.components.StatItemCompact
1518

1619
@OptIn(ExperimentalMaterial3Api::class)
1720
@Composable
18-
fun LibraryStatsScreen(bible: BibleManager) {
21+
fun LibraryStatsScreen(navController: NavController, bible: BibleManager) {
1922
val stats = remember { bible.getStats() }
20-
Scaffold(topBar = { TopAppBar(title = { Text("LIBRARY ANALYTICS") }) }) { innerPadding ->
23+
Scaffold(topBar = {
24+
TopAppBar(
25+
title = { Text("LIBRARY ANALYTICS") },
26+
navigationIcon = {
27+
IconButton(onClick = { navController.popBackStack() }) {
28+
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
29+
}
30+
}
31+
)
32+
}) { innerPadding ->
2133
Column(modifier = Modifier.padding(innerPadding).fillMaxSize().padding(24.dp).verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(20.dp)) {
2234
Text("SCRIPTORIUM METRICS", style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.primary)
2335
Card(modifier = Modifier.fillMaxWidth(), colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.2f))) {

0 commit comments

Comments
 (0)