flutterdartnavigationscoped-modelmulti-page-application

Updated values get overridden on Widget redraw


I am playing around with a simple flutter countdown app. It consists of 2 pages, the clock and a settings page to set minutes and seconds to be counted down.

On the clock page (HomeWidget) the user clicks a button to navigate to the settings page. After editing the values the user presses the back hardware key or the button in the app bar to navigate back to the clock page.

class _HomeWidgetState extends State<HomeWidget> {
@override
Widget build(BuildContext context) {
  TimeService _timeService = ScopedModel.of<TimeService>(context);
  SettingsModel _settingsModel = ScopedModel.of<SettingsModel>(context);
  _timeService.setTime(_settingsModel.minutes, _settingsModel.seconds);

return Scaffold( ... display the clock, navigation buttons, etc ... )}

My problem to understand is that when navigating back I am setting the new values in the time service class that handles counting down. But in the code sample the time service is updated every time the clock gets redrawn (every second). The countdown doesn't work, the value remains the same. Instead of displaying "10:29", it sticks with "10:30". I don't know how to handle the dependency between my TimeService class and my SettingsModel class.

How can I handle the assignment of the settings values in the time service class properly when the user navigates back? The build method is obviously the wrong place. Can anyone give me a hint?


Solution

  • Ok, I found a solution for my problem. It is described in detail (with some other content) here.

    Basically when navigating between pages you can pass objects along. So now I just pass the edited SettingsModel on the settings page via a Navigator.of(context).pop({'newSetting': _settingsModel}); command and the clock page then handles the result. I wasn't aware that navigation works like this.

    ControlButtonWidget(
            icon: Icons.settings,
            iconSize: 72.0,
            onPressedHandler: () async {
              Map results = await Navigator.of(context).push(
                  new MaterialPageRoute(
                      builder: (context) => SettingsWidget(model)));
    
              if (results != null && results.containsKey("newSetting")){
                SettingsModel model = results["newSetting"];
                ScopedModel.of<TimeService>(context).setTime(model.minutes, model.seconds);
              }
            })
    

    Make sure to wrap your page in a WillPopScope Widget.

    @override
    Widget build(BuildContext context) {
    return new WillPopScope(
        onWillPop: _backRequestedHandler,
        child: LayoutBuilder(builder:
            (BuildContext context, BoxConstraints viewportConstraints) {
          return Scaffold(
              appBar: new AppBar(title: Text("Settings")),
              body: ...
    
        }));
    }
    
    Future<bool> _backRequestedHandler() {
      Navigator.of(context).pop({'newSetting': _settingsModel});
      return new Future.value(true);
    }