mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-21 23:10:40 +00:00
synchronized timeline with actual timer
This commit is contained in:
parent
f77ef321d0
commit
7eb0ecde7f
4 changed files with 36 additions and 94 deletions
|
@ -5,75 +5,30 @@ import 'package:lightmeter/interactors/metering_interactor.dart';
|
|||
import 'package:lightmeter/screens/timer/event_timer.dart';
|
||||
import 'package:lightmeter/screens/timer/state_timer.dart';
|
||||
|
||||
const _kTimerStep = Duration(milliseconds: 1);
|
||||
|
||||
class TimerBloc extends Bloc<TimerEvent, TimerState> {
|
||||
final MeteringInteractor _meteringInteractor;
|
||||
late Timer? _timer;
|
||||
final Duration duration;
|
||||
|
||||
TimerBloc(this._meteringInteractor, this.duration)
|
||||
: super(
|
||||
TimerStoppedState(
|
||||
duration: duration,
|
||||
timeLeft: duration,
|
||||
),
|
||||
) {
|
||||
TimerBloc(this._meteringInteractor, this.duration) : super(const TimerStoppedState()) {
|
||||
on<StartTimerEvent>(_onStartTimer);
|
||||
on<SetTimeLeftEvent>(_onSetTimeLeft);
|
||||
on<StopTimerEvent>(_onStopTimer);
|
||||
on<ResetTimerEvent>(_onResetTimer);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
_timer?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
Future<void> _onStartTimer(StartTimerEvent _, Emitter emit) async {
|
||||
emit(
|
||||
TimerResumedState(
|
||||
duration: state.duration,
|
||||
timeLeft: state.timeLeft,
|
||||
),
|
||||
);
|
||||
|
||||
_timer = Timer.periodic(_kTimerStep, (_) {
|
||||
if (state.timeLeft.inMilliseconds == 0) {
|
||||
add(const StopTimerEvent());
|
||||
} else {
|
||||
add(SetTimeLeftEvent(state.timeLeft - _kTimerStep));
|
||||
}
|
||||
});
|
||||
emit(const TimerResumedState());
|
||||
}
|
||||
|
||||
Future<void> _onSetTimeLeft(SetTimeLeftEvent event, Emitter emit) async {
|
||||
emit(
|
||||
TimerResumedState(
|
||||
duration: state.duration,
|
||||
timeLeft: event.timeLeft,
|
||||
),
|
||||
);
|
||||
emit(const TimerResumedState());
|
||||
}
|
||||
|
||||
Future<void> _onStopTimer(StopTimerEvent _, Emitter emit) async {
|
||||
_timer?.cancel();
|
||||
emit(
|
||||
TimerStoppedState(
|
||||
duration: state.duration,
|
||||
timeLeft: state.timeLeft,
|
||||
),
|
||||
);
|
||||
emit(const TimerStoppedState());
|
||||
}
|
||||
|
||||
Future<void> _onResetTimer(ResetTimerEvent _, Emitter emit) async {
|
||||
_timer?.cancel();
|
||||
emit(
|
||||
TimerResetState(
|
||||
duration: state.duration,
|
||||
timeLeft: state.duration,
|
||||
),
|
||||
);
|
||||
emit(const TimerResetState());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,10 @@ class TimerFlow extends StatelessWidget {
|
|||
MeteringInteractorProvider.of(context),
|
||||
_duration,
|
||||
),
|
||||
child: TimerScreen(exposurePair: exposurePair),
|
||||
child: TimerScreen(
|
||||
exposurePair: exposurePair,
|
||||
duration: _duration,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/timer/bloc_timer.dart';
|
||||
import 'package:lightmeter/screens/timer/components/text/widget_text_timer.dart';
|
||||
import 'package:lightmeter/screens/timer/components/timeline/widget_timeline_timer.dart';
|
||||
import 'package:lightmeter/screens/timer/event_timer.dart';
|
||||
import 'package:lightmeter/screens/timer/state_timer.dart';
|
||||
import 'package:material_color_utilities/material_color_utilities.dart';
|
||||
|
||||
class TimerScreen extends StatefulWidget {
|
||||
final ExposurePair exposurePair;
|
||||
final Duration duration;
|
||||
|
||||
const TimerScreen({required this.exposurePair, super.key});
|
||||
const TimerScreen({
|
||||
required this.exposurePair,
|
||||
required this.duration,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<TimerScreen> createState() => _TimerScreenState();
|
||||
|
@ -31,11 +32,13 @@ class _TimerScreenState extends State<TimerScreen> with TickerProviderStateMixin
|
|||
void initState() {
|
||||
super.initState();
|
||||
|
||||
timelineController = AnimationController(
|
||||
vsync: this,
|
||||
duration: Duration(seconds: widget.exposurePair.shutterSpeed.value.toInt()),
|
||||
);
|
||||
timelineController = AnimationController(vsync: this, duration: widget.duration);
|
||||
timelineAnimation = Tween<double>(begin: 1, end: 0).animate(timelineController);
|
||||
timelineController.addStatusListener((status) {
|
||||
if (status == AnimationStatus.completed) {
|
||||
context.read<TimerBloc>().add(const StopTimerEvent());
|
||||
}
|
||||
});
|
||||
|
||||
startStopIconController = AnimationController(vsync: this, duration: Dimens.durationS);
|
||||
startStopIconAnimation = Tween<double>(begin: 0, end: 1).animate(startStopIconController);
|
||||
|
@ -56,7 +59,6 @@ class _TimerScreenState extends State<TimerScreen> with TickerProviderStateMixin
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO (@vodemn): split build in timer/components folder
|
||||
return BlocListener<TimerBloc, TimerState>(
|
||||
listenWhen: (previous, current) => previous.runtimeType != current.runtimeType,
|
||||
listener: (context, state) => _updateAnimations(state),
|
||||
|
@ -88,13 +90,9 @@ class _TimerScreenState extends State<TimerScreen> with TickerProviderStateMixin
|
|||
valueListenable: timelineAnimation,
|
||||
builder: (_, value, child) => TimerTimeline(
|
||||
progress: value,
|
||||
child: child!,
|
||||
),
|
||||
child: BlocBuilder<TimerBloc, TimerState>(
|
||||
buildWhen: (previous, current) => previous.timeLeft != current.timeLeft,
|
||||
builder: (_, state) => TimerText(
|
||||
timeLeft: state.timeLeft,
|
||||
duration: state.duration,
|
||||
child: TimerText(
|
||||
timeLeft: Duration(milliseconds: (widget.duration.inMilliseconds * value).toInt()),
|
||||
duration: widget.duration,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -117,13 +115,14 @@ class _TimerScreenState extends State<TimerScreen> with TickerProviderStateMixin
|
|||
child: BlocBuilder<TimerBloc, TimerState>(
|
||||
builder: (_, state) => FloatingActionButton(
|
||||
shape: state is TimerResumedState ? null : const CircleBorder(),
|
||||
onPressed: state.timeLeft.inSeconds == 0
|
||||
? null
|
||||
: () {
|
||||
final event =
|
||||
state is TimerStoppedState ? const StartTimerEvent() : const StopTimerEvent();
|
||||
context.read<TimerBloc>().add(event);
|
||||
},
|
||||
onPressed: () {
|
||||
if (timelineAnimation.value == 0) {
|
||||
return;
|
||||
}
|
||||
final event =
|
||||
state is TimerStoppedState ? const StartTimerEvent() : const StopTimerEvent();
|
||||
context.read<TimerBloc>().add(event);
|
||||
},
|
||||
child: AnimatedIcon(
|
||||
icon: AnimatedIcons.play_pause,
|
||||
progress: startStopIconAnimation,
|
||||
|
|
|
@ -2,32 +2,17 @@ import 'package:flutter/material.dart';
|
|||
|
||||
@immutable
|
||||
sealed class TimerState {
|
||||
final Duration duration;
|
||||
final Duration timeLeft;
|
||||
|
||||
const TimerState({
|
||||
required this.duration,
|
||||
required this.timeLeft,
|
||||
});
|
||||
const TimerState();
|
||||
}
|
||||
|
||||
class TimerStoppedState extends TimerState {
|
||||
const TimerStoppedState({
|
||||
required super.duration,
|
||||
required super.timeLeft,
|
||||
});
|
||||
const TimerStoppedState();
|
||||
}
|
||||
|
||||
class TimerResumedState extends TimerState {
|
||||
const TimerResumedState({
|
||||
required super.duration,
|
||||
required super.timeLeft,
|
||||
});
|
||||
const TimerResumedState();
|
||||
}
|
||||
|
||||
class TimerResetState extends TimerStoppedState {
|
||||
const TimerResetState({
|
||||
required super.duration,
|
||||
required super.timeLeft,
|
||||
});
|
||||
const TimerResetState();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue