// 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'; import '../../shared/widgets/walkguide_loading_screen.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 _screenCtrl; late final Animation _screenFade; @override void initState() { super.initState(); _screenCtrl = AnimationController( vsync: this, duration: const Duration(milliseconds: 260), value: 1, ); _screenFade = CurvedAnimation( parent: _screenCtrl, curve: Curves.easeOutCubic, ); _route(); } @override void dispose() { _screenCtrl.dispose(); super.dispose(); } Future _route() async { final routed = await runFriendlyAction( () async { // Animasi logo selalu tampil minimal 900ms agar tidak langsung flash. await Future.delayed(const Duration(milliseconds: 900)); 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) { await _fadeOutThenGo('/login'); return; } final serverUrl = await AppConstants.getServerUrl(); if (serverUrl != null && serverUrl.isNotEmpty) { _startAutoLoginServices(serverUrl); } else { sl().start(); } // Auto-login: arahkan ke home sesuai role. await _fadeOutThenGo( role == 'ROLE_GUARDIAN' ? '/guardian/dashboard' : '/user/walkguide', ); }, onError: (_) {}, fallback: 'Sesi belum bisa dipulihkan.', ); if (!routed && mounted) await _fadeOutThenGo('/login'); } Future _fadeOutThenGo(String route) async { if (!mounted) return; await _screenCtrl.reverse(); if (mounted) context.go(route); } @override Widget build(BuildContext context) { return FadeTransition( opacity: _screenFade, child: const WalkGuideLoadingScreen( subtitle: 'Restoring your session', ), ); } } 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'); }); }