Skip to main content

adaptive_nav 0.12.0 copy "adaptive_nav: ^0.12.0" to clipboard
adaptive_nav: ^0.12.0 copied to clipboard

A Navigator 2.0 router that renders one navigation state as a stack or as master-detail panes and keeps screen state across resizes and folds. Ready for iPhone Duo.

example/lib/main.dart

import 'package:adaptive_nav/adaptive_nav.dart';
import 'package:flutter/material.dart';

import 'data.dart';
import 'routes.dart';
import 'screens.dart';
import 'sections.dart';

/// Branches after People and Settings, in order.
const List<(String, IconData, String)> _sections = <(String, IconData, String)>[
  ('teams', Icons.groups_outlined, 'Teams'),
  ('starred', Icons.star_outline, 'Starred'),
  ('recent', Icons.history, 'Recent'),
  ('archive', Icons.inventory_2_outlined, 'Archive'),
  ('trash', Icons.delete_outline, 'Trash'),
];

void main() => runApp(const ExampleApp());

class ExampleApp extends StatefulWidget {
  const ExampleApp({super.key});

  @override
  State<ExampleApp> createState() => _ExampleAppState();
}

class _ExampleAppState extends State<ExampleApp> {
  final PeopleStore _store = PeopleStore();

  /// Stands in for real storage.
  final Map<Object, double> _savedFractions = <Object, double>{};

  /// Pane widths the user dragged, kept per branch. `onCommit` fires on release
  /// rather than on every drag frame; an app reading storage asynchronously
  /// would seed the controller later with `restore` instead of `initial`.
  late final PaneSplitController _paneSplit = PaneSplitController(
    initial: _savedFractions,
    onCommit: (Object branchId, double fraction) =>
        _savedFractions[branchId] = fraction,
  );

  late final AdaptiveShellConfig<AppRoute> _shellConfig =
      AdaptiveShellConfig<AppRoute>(
        branches: <BranchConfig<AppRoute>>[
          BranchConfig<AppRoute>(
            id: 'people',
            icon: Icons.people_outline,
            label: 'People',
            // With a master-detail config the branch splits into two panes
            // once the window is wide enough; below that it is a plain stack.
            //
            // The minimums are what "wide enough" means, and they are picked
            // for the narrowest display this demo wants two panes on: the
            // inner screen of an iPhone Duo in portrait. It is 669 points
            // across and keeps horizontal bars, so no rail takes a share and
            // the panes get all 669 — still under the package's own defaults
            // of 320 + 360, which are a desktop's.
            //
            // They also keep the outer display a single stack, which is what
            // Apple asks for: the widest it ever offers is 489.
            //
            // The boundary starts on the window centre — the hinge, on a Duo.
            masterDetail: const MasterDetailConfig(
              masterMinWidth: 270,
              detailMinWidth: 270,
              alignToWindowCenter: true,
            ),
            // Details fade when they swap the contents of a pane and slide
            // when they take the whole screen, decided as the animation runs.
            transition: AppTransition.adaptive,
            pageBuilder: _buildPage,
          ),
          BranchConfig<AppRoute>(
            id: 'settings',
            icon: Icons.settings_outlined,
            label: 'Settings',
            pageBuilder: _buildPage,
          ),
          // Enough sections that the rail runs out of column on a folded
          // iPhone Duo. What does not fit goes behind the menu button at the
          // end of the rail; on a desktop window they all fit and no button
          // appears.
          for (final (String id, IconData icon, String label) in _sections)
            BranchConfig<AppRoute>(
              id: id,
              icon: icon,
              label: label,
              pageBuilder: _buildPage,
            ),
        ],
        // Flush panes with no margins. Set `margin`, `gap`, `radius` and
        // `canvasColor` to get floating cards instead; margins and the gap
        // count towards the pane widths.
        //
        // The marker colour makes the draggable boundary visible. On a
        // touch screen there is no resize cursor to show it.
        panes: PaneDecoration(
          splitHandleColor: (BuildContext context) =>
              Theme.of(context).colorScheme.outline,
        ),
        paneSplit: _paneSplit,
        // Back at another tab's root returns to People.
        backToBranch: 0,
      );

  /// The rail (or bar), the master and the detail each get their own shade of
  /// the same seed colour.
  static final ThemeData _theme = () {
    final ThemeData base = ThemeData(colorSchemeSeed: Colors.indigo);
    final Color chrome = base.colorScheme.surfaceContainer;
    return base.copyWith(
      navigationRailTheme: base.navigationRailTheme.copyWith(
        backgroundColor: chrome,
      ),
      navigationBarTheme: base.navigationBarTheme.copyWith(
        backgroundColor: chrome,
      ),
    );
  }();

  late final AdaptiveRouterDelegate<AppRoute> _delegate =
      AdaptiveRouterDelegate<AppRoute>(
        shellConfig: _shellConfig,
        initialState: _initialState,
      );

  static final NavState<AppRoute> _initialState = NavState<AppRoute>(
    activeBranch: 0,
    branches: <BranchStack<AppRoute>>[
      BranchStack<AppRoute>(<NavEntry<AppRoute>>[
        NavEntry<AppRoute>(
          route: const PeopleList(),
          transition: AppTransition.platform,
        ),
      ]),
      BranchStack<AppRoute>(<NavEntry<AppRoute>>[
        NavEntry<AppRoute>(
          route: const SettingsRoute(),
          transition: AppTransition.platform,
        ),
      ]),
      for (final AppRoute root in const <AppRoute>[
        TeamsList(),
        StarredRoute(),
        NotesList(),
        ArchiveRoute(),
        TrashRoute(),
      ])
        BranchStack<AppRoute>(<NavEntry<AppRoute>>[
          NavEntry<AppRoute>(route: root, transition: AppTransition.platform),
        ]),
    ],
  );

  late final AdaptiveRouteInformationParser<AppRoute> _parser =
      AdaptiveRouteInformationParser<AppRoute>(
        codec: const AppRouteCodec(),
        baseState: _initialState,
      );

  Widget _buildPage(AppRoute route) => switch (route) {
    PeopleList() => const PeopleListScreen(),
    PersonDetail(:final int id) => PersonDetailScreen(id: id),
    PersonEdit(:final int id) => PersonEditScreen(id: id),
    SettingsRoute() => const SettingsScreen(),
    TeamsList() => const TeamsListScreen(),
    TeamDetail(:final int id) => TeamDetailScreen(id: id),
    StarredRoute() => const StarredScreen(),
    NotesList() => const NotesListScreen(),
    NoteDetail(:final int id) => NoteDetailScreen(id: id),
    ArchiveRoute() => const ArchiveScreen(),
    TrashRoute() => const TrashScreen(),
  };

  @override
  void dispose() {
    _paneSplit.dispose();
    _store.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AppScope(
      delegate: _delegate,
      store: _store,
      child: MaterialApp.router(
        title: 'adaptive_nav example',
        debugShowCheckedModeBanner: false,
        theme: _theme,
        routerDelegate: _delegate,
        routeInformationParser: _parser,
      ),
    );
  }
}
3
likes
0
points
790
downloads

Publisher

verified publishernightdevcraft.ru

Weekly Downloads

A Navigator 2.0 router that renders one navigation state as a stack or as master-detail panes and keeps screen state across resizes and folds. Ready for iPhone Duo.

Repository (GitHub)
View/report issues

Topics

#navigation #router #adaptive #master-detail #foldable

License

unknown (license)

Dependencies

flutter

More

Packages that depend on adaptive_nav