import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../main.dart'; import 'package:go_router/go_router.dart'; class SplashScreen extends ConsumerStatefulWidget { const SplashScreen({super.key}); @override ConsumerState createState() => _SplashState(); } class _SplashState extends ConsumerState with SingleTickerProviderStateMixin { late final AnimationController _ac = AnimationController( vsync: this, duration: const Duration(milliseconds: 600)) ..forward(); @override void initState() { super.initState(); _boot(); } Future _boot() async { final tokens = ref.read(tokenStorageProvider); final access = await tokens.access; var authed = _isJwtValid(access); if (!authed) { await tokens.refreshAccess(); authed = _isJwtValid(await tokens.access); } if (!mounted) return; await Future.delayed( const Duration(milliseconds: 300)); // kleines Fade-Finish if (!mounted) return; context.go(authed ? '/igel' : '/login'); } bool _isJwtValid(String? jwt) { if (jwt == null || jwt.isEmpty) return false; try { final parts = jwt.split('.'); if (parts.length != 3) return false; final payload = jsonDecode( utf8.decode(base64Url.decode(base64Url.normalize(parts[1])))) as Map; final exp = (payload['exp'] as num?)?.toInt(); final now = DateTime.now().millisecondsSinceEpoch ~/ 1000; return exp == null ? true : now < exp - 15; } catch (_) { return false; } } @override void dispose() { _ac.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final t = CurvedAnimation(parent: _ac, curve: Curves.easeOut); return Scaffold( body: FadeTransition( opacity: t, child: const Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.pets, size: 96), SizedBox(height: 12), CircularProgressIndicator(), ], ), ), ), ); } }