// ignore_for_file: use_build_context_synchronously import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import '../../app/router.dart'; import '../../app/injection_container.dart'; import '../../core/constants/app_constants.dart'; import '../../core/errors/friendly_error.dart'; import '../../core/network/api_client.dart'; import '../../core/services/fcm_service.dart'; import '../../core/services/incoming_call_polling_service.dart'; import '../../core/services/offline_queue_service.dart'; import '../../core/services/websocket_service.dart'; import '../../core/storage/secure_storage.dart'; // --------------------------------------------------------------------------- // SplashScreen // --------------------------------------------------------------------------- // // Ditampilkan sesaat setelah user berhasil connect ke server (dari // ServerConnectScreen) atau saat app dibuka dan serverUrl sudah tersimpan. // // Logic: // 1. Delay singkat 500ms untuk animasi logo. // 2. Baca accessToken dari SecureStorage. // 3. Jika tidak ada → redirect /login. // 4. Jika ada → baca role → redirect /user/walkguide atau /guardian/dashboard. // // TTS "Welcome back, {displayName}" jika auto-login (token sudah ada). // --------------------------------------------------------------------------- class SplashScreen extends StatefulWidget { const SplashScreen({super.key}); @override State createState() => _SplashScreenState(); } class _SplashScreenState extends State with SingleTickerProviderStateMixin { late final AnimationController _animCtrl; late final Animation _fadeAnim; @override void initState() { super.initState(); _animCtrl = AnimationController( vsync: this, duration: const Duration(milliseconds: 700), ); _fadeAnim = CurvedAnimation(parent: _animCtrl, curve: Curves.easeIn); _animCtrl.forward(); _route(); } @override void dispose() { _animCtrl.dispose(); super.dispose(); } Future _route() async { final routed = await runFriendlyAction( () async { // Animasi logo selalu tampil minimal 500ms agar tidak langsung flash. await Future.delayed(const Duration(milliseconds: 500)); final storage = sl(); final token = await storage.getAccessToken().timeout( const Duration(seconds: 3), ); final role = await storage.getUserRole().timeout( const Duration(seconds: 3), ); if (!mounted) return; if (token == null || role == null) { context.go('/login'); return; } final serverUrl = await AppConstants.getServerUrl(); if (serverUrl != null && serverUrl.isNotEmpty) { _startAutoLoginServices(serverUrl); } else { sl().start(); } // Auto-login: arahkan ke home sesuai role. context.go( role == 'ROLE_GUARDIAN' ? '/guardian/dashboard' : '/user/walkguide', ); }, onError: (_) {}, fallback: 'Sesi belum bisa dipulihkan.', ); if (!routed && mounted) context.go('/login'); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFF1A56DB), body: Center( child: FadeTransition( opacity: _fadeAnim, child: Column( mainAxisSize: MainAxisSize.min, children: [ // Logo / icon Container( width: 100, height: 100, decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(28), ), child: const Icon( Icons.navigation_rounded, color: Colors.white, size: 60, ), ), const SizedBox(height: 24), const Text( 'WalkGuide', style: TextStyle( color: Colors.white, fontSize: 34, fontWeight: FontWeight.w800, letterSpacing: -0.5, ), ), const SizedBox(height: 6), const Text( 'AI-powered navigation for everyone', style: TextStyle(color: Colors.white70, fontSize: 13), ), const SizedBox(height: 48), const SizedBox( width: 28, height: 28, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2.5, ), ), ], ), ), ), ); } } void _startAutoLoginServices(String serverUrl) { Future.microtask(() async { sl().start(); await sl().init(serverUrl); await sl().init().timeout(const Duration(seconds: 4)); final ws = sl(); await ws.connect(serverUrl).timeout(const Duration(seconds: 2)); ws.subscribeCall((data) { if (data['type']?.toString() == 'INCOMING_CALL') { appRouter.go('/incoming-call', extra: data); } }); await sl() .syncPending(sl()) .timeout(const Duration(seconds: 3)); }).catchError((Object e) { debugPrint('Auto-login services skipped: $e'); }); }