I am learning flutter_bloc
and did the timer example at https://bloclibrary.dev/#/fluttertimertutorial?id=flutter-timer-tutorial
However the timer always resets to 60 seconds, so I wanted to the ability to set a custom initial duration.
My approach:
initialDuration
to TimerState and all subclass constructorsTimerNewDuration
event to timer_event.dartemit
lines in each state handler:constructor: super(TimerInitial(_defaultDuration)) # i.e. 60 seconds
_onNewDuration: emit(TimerInitial(event.duration))
_onStarted: emit(TimerRunInProgress(event.duration, state.initialDuration))
_onReset: emit(TimerInitial(state.initialDuration))
_onPaused: emit(TimerRunPause(state.duration, state.initialDuration))
_onTicked: emit(event.duration > 0
? TimerRunInProgress(event.duration, state.initialDuration)
: TimerRunComplete(state.initialDuration));
...and so on. However, this is a bit cumbersome: the timer state and the initial duration are not really related (except updating initial duration should reset the timer) and so I have to pass this value through every event handler in the BLoC.
If more state values are added, this would obviously get very messy.
Is there a more idiomatic way to handle this situation? Any github examples would be appreciated.
You could use one state with copyWith(...) method:
import 'package:equatable/equatable.dart';
class TimerState extends Equatable {
const TimerState({
this.isPause = false,
this.isInProgress = false,
this.isComplete = false,
this.duration = 0,
});
final bool isPause;
final bool isInProgress;
final bool isComplete;
final int duration;
@override
List<Object?> get props => [isPause, isInProgress, isComplete, duration];
TimerState copyWith({
bool? isPause,
bool? isInProgress,
bool? isComplete,
int? duration,
}) {
return TimerState(
isPause: isPause ?? this.isPause,
isInProgress: isInProgress ?? this.isInProgress,
isComplete: isComplete ?? this.isComplete,
duration: duration ?? this.duration,
);
}
}
then your code will be something like:
constructor: super(TimerState(duration: _defaultDuration)) # i.e. 60 seconds
_onNewDuration: emit(state.copyWith(duration: event.duration))
_onStarted: emit(state.copyWith(isInProgress: true, isPaused: false))
_onReset: emit(TimerState(duration: _defaultDuration))
_onPaused: emit(state.copyWith(isPaused: true, isInProgress: false))
_onTicked: emit(state.copyWith(isCompleted: event.duration > 0);
p.s. TimerState could be sealed and for state complete could be used state:
final class TimerRunComplete extends TimerState {
const TimerRunComplete();
}