felangel / flow_builder

Flutter Flows made easy! A Flutter package which simplifies navigation flows with a flexible, declarative API.
https://pub.dev/packages/flow_builder
MIT License
395 stars 65 forks source link

Add a way to prevent popping the first page of the FlowBuilder #44

Closed bselwe closed 3 years ago

bselwe commented 3 years ago

Is your feature request related to a problem? Please describe.

Currently, the only way to show a back button on the first page of the FlowBuilder is to manually add it to the app bar as described here. In that case, WillPopScope included on the same page will not trigger after using either the app bar or Android back button. Similarly, neither didPop nor didRemove will be triggered when using a navigator observer passed to the FlowBuilder. This means that there is no easy way to observe and prevent popping the first page of the FlowBuilder.

An example could be an onboarding page (as the first page of the FlowBuilder) where the Android back button should swipe back to the previous onboarding screen (but not pop the page). The problem does not occur if the onboarding page is the second page of the FlowBuilder with an app bar that uses a default back button - in that case WillPopScope can prevent the navigation back.

Describe the solution you'd like It would be nice to have a similar structure as WillPopScope. I am not sure though about this solution, it could result in an incorrect navigation stack when onPopPage returns false after the flow being updated.

FlowBuilder(
  state: const FlowState(),
  onGeneratePages: (state, pages) {...},
  onComplete: (state) {...},
  onPopPage: (state, page) async {
    return shouldPop;
  }
)

Describe alternatives you've considered

FlowBuilder(
  state: const FlowState(),
  onGeneratePages: (state, pages) => [
    PageA.page(),
    ...
  ],
);
class PageA extends StatelessWidget {
  static Page page() => MaterialPage<void>(child: PageA());

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        /// This will not trigger when either the app bar or Android back button is pressed.
        return false;
      },
      child: Scaffold(
        backgroundColor: Colors.yellow,
        appBar: AppBar(
          leading: BackButton(
            onPressed: () => context.flow<FlowState>().complete(),
          ),
          title: const Text('Page A'),
        ),
      ),
    );
  }
}

Additional context None