import 'dart:async'; import 'package:flutter/material.dart'; import 'package:qrscanner/models/auth_session.dart'; import 'package:qrscanner/screens/home_screen.dart'; import 'package:qrscanner/screens/scanner_screen.dart'; import 'package:qrscanner/services/auth_service.dart'; import 'package:qrscanner/services/scan_launch_service.dart'; class ScanNavigationService { ScanNavigationService._(); static final ScanNavigationService instance = ScanNavigationService._(); final GlobalKey navigatorKey = GlobalKey(); final AuthService _authService = AuthService(); StreamSubscription? _scanSubscription; String? _pendingCode; bool _handlingScan = false; bool _scannerOpen = false; String? get pendingCode => _pendingCode; void setPendingCode(String code) { final trimmed = code.trim(); if (trimmed.isEmpty) return; _pendingCode = trimmed; } String? takePendingCode() { final code = _pendingCode; _pendingCode = null; return code; } Future initialize() async { await ScanLaunchService.instance.claimScanner(); final pending = await ScanLaunchService.instance.consumePendingScan(); if (pending != null) { setPendingCode(pending); } await _scanSubscription?.cancel(); _scanSubscription = ScanLaunchService.instance.scanStream.listen( (code) => unawaited(handleScan(code)), ); } Future dispose() async { await _scanSubscription?.cancel(); _scanSubscription = null; } Future handleScan(String code, {AuthSession? session}) async { final trimmed = code.trim(); if (trimmed.isEmpty || _handlingScan) return; _handlingScan = true; try { setPendingCode(trimmed); final activeSession = session ?? _authService.currentSession ?? await _authService.loadStoredSession(); if (activeSession == null) return; final navigator = navigatorKey.currentState; if (navigator == null) return; takePendingCode(); if (_scannerOpen) return; _scannerOpen = true; try { await navigator.push( PageRouteBuilder( settings: const RouteSettings(name: '/scanner'), pageBuilder: (context, animation, secondaryAnimation) => ScannerScreen( session: activeSession, initialCode: trimmed, ), transitionsBuilder: (context, animation, secondaryAnimation, child) { return FadeTransition( opacity: animation, child: SlideTransition( position: Tween( begin: const Offset(0, 0.06), end: Offset.zero, ).animate(CurvedAnimation( parent: animation, curve: Curves.easeOutCubic, )), child: child, ), ); }, transitionDuration: const Duration(milliseconds: 380), ), ); } finally { _scannerOpen = false; } } finally { _handlingScan = false; } } Future openPendingScanAfterAuth(AuthSession session) async { final code = takePendingCode(); if (code == null) return; await handleScan(code, session: session); } Future navigateToHome(AuthSession session) async { final navigator = navigatorKey.currentState; if (navigator == null) return; await navigator.pushAndRemoveUntil( PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => HomeScreen(session: session), transitionsBuilder: (context, animation, secondaryAnimation, child) { return FadeTransition(opacity: animation, child: child); }, transitionDuration: const Duration(milliseconds: 400), ), (route) => false, ); await openPendingScanAfterAuth(session); } }