I'm new to flutter and very new to riverpod. I've just been helped with some code to use a countdown clock that can then be viewed on multiple pages using Riverpod. here is the Riverpod State Notifier.
final countDownControllerProvider = StateNotifierProvider.family
.autoDispose<CountdownController, Duration, Duration>(
(ref, initialDuration) {
return CountdownController(initialDuration);
});
class CountdownController extends StateNotifier<Duration> {
Timer? timer;
final Duration initialDuration;
CountdownController(this.initialDuration) : super(initialDuration) {
stopTimer();
}
void startTimer() {
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (state == Duration.zero) {
timer.cancel();
} else {
if (mounted) {
state = state - const Duration(seconds: 1);
} else {
timer.cancel();
}
}
});
}
}
Currently, the input for the time to display on the countdown clock is inputted when you call CountdownController. (the class with startTimer function inside it). the problem I'm having is if I want to call startTimer(), I need to reinput the time to display which is a problem if I'm stopping and starting the clock.
how would I move the time input from a parameter of the CountdownController class, into a function inside the class that I can then call on when needed so I don't have to set it when starting/stopping the clock? and what would that code look like?
thanks so much
I didn't test it. If you need to save duration to state, consider making the state a data class.
EDIT: tested.
import 'dart:math';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
runApp(const ProviderScope(child: App()));
}
final countDownControllerProvider =
StateNotifierProvider.autoDispose<CountdownController, Timer?>((ref) {
return CountdownController(ref);
});
final counterProvider = StateProvider((_) => 0);
final intervalProvider = StateProvider((_) => Duration(seconds: 1));
class CountdownController extends StateNotifier<Timer?> {
CountdownController(this.ref) : super(null);
final Ref ref;
void startTimer() {
state?.cancel();
state = Timer.periodic(ref.read(intervalProvider), (timer) {
ref.read(counterProvider.notifier).state++;
});
}
void stopTimer() {
state?.cancel();
}
void accelerate(double multiplier) {
final duration = ref.read(intervalProvider);
ref.read(intervalProvider.notifier).state = Duration(
milliseconds: (duration.inMilliseconds * (1 / multiplier)).floor(),
);
startTimer();
}
void speedUp() {
accelerate(sqrt2);
}
void speedDown() {
accelerate(1 / sqrt2);
}
}
class App extends ConsumerWidget {
const App();
@override
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider);
final controller = ref.watch(countDownControllerProvider.notifier);
final timer = ref.watch(countDownControllerProvider);
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Text("$counter", style: Theme.of(context).textTheme.headlineLarge),
SizedBox(height: 24),
Row(children: [
SizedBox(width: 24),
Expanded(
child: ElevatedButton(
onPressed: controller.startTimer,
child: Text(timer == null ? "start" : "stop"),
),
),
SizedBox(width: 24),
Expanded(
child: ElevatedButton(
onPressed: controller.speedUp,
child: Text("+"),
),
),
SizedBox(width: 24),
Expanded(
child: ElevatedButton(
onPressed: controller.speedDown,
child: Text("-"),
),
),
SizedBox(width: 24),
]),
]),
),
),
);
}
}