added reset button (wip)

This commit is contained in:
Vadim 2024-04-30 22:45:46 +02:00
parent b008ef7c83
commit 985ecaa41e
4 changed files with 97 additions and 37 deletions

View file

@ -68,7 +68,7 @@ class TimerBloc extends Bloc<TimerEvent, TimerState> {
Future<void> _onResetTimer(ResetTimerEvent _, Emitter emit) async { Future<void> _onResetTimer(ResetTimerEvent _, Emitter emit) async {
_timer?.cancel(); _timer?.cancel();
emit( emit(
TimerStoppedState( TimerResetState(
duration: state.duration, duration: state.duration,
timeLeft: state.duration, timeLeft: state.duration,
), ),

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/interactors/metering_interactor.dart'; import 'package:lightmeter/interactors/metering_interactor.dart';
import 'package:lightmeter/providers/services_provider.dart'; import 'package:lightmeter/providers/services_provider.dart';
import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/timer/bloc_timer.dart'; import 'package:lightmeter/screens/timer/bloc_timer.dart';
import 'package:lightmeter/screens/timer/screen_timer.dart'; import 'package:lightmeter/screens/timer/screen_timer.dart';
@ -10,7 +11,19 @@ class TimerFlow extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MeteringInteractorProvider( final scheme = Theme.of(context).colorScheme;
return IconButtonTheme(
data: IconButtonThemeData(
style: ButtonStyle(
backgroundColor: MaterialStatePropertyAll(scheme.surface),
elevation: const MaterialStatePropertyAll(4),
iconColor: MaterialStatePropertyAll(scheme.onSurface),
shadowColor: const MaterialStatePropertyAll(Colors.transparent),
surfaceTintColor: MaterialStatePropertyAll(scheme.surfaceTint),
fixedSize: const MaterialStatePropertyAll(Size(Dimens.grid48, Dimens.grid48)),
),
),
child: MeteringInteractorProvider(
data: MeteringInteractor( data: MeteringInteractor(
ServicesProvider.of(context).userPreferencesService, ServicesProvider.of(context).userPreferencesService,
ServicesProvider.of(context).caffeineService, ServicesProvider.of(context).caffeineService,
@ -22,10 +35,11 @@ class TimerFlow extends StatelessWidget {
child: BlocProvider( child: BlocProvider(
create: (context) => TimerBloc( create: (context) => TimerBloc(
MeteringInteractorProvider.of(context), MeteringInteractorProvider.of(context),
124, 60,
), ),
child: const TimerScreen( child: const TimerScreen(
duration: const Duration(seconds: 124), duration: const Duration(seconds: 60),
),
), ),
), ),
); );

View file

@ -50,10 +50,9 @@ class _TimerScreenState extends State<TimerScreen> with TickerProviderStateMixin
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// TODO (@vodemn): split build in timer/components folder
return BlocListener<TimerBloc, TimerState>( return BlocListener<TimerBloc, TimerState>(
listenWhen: (previous, current) => listenWhen: (previous, current) => previous.runtimeType != current.runtimeType,
previous is TimerStoppedState && current is TimerResumedState ||
previous is TimerResumedState && current is TimerStoppedState,
listener: (context, state) => _updateAnimations(state), listener: (context, state) => _updateAnimations(state),
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
@ -95,12 +94,29 @@ class _TimerScreenState extends State<TimerScreen> with TickerProviderStateMixin
), ),
), ),
const Spacer(), const Spacer(),
BlocBuilder<TimerBloc, TimerState>( Row(
builder: (_, state) => FloatingActionButton( children: [
Expanded(
child: Center(
child: IconButton(
onPressed: () { onPressed: () {
context.read<TimerBloc>().add( context.read<TimerBloc>().add(const ResetTimerEvent());
state is TimerStoppedState ? const StartTimerEvent() : const StopTimerEvent(), },
); icon: const Icon(Icons.restore),
),
),
),
SizedBox.fromSize(
size: const Size.square(Dimens.grid72),
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);
}, },
child: AnimatedIcon( child: AnimatedIcon(
icon: AnimatedIcons.play_pause, icon: AnimatedIcons.play_pause,
@ -108,6 +124,10 @@ class _TimerScreenState extends State<TimerScreen> with TickerProviderStateMixin
), ),
), ),
), ),
),
const Spacer(),
],
),
], ],
), ),
), ),
@ -119,6 +139,10 @@ class _TimerScreenState extends State<TimerScreen> with TickerProviderStateMixin
void _updateAnimations(TimerState state) { void _updateAnimations(TimerState state) {
switch (state) { switch (state) {
case TimerResetState():
startStopIconController.reverse();
timelineController.stop();
timelineController.animateTo(0, duration: Dimens.durationS);
case TimerResumedState(): case TimerResumedState():
startStopIconController.forward(); startStopIconController.forward();
timelineController.forward(); timelineController.forward();
@ -210,7 +234,6 @@ class _TimelinePainter extends CustomPainter {
final double progress; final double progress;
late final double timelineEdgeRadius = strokeWidth / 2; late final double timelineEdgeRadius = strokeWidth / 2;
late final double radiansProgress = 2 * pi * progress;
static const double radiansQuarterTurn = -pi / 2; static const double radiansQuarterTurn = -pi / 2;
static const double strokeWidth = Dimens.grid8; static const double strokeWidth = Dimens.grid8;
@ -222,11 +245,22 @@ class _TimelinePainter extends CustomPainter {
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
print('PROGRESS: $progress');
late final double radiansProgress = 2 * pi * progress;
final radius = size.height / 2; final radius = size.height / 2;
final timerCenter = Offset(radius, radius); final timerCenter = Offset(radius, radius);
final timelineSegmentPath = Path.combine(
PathOperation.difference, final timelineSegmentPath = Path();
Path() if (progress == 1) {
timelineSegmentPath.addOval(
Rect.fromCenter(
center: timerCenter,
height: size.height,
width: size.width,
),
);
} else {
timelineSegmentPath
..arcTo( ..arcTo(
Rect.fromCenter( Rect.fromCenter(
center: timerCenter, center: timerCenter,
@ -238,7 +272,12 @@ class _TimelinePainter extends CustomPainter {
false, false,
) )
..lineTo(radius, radius) ..lineTo(radius, radius)
..lineTo(radius, 0), ..lineTo(radius, 0);
}
final timelinePath = Path.combine(
PathOperation.difference,
timelineSegmentPath,
Path() Path()
..addOval( ..addOval(
Rect.fromCircle( Rect.fromCircle(
@ -293,7 +332,7 @@ class _TimelinePainter extends CustomPainter {
canvas.drawPath( canvas.drawPath(
Path.combine( Path.combine(
PathOperation.union, PathOperation.union,
timelineSegmentPath, timelinePath,
smoothEdgesPath, smoothEdgesPath,
), ),
Paint()..color = progressColor, Paint()..color = progressColor,
@ -301,5 +340,5 @@ class _TimelinePainter extends CustomPainter {
} }
@override @override
bool shouldRepaint(_TimelinePainter oldDelegate) => oldDelegate.progress != progress; bool shouldRepaint(_TimelinePainter oldDelegate) => true;
} }

View file

@ -24,3 +24,10 @@ class TimerResumedState extends TimerState {
required super.timeLeft, required super.timeLeft,
}); });
} }
class TimerResetState extends TimerStoppedState {
const TimerResetState({
required super.duration,
required super.timeLeft,
});
}