0

I’m making a pomodoro timer app. When I go to the SettingsScreen and come back to the home screen it reset the setNum value to 0 and the done value to 0. I need to keep those previous values when I come back from the SettingsScreen. In the settings screen, If I changed Navigator.of(context).push(MaterialPageRoute() To this Navigator.of(context).pop(MaterialPageRoute() In home screen, it will keep the previous values and it won’t change setNum to 0 but then I cannot change Times from that screen. How to solve this?

Home Screen

import 'dart:async';
import 'dart:ffi';

import 'package:audioplayers/audio_cache.dart';
import 'package:flutter/material.dart';
import 'package:percent_indicator/percent_indicator.dart';
import 'package:pomodoroapp/model/menu_item.dart';
import 'package:pomodoroapp/model/pomodoro_status.dart';
import 'package:pomodoroapp/screens/report_screen.dart';
import 'package:pomodoroapp/screens/settings_screen.dart';
import 'package:pomodoroapp/utils/constants.dart';
import 'package:pomodoroapp/widget/custom_button.dart';
import 'package:pomodoroapp/widget/menu_items.dart';
import 'package:pomodoroapp/widget/progress_icons.dart';

class Home extends StatefulWidget {
//////////////////////// passed (changed) values //////////////////////
  final pomodoroTimeChanged;
  final shortBreakTimeChanged;
  final longBreakTimeChanged;

  Home(
      {Key key,
      this.pomodoroTimeChanged,
      this.shortBreakTimeChanged,
      this.longBreakTimeChanged})
      : super(key: key);

  @override
  State<Home> createState() => _HomeState(
      pomodoroTimeChanged, shortBreakTimeChanged, longBreakTimeChanged);
}

//////////////////////// main button labels ////////////////////////
const _btnTextStart = 'START';
const _btnTextResumePomodoro = 'RESUME';
const _btnTextResumeBreak = 'RESUME';
const _btnTextStartShortBreak = 'START';
const _btnTextStartLongBreak = 'START';
const _btnTextStartNewSet = 'START NEW SET';
const _btnTextPause = 'PAUSE';
const _btnTextReset = 'RESET';

@override
class _HomeState extends State<Home> {
  //////////////////////// values //////////////////////
  int pomodoroTime;
  int shortBreakTime;
  int longBreakTime;

  //////////////////////// default times //////////////////////
  int pomodoroTimeDefault = 5;
  int shortBreakTimeDefault = 2;
  int longBreakTimeDefault = 3;
  int pomodoriPerSet = 4;

  int pomodoroTimeChanged;
  int shortBreakTimeChanged;
  int longBreakTimeChanged;
  _HomeState(this.pomodoroTimeChanged, this.shortBreakTimeChanged,
      this.longBreakTimeChanged);

  static AudioCache player = AudioCache();

  int remainingTime = pomodoroTotalTime;
  String mainBtnText = _btnTextStart;
  PomodoroStatus pomodoroStatus = PomodoroStatus.pausedPomodoro;
  Timer _timer;
  int pomodoroNum = 0;
  int setNum = 0;

  //////////////////////// dispose, to avoid memory leak //////////////////////
  @override
  void dispose() {
    _cancelTimer();
    super.dispose();
  }

  /////////////////////// Update state function for changed value ///////////////////////

  _updateStatepomodoroTime() {
    setState(() {
      remainingTime = pomodoroTime;
    });
  }

  _updateStateShortBreakTime() {
    setState(() {
      remainingTime = shortBreakTime;
    });
  }

  _updateStateLongBreakTime() {
    setState(() {
      remainingTime = longBreakTime;
    });
  }

  @override
  void initState() {
    super.initState();
    player.load('bell.mp3');

    //////////////////// setting an initial value //////////////////////
    if (pomodoroTimeChanged != null) {
      pomodoroTime = pomodoroTimeChanged;
      _updateStatepomodoroTime();
    } else {
      pomodoroTime = pomodoroTimeDefault;
    }

    if (shortBreakTimeChanged != null) {
      shortBreakTime = shortBreakTimeChanged;
      //_updateStateShortBreakTime();
      _updateStatepomodoroTime();
    } else {
      shortBreakTime = shortBreakTimeDefault;
    }

    if (longBreakTimeChanged != null) {
      longBreakTime = longBreakTimeChanged;
      //_updateStateLongBreakTime();
      _updateStatepomodoroTime();
    } else {
      longBreakTime = longBreakTimeDefault;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBodyBehindAppBar: true,
      backgroundColor: Colors.grey[900],
      appBar: PreferredSize(
        preferredSize: Size.fromHeight(27.0),
        child: AppBar(
          backgroundColor: Colors.transparent,
          automaticallyImplyLeading: false,
          iconTheme: IconThemeData(color: Colors.white, size: 10.0),
          elevation: 0,
          actions: [
            PopupMenuButton<MenuItem>(
              onSelected: (item) => onSelected(context, item),
              itemBuilder: (context) =>
                  [...MenuItems.itemsFirst.map(buildItem).toList()],
            )
          ],
        ),
      ),
      body: Container(
        width: double.infinity,
        height: double.infinity,
        decoration: const BoxDecoration(
          image: DecorationImage(
            image: NetworkImage(
                'https://firebasestorage.googleapis.com/v0/b/flutterbricks-1926c.appspot.com/o/images%2Fwidgets%2F1634411682152%2FScreen%20Shot%202021-10-16%20at%203.14.09%20PM.png?alt=media&token=ec556af9-6dff-4020-a530-2b1eec58dafe'),
            fit: BoxFit.cover,
          ),
        ),
        child: Center(
          child: Column(
            children: [
              
              Expanded(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    CircularPercentIndicator(
                      radius: 220.0,
                      lineWidth: 15.0,
                      percent: _getPomodoroPercentage(),
                      circularStrokeCap: CircularStrokeCap.round,
                      center: Text(
                        _secondsToFormatedString(remainingTime),
                        style:
                            const TextStyle(fontSize: 40, color: Colors.white),
                      ),
                      progressColor: statusColor[pomodoroStatus],
                    ),
                    const SizedBox(
                      height: 12,
                    ),
                    ProgressIcons(
                      total: pomodoriPerSet,
                      done: pomodoroNum - (setNum * pomodoriPerSet),
                    ),
                    const SizedBox(
                      height: 12,
                    ),
                    Text(
                      '#$setNum',
                      style: const TextStyle(fontSize: 15, color: Colors.grey),
                    ),
                    const SizedBox(
                      height: 5,
                    ),
                    
                    Text(
                      statusDescription[pomodoroStatus],
                      style: const TextStyle(color: Colors.white),
                    ),
                    const SizedBox(
                      height: 12,
                    ),
                    const SizedBox(
                      height: 12,
                    ),
                    CustomButton(
                      onTap: _mainButtonPressed,
                      text: mainBtnText,
                    ),
                    CustomButton(
                      onTap: _resetButtonPressed,
                      text: _btnTextReset,
                    )
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }

  _secondsToFormatedString(int seconds) {
    int roundedMinutes = seconds ~/ 60;
    int remainingSeconds = seconds - (roundedMinutes * 60);
    String remainingSecondsFormated;

    if (remainingSeconds < 10) {
      remainingSecondsFormated = '0$remainingSeconds';
    } else {
      remainingSecondsFormated = remainingSeconds.toString();
    }

    return '$roundedMinutes:$remainingSecondsFormated';
  }

  _getPomodoroPercentage() {
    int totalTime;
    switch (pomodoroStatus) {
      case PomodoroStatus.runingPomodoro:
        totalTime = pomodoroTime;
        break;
      case PomodoroStatus.pausedPomodoro:
        totalTime = pomodoroTime;
        break;
      case PomodoroStatus.runningShortBreak:
        totalTime = shortBreakTime;
        break;
      case PomodoroStatus.pausedShortBreak:
        totalTime = shortBreakTime;
        break;
      case PomodoroStatus.runningLongBreak:
        totalTime = longBreakTime;
        break;
      case PomodoroStatus.pausedLongBreak:
        totalTime = longBreakTime;
        break;
      case PomodoroStatus.setFinished:
        totalTime = pomodoroTime;
        break;
    }

    double percentage = (totalTime - remainingTime) / totalTime;
    return percentage;
  }

  _mainButtonPressed() {
    switch (pomodoroStatus) {
      case PomodoroStatus.pausedPomodoro:
        _startPomodoroCountdown();
        break;

      case PomodoroStatus.runingPomodoro:
        _pausePomodoroCountdown();
        break;
      case PomodoroStatus.runningShortBreak:
        _pauseShortBreakCountdown();
        break;
      case PomodoroStatus.pausedShortBreak:
        _startShortBreak();
        break;
      case PomodoroStatus.runningLongBreak:
        _pauseLongBreakCountdown();
        break;
      case PomodoroStatus.pausedLongBreak:
        _startLongBreak();
        break;
      case PomodoroStatus.setFinished:
        setNum++;
        _startPomodoroCountdown();
        break;
    }
  }

  _startPomodoroCountdown() {
    pomodoroStatus = PomodoroStatus.runingPomodoro;
    _cancelTimer();
    if (_timer != null) {
      _timer.cancel();
    }

    _timer = Timer.periodic(
        Duration(seconds: 1),
        (timer) => {
              if (remainingTime > 0)
                {
                  setState(() {
                    remainingTime--;
                    mainBtnText = _btnTextPause;
                  })
                }
              else
                {
                  _playSound(),
                  pomodoroNum++,
                  _cancelTimer(),
                  if (pomodoroNum % pomodoriPerSet == 0)
                    {
                      pomodoroStatus = PomodoroStatus.pausedLongBreak,
                      setState(() {
                        remainingTime = longBreakTime;
                        mainBtnText = _btnTextStartLongBreak;
                      }),
                    }
                  else
                    {
                      pomodoroStatus = PomodoroStatus.pausedShortBreak,
                      setState(() {
                        remainingTime = shortBreakTime;
                        mainBtnText = _btnTextStartShortBreak;
                      }),
                    }
                }
            });
  }

  _startShortBreak() {
    pomodoroStatus = PomodoroStatus.runningShortBreak;
    setState(() {
      mainBtnText = _btnTextPause;
    });
    _cancelTimer();
    _timer = Timer.periodic(
        Duration(seconds: 1),
        (timer) => {
              if (remainingTime > 0)
                {
                  setState(() {
                    remainingTime--;
                  }),
                }
              else
                {
                  _playSound(),
                  remainingTime = pomodoroTime,
                  _cancelTimer(),
                  pomodoroStatus = PomodoroStatus.pausedPomodoro,
                  setState(() {
                    mainBtnText = _btnTextStart;
                  }),
                }
            });
  }

  _startLongBreak() {
    pomodoroStatus = PomodoroStatus.runningLongBreak;
    setState(() {
      mainBtnText = _btnTextPause;
    });
    _cancelTimer();
    _timer = Timer.periodic(
        Duration(seconds: 1),
        (timer) => {
              if (remainingTime > 0)
                {
                  setState(() {
                    remainingTime--;
                  }),
                }
              else
                {
                  _playSound(),
                  remainingTime = pomodoroTime,
                  _cancelTimer(),
                  pomodoroStatus = PomodoroStatus.setFinished,
                  setState(() {
                    mainBtnText = _btnTextStartNewSet;
                  }),
                }
            });
  }

  _pausePomodoroCountdown() {
    pomodoroStatus = PomodoroStatus.pausedPomodoro;
    _cancelTimer();
    setState(() {
      mainBtnText = _btnTextResumePomodoro;
    });
  }

  _resetButtonPressed() {
    pomodoroNum = 0;
    setNum = 0;
    _cancelTimer();
    _stopCountdown();
  }

  _stopCountdown() {
    pomodoroStatus = PomodoroStatus.pausedPomodoro;
    setState(() {
      mainBtnText = _btnTextStart;
      remainingTime = pomodoroTime;
    });
  }

  _pauseShortBreakCountdown() {
    pomodoroStatus = PomodoroStatus.pausedShortBreak;
    _pauseBreakCountdown();
  }

  _pauseLongBreakCountdown() {
    pomodoroStatus = PomodoroStatus.pausedLongBreak;
    _pauseBreakCountdown();
  }

  _pauseBreakCountdown() {
    _cancelTimer();
    setState(() {
      mainBtnText = _btnTextResumeBreak;
    });
  }

  _cancelTimer() {
    if (_timer != null) {
      _timer.cancel();
    }
  }

  _playSound() {
    player.play('bell.mp3');
  }

  PopupMenuItem<MenuItem> buildItem(MenuItem item) => PopupMenuItem<MenuItem>(
        value: item,
        child: Row(children: [
          Icon(
            item.icon,
            color: Colors.black,
            size: 20,
          ),
          const SizedBox(
            width: 12,
          ),
          Text(item.text)
        ]),
      );

  void onSelected(BuildContext context, MenuItem item) {
    switch (item) {
      case MenuItems.itemSettings:
        Navigator.of(context).push(
          MaterialPageRoute(builder: (context) => SettingsScreen()),
        );
        break;
      case MenuItems.itemReport:
        Navigator.of(context).push(
          MaterialPageRoute(builder: (context) => ReportScreen()),
        );
        break;
    }
  }
}

class PopUpMenu extends StatelessWidget {
  final List<PopupMenuEntry> menuList;
  final Widget icon;

  const PopUpMenu({Key key, this.menuList, this.icon}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return PopupMenuButton(
      itemBuilder: (context) => menuList,
      icon: icon,
    );
  }
}

Settings Screen

import 'package:flutter/material.dart';
import 'package:numberpicker/numberpicker.dart';
import 'package:pomodoroapp/screens/home_screen.dart';

class SettingsScreen extends StatefulWidget {
  const SettingsScreen({Key key}) : super(key: key);

  @override
  _SettingsScreen createState() => _SettingsScreen();
}

class _SettingsScreen extends State<SettingsScreen>
    with TickerProviderStateMixin {
  // Switch states

  int _workSessionValue = 25;
  int _shortBreakValue = 5;
  int _longBreakValue = 15;
  NumberPicker integerNumberPicker;

  ////////////////////// values to pass //////////////////////
  int pomodoroTimeToChanged;
  int shortBreakTimeToChanged;
  int longBreakTimeToChanged;

// Work Session
  _handleWorkValueChange(num value) {
    if (value != null) {
      setState(() {
        _workSessionValue = value;
      });
    }
  }

  _handleWorkValueChangedExternally(num value) {
    if (value != null) {
      setState(() {
        _workSessionValue = value;
      });
      integerNumberPicker.animateInt(value);
    }
    print('Updated pomodoro value:  $_workSessionValue ');
    pomodoroTimeToChanged = value * 60;
  }

  // Short break
  _handleShortBreakValueChange(num value) {
    if (value != null) {
      setState(() {
        _shortBreakValue = value;
      });
    }
  }

  _handleShortBreakValueChangedExternally(num value) {
    if (value != null) {
      setState(() {
        _shortBreakValue = value;
      });
      integerNumberPicker.animateInt(value);
    }
    print('Updated short break value:  $_shortBreakValue ');
    shortBreakTimeToChanged = value * 60;
  }

  // Long Break
  _handleLongBreakValueChange(num value) {
    if (value != null) {
      setState(() {
        _longBreakValue = value;
      });
    }
  }

  _handleLongBreakChangedExternally(num value) {
    if (value != null) {
      setState(() {
        _longBreakValue = value;
      });
      integerNumberPicker.animateInt(value);
    }

    print('Updated Long break value:  $_longBreakValue ');
    longBreakTimeToChanged = value * 60;
  }

  // Animation
  AnimationController animationController;

  String get timerString {
    Duration duration =
        animationController.duration * animationController.value;
    return '${duration.inMinutes.toString().padLeft(2, '0')}\n${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
  }

  @override
  void initState() {
    super.initState();
    animationController = AnimationController(
        vsync: this, duration: const Duration(seconds: 1500));
  }

  //number pick values
  @override
  Widget build(BuildContext context) {
    integerNumberPicker = NumberPicker.integer(
      initialValue: _workSessionValue,
      minValue: 1,
      maxValue: 50,
      onChanged: _handleWorkValueChange,
    );

    integerNumberPicker = NumberPicker.integer(
      initialValue: _shortBreakValue,
      minValue: 1,
      maxValue: 50,
      onChanged: _handleShortBreakValueChange,
    );

    integerNumberPicker = NumberPicker.integer(
      initialValue: _longBreakValue,
      minValue: 1,
      maxValue: 50,
      onChanged: _handleLongBreakValueChange,
    );

    //UI
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: Icon(Icons.chevron_left),
          onPressed: () => {
            Navigator.of(context).push(MaterialPageRoute(
                builder: (context) => Home(
                      pomodoroTimeChanged: pomodoroTimeToChanged,
                      shortBreakTimeChanged: shortBreakTimeToChanged,
                      longBreakTimeChanged: longBreakTimeToChanged,
                    )))
          },
        ),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                const Text("Timer",
                    textAlign: TextAlign.left,
                    style: TextStyle(
                        color: Colors.black,
                        fontSize: 32,
                        fontWeight: FontWeight.w700)),
                const Divider(
                  thickness: 2,
                  color: Colors.black26,
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      const Text(
                        "Pomodoro",
                        style: TextStyle(
                            color: Colors.black,
                            fontSize: 22,
                            fontWeight: FontWeight.w400),
                      ),
                      Row(
                        children: <Widget>[
                          Container(
                            width: 30,
                            height: 30,
                            child: RawMaterialButton(
                              shape: const CircleBorder(),
                              onPressed: _showWorkSessionDialog,
                              fillColor: Colors.amber,
                              elevation: 0,
                              child: Text(
                                "$_workSessionValue",
                                style: const TextStyle(
                                    color: Colors.white,
                                    fontSize: 18,
                                    fontWeight: FontWeight.w500),
                              ),
                            ),
                          ),
                          const Padding(
                            padding: EdgeInsets.all(5),
                            child: Text(
                              "min",
                              style: TextStyle(
                                  color: Colors.black,
                                  fontSize: 18,
                                  fontWeight: FontWeight.w500),
                            ),
                          )
                        ],
                      )
                    ],
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      const Text(
                        "Short Break",
                        style: TextStyle(
                            color: Colors.black,
                            fontSize: 22,
                            fontWeight: FontWeight.w400),
                      ),
                      Row(
                        children: <Widget>[
                          Container(
                            width: 30,
                            height: 30,
                            child: RawMaterialButton(
                              shape: CircleBorder(),
                              onPressed: _showShortBreakDialog,
                              fillColor: Colors.amber,
                              elevation: 0,
                              child: Text(
                                "$_shortBreakValue",
                                style: const TextStyle(
                                    color: Colors.white,
                                    fontSize: 18,
                                    fontWeight: FontWeight.w500),
                              ),
                            ),
                          ),
                          const Padding(
                            padding: EdgeInsets.all(5),
                            child: Text(
                              "min",
                              style: TextStyle(
                                  color: Colors.black,
                                  fontSize: 18,
                                  fontWeight: FontWeight.w500),
                            ),
                          )
                        ],
                      )
                    ],
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      const Text(
                        "Long Break",
                        style: TextStyle(
                            color: Colors.black,
                            fontSize: 22,
                            fontWeight: FontWeight.w400),
                      ),
                      Row(
                        children: <Widget>[
                          Container(
                            width: 30,
                            height: 30,
                            child: RawMaterialButton(
                              shape: CircleBorder(),
                              onPressed: _showLongBreakDialog,
                              fillColor: Colors.amber,
                              elevation: 0,
                              child: Text(
                                "$_longBreakValue",
                                style: const TextStyle(
                                    color: Colors.white,
                                    fontSize: 18,
                                    fontWeight: FontWeight.w500),
                              ),
                            ),
                          ),
                          const Padding(
                            padding: EdgeInsets.all(5),
                            child: Text(
                              "min",
                              style: TextStyle(
                                  color: Colors.black,
                                  fontSize: 18,
                                  fontWeight: FontWeight.w500),
                            ),
                          )
                        ],
                      )
                    ],
                  ),
                )
              ],
            )
          ],
        ),
      ),
    );
  }

  //dialog boxes
  _showWorkSessionDialog() {
    showDialog<int>(
      context: context,
      builder: (BuildContext context) {
        return NumberPickerDialog.integer(
          minValue: 0,
          maxValue: 50,
          initialIntegerValue: _workSessionValue,
          title: const Text("Select a minute"),
        );
      },
    ).then(_handleWorkValueChangedExternally);
  }

  _showShortBreakDialog() {
    showDialog<int>(
      context: context,
      builder: (BuildContext context) {
        return NumberPickerDialog.integer(
          minValue: 0,
          maxValue: 50,
          initialIntegerValue: _shortBreakValue,
          title: const Text("Select a minute"),
        );
      },
    ).then(_handleShortBreakValueChangedExternally);
  }

  _showLongBreakDialog() {
    showDialog<int>(
      context: context,
      builder: (BuildContext context) {
        return NumberPickerDialog.integer(
          minValue: 0,
          maxValue: 50,
          initialIntegerValue: _longBreakValue,
          title: const Text("Select a minute"),
        );
      },
    ).then(_handleLongBreakChangedExternally);
  }
}

  • There is nothing wrong that your home screen keep its values because it is not disposed when you push to your settings screen, so set setNum is not initialized again. You can still get a callback value from your settings screen to set your setNum variable to 0 – F Perroch Nov 23 '22 at 18:55
  • If I were you, I would use a state management library the easiest is Provider. `https://pub.dev/packages/provider` – Sajjad Nov 23 '22 at 19:26
  • this is another solution `Navigator.pop(context, 'returnDataAterPop');` https://stackoverflow.com/a/53861303/6813907 – Sajjad Nov 23 '22 at 19:39

0 Answers0