неко пофиксил ебень
This commit is contained in:
@@ -193,18 +193,7 @@ class _CodeConfirmationScreenState extends State<CodeConfirmationScreen>
|
|||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
||||||
Navigator.pushAndRemoveUntil(
|
showLoginSuccess(context, avatar: avatar);
|
||||||
context,
|
|
||||||
PageRouteBuilder(
|
|
||||||
transitionDuration: const Duration(milliseconds: 240),
|
|
||||||
pageBuilder: (_, __, ___) => LoginSuccessScreen(avatar: avatar),
|
|
||||||
transitionsBuilder: (_, animation, __, child) => FadeTransition(
|
|
||||||
opacity: animation,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(route) => false,
|
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
_showError(e.toString());
|
_showError(e.toString());
|
||||||
|
|||||||
@@ -51,18 +51,7 @@ class _Password2FAScreenState extends State<Password2FAScreen> {
|
|||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
||||||
Navigator.pushAndRemoveUntil(
|
showLoginSuccess(context, avatar: avatar);
|
||||||
context,
|
|
||||||
PageRouteBuilder(
|
|
||||||
transitionDuration: const Duration(milliseconds: 240),
|
|
||||||
pageBuilder: (_, __, ___) => LoginSuccessScreen(avatar: avatar),
|
|
||||||
transitionsBuilder: (_, animation, __, child) => FadeTransition(
|
|
||||||
opacity: animation,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(route) => false,
|
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,30 @@ Future<ImageProvider?> precacheLoginAvatar(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showLoginSuccess(BuildContext context, {ImageProvider? avatar}) {
|
||||||
|
final navigator = Navigator.of(context);
|
||||||
|
navigator.pushAndRemoveUntil(
|
||||||
|
PageRouteBuilder(
|
||||||
|
transitionDuration: Duration.zero,
|
||||||
|
pageBuilder: (_, _, _) => const AdaptiveShell(),
|
||||||
|
),
|
||||||
|
(route) => false,
|
||||||
|
);
|
||||||
|
navigator.push(
|
||||||
|
PageRouteBuilder(
|
||||||
|
opaque: false,
|
||||||
|
barrierColor: Colors.transparent,
|
||||||
|
transitionDuration: const Duration(milliseconds: 240),
|
||||||
|
reverseTransitionDuration: Duration.zero,
|
||||||
|
pageBuilder: (_, _, _) => LoginSuccessScreen(avatar: avatar),
|
||||||
|
transitionsBuilder: (_, animation, _, child) => FadeTransition(
|
||||||
|
opacity: animation,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
class LoginSuccessScreen extends StatefulWidget {
|
class LoginSuccessScreen extends StatefulWidget {
|
||||||
final ImageProvider? avatar;
|
final ImageProvider? avatar;
|
||||||
|
|
||||||
@@ -32,7 +56,7 @@ class LoginSuccessScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _LoginSuccessScreenState extends State<LoginSuccessScreen>
|
class _LoginSuccessScreenState extends State<LoginSuccessScreen>
|
||||||
with SingleTickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
static const Duration _duration = Duration(milliseconds: 1900);
|
static const Duration _duration = Duration(milliseconds: 1900);
|
||||||
|
|
||||||
static const List<String> _greetings = [
|
static const List<String> _greetings = [
|
||||||
@@ -55,9 +79,11 @@ class _LoginSuccessScreenState extends State<LoginSuccessScreen>
|
|||||||
late final Animation<double> _subtitleOffset;
|
late final Animation<double> _subtitleOffset;
|
||||||
late final Animation<double> _fadeOut;
|
late final Animation<double> _fadeOut;
|
||||||
|
|
||||||
|
late final AnimationController _exitController;
|
||||||
|
late final Animation<double> _bgFadeOut;
|
||||||
|
late final Animation<double> _greetingFadeOut;
|
||||||
|
|
||||||
bool _navigated = false;
|
bool _navigated = false;
|
||||||
bool _handedOff = false;
|
|
||||||
final GlobalKey _subtitleKey = GlobalKey();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -110,7 +136,21 @@ class _LoginSuccessScreenState extends State<LoginSuccessScreen>
|
|||||||
curve: const Interval(0.88, 1.0, curve: Curves.easeInCubic),
|
curve: const Interval(0.88, 1.0, curve: Curves.easeInCubic),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_exitController = AnimationController(
|
||||||
|
vsync: this,
|
||||||
|
duration: const Duration(milliseconds: 1200),
|
||||||
|
);
|
||||||
|
_bgFadeOut = CurvedAnimation(
|
||||||
|
parent: _exitController,
|
||||||
|
curve: const Interval(0.0, 0.3, curve: Curves.easeOut),
|
||||||
|
);
|
||||||
|
_greetingFadeOut = CurvedAnimation(
|
||||||
|
parent: _exitController,
|
||||||
|
curve: const Interval(0.55, 1.0, curve: Curves.easeInCubic),
|
||||||
|
);
|
||||||
|
|
||||||
_controller.addStatusListener(_onStatus);
|
_controller.addStatusListener(_onStatus);
|
||||||
|
_exitController.addStatusListener(_onExitStatus);
|
||||||
_controller.forward();
|
_controller.forward();
|
||||||
Haptics.success();
|
Haptics.success();
|
||||||
}
|
}
|
||||||
@@ -118,82 +158,26 @@ class _LoginSuccessScreenState extends State<LoginSuccessScreen>
|
|||||||
void _onStatus(AnimationStatus status) {
|
void _onStatus(AnimationStatus status) {
|
||||||
if (status == AnimationStatus.completed && !_navigated && mounted) {
|
if (status == AnimationStatus.completed && !_navigated && mounted) {
|
||||||
_navigated = true;
|
_navigated = true;
|
||||||
|
|
||||||
final navigator = Navigator.of(context);
|
|
||||||
final overlay = navigator.overlay;
|
|
||||||
final entry = _buildGreetingEntry();
|
|
||||||
if (entry != null) {
|
|
||||||
setState(() => _handedOff = true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (widget.preview) {
|
if (widget.preview) {
|
||||||
navigator.pop();
|
Navigator.of(context).pop();
|
||||||
} else {
|
} else {
|
||||||
navigator.pushAndRemoveUntil(
|
_exitController.forward();
|
||||||
PageRouteBuilder(
|
|
||||||
transitionDuration: const Duration(milliseconds: 360),
|
|
||||||
reverseTransitionDuration: const Duration(milliseconds: 200),
|
|
||||||
pageBuilder: (_, _, _) => const AdaptiveShell(),
|
|
||||||
transitionsBuilder: (_, animation, _, child) {
|
|
||||||
return FadeTransition(
|
|
||||||
opacity: CurvedAnimation(
|
|
||||||
parent: animation,
|
|
||||||
curve: Curves.easeOutCubic,
|
|
||||||
),
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(route) => false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry != null && overlay != null) {
|
|
||||||
overlay.insert(entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayEntry? _buildGreetingEntry() {
|
void _onExitStatus(AnimationStatus status) {
|
||||||
final subtitleContext = _subtitleKey.currentContext;
|
if (status == AnimationStatus.completed && mounted) {
|
||||||
if (subtitleContext == null) return null;
|
Navigator.of(context).pop();
|
||||||
final box = subtitleContext.findRenderObject() as RenderBox?;
|
}
|
||||||
if (box == null || !box.attached) return null;
|
|
||||||
|
|
||||||
final topLeft = box.localToGlobal(Offset.zero);
|
|
||||||
final size = box.size;
|
|
||||||
final style = DefaultTextStyle.of(subtitleContext)
|
|
||||||
.style
|
|
||||||
.merge(const TextStyle(
|
|
||||||
fontSize: 15,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
height: 1.3,
|
|
||||||
))
|
|
||||||
.copyWith(
|
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
||||||
decoration: TextDecoration.none,
|
|
||||||
);
|
|
||||||
|
|
||||||
late final OverlayEntry entry;
|
|
||||||
entry = OverlayEntry(
|
|
||||||
builder: (_) => Positioned(
|
|
||||||
left: topLeft.dx,
|
|
||||||
top: topLeft.dy,
|
|
||||||
width: size.width,
|
|
||||||
child: _GreetingLinger(
|
|
||||||
greeting: _greeting,
|
|
||||||
style: style,
|
|
||||||
onDone: () => entry.remove(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_controller.removeStatusListener(_onStatus);
|
_controller.removeStatusListener(_onStatus);
|
||||||
_controller.dispose();
|
_controller.dispose();
|
||||||
|
_exitController.removeStatusListener(_onExitStatus);
|
||||||
|
_exitController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,16 +185,24 @@ class _LoginSuccessScreenState extends State<LoginSuccessScreen>
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final cs = Theme.of(context).colorScheme;
|
final cs = Theme.of(context).colorScheme;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: cs.surface,
|
backgroundColor: Colors.transparent,
|
||||||
body: AnimatedBuilder(
|
body: AnimatedBuilder(
|
||||||
animation: _controller,
|
animation: Listenable.merge([_controller, _exitController]),
|
||||||
builder: (context, _) {
|
builder: (context, _) {
|
||||||
final celebrationOpacity = 1.0 - _fadeOut.value;
|
final celebrationOpacity = 1.0 - _fadeOut.value;
|
||||||
|
final bgOpacity = 1.0 - _bgFadeOut.value;
|
||||||
|
final greetingOpacity = 1.0 - _greetingFadeOut.value;
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Opacity(
|
child: Opacity(
|
||||||
opacity: celebrationOpacity,
|
opacity: bgOpacity,
|
||||||
|
child: ColoredBox(color: cs.surface),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned.fill(
|
||||||
|
child: Opacity(
|
||||||
|
opacity: celebrationOpacity * bgOpacity,
|
||||||
child: DecoratedBox(
|
child: DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: RadialGradient(
|
gradient: RadialGradient(
|
||||||
@@ -254,7 +246,7 @@ class _LoginSuccessScreenState extends State<LoginSuccessScreen>
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Opacity(
|
Opacity(
|
||||||
opacity: _handedOff ? 0.0 : 1.0,
|
opacity: greetingOpacity,
|
||||||
child: _buildSubtitle(cs),
|
child: _buildSubtitle(cs),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -381,7 +373,6 @@ class _LoginSuccessScreenState extends State<LoginSuccessScreen>
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 40),
|
padding: const EdgeInsets.symmetric(horizontal: 40),
|
||||||
child: Text(
|
child: Text(
|
||||||
_greeting,
|
_greeting,
|
||||||
key: _subtitleKey,
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: cs.onSurfaceVariant,
|
color: cs.onSurfaceVariant,
|
||||||
@@ -396,76 +387,6 @@ class _LoginSuccessScreenState extends State<LoginSuccessScreen>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GreetingLinger extends StatefulWidget {
|
|
||||||
final String greeting;
|
|
||||||
final TextStyle style;
|
|
||||||
final VoidCallback onDone;
|
|
||||||
|
|
||||||
const _GreetingLinger({
|
|
||||||
required this.greeting,
|
|
||||||
required this.style,
|
|
||||||
required this.onDone,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<_GreetingLinger> createState() => _GreetingLingerState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _GreetingLingerState extends State<_GreetingLinger>
|
|
||||||
with SingleTickerProviderStateMixin {
|
|
||||||
late final AnimationController _controller;
|
|
||||||
late final Animation<double> _opacity;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_controller = AnimationController(
|
|
||||||
vsync: this,
|
|
||||||
duration: const Duration(milliseconds: 1200),
|
|
||||||
);
|
|
||||||
_opacity = TweenSequence<double>([
|
|
||||||
TweenSequenceItem(tween: ConstantTween<double>(1.0), weight: 55),
|
|
||||||
TweenSequenceItem(
|
|
||||||
tween: Tween<double>(begin: 1.0, end: 0.0)
|
|
||||||
.chain(CurveTween(curve: Curves.easeInCubic)),
|
|
||||||
weight: 45,
|
|
||||||
),
|
|
||||||
]).animate(_controller);
|
|
||||||
_controller.addStatusListener((status) {
|
|
||||||
if (status == AnimationStatus.completed) widget.onDone();
|
|
||||||
});
|
|
||||||
_controller.forward();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return IgnorePointer(
|
|
||||||
child: Material(
|
|
||||||
type: MaterialType.transparency,
|
|
||||||
child: AnimatedBuilder(
|
|
||||||
animation: _opacity,
|
|
||||||
builder: (context, _) {
|
|
||||||
return Opacity(
|
|
||||||
opacity: _opacity.value,
|
|
||||||
child: Text(
|
|
||||||
widget.greeting,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: widget.style,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CheckPainter extends CustomPainter {
|
class _CheckPainter extends CustomPainter {
|
||||||
final double progress;
|
final double progress;
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|||||||
Reference in New Issue
Block a user