flow_builder icon indicating copy to clipboard operation
flow_builder copied to clipboard

Popping the last page of the flow should complete the flow

Open alestiago opened this issue 3 years ago • 1 comments

Is your feature request related to a problem? Please describe. Since using Navigator.pop() goes back in the flow, it would be nice if this remains consistent even when the flow only has one page. I would expect popping the last page to complete the flow.

Having the above functionality makes nesting FlowBuilders very convenient.

Example
import 'package:flow_builder/flow_builder.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(home: _HomeFlow()));
}

enum _HomeFlowState {
  home,
  settings,
}

class _HomeFlow extends StatelessWidget {
  const _HomeFlow({Key? key}) : super(key: key);

  static List<Page> _onGeneratePages(_HomeFlowState state, List<Page> pages) {
    switch (state) {
      case _HomeFlowState.home:
        return [_HomePage.page()];
      case _HomeFlowState.settings:
        return [_HomePage.page(), _SettingsFlow.page()];
    }
  }

  @override
  Widget build(BuildContext context) {
    return const FlowBuilder(
      state: _HomeFlowState.home,
      onGeneratePages: _onGeneratePages,
    );
  }
}

class _HomePage extends StatelessWidget {
  const _HomePage({Key? key}) : super(key: key);

  static Page<void> page() => const MaterialPage<void>(child: _HomePage());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(
            onPressed: () => context
                .flow<_HomeFlowState>()
                .update((_) => _HomeFlowState.settings),
            icon: const Icon(Icons.settings),
          ),
        ],
      ),
      body: const Center(child: Text('home')),
    );
  }
}

enum _SettingsFlowState {
  settings,
  about,
  support,
}

class _SettingsFlow extends StatelessWidget {
  const _SettingsFlow({Key? key}) : super(key: key);

  static Page<void> page() => const MaterialPage<void>(child: _SettingsFlow());

  static List<Page> _onGeneratePages(
      _SettingsFlowState state, List<Page> pages) {
    switch (state) {
      case _SettingsFlowState.settings:
        return [_SettingsPage.page()];
      case _SettingsFlowState.about:
        return [_SettingsPage.page(), _AboutPage.page()];
      case _SettingsFlowState.support:
        return [_SettingsPage.page(), _SupportPage.page()];
    }
  }

  @override
  Widget build(BuildContext context) {
    return const FlowBuilder(
      state: _SettingsFlowState.settings,
      onGeneratePages: _onGeneratePages,
    );
  }
}

class _SettingsPage extends StatelessWidget {
  const _SettingsPage({Key? key}) : super(key: key);

  static Page<void> page() => const MaterialPage<void>(child: _SettingsPage());

  @override
  Widget build(BuildContext context) {
   // Native pop should also complete the flow.
    return Scaffold(
      appBar: AppBar(
        leading: BackButton(onPressed: () => Navigator.of(context).pop()), // Should complete the flow
        title: const Text('Settings'),
      ),
      body: Center(
        child: Column(
          children: [
            TextButton(
              onPressed: () => context
                  .flow<_SettingsFlowState>()
                  .update((_) => _SettingsFlowState.about),
              child: const Text('About'),
            ),
            TextButton(
              onPressed: () => context
                  .flow<_SettingsFlowState>()
                  .update((_) => _SettingsFlowState.support),
              child: const Text('Support'),
            ),
          ],
        ),
      ),
    );
  }
}

class _AboutPage extends StatelessWidget {
  const _AboutPage({Key? key}) : super(key: key);

  static Page<void> page() => const MaterialPage<void>(child: _AboutPage());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('About')),
      body: const Center(child: Text('About')),
    );
  }
}

class _SupportPage extends StatelessWidget {
  const _SupportPage({Key? key}) : super(key: key);

  static Page<void> page() => const MaterialPage<void>(child: _SupportPage());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Support')),
      body: const Center(child: Text('Support')),
    );
  }
}

Describe the solution you'd like I would like to have some logic that makes the flow complete whenever the last page of the flow is popped.

Describe alternatives you've considered N/A

Additional context N/A

alestiago avatar Aug 26 '22 14:08 alestiago

Sorry for offtop, but what is the right way to do nested FlowBuilders?

In the example from @alestiago FlowBuilders are actually nested, but in the examples from the repository Navigator.of(context).push(...) is used to begin some flow. The last one looks like a mix of declarative and imperative approaches, which does not seem quite right.

Is there any cons to the approach that @alestiago uses?

Related:

  • https://github.com/felangel/flow_builder/issues/41#issuecomment-806478624
  • https://github.com/felangel/flow_builder/issues/98 (not sure)

anjerukare avatar May 07 '23 17:05 anjerukare