Skip to content

Commit 1e006b7

Browse files
0xadam-browncodex
andcommitted
ref(android): Split Nav3 fragment scenarios into tabs in the Nav3 sample
Give fragment replacement, dialog overlays, and ViewPager2 pages separate entry points while preserving their test paths. Remove unused placeholders and place Custom before Performance. Co-Authored-By: Codex <noreply@openai.com>
1 parent 244b092 commit 1e006b7

4 files changed

Lines changed: 140 additions & 101 deletions

File tree

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

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,16 @@ private fun Nav3SampleApp(
352352
}
353353
}
354354

355+
val openFragmentScenario: (Nav3FragmentMode) -> Unit = { mode ->
356+
activity?.let { host ->
357+
host.startActivity(
358+
Intent(host, Nav3FragmentsActivity::class.java)
359+
.putExtra(Nav3FragmentsActivity.EXTRA_MODE, mode.name)
360+
.putExtras(Bundle().apply { putNav3SampleConfiguration(configuration) })
361+
)
362+
}
363+
}
364+
355365
Scaffold(
356366
// Expose test tags as resource IDs so adb/uiautomator can target them.
357367
modifier =
@@ -472,12 +482,19 @@ private fun Nav3SampleApp(
472482
entry<Nav3Route.MultiFragment> { route ->
473483
TracedNav3Route(route, selectedScenario) {
474484
Nav3RouteWorkEffect(route, routeWorkOptions)
475-
MultiFragmentRoute {
476-
activity?.startActivity(
477-
Intent(activity, Nav3FragmentsActivity::class.java)
478-
.putExtras(Bundle().apply { putNav3SampleConfiguration(configuration) })
479-
)
480-
}
485+
FragmentScenarioRoute(route, Nav3FragmentMode.REPLACE, openFragmentScenario)
486+
}
487+
}
488+
entry<Nav3Route.FragmentOverlay> { route ->
489+
TracedNav3Route(route, selectedScenario) {
490+
Nav3RouteWorkEffect(route, routeWorkOptions)
491+
FragmentScenarioRoute(route, Nav3FragmentMode.DIALOG, openFragmentScenario)
492+
}
493+
}
494+
entry<Nav3Route.ViewPager2> { route ->
495+
TracedNav3Route(route, selectedScenario) {
496+
Nav3RouteWorkEffect(route, routeWorkOptions)
497+
FragmentScenarioRoute(route, Nav3FragmentMode.PAGER, openFragmentScenario)
481498
}
482499
}
483500
entry<Nav3Route.Landing> { route ->
@@ -550,18 +567,6 @@ private fun Nav3SampleApp(
550567
}
551568
}
552569

553-
entry<Nav3Route.Multipane> { route ->
554-
TracedNav3Route(route, selectedScenario) {
555-
Nav3RouteWorkEffect(route, routeWorkOptions)
556-
FutureRoute(routeName = "Multipane", scenario = "multipane")
557-
}
558-
}
559-
entry<Nav3Route.Multistack> { route ->
560-
TracedNav3Route(route, selectedScenario) {
561-
Nav3RouteWorkEffect(route, routeWorkOptions)
562-
FutureRoute(routeName = "Multiple Stacks", scenario = "multistack")
563-
}
564-
}
565570
entry<Nav3Route.Performance> { route ->
566571
TracedNav3Route(route, selectedScenario) {
567572
Nav3RouteWorkEffect(route, routeWorkOptions)

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

Lines changed: 73 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import android.view.LayoutInflater
55
import android.view.View
66
import android.view.ViewGroup
77
import android.widget.LinearLayout
8-
import androidx.activity.ComponentActivity
98
import androidx.compose.foundation.layout.Arrangement
109
import androidx.compose.foundation.layout.Column
1110
import androidx.compose.foundation.layout.Row
@@ -41,14 +40,15 @@ import androidx.fragment.app.Fragment
4140
import androidx.fragment.app.FragmentActivity
4241
import androidx.fragment.app.FragmentContainerView
4342
import androidx.fragment.app.commit
43+
import androidx.fragment.app.commitNow
4444
import androidx.viewpager2.adapter.FragmentStateAdapter
4545
import androidx.viewpager2.widget.ViewPager2
4646
import io.sentry.samples.android.R
4747
import io.sentry.samples.android.navigation.common.NavigationSampleConfig
4848

4949
/**
5050
* Hosts Fragments that each own a Nav3 root (back stack, `SentryNavEffect`, and `NavDisplay`), to
51-
* exercise how separate effects hand off during Fragment transactions:
51+
* exercise how separate effects hand off in three independently selectable scenarios:
5252
*
5353
* - `replace` + back stack (Products → Checkout), optionally with a slow enter animation;
5454
* - a full-screen `DialogFragment` overlay whose host Fragment stays resumed;
@@ -58,6 +58,15 @@ import io.sentry.samples.android.navigation.common.NavigationSampleConfig
5858
// the NavigationEventDispatcherOwner that NavDisplay needs on the view tree.
5959
class Nav3FragmentsActivity : FragmentActivity() {
6060

61+
internal val mode: Nav3FragmentMode
62+
get() =
63+
Nav3FragmentMode.entries.firstOrNull { it.name == intent.getStringExtra(EXTRA_MODE) }
64+
?: Nav3FragmentMode.REPLACE
65+
66+
internal companion object {
67+
const val EXTRA_MODE = "io.sentry.samples.android.navigation.nav3.FRAGMENT_MODE"
68+
}
69+
6170
/** When true, Fragment `replace` uses a slow enter animation. */
6271
internal var slowTransitions by mutableStateOf(false)
6372

@@ -76,10 +85,9 @@ class Nav3FragmentsActivity : FragmentActivity() {
7685
setContent {
7786
Nav3SampleTheme {
7887
MultiFragmentControls(
88+
mode = mode,
7989
slowTransitions = slowTransitions,
8090
onSlowTransitionsChanged = { slowTransitions = it },
81-
onOpenCheckoutSheet = ::openCheckoutSheet,
82-
onOpenPager = ::openPager,
8391
)
8492
}
8593
}
@@ -101,9 +109,22 @@ class Nav3FragmentsActivity : FragmentActivity() {
101109
)
102110

103111
if (savedInstanceState == null) {
104-
supportFragmentManager.commit {
105-
setReorderingAllowed(true)
106-
add(R.id.nav3_multi_fragment_container, Nav3RootFragment.products())
112+
if (mode == Nav3FragmentMode.REPLACE) {
113+
supportFragmentManager.commit {
114+
setReorderingAllowed(true)
115+
add(R.id.nav3_multi_fragment_container, Nav3RootFragment.products())
116+
}
117+
} else {
118+
// Keep Products beneath the overlay or pager for dismissal and Back handoffs.
119+
supportFragmentManager.commitNow {
120+
setReorderingAllowed(true)
121+
add(R.id.nav3_multi_fragment_container, Nav3RootFragment.products())
122+
}
123+
if (mode == Nav3FragmentMode.DIALOG) {
124+
openCheckoutSheet()
125+
} else {
126+
openPager()
127+
}
107128
}
108129
}
109130
}
@@ -153,6 +174,12 @@ class Nav3FragmentsActivity : FragmentActivity() {
153174
}
154175
}
155176

177+
internal enum class Nav3FragmentMode(val scenario: Nav3Scenario) {
178+
REPLACE(Nav3Scenario.MULTI_FRAGMENT),
179+
DIALOG(Nav3Scenario.FRAGMENT_OVERLAY),
180+
PAGER(Nav3Scenario.VIEW_PAGER2),
181+
}
182+
156183
/** A Fragment that owns one Nav3 root. Pager pages are child Fragments of [Nav3PagerFragment]. */
157184
class Nav3RootFragment : Fragment() {
158185

@@ -170,7 +197,8 @@ class Nav3RootFragment : Fragment() {
170197
KIND_PAGE -> pageRoots[args.getInt(ARG_PAGE)]
171198
else -> Nav3Route.ProductList
172199
}
173-
val opensCheckoutFragment = args.getString(ARG_KIND) == KIND_PRODUCTS
200+
val opensCheckoutFragment =
201+
args.getString(ARG_KIND) == KIND_PRODUCTS && activity.mode == Nav3FragmentMode.REPLACE
174202

175203
return nav3RootComposeView(
176204
activity = activity,
@@ -233,6 +261,7 @@ class Nav3CheckoutSheetFragment : DialogFragment() {
233261
return nav3RootComposeView(
234262
activity = activity,
235263
host = "CheckoutSheet",
264+
title = "Checkout dialog",
236265
initialRoute = Nav3Route.Checkout("42"),
237266
configuration = activity.configuration,
238267
onFinish = ::dismiss,
@@ -307,23 +336,36 @@ class Nav3PagerFragment : Fragment() {
307336
}
308337

309338
@Composable
310-
internal fun MultiFragmentRoute(onOpenFragments: () -> Unit) {
339+
internal fun FragmentScenarioRoute(
340+
route: Nav3Route,
341+
mode: Nav3FragmentMode,
342+
onOpenFragments: (Nav3FragmentMode) -> Unit,
343+
) {
311344
RouteScaffold(
312-
routeSpec = Nav3Route.MultiFragment.routeSpec(),
313-
testTagPrefix = nav3TestTag("route_multi_fragment"),
345+
routeSpec = route.routeSpec(),
346+
testTagPrefix = nav3TestTag("route_${mode.name.lowercase()}_fragments"),
314347
cardContent = {
315348
RouteButton(
316-
"Open fragments Activity",
317-
onClick = onOpenFragments,
318-
testTag = nav3TestTag("multi_fragment_open_fragments"),
349+
when (mode) {
350+
Nav3FragmentMode.REPLACE -> "Open Products Fragment"
351+
Nav3FragmentMode.DIALOG -> "Open Checkout dialog"
352+
Nav3FragmentMode.PAGER -> "Open ViewPager2"
353+
},
354+
onClick = { onOpenFragments(mode) },
355+
testTag =
356+
nav3TestTag(
357+
if (mode == Nav3FragmentMode.REPLACE) "multi_fragment_open_fragments"
358+
else "${mode.name.lowercase()}_open_fragments"
359+
),
319360
)
320361
},
321362
)
322363
}
323364

324365
private fun Fragment.nav3RootComposeView(
325-
activity: ComponentActivity,
366+
activity: Nav3FragmentsActivity,
326367
host: String,
368+
title: String = host,
327369
initialRoute: Nav3Route,
328370
configuration: NavigationSampleConfig,
329371
onFinish: () -> Unit,
@@ -338,9 +380,9 @@ private fun Fragment.nav3RootComposeView(
338380
CompositionLocalProvider(LocalNav3SampleHost provides host) {
339381
MultiRootNavDisplay(
340382
activity = activity,
341-
title = host,
383+
title = title,
342384
initialRoute = initialRoute,
343-
scenario = Nav3Scenario.MULTI_FRAGMENT,
385+
scenario = activity.mode.scenario,
344386
configuration = configuration,
345387
onFinish = onFinish,
346388
onCheckout = onCheckout,
@@ -353,38 +395,29 @@ private fun Fragment.nav3RootComposeView(
353395
@OptIn(ExperimentalComposeUiApi::class)
354396
@Composable
355397
private fun MultiFragmentControls(
398+
mode: Nav3FragmentMode,
356399
slowTransitions: Boolean,
357400
onSlowTransitionsChanged: (Boolean) -> Unit,
358-
onOpenCheckoutSheet: () -> Unit,
359-
onOpenPager: () -> Unit,
360401
) {
361402
Surface(
362403
shadowElevation = 4.dp,
363404
modifier = Modifier.statusBarsPadding().semantics { testTagsAsResourceId = true },
364405
) {
365406
Column(modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp)) {
366-
Text("Fragments Activity", style = MaterialTheme.typography.titleMedium)
367-
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
368-
OutlinedButton(
369-
onClick = onOpenCheckoutSheet,
370-
modifier = Modifier.testTag(nav3TestTag("multi_fragment_open_checkout_sheet")),
371-
) {
372-
Text("Checkout sheet")
373-
}
374-
OutlinedButton(
375-
onClick = onOpenPager,
376-
modifier = Modifier.testTag(nav3TestTag("multi_fragment_open_pager")),
377-
) {
378-
Text("Pager")
407+
Text(mode.scenario.label, style = MaterialTheme.typography.titleMedium)
408+
when (mode) {
409+
Nav3FragmentMode.REPLACE -> {
410+
Row(verticalAlignment = Alignment.CenterVertically) {
411+
Text("Slow Fragment transitions", modifier = Modifier.weight(1f))
412+
Switch(
413+
checked = slowTransitions,
414+
onCheckedChange = onSlowTransitionsChanged,
415+
modifier = Modifier.testTag(nav3TestTag("multi_fragment_slow_transitions")),
416+
)
417+
}
379418
}
380-
}
381-
Row(verticalAlignment = Alignment.CenterVertically) {
382-
Text("Slow Fragment transitions", modifier = Modifier.weight(1f))
383-
Switch(
384-
checked = slowTransitions,
385-
onCheckedChange = onSlowTransitionsChanged,
386-
modifier = Modifier.testTag(nav3TestTag("multi_fragment_slow_transitions")),
387-
)
419+
Nav3FragmentMode.DIALOG,
420+
Nav3FragmentMode.PAGER -> Unit
388421
}
389422
}
390423
}

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

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -734,21 +734,6 @@ internal fun ShareSheetRoute(
734734
}
735735
}
736736

737-
@Composable
738-
internal fun FutureRoute(routeName: String, scenario: String) {
739-
RouteScaffold(
740-
routeSpec =
741-
RouteSpecs.get(routeName)
742-
.copy(
743-
title = "$routeName: WIP",
744-
description =
745-
"Reserved for a future milestone when SentryNavEffect supports $scenario navigation " +
746-
"state.",
747-
),
748-
testTagPrefix = nav3RouteTag(routeName),
749-
)
750-
}
751-
752737
@OptIn(ExperimentalComposeUiApi::class)
753738
@Composable
754739
private fun Nav3ProductListItem(index: Int) {

0 commit comments

Comments
 (0)