import 'dart:async'; import 'package:flutter/material.dart'; import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/views/app_style/colors.dart'; import 'package:test_sa/views/app_style/sizing.dart'; class AppTimer extends StatefulWidget { final TimerModel timer; final Future Function(TimerModel) onChange; final TextStyle style; const AppTimer({ Key key, this.timer, this.onChange, this.style, }) : super(key: key); @override State createState() => _AppTimerState(); } class _AppTimerState extends State { Timer _timer; DateTime _startAt; DateTime _endAt; int _delay = 0; bool _running = false; bool _loading = false; final ValueNotifier _period = ValueNotifier("0:00:00"); _startTimer() async { if (!_running) { final time = DateTime.now(); bool result = await widget.onChange( TimerModel(startAt: time,endAt: null,durationInSecond: _delay)); if(!result) return; _running = true; if(_endAt != null){ _delay += _endAt.difference(_startAt).inSeconds; } _startAt = time.subtract(Duration(seconds: _delay)); _endAt = null; } _timer = Timer.periodic(const Duration(seconds: 1), (timer) { if(_loading == true) return; _period.value = (_endAt ?? DateTime.now()).difference( _startAt ).toString().split(".").first; }); } _stopTimer() async { final time = DateTime.now(); final tempStartAt = _startAt.add(Duration(seconds: _delay)); bool result = await widget.onChange( TimerModel(startAt: tempStartAt,endAt: time,durationInSecond: _delay)); if(!result) return; _running = false; _endAt = time; _startAt = tempStartAt; _timer?.cancel(); } _onPressed() async { _loading = true; setState(() {}); if(!_running){ await _startTimer(); }else{ await _stopTimer(); } _loading = false; setState(() {}); } @override void initState() { _startAt = widget.timer?.startAt; _endAt = widget.timer?.endAt; _running = _startAt != null && _endAt == null; _delay = (widget.timer?.durationInSecond ?? 0); final difference = _startAt == null ? 0: (_endAt ?? DateTime.now())?.difference(_startAt)?.inSeconds ?? 0; _period.value = Duration(seconds: _running ? difference : _delay + difference).toString().split(".").first; super.initState(); if(_running){_startTimer();} } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return SizedBox( width: 100 * AppStyle.getScaleFactor(context), height: 28 * AppStyle.getScaleFactor(context), child: ElevatedButton( style: ElevatedButton.styleFrom( minimumSize: const Size(1, 1), padding: EdgeInsets.all(4 * AppStyle.getScaleFactor(context)), backgroundColor: _running ? AColors.green[300] : AColors.grey, foregroundColor: Colors.black ), onPressed: _loading ? null : _onPressed, child: _loading ? const SizedBox.square( dimension: 18,child: CircularProgressIndicator(color: Colors.white,)): Row( children: [ Icon(_running ? Icons.pause : Icons.play_arrow), Expanded( child: Center( child: ValueListenableBuilder( valueListenable: _period, builder: (context,value,_){ return Text(value, style: widget.style, ); } ), ), ), ], ), ), ); } }