Skip to content

Commit 72bcb18

Browse files
0xadam-browncodex
andauthored
ref(android): Split Nav3 fragment scenarios into tabs in the Nav3 sample (#6372)
Give fragment replacement, dialog overlays, and ViewPager2 pages separate entry points while preserving their test paths. Remove unused placeholders and place Custom tab before Performance tab. Co-authored-by: Codex <noreply@openai.com>
1 parent 28e2389 commit 72bcb18

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)