m3_lightmeter/lib/screens/timer/screen_timer.dart

145 lines
5.3 KiB
Dart
Raw Permalink Normal View History

2024-04-30 14:32:01 +00:00
import 'package:flutter/material.dart';
2024-04-30 19:50:09 +00:00
import 'package:flutter_bloc/flutter_bloc.dart';
2024-05-02 15:11:53 +00:00
import 'package:lightmeter/data/models/exposure_pair.dart';
2024-04-30 14:32:01 +00:00
import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/shared/animated_circular_button/widget_button_circular_animated.dart';
2024-05-03 09:26:00 +00:00
import 'package:lightmeter/screens/shared/bottom_controls_bar/widget_bottom_controls_bar.dart';
2024-04-30 19:50:09 +00:00
import 'package:lightmeter/screens/timer/bloc_timer.dart';
import 'package:lightmeter/screens/timer/components/metering_config/widget_metering_config_timer.dart';
2024-05-03 08:50:35 +00:00
import 'package:lightmeter/screens/timer/components/text/widget_text_timer.dart';
2024-05-02 17:24:32 +00:00
import 'package:lightmeter/screens/timer/components/timeline/widget_timeline_timer.dart';
2024-04-30 19:50:09 +00:00
import 'package:lightmeter/screens/timer/event_timer.dart';
import 'package:lightmeter/screens/timer/state_timer.dart';
2024-05-04 16:51:56 +00:00
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
2024-04-30 14:32:01 +00:00
2024-04-30 19:50:09 +00:00
class TimerScreen extends StatefulWidget {
2024-05-02 15:11:53 +00:00
final ExposurePair exposurePair;
2024-05-04 16:51:56 +00:00
final IsoValue isoValue;
final NdValue ndValue;
final Duration duration;
2024-04-30 19:57:02 +00:00
const TimerScreen({
required this.exposurePair,
2024-05-04 16:51:56 +00:00
required this.isoValue,
required this.ndValue,
required this.duration,
super.key,
});
2024-04-30 14:32:01 +00:00
2024-04-30 19:50:09 +00:00
@override
2024-05-03 11:31:18 +00:00
State<TimerScreen> createState() => TimerScreenState();
2024-04-30 19:50:09 +00:00
}
2024-05-03 11:31:18 +00:00
@visibleForTesting
class TimerScreenState extends State<TimerScreen> with TickerProviderStateMixin {
2024-04-30 19:50:09 +00:00
late AnimationController timelineController;
late Animation<double> timelineAnimation;
late AnimationController startStopIconController;
late Animation<double> startStopIconAnimation;
@override
void initState() {
super.initState();
timelineController = AnimationController(vsync: this, duration: widget.duration);
2024-04-30 19:57:02 +00:00
timelineAnimation = Tween<double>(begin: 1, end: 0).animate(timelineController);
timelineController.addStatusListener((status) {
2024-05-04 19:13:06 +00:00
if (status == AnimationStatus.completed) {
2024-05-03 10:43:45 +00:00
context.read<TimerBloc>().add(const TimerEndedEvent());
}
});
2024-04-30 19:50:09 +00:00
startStopIconController = AnimationController(vsync: this, duration: Dimens.durationS);
2024-04-30 19:57:02 +00:00
startStopIconAnimation = Tween<double>(begin: 0, end: 1).animate(startStopIconController);
2024-04-30 19:50:09 +00:00
}
@override
void dispose() {
timelineController.dispose();
startStopIconController.dispose();
super.dispose();
}
2024-04-30 14:32:01 +00:00
@override
Widget build(BuildContext context) {
2024-04-30 19:50:09 +00:00
return BlocListener<TimerBloc, TimerState>(
2024-04-30 20:45:46 +00:00
listenWhen: (previous, current) => previous.runtimeType != current.runtimeType,
2024-04-30 19:50:09 +00:00
listener: (context, state) => _updateAnimations(state),
child: Scaffold(
2024-05-04 18:14:53 +00:00
backgroundColor: Theme.of(context).colorScheme.background,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
2024-05-04 16:51:56 +00:00
TimerMeteringConfig(
exposurePair: widget.exposurePair,
isoValue: widget.isoValue,
ndValue: widget.ndValue,
),
const Spacer(),
Padding(
padding: const EdgeInsets.all(Dimens.paddingL),
child: SizedBox.fromSize(
size: Size.square(MediaQuery.sizeOf(context).width - Dimens.paddingL * 4),
child: ValueListenableBuilder(
valueListenable: timelineAnimation,
builder: (_, value, child) => TimerTimeline(
progress: value,
child: TimerText(
timeLeft: Duration(milliseconds: (widget.duration.inMilliseconds * value).toInt()),
duration: widget.duration,
2024-04-30 19:57:02 +00:00
),
2024-04-30 19:50:09 +00:00
),
),
2024-05-03 09:26:00 +00:00
),
),
const Spacer(),
BottomControlsBar(
left: IconButton(
onPressed: () {
context.read<TimerBloc>().add(const ResetTimerEvent());
},
icon: const Icon(Icons.restore),
),
center: BlocBuilder<TimerBloc, TimerState>(
builder: (_, state) => AnimatedCircluarButton(
isPressed: state is TimerResumedState,
2024-05-03 09:26:00 +00:00
onPressed: () {
if (timelineAnimation.value == 0) {
return;
}
final event = state is TimerStoppedState ? const StartTimerEvent() : const StopTimerEvent();
context.read<TimerBloc>().add(event);
2024-05-03 09:26:00 +00:00
},
child: AnimatedIcon(
icon: AnimatedIcons.play_pause,
progress: startStopIconAnimation,
color: Theme.of(context).colorScheme.surface,
2024-05-03 09:26:00 +00:00
),
2024-04-30 19:50:09 +00:00
),
2024-05-03 09:26:00 +00:00
),
2024-05-03 11:31:18 +00:00
right: const CloseButton(),
),
],
2024-04-30 14:32:01 +00:00
),
),
),
);
}
2024-04-30 19:50:09 +00:00
void _updateAnimations(TimerState state) {
switch (state) {
2024-04-30 20:45:46 +00:00
case TimerResetState():
startStopIconController.reverse();
timelineController.stop();
timelineController.animateTo(0, duration: Dimens.durationS);
2024-04-30 19:50:09 +00:00
case TimerResumedState():
startStopIconController.forward();
2024-04-30 19:57:02 +00:00
timelineController.forward();
2024-04-30 19:50:09 +00:00
case TimerStoppedState():
startStopIconController.reverse();
2024-04-30 19:57:02 +00:00
timelineController.stop();
2024-04-30 19:50:09 +00:00
}
}
2024-04-30 14:32:01 +00:00
}