How to update timer in BottomModalSheet

Viewed 200

I have a floating action button in my scaffold and I am starting a timer when that button is pressed and also it opens the BottomModalSheet by using showModalBottomSheet() function but the timer is not updating in the BottomSheet

Code Example:

// Bottom sheet timer
  Duration duration = Duration();
  Timer? timer;

  // Start timer method
  void startTimer() {
    print("timer start");
    timer = Timer.periodic(Duration(seconds: 1), (_) => addTime());
  }

  void addTime() {
    final addSeconds = 1;

    setState(() {
      final seconds = duration.inSeconds + addSeconds;
      duration = Duration(seconds: seconds);
    });
  }
@override
  Widget build(BuildContext context) {
    if (isProfileLoaded) {
      return Scaffold(
        key: _scaffoldKey,
        backgroundColor: CassettColors.gray,
        extendBodyBehindAppBar: true,
        floatingActionButton: FloatingActionButton.large(
          onPressed: () {
            startTimer();
            showModalBottomSheet(
                context: context,
                builder: (context) {
                  return StatefulBuilder(builder: (BuildContext context,
                      StateSetter setState /*You can rename this!*/) {
                    return buildSheet(duration);
                  });
                });
          },
          child: Text(
            "Start",
            style: GoogleFonts.openSans(
              textStyle: TextStyle(
                  color: CassettColors.text100,
                  fontSize: 16,
                  fontWeight: FontWeight.w600),
            ),
          ),
          backgroundColor: CassettColors.primaryRed,
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
  }
1 Answers

one way of doing that without using a state management solution: You can save the setState of the bottom sheet in a variable

  late Function sheetSetState;

 return StatefulBuilder(builder: (BuildContext context,
                  StateSetter setState /*You can rename this!*/) {
                     //now we can use setState anywhere
                     sheetSetState = setState 

                return buildSheet(duration);
              });

then instead of changing the state of the parent widget we change the state of the sheet

void addTime() {
    final addSeconds = 1;

    //setState(() {
     // final seconds = duration.inSeconds + addSeconds;
    //  duration = Duration(seconds: seconds);
   // });

     sheetSetState(() {
        final seconds = duration.inSeconds + addSeconds;
        duration = Duration(seconds: seconds);
      });
    
  }

but you will be facing setState called after dispose error when closing the sheet because there is no longer state

and we can avoid that by checking if the sheet is open or not using a simple boolean

  bool isSheetOpen = false;

full code:

// Bottom sheet timer
  Duration duration = Duration();
  Timer? timer;

  //to check if sheet is open
  bool isSheetOpen = false;
  //to access setState of sheet
  late Function sheetSetState;

  // Start timer method
  void startTimer() {
 //Not related to the answer but you should consider resetting the timer when it starts
         timer?.cancel();
         duration = duration = Duration();

    print("timer start");
    timer = Timer.periodic(Duration(seconds: 1), (_) => addTime());
  }

  void addTime() {
    final addSeconds = 1;

    //if sheet is open call setState if not don't
    if(isSheetOpen){
      sheetSetState(() {
        final seconds = duration.inSeconds + addSeconds;
        duration = Duration(seconds: seconds);
      });
    }
    else{
      final seconds = duration.inSeconds + addSeconds;
      duration = Duration(seconds: seconds);
    }


}


@override
  Widget build(BuildContext context) {
    if (isProfileLoaded) {
      return Scaffold(
        key: _scaffoldKey,
        backgroundColor: CassettColors.gray,
        extendBodyBehindAppBar: true,
        floatingActionButton: FloatingActionButton.large(
          onPressed: () {
            //sheet is opend
            isSheetOpen = true;
            startTimer();
            showModalBottomSheet(
                context: context,
                builder: (context) {
                  return StatefulBuilder(builder: (BuildContext context,
                      StateSetter setState /*You can rename this!*/) {
                        sheetSetState = setState;
                    return buildSheet(duration);
                  });
                }).then((value){
              //SHEET IS CLOSED
             isSheetOpen = false;

      });
          },
          child: Text(
            "Start",
            style: GoogleFonts.openSans(
              textStyle: TextStyle(
                  color: CassettColors.text100,
                  fontSize: 16,
                  fontWeight: FontWeight.w600),
            ),
          ),
          backgroundColor: CassettColors.primaryRed,
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
  }
Related