Files
krow-worker-app/lib/core/transitions.dart
2026-09-17 22:26:11 +05:30

85 lines
3.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
/// Page transitions, kept in one place so every screen arrives the same way.
///
/// Two kinds only. Moving *deeper* (a shift, a document, a timecard) slides
/// forward, and the screen behind it slides back a little so the stack reads
/// as a stack. Moving *sideways* — between steps of sign-up, or replacing the
/// whole screen — cross-fades, because nothing is being pushed onto anything.
abstract final class Transitions {
static const _forward = Duration(milliseconds: 320);
static const _back = Duration(milliseconds: 260);
/// Pushed detail screens.
static CustomTransitionPage<T> push<T>(GoRouterState state, Widget child) {
return CustomTransitionPage<T>(
key: state.pageKey,
child: child,
transitionDuration: _forward,
reverseTransitionDuration: _back,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
final incoming = CurvedAnimation(
parent: animation,
curve: Curves.easeOutCubic,
reverseCurve: Curves.easeInCubic,
);
// The outgoing screen eases back rather than sitting still, which is
// what gives the push its depth.
final outgoing = CurvedAnimation(
parent: secondaryAnimation,
curve: Curves.easeOutCubic,
reverseCurve: Curves.easeInCubic,
);
// secondaryAnimation rests at 0 while this page is on top, so the
// resting state has to be `begin`. Reversing these two leaves every
// pushed screen sitting 12% off to the left.
return SlideTransition(
position: Tween(
begin: Offset.zero,
end: const Offset(-0.12, 0),
).animate(outgoing),
child: FadeTransition(
opacity: Tween(begin: 1.0, end: 0.0).animate(outgoing),
child: SlideTransition(
position: Tween(
begin: const Offset(1, 0),
end: Offset.zero,
).animate(incoming),
child: child,
),
),
);
},
);
}
/// Screens that replace what came before: splash, onboarding, sign-in steps.
static CustomTransitionPage<T> fade<T>(GoRouterState state, Widget child) {
return CustomTransitionPage<T>(
key: state.pageKey,
child: child,
transitionDuration: _forward,
reverseTransitionDuration: _back,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
final curved = CurvedAnimation(
parent: animation,
curve: Curves.easeOutCubic,
);
return FadeTransition(
opacity: curved,
// A few pixels of rise stops the cross-fade feeling inert.
child: SlideTransition(
position: Tween(
begin: const Offset(0, 0.015),
end: Offset.zero,
).animate(curved),
child: child,
),
);
},
);
}
}