Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import android.widget.LinearLayout
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
Expand Down Expand Up @@ -195,11 +194,10 @@ class Nav2Activity : AppCompatActivity() {

private fun createComposeNavHostView(): ComposeView =
ComposeView(this).apply {
setBackgroundColor(color(android.R.color.white))
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)

setContent {
MaterialTheme {
Nav2SampleTheme {
Nav2ComposeApp(
navListener = sentryNavigationListener,
routeWorkOptions = routeWorkOptions.value,
Expand Down Expand Up @@ -256,11 +254,10 @@ class Nav2Activity : AppCompatActivity() {

private fun createPerformanceView(): ComposeView =
ComposeView(this).apply {
setBackgroundColor(color(android.R.color.white))
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)

setContent {
MaterialTheme {
Nav2SampleTheme {
NavigationPerformancePanel(
title = "Performance",
description =
Expand All @@ -287,7 +284,7 @@ class Nav2Activity : AppCompatActivity() {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)

setContent {
MaterialTheme {
Nav2SampleTheme {
if (showTransactionHistorySheet.value) {
Nav2TransactionHistorySheet(
transactions = transactionHistory.transactions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
Expand Down Expand Up @@ -123,127 +124,129 @@ internal fun Nav2ComposeApp(
routeWorkOptions = routeWorkOptions,
)

Column(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) {
NavHost(
navController = navController,
startDestination = Home.route,
modifier = Modifier.weight(1f),
) {
composable(Home.route) {
TracedNav2ComposeRoute(Home.routeName) {
Nav2ComposeHomeRoute(routeSpec = Nav2RouteSpecs.home) { navigateTo(ProductList) }
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
Column(modifier = Modifier.fillMaxSize()) {
NavHost(
navController = navController,
startDestination = Home.route,
modifier = Modifier.weight(1f),
) {
composable(Home.route) {
TracedNav2ComposeRoute(Home.routeName) {
Nav2ComposeHomeRoute(routeSpec = Nav2RouteSpecs.home) { navigateTo(ProductList) }
}
}
}

composable(ProductList.route) {
TracedNav2ComposeRoute(ProductList.routeName) {
Nav2ComposeProductListRoute(
routeSpec = Nav2RouteSpecs.productList,
onOpenProduct42 = {
navigateTo(
ProductDetail(
productId = "42",
source = "product-list",
campaign = "summer-sale",
composable(ProductList.route) {
TracedNav2ComposeRoute(ProductList.routeName) {
Nav2ComposeProductListRoute(
routeSpec = Nav2RouteSpecs.productList,
onOpenProduct42 = {
navigateTo(
ProductDetail(
productId = "42",
source = "product-list",
campaign = "summer-sale",
)
)
)
},
onOpenProduct7 = {
navigateTo(ProductDetail(productId = "7", source = "product-list"))
},
)
},
onOpenProduct7 = {
navigateTo(ProductDetail(productId = "7", source = "product-list"))
},
)
}
}
}

composable(
route = Nav2ComposeDestination.PRODUCT_DETAIL_ROUTE,
arguments =
listOf(
navArgument(Nav2Args.PRODUCT_ID) { type = NavType.StringType },
navArgument(Nav2Args.SOURCE) { type = NavType.StringType },
navArgument(Nav2Args.CAMPAIGN) {
type = NavType.StringType
defaultValue = ""
},
),
) { entry ->
val productId = entry.arguments?.getString(Nav2Args.PRODUCT_ID).orEmpty()
val source = entry.arguments?.getString(Nav2Args.SOURCE).orEmpty()
val campaign = entry.arguments?.getString(Nav2Args.CAMPAIGN).orEmpty()
TracedNav2ComposeRoute(Nav2RouteNames.PRODUCT_DETAIL) {
Nav2ComposeProductDetailRoute(
routeSpec = Nav2RouteSpecs.productDetail,
productId = productId,
source = source,
campaign = campaign,
onShowPromoDialog = {
navigateTo(PromoDialog("detail-$productId"))
},
onOpenShareSheet = { openShareSheet(productId) },
onCheckout = { navigateTo(Checkout(productId)) },
)
composable(
route = Nav2ComposeDestination.PRODUCT_DETAIL_ROUTE,
arguments =
listOf(
navArgument(Nav2Args.PRODUCT_ID) { type = NavType.StringType },
navArgument(Nav2Args.SOURCE) { type = NavType.StringType },
navArgument(Nav2Args.CAMPAIGN) {
type = NavType.StringType
defaultValue = ""
},
),
) { entry ->
val productId = entry.arguments?.getString(Nav2Args.PRODUCT_ID).orEmpty()
val source = entry.arguments?.getString(Nav2Args.SOURCE).orEmpty()
val campaign = entry.arguments?.getString(Nav2Args.CAMPAIGN).orEmpty()
TracedNav2ComposeRoute(Nav2RouteNames.PRODUCT_DETAIL) {
Nav2ComposeProductDetailRoute(
routeSpec = Nav2RouteSpecs.productDetail,
productId = productId,
source = source,
campaign = campaign,
onShowPromoDialog = {
navigateTo(PromoDialog("detail-$productId"))
},
onOpenShareSheet = { openShareSheet(productId) },
onCheckout = { navigateTo(Checkout(productId)) },
)
}
}
}

composable(
route = Nav2ComposeDestination.CHECKOUT_ROUTE,
arguments = listOf(navArgument(Nav2Args.PRODUCT_ID) { type = NavType.StringType }),
) { entry ->
val productId = entry.arguments?.getString(Nav2Args.PRODUCT_ID).orEmpty()
TracedNav2ComposeRoute(Nav2RouteNames.CHECKOUT) {
Nav2ComposeCheckoutRoute(
routeSpec = Nav2RouteSpecs.checkout,
productId = productId,
onCompleteOrder = {
navigateTo(Confirmation(orderId = "order-$productId"))
},
)
composable(
route = Nav2ComposeDestination.CHECKOUT_ROUTE,
arguments = listOf(navArgument(Nav2Args.PRODUCT_ID) { type = NavType.StringType }),
) { entry ->
val productId = entry.arguments?.getString(Nav2Args.PRODUCT_ID).orEmpty()
TracedNav2ComposeRoute(Nav2RouteNames.CHECKOUT) {
Nav2ComposeCheckoutRoute(
routeSpec = Nav2RouteSpecs.checkout,
productId = productId,
onCompleteOrder = {
navigateTo(Confirmation(orderId = "order-$productId"))
},
)
}
}
}

composable(
route = Nav2ComposeDestination.CONFIRMATION_ROUTE,
arguments = listOf(navArgument(Nav2Args.ORDER_ID) { type = NavType.StringType }),
) { entry ->
TracedNav2ComposeRoute(Nav2RouteNames.CONFIRMATION) {
Nav2ComposeConfirmationRoute(
routeSpec = Nav2RouteSpecs.confirmation,
orderId = entry.arguments?.getString(Nav2Args.ORDER_ID).orEmpty(),
onResetBackStack = { resetToHome() },
)
composable(
route = Nav2ComposeDestination.CONFIRMATION_ROUTE,
arguments = listOf(navArgument(Nav2Args.ORDER_ID) { type = NavType.StringType }),
) { entry ->
TracedNav2ComposeRoute(Nav2RouteNames.CONFIRMATION) {
Nav2ComposeConfirmationRoute(
routeSpec = Nav2RouteSpecs.confirmation,
orderId = entry.arguments?.getString(Nav2Args.ORDER_ID).orEmpty(),
onResetBackStack = { resetToHome() },
)
}
}
}

dialog(
route = Nav2ComposeDestination.PROMO_DIALOG_ROUTE,
arguments = listOf(navArgument(Nav2Args.PROMO_ID) { type = NavType.StringType }),
) { entry ->
// This dialog is a real Nav destination, so it participates in Nav2 the same way as the
// rest of the route graph. Compare it with the share sheet overlay below when inspecting
// Sentry's Nav2 breadcrumbs, destination arguments, and route transactions.
TracedNav2ComposeRoute(Nav2RouteNames.PROMO_DIALOG) {
Nav2ComposePromoDialogRoute(
routeSpec = Nav2RouteSpecs.promoDialog,
promoId = entry.arguments?.getString(Nav2Args.PROMO_ID).orEmpty(),
onCaptureException = onCaptureException,
onCrashApp = onCrashApp,
onDismiss = { navigateBack() },
)
dialog(
route = Nav2ComposeDestination.PROMO_DIALOG_ROUTE,
arguments = listOf(navArgument(Nav2Args.PROMO_ID) { type = NavType.StringType }),
) { entry ->
// This dialog is a real Nav destination, so it participates in Nav2 the same way as the
// rest of the route graph. Compare it with the share sheet overlay below when inspecting
// Sentry's Nav2 breadcrumbs, destination arguments, and route transactions.
TracedNav2ComposeRoute(Nav2RouteNames.PROMO_DIALOG) {
Nav2ComposePromoDialogRoute(
routeSpec = Nav2RouteSpecs.promoDialog,
promoId = entry.arguments?.getString(Nav2Args.PROMO_ID).orEmpty(),
onCaptureException = onCaptureException,
onCrashApp = onCrashApp,
onDismiss = { navigateBack() },
)
}
}
}
}

shareSheetProductId.value?.let { productId ->
// This share sheet is intentionally just a screen overlay, not a Nav destination. It lets
// the sample compare how Sentry's Nav2 integration behaves for proper Nav destinations vs.
// UI layered on top of the current route.
Nav2ComposeShareSheetRoute(
routeSpec = Nav2RouteSpecs.shareSheet,
productId = productId,
onCaptureException = onCaptureException,
onCrashApp = onCrashApp,
onDone = ::dismissShareSheet,
)
shareSheetProductId.value?.let { productId ->
// This share sheet is intentionally just a screen overlay, not a Nav destination. It lets
// the sample compare how Sentry's Nav2 integration behaves for proper Nav destinations vs.
// UI layered on top of the current route.
Nav2ComposeShareSheetRoute(
routeSpec = Nav2RouteSpecs.shareSheet,
productId = productId,
onCaptureException = onCaptureException,
onCrashApp = onCrashApp,
onDone = ::dismissShareSheet,
)
}
}
}
}
Expand Down Expand Up @@ -528,30 +531,33 @@ private fun Nav2ComposeRouteScaffold(
cardContent: (@Composable ColumnScope.() -> Unit)? = null,
content: (@Composable ColumnScope.() -> Unit)? = null,
) {
Column(
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Text(
routeSpec.title,
style = MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.Bold,
)
routeSpec.description?.let { Text(it, style = MaterialTheme.typography.bodyMedium) }
if (cardContent != null) {
Card(
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
modifier = Modifier.fillMaxWidth(),
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
Column(
modifier = Modifier.verticalScroll(rememberScrollState()).padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Text(
routeSpec.title,
style = MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.Bold,
)
routeSpec.description?.let { Text(it, style = MaterialTheme.typography.bodyMedium) }
if (cardContent != null) {
Card(
colors =
CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
modifier = Modifier.fillMaxWidth(),
) {
cardContent()
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
cardContent()
}
}
}
content?.invoke(this)
}
content?.invoke(this)
}
}

Expand Down Expand Up @@ -599,16 +605,19 @@ private const val PRODUCT_LIST_ITEM_COUNT = 20

@Composable
private fun Nav2ComposeRouteInfo(label: String, value: String) {
Row(
modifier =
Modifier.fillMaxWidth()
.background(MaterialTheme.colorScheme.surface, RoundedCornerShape(8.dp))
.padding(12.dp),
horizontalArrangement = Arrangement.SpaceBetween,
Surface(
color = MaterialTheme.colorScheme.surface,
shape = RoundedCornerShape(8.dp),
modifier = Modifier.fillMaxWidth(),
) {
Text(label, fontWeight = FontWeight.Bold)
Spacer(Modifier.size(12.dp))
Text(value, maxLines = 1, overflow = TextOverflow.Ellipsis)
Row(
modifier = Modifier.padding(12.dp),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(label, fontWeight = FontWeight.Bold)
Spacer(Modifier.size(12.dp))
Text(value, maxLines = 1, overflow = TextOverflow.Ellipsis)
}
}
}

Expand Down
Loading
Loading