I'm experiencing an issue with the CircularCountDownTimer widget in my Flutter application. The animation displaying the countdown appears to run significantly faster than real-time only on certain devices, such as devices running MagicOS 6. On emulators, the timer functions correctly.
Run the application on a device running MagicOS 6 (or the device exhibiting the issue).
Start the CircularCountDownTimer.
Observe the countdown animation. It will be noticeably faster than a real-time second.
Expected Behavior:
The CircularCountDownTimer animation should accurately reflect real-time passage, with each second in the animation corresponding to one actual second.
The countdown animation runs faster than real-time.
class TimerPage extends StatefulWidget {
const TimerPage({super.key});
@override
TimerPageState createState() => TimerPageState();
}
class TimerPageState extends State<TimerPage> {
final CountDownController _controller = CountDownController();
bool isPause = true;
bool isStarted = false;
bool isBreakTime = false;
String currentTask = '';
int _getCurrentDuration(SettingsProvider settings) {
return (isBreakTime ? settings.breakDuration : settings.focusDuration).toInt() * 60;
}
String _timeFormatter(
Function(Duration) defaultFormatter,
Duration duration) {
if (duration.inMinutes >= 60) {
return '${duration.inHours.toString().padLeft(2,'0')}:'
'${(duration.inMinutes%60).toString().padLeft(2,'0')}:'
'${(duration.inSeconds%60).toString().padLeft(2,'0')}';
} else {
return '${duration.inMinutes.toString().padLeft(2,'0')}:'
'${(duration.inSeconds%60).toString().padLeft(2,'0')}';
}
}
@override
Widget build(BuildContext context) {
return Consumer<SettingsProvider>(
builder: (context, settings, child) {
final theme = Theme.of(context);
final iconColor = theme.textTheme.bodyMedium!.color;
return Center(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: TextFormField(
style: TextStyle(color: theme.textTheme.bodyMedium!.color),
decoration: InputDecoration(
labelText: 'Input Task',
border: OutlineInputBorder(),
),
onChanged: (value) {
setState(() {
currentTask = value;
});
},
),
),
CircularCountDownTimer(
duration: _getCurrentDuration(settings),
controller: _controller,
width: MediaQuery.of(context).size.width / 2,
height: MediaQuery.of(context).size.height / 2,
ringColor: theme.cardColor,
fillColor: Colors.transparent,
fillGradient: LinearGradient(
colors: [theme.colorScheme.primary, theme.colorScheme.secondary],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
backgroundColor: theme.scaffoldBackgroundColor,
strokeWidth: 20.0,
strokeCap: StrokeCap.round,
textStyle: TextStyle(
fontSize: 33.0,
color: theme.textTheme.bodyMedium!.color,
fontWeight: FontWeight.bold,
),
isReverse: true,
isReverseAnimation: false,
isTimerTextShown: true,
autoStart: false,
timeFormatterFunction: _timeFormatter,
onStart: () {
debugPrint('Countdown Started');
},
onComplete: () {
_handleTimerComplete();
},
onChange: (String timeStamp) {
debugPrint('Countdown Changed $timeStamp');
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Column(
children: [
Text(
isBreakTime ? "Break" : "Focus",
style: TextStyle(
fontSize: 20,
color: theme.textTheme.bodyMedium!.color,
),
),
if (currentTask.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
currentTask,
style: TextStyle(
fontSize: 16,
color: theme.textTheme.bodyMedium!.color?.withOpacity(0.7),
),
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
color: iconColor,
onPressed: _handlePlayPause,
icon: Icon(isPause ? Icons.play_arrow : Icons.pause),
),
IconButton(
color: iconColor,
onPressed: _handleReset,
icon: Icon(Icons.restart_alt),
),
IconButton(
color: iconColor,
onPressed: _handleSkip,
icon: Icon(Icons.skip_next),
)
],
)
],
),
);
},
);
}
void _switchToNextPhase() {
final settings = Provider.of<SettingsProvider>(context, listen: false);
setState(() {
isBreakTime = !isBreakTime;
isStarted = true;
isPause = false;
});
WidgetsBinding.instance.addPostFrameCallback((_) {
_controller.restart(duration: _getCurrentDuration(settings));
});
}
void _handleTimerComplete() {
debugPrint('Timer Complete');
_switchToNextPhase();
}
void _handlePlayPause() {
setState(() {
if (!isStarted) {
_controller.start();
isStarted = true;
isPause = false;
return;
}
if (isPause) {
_controller.resume();
} else {
_controller.pause();
}
isPause = !isPause;
});
}
void _handleReset() {
setState(() {
isPause = true;
isStarted = false;
});
final settings = Provider.of<SettingsProvider>(context, listen: false);
WidgetsBinding.instance.addPostFrameCallback((_) {
_controller.restart(duration: _getCurrentDuration(settings));
_controller.pause();
});
}
void _handleSkip() {
_switchToNextPhase();
}
}
I'm experiencing an issue with the CircularCountDownTimer widget in my Flutter application. The animation displaying the countdown appears to run significantly faster than real-time only on certain devices, such as devices running MagicOS 6. On emulators, the timer functions correctly.
Steps to Reproduce:
Run the application on a device running MagicOS 6 (or the device exhibiting the issue).
Start the CircularCountDownTimer.
Observe the countdown animation. It will be noticeably faster than a real-time second.
Expected Behavior:
The CircularCountDownTimer animation should accurately reflect real-time passage, with each second in the animation corresponding to one actual second.
Actual Behavior:
The countdown animation runs faster than real-time.
Here is my code: