flutterdartnavigationflutter-navigation

How to automatically switch pages in Flutter when a timer ends?


I'm building a Pomodoro timer in Flutter and want to automatically navigate to a different page when the timer completes. Here's my current setup:

Images:

StartPomodoro Page

enter image description here

Desired 'StartShortBreak' Page

enter image description here

Code:

so, if time is over in StartPomodoro I want to switch it to StartShortBreak automatically

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

  @override
  State<StartPomodoro> createState() => _StartPomodoro();
}

class _StartPomodoro extends State<StartPomodoro>
    with TickerProviderStateMixin {
  late AnimationController controller;

  String get countText {
    Duration count = controller.duration! * controller.value;
    return controller.isDismissed
        ? '${controller.duration!.inHours.toString().padLeft(2, '0')}:${(controller.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(controller.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
        : '${count.inHours.toString().padLeft(2, '0')}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
  }

  double progress = 1.0;
  bool Pomodoro = false;

  void notify() {
    if (countText == '00:00:00') {
      FlutterRingtonePlayer.playNotification();
    }
  }


  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: Duration(seconds: 10),
    );

    controller.addListener(() {
      notify();
      if (controller.isAnimating) {
        setState(() {
          progress = controller.value;
        });
      } else {
        setState(() {
          progress = 1.0;
          Pomodoro = false;
        });
      }
    });
  }

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

  @override
  Widget build(BuildContext context) {
    ThemeData themeData = Theme.of(context);
    return Scaffold(
      backgroundColor:  Color(0xffF2B749),
      body: GestureDetector(
        onTap: () {
          if (controller.isDismissed) {
            showModalBottomSheet(
              context: context,
              builder: (context) => Container(
                height: 300,
                child: CupertinoTimerPicker(
                  initialTimerDuration: controller.duration!,
                  onTimerDurationChanged: (time) {
                    setState(() {
                      controller.duration = time;
                    });
                  },
                ),
              ),
            );
          }
        },
        child: AnimatedBuilder(
            animation: controller,
            builder: (context, child) {
              return Stack(
                children: <Widget>[
                  Align(
                    alignment: Alignment.bottomCenter,
                    child: Container(
                      color: Color(0xffD94530),
                      height:
                      controller.value * MediaQuery.of(context).size.height,
                    ),
                  ),
                  Padding(
                    padding: EdgeInsets.all(8.0),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Expanded(
                          child: Align(
                            alignment: Alignment.bottomCenter,
                            child:
                            Align(
                              alignment: FractionalOffset.bottomCenter,
                              child: Column(
                                mainAxisAlignment: MainAxisAlignment.end,
                                crossAxisAlignment: CrossAxisAlignment.center,
                                children: <Widget>[
                                  Text(
                                    Pomodoro? "Time to work" : "Time to work",
                                    style: TextStyle(
                                        fontSize: 30,
                                        color: Colors.white
                                    ),
                                  ),
                                  Text(
                                    countText,
                                    style: TextStyle(
                                      fontSize: 90.0,
                                      color: Color(0xffF2F2F2),),
                                  ),
                                ],
                              ),
                            ),
                          ),
                        ),

                        SingleChildScrollView(
                          scrollDirection: Axis.horizontal,
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            crossAxisAlignment: CrossAxisAlignment.center,
                            children: [
                              AnimatedBuilder(
                                  animation: controller,
                                  builder: (context, child) {
                                    return Padding(
                                      padding: EdgeInsets.symmetric(vertical: 2.0, horizontal: 15.0),
                                      child: FloatingActionButton.extended(
                                          backgroundColor: Color(0xffF2F2F2),
                                          onPressed: () {
                                            setState ((){
                                              Pomodoro? "POMODORO" : "POMODORO";
                                            });
                                            if (controller.isAnimating)
                                              controller.stop();
                                            else {
                                              controller.reverse(
                                                  from: controller.value == 0.0
                                                      ? 1.0
                                                      : controller.value);
                                            }
                                          },
                                          icon: Icon(
                                            controller.isAnimating
                                                ? Icons.work_history
                                                : Icons.emoji_food_beverage,

                                            color: Color(0xff3B3B3B),),

                                          label: Text(
                                            controller.isAnimating
                                                ? "POMODORO"
                                                : "POMODORO",

                                            style: TextStyle(color: Color(0xff3B3B3B)),)),

                                    );
                                  }),
                            ],
                          ),
                        ),
                        SizedBox(height: 10,),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          crossAxisAlignment: CrossAxisAlignment.center,
                          children: [
                            AnimatedBuilder(
                                animation: controller,
                                builder: (context, child) {
                                  return Padding(
                                    padding: EdgeInsets.symmetric(vertical: 2.0, horizontal: 15.0),
                                    child: FloatingActionButton.extended(
                                          backgroundColor: Color(0xffF2F2F2),
                                          onPressed: () {
                                            if (controller.isAnimating) {
                                              controller.stop();
                                              setState(() {
                                                Pomodoro = false;
                                              });
                                            } else {
                                              controller.reverse(
                                                  from: controller.value == 0 ? 1.0 : controller.value);
                                              setState(() {
                                                Pomodoro = true;
                                              });
                                            }
                                          },
                                          icon: Icon(
                                            controller.isAnimating
                                                ? Icons.play_arrow
                                                : Icons.pause,
                                            color: Color(0xff3B3B3B),),

                                          label: Text(
                                            controller.isAnimating ? "PLAY" :"PAUSE",
                                            style: TextStyle(color: Color(0xff3B3B3B)),)),
                                  );
                                }),
                            SizedBox(width: 20,),
                            AnimatedBuilder(
                                animation: controller,
                                builder: (context, child) {
                                  return SingleChildScrollView(
                                      scrollDirection: Axis.horizontal,
                                      child: Row(
                                        children: [
                                          Padding(
                                            padding: const EdgeInsets.fromLTRB(48.0, 2.0, 3.0, 4.0),
                                            child: FloatingActionButton.extended(
                                              backgroundColor: Color(0xffF2F2F2),
                                              onPressed: () {
                                                if (controller.isAnimating)
                                                  controller.reset();
                                                else (controller.isAnimating);
                                                controller.reset();
                                              },
                                              icon: Icon(Icons.refresh,
                                                color: Color(0xff3B3B3B),),
                                              label: Text("RESTART",
                                                style: TextStyle(color:Color(0xff3B3B3B)),),),
                                          ),
                                        ],
                                      ),
                                    );
                                }),
                          ],
                        )
                      ],
                    ),
                  ),
                ],
              );
            }),
      ),
    );
  }
}

StartShortBreak.dart

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

  @override
  State<StartShortBreak> createState() => _StartShortBreak();
}

class _StartShortBreak extends State<StartShortBreak>
    with TickerProviderStateMixin {
  late AnimationController controller;

  String get countText {
    Duration count = controller.duration! * controller.value;
    return controller.isDismissed
        ? '${controller.duration!.inHours.toString().padLeft(2, '0')}:${(controller.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(controller.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
        : '${count.inHours.toString().padLeft(2, '0')}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
  }

  double progress = 1.0;
  bool ShortBreak = false;

  void notify() {
    if (countText == '00:00:00') {
      FlutterRingtonePlayer.playNotification();
    }
  }

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: Duration(seconds: 10),
    );

    controller.addListener(() {
      notify();
      if (controller.isAnimating) {
        setState(() {
          progress = controller.value;
        });
      } else {
        setState(() {
          progress = 1.0;
          ShortBreak = false;
        });
      }
    });
  }

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

  @override
  Widget build(BuildContext context) {
    ThemeData themeData = Theme.of(context);
    return Scaffold(
      backgroundColor:  Color(0xffD94530),
      body: GestureDetector(
        onTap: () {
          if (controller.isDismissed) {
            showModalBottomSheet(
              context: context,
              builder: (context) => Container(
                height: 300,
                child: CupertinoTimerPicker(
                  initialTimerDuration: controller.duration!,
                  onTimerDurationChanged: (time) {
                    setState(() {
                      controller.duration = time;
                    });
                  },
                ),
              ),
            );
          }
        },
        child: AnimatedBuilder(
            animation: controller,
            builder: (context, child) {
              return Stack(
                children: <Widget>[
                  Align(
                    alignment: Alignment.bottomCenter,
                    child: Container(
                      color: Color(0xffF2B749),
                      height:
                      controller.value * MediaQuery.of(context).size.height,
                    ),
                  ),
                  Padding(
                    padding: EdgeInsets.all(8.0),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Expanded(
                          child: Align(
                            alignment: Alignment.bottomCenter,
                            child:
                            Align(
                              alignment: FractionalOffset.bottomCenter,
                              child: Column(
                                mainAxisAlignment: MainAxisAlignment.end,
                                crossAxisAlignment: CrossAxisAlignment.center,
                                children: <Widget>[
                                  Text(
                                    ShortBreak? "Short Break" : "Short Break",
                                    style: TextStyle(
                                        fontSize: 30,
                                        color: Colors.white
                                    ),
                                  ),
                                  Text(
                                    countText,
                                    style: TextStyle(
                                      fontSize: 90.0,
                                      color: Color(0xffF2F2F2),),
                                  ),
                                ],
                              ),
                            ),
                          ),
                        ),

                        SingleChildScrollView(
                          scrollDirection: Axis.horizontal,
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            crossAxisAlignment: CrossAxisAlignment.center,
                            children: [
                              AnimatedBuilder(
                                  animation: controller,
                                  builder: (context, child) {
                                    return Padding(
                                      padding: EdgeInsets.symmetric(vertical: 2.0, horizontal: 15.0),
                                      child: FloatingActionButton.extended(
                                          backgroundColor: Color(0xffF2F2F2),
                                          onPressed: () {
                                            setState ((){
                                              ShortBreak? "Short Break" : "Short Break";
                                            });
                                            if (controller.isAnimating)
                                              controller.stop();
                                            else {
                                              controller.reverse(
                                                  from: controller.value == 0.0
                                                      ? 1.0
                                                      : controller.value);
                                            }
                                          },
                                          icon: Icon(
                                            controller.isAnimating
                                                ? Icons.emoji_food_beverage
                                                : Icons.emoji_food_beverage,

                                            color: Color(0xff3B3B3B),),

                                          label: Text(
                                            controller.isAnimating
                                                ? "Short Break"
                                                : "Short Break",

                                            style: TextStyle(color: Color(0xff3B3B3B)),)),

                                    );
                                  }),
                            ],
                          ),
                        ),
                        SizedBox(height: 10,),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          crossAxisAlignment: CrossAxisAlignment.center,
                          children: [
                            AnimatedBuilder(
                                animation: controller,
                                builder: (context, child) {
                                  return Padding(
                                    padding: EdgeInsets.symmetric(vertical: 2.0, horizontal: 15.0),
                                    child: FloatingActionButton.extended(
                                        backgroundColor: Color(0xffF2F2F2),
                                        onPressed: () {
                                          if (controller.isAnimating) {
                                            controller.stop();
                                            setState(() {
                                              ShortBreak = false;
                                            });
                                          } else {
                                            controller.reverse(
                                                from: controller.value == 0 ? 1.0 : controller.value);
                                            setState(() {
                                              ShortBreak = true;
                                            });
                                          }
                                        },
                                        icon: Icon(
                                          controller.isAnimating
                                              ? Icons.play_arrow
                                              : Icons.pause,
                                          color: Color(0xff3B3B3B),),

                                        label: Text(
                                          controller.isAnimating ? "PLAY" :"PAUSE",
                                          style: TextStyle(color: Color(0xff3B3B3B)),)),
                                  );
                                }),
                            SizedBox(width: 20,),
                            AnimatedBuilder(
                                animation: controller,
                                builder: (context, child) {
                                  return SingleChildScrollView(
                                    scrollDirection: Axis.horizontal,
                                    child: Row(
                                      children: [
                                        Padding(
                                          padding: const EdgeInsets.fromLTRB(48.0, 2.0, 3.0, 4.0),
                                          child: FloatingActionButton.extended(
                                            backgroundColor: Color(0xffF2F2F2),
                                            onPressed: () {
                                              if (controller.isAnimating)
                                                controller.reset();
                                              else (controller.isAnimating);
                                              controller.reset();
                                            },
                                            icon: Icon(Icons.refresh,
                                              color: Color(0xff3B3B3B),),
                                            label: Text("RESTART",
                                              style: TextStyle(color:Color(0xff3B3B3B)),),),
                                        ),
                                      ],
                                    ),
                                  );
                                }),
                          ],
                        )
                      ],
                    ),
                  ),
                ],
              );
            }),
      ),
    );
  }
}

What I've Tried:

Specific Request:

Could you please guide me on how to:

  1. Detect when the timer in StartPomodoro reaches zero.
  2. Automatically navigate from StartPomodoro to StartShortBreak upon timer completion.

Solution

  • void notify() {
        if (countText == '00:00:00') {
          FlutterRingtonePlayer.playNotification();
          Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=> 
     StartShortBreak()));
    });
        }
      }
    

    You have a notify method which is triggered when the time is 0. You can add navigator in that method