Home > Mobile >  How to change value of timer on gesture tap?
How to change value of timer on gesture tap?

Time:09-29

So I ran into another problem with my timer.

I have a sized box, and when I tap on it I would want the timer to change the value from 5 minutes to 15 minutes (Or best, when I tap the first time it will increase from 5 minutes > 10 minutes on the second tap 15 minutes on the third tap to 20 minutes and on fourth to 25 minutes) For this to happen the timer should be not active(The user can only change it when the timer is not running) -- But I'm running into the problem of "Undefined name 'isRunning'." from my final in another widget

Here is my code (Also side question, currently the timer only displays seconds, how can I make it display the actual 5 minutes as in 5:00)

class timeryypage extends State<timerry> {
  static const maxSeconds = 5;
  int seconds = maxSeconds;
  Timer? timer;

  void resetTimer() => setState(() => seconds = maxSeconds);

  void startTimer({bool reset = true}) {
    if (reset) {
      resetTimer();
    }
    timer = Timer.periodic(Duration(seconds: 1), (_) {
      //add here instead seconds say minutes/miliseconds
      if (!mounted) // Putting this line of code with return under, fixed my issue i been having about mounted
        return;
      else if (seconds > 0) {
        setState(() => seconds--);
      } else {
        stopTimer(reset: false);
      }
    });
  }

  void stopTimer({bool reset = true}) {
    if (reset == mounted) {
      resetTimer();
    }
    setState(() => timer?.cancel());
  }

  @override
  Widget buildButtons() {
    final isRunning = timer == null ? false : timer!.isActive;
    final isCompleted = seconds == maxSeconds || seconds == 0;
    return isRunning || !isCompleted
        ? Row(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              ButtonWidget(
                text: isRunning ? "Pause" : "Resume",
                onClicked: () {
                  if (isRunning) {
                    stopTimer(reset: false);
                  } else {
                    startTimer(reset: false);
                  }
                },
              ),
              const SizedBox(width: 12),
              ButtonWidget(text: "Cancel", onClicked: stopTimer)
            ],
          )
        : ButtonWidget(
            text: "Start Timer!",
            color: Colors.black,
            backgroundColor: Colors.white,
            onClicked: () {
              startTimer();
            },
          );
  }

  Widget buildTimer() => SizedBox(
        width: 200,
        height: 200,
        child: Stack(
          fit: StackFit.expand,
          children: [
            CircularProgressIndicator(
              value: seconds / maxSeconds,
              //if you delete 1 - then it goes to other direction
              valueColor: AlwaysStoppedAnimation(Colors.white),
              strokeWidth: 12,
              backgroundColor: Colors.greenAccent,
            ),
            GestureDetector(
              behavior: HitTestBehavior.opaque,
              onTap: () {
                if (isRunning) {
                  print("do nothing");
                } else {
                  const snackBar = SnackBar(content: Text('Tap'));
                  ScaffoldMessenger.of(context).showSnackBar(snackBar);
                  print("tapped");
                  // later on i want to change timer from 5 minutes 10 minutes on first tap, then second tap to 15 minutes
                }
              },
              child: Center(child: buildTime()),
            ),
            //Center(child: buildTime()),
          ],
        ),
      );

  Widget buildTime() {
    if (seconds == 0) {
      return Icon(Icons.done, color: Colors.greenAccent, size: 112);
    } else {
      return Text(
        "$seconds",
        style: TextStyle(
          fontWeight: FontWeight.bold,
          color: Colors.white,
          fontSize: 80,
        ),
      );
    }
  }

Thank you so much for help!

Edit Adding extra code :

bool get isRunning => _timer?.isActive ?? false;
  int _seconds = 00;
  int _minutes = setminutes;
  static const setminutes = 25;
  Timer? _timer;
  var f = NumberFormat("00");

  void _stopTimer({bool reset = true}) {
    if (reset == true) {
      resetTimer();
    }
    setState(() => _timer?.cancel());
    ;
  }

  void resetTimer() => setState(() => _minutes = setminutes);

  void _startTimer({bool reset = true}) {
    if (reset) {
      resetTimer();
    }
    if (_timer != null) {
      _stopTimer();
    }
    if (_minutes > 0) {
      _seconds = _minutes * 60;
    }
    if (_seconds > 60) {
      _minutes = (_seconds / 60).floor();
      _seconds -= (_minutes * 60);
    }
    _timer = Timer.periodic(Duration(seconds: 1), (_) {
      if (!mounted)
        return;
      else if (_seconds > 0) {
        setState(() => _seconds--);
      }

      setState(() {
        if (_seconds > 0) {
          _seconds--;
        } else {
          if (_minutes > 0) {
            _seconds = 59;
            _minutes--;
          } else {
            _stopTimer(reset: false);
          }
        }
      });
    });
  }

  @override
  Widget buildButtons() {
    //final isRunning = timer == null ? false : timer!.isActive;
    final isCompleted = _minutes == setminutes || _seconds == 0;
    return isRunning || !isCompleted
        ? Row(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              ButtonWidget(
                text: isRunning ? "Pause" : "Resume",
                onClicked: () {
                  if (isRunning) {
                    _stopTimer(reset: false);
                  } else {
                    _startTimer(reset: false);
                  }
                },
              ),
              const SizedBox(width: 12),
              ButtonWidget(
                  text: "Cancel",
                  onClicked: () {
                    _stopTimer(reset: true);
                  })
            ],
          )
        : ButtonWidget(
            text: "Start Timer!",
            color: Colors.black,
            backgroundColor: Colors.white,
            onClicked: () {
              _startTimer();
            },
          );
  }

CodePudding user response:

Your buildTime function creates a Text widget from the number of seconds. If you want to format it in some other way, you will need format the number of seconds to a String yourself. For example:

var minutes = seconds ~/ 60;
var remainderSeconds = seconds % 60;
return Text('$minutes:${remainderSeconds.toString().padLeft(2, '0')}',
  ...);

Also see:

  • Related