Skip to content

Commit 0dbf275

Browse files
0xadam-brownOpenCode
andauthored
fix(samples): Make Nav2 sample dark-mode compatible (#6066)
Resolve the remaining light-only colors in the Nav2 sample so the view and Compose paths follow the active DayNight theme. Replace fixed black and white surfaces and text with theme-derived colors, and let the Compose hosts render their own themed backgrounds instead of forcing white containers. Co-authored-by: OpenCode <noreply@opencode.ai>
1 parent c4d2559 commit 0dbf275

10 files changed

Lines changed: 272 additions & 220 deletions

File tree

‎sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/Nav2Activity.kt‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import android.widget.LinearLayout
2020
import android.widget.Toast
2121
import androidx.appcompat.app.AlertDialog
2222
import androidx.appcompat.app.AppCompatActivity
23-
import androidx.compose.material3.MaterialTheme
2423
import androidx.compose.runtime.mutableStateOf
2524
import androidx.compose.ui.platform.ComposeView
2625
import androidx.compose.ui.platform.ViewCompositionStrategy
@@ -195,11 +194,10 @@ class Nav2Activity : AppCompatActivity() {
195194

196195
private fun createComposeNavHostView(): ComposeView =
197196
ComposeView(this).apply {
198-
setBackgroundColor(color(android.R.color.white))
199197
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
200198

201199
setContent {
202-
MaterialTheme {
200+
Nav2SampleTheme {
203201
Nav2ComposeApp(
204202
navListener = sentryNavigationListener,
205203
routeWorkOptions = routeWorkOptions.value,
@@ -256,11 +254,10 @@ class Nav2Activity : AppCompatActivity() {
256254

257255
private fun createPerformanceView(): ComposeView =
258256
ComposeView(this).apply {
259-
setBackgroundColor(color(android.R.color.white))
260257
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
261258

262259
setContent {
263-
MaterialTheme {
260+
Nav2SampleTheme {
264261
NavigationPerformancePanel(
265262
title = "Performance",
266263
description =
@@ -287,7 +284,7 @@ class Nav2Activity : AppCompatActivity() {
287284
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
288285

289286
setContent {
290-
MaterialTheme {
287+
Nav2SampleTheme {
291288
if (showTransactionHistorySheet.value) {
292289
Nav2TransactionHistorySheet(
293290
transactions = transactionHistory.transactions,

‎sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/Nav2ComposeRoutes.kt‎

Lines changed: 145 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import androidx.compose.material3.CardDefaults
2323
import androidx.compose.material3.ExperimentalMaterial3Api
2424
import androidx.compose.material3.MaterialTheme
2525
import androidx.compose.material3.ModalBottomSheet
26+
import androidx.compose.material3.Surface
2627
import androidx.compose.material3.Text
2728
import androidx.compose.material3.TextButton
2829
import androidx.compose.runtime.Composable
@@ -123,127 +124,129 @@ internal fun Nav2ComposeApp(
123124
routeWorkOptions = routeWorkOptions,
124125
)
125126

126-
Column(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) {
127-
NavHost(
128-
navController = navController,
129-
startDestination = Home.route,
130-
modifier = Modifier.weight(1f),
131-
) {
132-
composable(Home.route) {
133-
TracedNav2ComposeRoute(Home.routeName) {
134-
Nav2ComposeHomeRoute(routeSpec = Nav2RouteSpecs.home) { navigateTo(ProductList) }
127+
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
128+
Column(modifier = Modifier.fillMaxSize()) {
129+
NavHost(
130+
navController = navController,
131+
startDestination = Home.route,
132+
modifier = Modifier.weight(1f),
133+
) {
134+
composable(Home.route) {
135+
TracedNav2ComposeRoute(Home.routeName) {
136+
Nav2ComposeHomeRoute(routeSpec = Nav2RouteSpecs.home) { navigateTo(ProductList) }
137+
}
135138
}
136-
}
137139

138-
composable(ProductList.route) {
139-
TracedNav2ComposeRoute(ProductList.routeName) {
140-
Nav2ComposeProductListRoute(
141-
routeSpec = Nav2RouteSpecs.productList,
142-
onOpenProduct42 = {
143-
navigateTo(
144-
ProductDetail(
145-
productId = "42",
146-
source = "product-list",
147-
campaign = "summer-sale",
140+
composable(ProductList.route) {
141+
TracedNav2ComposeRoute(ProductList.routeName) {
142+
Nav2ComposeProductListRoute(
143+
routeSpec = Nav2RouteSpecs.productList,
144+
onOpenProduct42 = {
145+
navigateTo(
146+
ProductDetail(
147+
productId = "42",
148+
source = "product-list",
149+
campaign = "summer-sale",
150+
)
148151
)
149-
)
150-
},
151-
onOpenProduct7 = {
152-
navigateTo(ProductDetail(productId = "7", source = "product-list"))
153-
},
154-
)
152+
},
153+
onOpenProduct7 = {
154+
navigateTo(ProductDetail(productId = "7", source = "product-list"))
155+
},
156+
)
157+
}
155158
}
156-
}
157159

158-
composable(
159-
route = Nav2ComposeDestination.PRODUCT_DETAIL_ROUTE,
160-
arguments =
161-
listOf(
162-
navArgument(Nav2Args.PRODUCT_ID) { type = NavType.StringType },
163-
navArgument(Nav2Args.SOURCE) { type = NavType.StringType },
164-
navArgument(Nav2Args.CAMPAIGN) {
165-
type = NavType.StringType
166-
defaultValue = ""
167-
},
168-
),
169-
) { entry ->
170-
val productId = entry.arguments?.getString(Nav2Args.PRODUCT_ID).orEmpty()
171-
val source = entry.arguments?.getString(Nav2Args.SOURCE).orEmpty()
172-
val campaign = entry.arguments?.getString(Nav2Args.CAMPAIGN).orEmpty()
173-
TracedNav2ComposeRoute(Nav2RouteNames.PRODUCT_DETAIL) {
174-
Nav2ComposeProductDetailRoute(
175-
routeSpec = Nav2RouteSpecs.productDetail,
176-
productId = productId,
177-
source = source,
178-
campaign = campaign,
179-
onShowPromoDialog = {
180-
navigateTo(PromoDialog("detail-$productId"))
181-
},
182-
onOpenShareSheet = { openShareSheet(productId) },
183-
onCheckout = { navigateTo(Checkout(productId)) },
184-
)
160+
composable(
161+
route = Nav2ComposeDestination.PRODUCT_DETAIL_ROUTE,
162+
arguments =
163+
listOf(
164+
navArgument(Nav2Args.PRODUCT_ID) { type = NavType.StringType },
165+
navArgument(Nav2Args.SOURCE) { type = NavType.StringType },
166+
navArgument(Nav2Args.CAMPAIGN) {
167+
type = NavType.StringType
168+
defaultValue = ""
169+
},
170+
),
171+
) { entry ->
172+
val productId = entry.arguments?.getString(Nav2Args.PRODUCT_ID).orEmpty()
173+
val source = entry.arguments?.getString(Nav2Args.SOURCE).orEmpty()
174+
val campaign = entry.arguments?.getString(Nav2Args.CAMPAIGN).orEmpty()
175+
TracedNav2ComposeRoute(Nav2RouteNames.PRODUCT_DETAIL) {
176+
Nav2ComposeProductDetailRoute(
177+
routeSpec = Nav2RouteSpecs.productDetail,
178+
productId = productId,
179+
source = source,
180+
campaign = campaign,
181+
onShowPromoDialog = {
182+
navigateTo(PromoDialog("detail-$productId"))
183+
},
184+
onOpenShareSheet = { openShareSheet(productId) },
185+
onCheckout = { navigateTo(Checkout(productId)) },
186+
)
187+
}
185188
}
186-
}
187189

188-
composable(
189-
route = Nav2ComposeDestination.CHECKOUT_ROUTE,
190-
arguments = listOf(navArgument(Nav2Args.PRODUCT_ID) { type = NavType.StringType }),
191-
) { entry ->
192-
val productId = entry.arguments?.getString(Nav2Args.PRODUCT_ID).orEmpty()
193-
TracedNav2ComposeRoute(Nav2RouteNames.CHECKOUT) {
194-
Nav2ComposeCheckoutRoute(
195-
routeSpec = Nav2RouteSpecs.checkout,
196-
productId = productId,
197-
onCompleteOrder = {
198-
navigateTo(Confirmation(orderId = "order-$productId"))
199-
},
200-
)
190+
composable(
191+
route = Nav2ComposeDestination.CHECKOUT_ROUTE,
192+
arguments = listOf(navArgument(Nav2Args.PRODUCT_ID) { type = NavType.StringType }),
193+
) { entry ->
194+
val productId = entry.arguments?.getString(Nav2Args.PRODUCT_ID).orEmpty()
195+
TracedNav2ComposeRoute(Nav2RouteNames.CHECKOUT) {
196+
Nav2ComposeCheckoutRoute(
197+
routeSpec = Nav2RouteSpecs.checkout,
198+
productId = productId,
199+
onCompleteOrder = {
200+
navigateTo(Confirmation(orderId = "order-$productId"))
201+
},
202+
)
203+
}
201204
}
202-
}
203205

204-
composable(
205-
route = Nav2ComposeDestination.CONFIRMATION_ROUTE,
206-
arguments = listOf(navArgument(Nav2Args.ORDER_ID) { type = NavType.StringType }),
207-
) { entry ->
208-
TracedNav2ComposeRoute(Nav2RouteNames.CONFIRMATION) {
209-
Nav2ComposeConfirmationRoute(
210-
routeSpec = Nav2RouteSpecs.confirmation,
211-
orderId = entry.arguments?.getString(Nav2Args.ORDER_ID).orEmpty(),
212-
onResetBackStack = { resetToHome() },
213-
)
206+
composable(
207+
route = Nav2ComposeDestination.CONFIRMATION_ROUTE,
208+
arguments = listOf(navArgument(Nav2Args.ORDER_ID) { type = NavType.StringType }),
209+
) { entry ->
210+
TracedNav2ComposeRoute(Nav2RouteNames.CONFIRMATION) {
211+
Nav2ComposeConfirmationRoute(
212+
routeSpec = Nav2RouteSpecs.confirmation,
213+
orderId = entry.arguments?.getString(Nav2Args.ORDER_ID).orEmpty(),
214+
onResetBackStack = { resetToHome() },
215+
)
216+
}
214217
}
215-
}
216218

217-
dialog(
218-
route = Nav2ComposeDestination.PROMO_DIALOG_ROUTE,
219-
arguments = listOf(navArgument(Nav2Args.PROMO_ID) { type = NavType.StringType }),
220-
) { entry ->
221-
// This dialog is a real Nav destination, so it participates in Nav2 the same way as the
222-
// rest of the route graph. Compare it with the share sheet overlay below when inspecting
223-
// Sentry's Nav2 breadcrumbs, destination arguments, and route transactions.
224-
TracedNav2ComposeRoute(Nav2RouteNames.PROMO_DIALOG) {
225-
Nav2ComposePromoDialogRoute(
226-
routeSpec = Nav2RouteSpecs.promoDialog,
227-
promoId = entry.arguments?.getString(Nav2Args.PROMO_ID).orEmpty(),
228-
onCaptureException = onCaptureException,
229-
onCrashApp = onCrashApp,
230-
onDismiss = { navigateBack() },
231-
)
219+
dialog(
220+
route = Nav2ComposeDestination.PROMO_DIALOG_ROUTE,
221+
arguments = listOf(navArgument(Nav2Args.PROMO_ID) { type = NavType.StringType }),
222+
) { entry ->
223+
// This dialog is a real Nav destination, so it participates in Nav2 the same way as the
224+
// rest of the route graph. Compare it with the share sheet overlay below when inspecting
225+
// Sentry's Nav2 breadcrumbs, destination arguments, and route transactions.
226+
TracedNav2ComposeRoute(Nav2RouteNames.PROMO_DIALOG) {
227+
Nav2ComposePromoDialogRoute(
228+
routeSpec = Nav2RouteSpecs.promoDialog,
229+
promoId = entry.arguments?.getString(Nav2Args.PROMO_ID).orEmpty(),
230+
onCaptureException = onCaptureException,
231+
onCrashApp = onCrashApp,
232+
onDismiss = { navigateBack() },
233+
)
234+
}
232235
}
233236
}
234-
}
235237

236-
shareSheetProductId.value?.let { productId ->
237-
// This share sheet is intentionally just a screen overlay, not a Nav destination. It lets
238-
// the sample compare how Sentry's Nav2 integration behaves for proper Nav destinations vs.
239-
// UI layered on top of the current route.
240-
Nav2ComposeShareSheetRoute(
241-
routeSpec = Nav2RouteSpecs.shareSheet,
242-
productId = productId,
243-
onCaptureException = onCaptureException,
244-
onCrashApp = onCrashApp,
245-
onDone = ::dismissShareSheet,
246-
)
238+
shareSheetProductId.value?.let { productId ->
239+
// This share sheet is intentionally just a screen overlay, not a Nav destination. It lets
240+
// the sample compare how Sentry's Nav2 integration behaves for proper Nav destinations vs.
241+
// UI layered on top of the current route.
242+
Nav2ComposeShareSheetRoute(
243+
routeSpec = Nav2RouteSpecs.shareSheet,
244+
productId = productId,
245+
onCaptureException = onCaptureException,
246+
onCrashApp = onCrashApp,
247+
onDone = ::dismissShareSheet,
248+
)
249+
}
247250
}
248251
}
249252
}
@@ -528,30 +531,33 @@ private fun Nav2ComposeRouteScaffold(
528531
cardContent: (@Composable ColumnScope.() -> Unit)? = null,
529532
content: (@Composable ColumnScope.() -> Unit)? = null,
530533
) {
531-
Column(
532-
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(16.dp),
533-
verticalArrangement = Arrangement.spacedBy(12.dp),
534-
) {
535-
Text(
536-
routeSpec.title,
537-
style = MaterialTheme.typography.headlineMedium,
538-
fontWeight = FontWeight.Bold,
539-
)
540-
routeSpec.description?.let { Text(it, style = MaterialTheme.typography.bodyMedium) }
541-
if (cardContent != null) {
542-
Card(
543-
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
544-
modifier = Modifier.fillMaxWidth(),
545-
) {
546-
Column(
547-
modifier = Modifier.padding(16.dp),
548-
verticalArrangement = Arrangement.spacedBy(8.dp),
534+
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
535+
Column(
536+
modifier = Modifier.verticalScroll(rememberScrollState()).padding(16.dp),
537+
verticalArrangement = Arrangement.spacedBy(12.dp),
538+
) {
539+
Text(
540+
routeSpec.title,
541+
style = MaterialTheme.typography.headlineMedium,
542+
fontWeight = FontWeight.Bold,
543+
)
544+
routeSpec.description?.let { Text(it, style = MaterialTheme.typography.bodyMedium) }
545+
if (cardContent != null) {
546+
Card(
547+
colors =
548+
CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
549+
modifier = Modifier.fillMaxWidth(),
549550
) {
550-
cardContent()
551+
Column(
552+
modifier = Modifier.padding(16.dp),
553+
verticalArrangement = Arrangement.spacedBy(8.dp),
554+
) {
555+
cardContent()
556+
}
551557
}
552558
}
559+
content?.invoke(this)
553560
}
554-
content?.invoke(this)
555561
}
556562
}
557563

@@ -599,16 +605,19 @@ private const val PRODUCT_LIST_ITEM_COUNT = 20
599605

600606
@Composable
601607
private fun Nav2ComposeRouteInfo(label: String, value: String) {
602-
Row(
603-
modifier =
604-
Modifier.fillMaxWidth()
605-
.background(MaterialTheme.colorScheme.surface, RoundedCornerShape(8.dp))
606-
.padding(12.dp),
607-
horizontalArrangement = Arrangement.SpaceBetween,
608+
Surface(
609+
color = MaterialTheme.colorScheme.surface,
610+
shape = RoundedCornerShape(8.dp),
611+
modifier = Modifier.fillMaxWidth(),
608612
) {
609-
Text(label, fontWeight = FontWeight.Bold)
610-
Spacer(Modifier.size(12.dp))
611-
Text(value, maxLines = 1, overflow = TextOverflow.Ellipsis)
613+
Row(
614+
modifier = Modifier.padding(12.dp),
615+
horizontalArrangement = Arrangement.SpaceBetween,
616+
) {
617+
Text(label, fontWeight = FontWeight.Bold)
618+
Spacer(Modifier.size(12.dp))
619+
Text(value, maxLines = 1, overflow = TextOverflow.Ellipsis)
620+
}
612621
}
613622
}
614623

0 commit comments

Comments
 (0)