Изучение

Как запрос навигации доходит до Flutter

Пять сущностей одного рабочего перехода, места их создания и минимальная зависимость функционального кода.

v1.1.0Начальный уровень

Как запрос навигации доходит до Flutter

Страница каталога открывает Product и ожидает результат покупки:

dart
final NavigationTicket<bool> ticket = context.readNavigation.push<bool>(
  const ProductDestination('keyboard-42'),
);

В переходе участвуют пять сущностей. В обычном UI-коде нужны только Destination и NavigationPort.

СущностьНазначениеГде создаётся
ProductDestinationПараметры и ожидаемый результат переходаФункциональный код
productRouteСтраница и URI для DestinationНавигационный модуль функциональности
NavigationGraphКомпозиция Route, Module, Scope и политикКорень приложения
NavigationSessionСтеки и объекты Flutter Router одного окнаКорневой StatefulWidget
NavigationPortКонкретные операции над стекомИз BuildContext или через DI

Что происходит после push

Ark Navigation:

  1. находит Route Definition для ProductDestination;
  2. определяет Module, Mount и Navigator Scope;
  3. применяет Redirect;
  4. проверяет Guard для выхода (leave) и входа (enter);
  5. фиксирует новый Snapshot одним изменением;
  6. передаёт страницы Flutter Router;
  7. завершает ticket.committed;
  8. завершает ticket.completed, когда Product будет закрыт или удалён.

Защищённая страница не попадает в стек до завершения политик.

Где хранить Session

dart
final class AppHostState extends State<AppHost> {
  late final NavigationSession navigation = NavigationSession(
    id: const NavigationSessionId('main-window'),
    graph: createAppGraph(),
  );

  @override
  Widget build(BuildContext context) => MaterialApp.router(
    routerConfig: navigation.routerConfig,
  );

  @override
  void dispose() {
    navigation.dispose();
    super.dispose();
  }
}

Не создавайте Session в build(): при перестроении потеряются ключи Navigator, история, стеки и ожидающие результата Ticket.

Зависимость Presenter или сервиса

Передайте NavigationPort, а не BuildContext:

dart
final class CheckoutPresenter {
  CheckoutPresenter(this.navigation);
  final NavigationPort navigation;

  void showReceipt(String orderId) {
    navigation.replaceTop<void>(ReceiptDestination(orderId));
  }
}

Конкретный NavigationController нужен только инфраструктуре: восстановлению, диагностике и обновлению Graph.