buildContractScene function

Widget buildContractScene(
  1. SceneSpec spec, {
  2. required bool withLibrary,
  3. required Widget wrapRow(
    1. int index,
    2. Widget row
    ),
  4. Widget wrapHome(
    1. Widget home
    )?,
  5. ThemeData? theme,
  6. List<NavigatorObserver>? navigatorObservers,
  7. Widget appBuilder(
    1. BuildContext,
    2. Widget?
    )?,
})

Builds the neutral contract scene for a LibraryDriver: the AppBar + element A (FAB, increments SceneSpec.aTaps) + the ListView of 12 rows (element B at kSceneBRow) + the scroll margin, all under a MaterialApp. The consumer's driver supplies only the library-specific parts:

  • wrapRow: called once per row with the neutral row; the driver wraps the rows its solution anchors (A/B are always rows kSceneBRow and the driver's own second target). Called for every row so a driver can also replace row content if its solution needs it.
  • wrapHome: wraps the whole MaterialApp.home — for solutions that need a live context / host above the scene (e.g. tcm's context capture). Receives the neutral Scaffold.
  • navigatorObservers / appBuilder: app-level wiring some solutions need (dialog/toast hosts mount their overlay through MaterialApp's navigatorObservers/builder). Passed through verbatim; the base scene (S1) must leave them null so it does not touch the solution.

withLibrary selects the with-library vs the base scene; the base scene (S1) must not touch the solution at all, so the driver must return the neutral row/home unchanged when withLibrary is false.

Implementation

Widget buildContractScene(
  SceneSpec spec, {
  required bool withLibrary,
  required Widget Function(int index, Widget row) wrapRow,
  Widget Function(Widget home)? wrapHome,
  ThemeData? theme,
  List<NavigatorObserver>? navigatorObservers,
  Widget Function(BuildContext, Widget?)? appBuilder,
}) {
  Widget neutralRow(int index) => SizedBox(
        key: Key(sceneRowKey(index)),
        height: kSceneRowHeight,
        child: Align(
          alignment: Alignment.centerLeft,
          child: Text('Row $index'),
        ),
      );

  final list = ListView(
    key: const Key(kSceneListKey),
    controller: spec.listScroll,
    children: [
      for (var i = 0; i < kSceneRowCount; i++) wrapRow(i, neutralRow(i)),
      const SizedBox(height: kSceneScrollMargin),
    ],
  );

  final scaffold = Scaffold(
    appBar: AppBar(title: const Text('Contract scene')),
    floatingActionButton: FloatingActionButton(
      key: const Key(kSceneAKey),
      onPressed: () => spec.aTaps.value++, // S6: tap on A after hide
      child: const Icon(Icons.add),
    ),
    body: list,
  );

  return MaterialApp(
    theme: theme ??
        ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
          useMaterial3: true,
        ),
    navigatorObservers: navigatorObservers ?? const [],
    builder: appBuilder,
    home: wrapHome != null ? wrapHome(scaffold) : scaffold,
  );
}