{ "output": "package com.servicebook.ui.navigation\n\nimport android.content.Intent\nimport androidx.activity.compose.rememberLauncherForActivityResult\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.compose.animation.AnimatedContentTransitionScope\nimport androidx.compose.animation.ContentTransform\nimport androidx.compose.animation.core.CubicBezierEasing\nimport androidx.compose.animation.core.tween\nimport androidx.compose.animation.fadeIn\nimport androidx.compose.animation.fadeOut\nimport androidx.compose.animation.slideInHorizontally\nimport androidx.compose.animation.slideOutHorizontally\nimport androidx.compose.animation.togetherWith\nimport androidx.compose.foundation.background\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material3.Button\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Surface\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.CompositionLocalProvider\nimport androidx.compose.runtime.compositionLocalOf\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.style.TextAlign\nimport androidx.compose.ui.unit.dp\nimport androidx.navigation3.runtime.NavBackStack\nimport androidx.navigation3.runtime.NavKey\nimport androidx.navigation3.runtime.entryProvider\nimport androidx.navigation3.runtime.rememberNavBackStack\nimport androidx.navigation3.ui.NavDisplay\nimport com.servicebook.R\nimport com.servicebook.ServiceBookApplication\nimport com.servicebook.ui.records.AddEditRecordScreen\nimport com.servicebook.ui.records.ImageViewerScreen\nimport com.servicebook.ui.records.RecordDetailScreen\nimport com.servicebook.ui.records.VehicleDetailScreen\nimport com.servicebook.ui.settings.CategoriesScreen\nimport com.servicebook.ui.settings.SettingsScreen\nimport com.servicebook.ui.vehicles.AddEditVehicleScreen\nimport com.servicebook.ui.vehicles.VehicleListScreen\nimport kotlinx.coroutines.launch\n\nval LocalNavBackStack = compositionLocalOf> { error(\"No backstack\") }\n\nprivate val MaterialEmphasizedEasing = CubicBezierEasing(0.35f, 0.0f, 0.0f, 1.0f)\nprivate const val STANDARD_DURATION = 450\n\nprivate fun AnimatedContentTransitionScope.modernForwardSpec(): ContentTransform =\n (\n slideInHorizontally(tween(STANDARD_DURATION, easing = MaterialEmphasizedEasing)) { it } +\n fadeIn(tween(STANDARD_DURATION, easing = MaterialEmphasizedEasing)) togetherWith\n slideOutHorizontally(tween(STANDARD_DURATION, easing = MaterialEmphasizedEasing)) { -it / 4 } +\n fadeOut(tween(STANDARD_DURATION, easing = MaterialEmphasizedEasing))\n ).apply {\n targetContentZIndex = 1f\n }\n\nprivate fun AnimatedContentTransitionScope.modernBackwardSpec(): ContentTransform =\n (\n slideInHorizontally(tween(STANDARD_DURATION, easing = MaterialEmphasizedEasing)) { -it / 4 } +\n fadeIn(tween(STANDARD_DURATION, easing = MaterialEmphasizedEasing)) togetherWith\n slideOutHorizontally(tween(STANDARD_DURATION, easing = MaterialEmphasizedEasing)) { it } +\n fadeOut(tween(STANDARD_DURATION, easing = MaterialEmphasizedEasing))\n ).apply {\n targetContentZIndex = -1f\n }\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nfun AppNavGraph(startDestination: NavKey) {\n val backStack = rememberNavBackStack(startDestination)\n\n CompositionLocalProvider(\n LocalNavBackStack provides backStack,\n ) {\n NavDisplay(\n backStack = backStack,\n modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background),\n onBack = { backStack.removeLastOrNull() },\n transitionSpec = {\n modernForwardSpec()\n },\n popTransitionSpec = {\n modernBackwardSpec()\n },\n entryProvider =\n entryProvider {\n entry {\n VanillaEntry {\n SetupScreen()\n }\n }\n entry {\n VanillaEntry {\n VehicleListScreen(backStack = backStack)\n }\n }\n entry {\n VanillaEntry {\n AddEditVehicleScreen(vehicleId = null, backStack = backStack)\n }\n }\n entry { key ->\n VanillaEntry {\n AddEditVehicleScreen(vehicleId = key.vehicleId, backStack = backStack)\n }\n }\n entry { key ->\n VanillaEntry {\n VehicleDetailScreen(vehicleId = key.vehicleId, backStack = backStack)\n }\n }\n entry { key ->\n VanillaEntry {\n AddEditRecordScreen(vehicleId = key.vehicleId, recordId = null, backStack = backStack)\n }\n }\n entry { key ->\n VanillaEntry {\n AddEditRecordScreen(vehicleId = key.vehicleId, recordId = key.recordId, backStack = backStack)\n }\n }\n entry { key ->\n VanillaEntry {\n RecordDetailScreen(vehicleId = key.vehicleId, recordId = key.recordId, backStack = backStack)\n }\n }\n entry {\n VanillaEntry {\n SettingsScreen(backStack = backStack)\n }\n }\n entry {\n VanillaEntry {\n CategoriesScreen(backStack = backStack)\n }\n }\n entry { key ->\n VanillaEntry {\n ImageViewerScreen(uriString = key.uriString, backStack = backStack)\n }\n }\n },\n )\n }\n}\n\n@Composable\nprivate fun VanillaEntry(content: @Composable () -> Unit) {\n Surface(\n modifier = Modifier.fillMaxSize(),\n color = MaterialTheme.colorScheme.background,\n ) {\n content()\n }\n}\n\n@Composable\ninternal fun SetupScreen() {\n val context = LocalContext.current\n val application = context.applicationContext as ServiceBookApplication\n val scope = rememberCoroutineScope()\n\n val folderPicker =\n rememberLauncherForActivityResult(\n ActivityResultContracts.OpenDocumentTree(),\n ) { uri ->\n if (uri == null) return@rememberLauncherForActivityResult\n context.contentResolver.takePersistableUriPermission(\n uri,\n Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION,\n )\n // Saving the URI to DataStore triggers MainContent's reactive collect,\n // which updates startDestination → VehicleList automatically.\n scope.launch { application.preferences.setVaultUri(uri.toString()) }\n }\n\n Scaffold { padding ->\n Column(\n modifier =\n Modifier\n .fillMaxSize()\n .padding(padding)\n .padding(32.dp),\n horizontalAlignment = Alignment.CenterHorizontally,\n verticalArrangement = Arrangement.Center,\n ) {\n Text(\n text = stringResource(R.string.setup_title),\n style = MaterialTheme.typography.headlineMedium,\n textAlign = TextAlign.Center,\n )\n Spacer(Modifier.height(16.dp))\n Text(\n text = stringResource(R.string.setup_description),\n style = MaterialTheme.typography.bodyLarge,\n color = MaterialTheme.colorScheme.onSurfaceVariant,\n textAlign = TextAlign.Center,\n )\n Spacer(Modifier.height(32.dp))\n Button(onClick = { folderPicker.launch(null) }) {\n Text(stringResource(R.string.setup_choose_folder))\n }\n }\n }\n}\n" }