Files
Base-QR-FlutterApp/lib/services/scan_navigation_service.dart
T
2026-06-19 08:57:58 -06:00

137 lines
3.9 KiB
Dart

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<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
final AuthService _authService = AuthService();
StreamSubscription<String>? _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<void> 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<void> dispose() async {
await _scanSubscription?.cancel();
_scanSubscription = null;
}
Future<void> 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<void>(
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<Offset>(
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<void> openPendingScanAfterAuth(AuthSession session) async {
final code = takePendingCode();
if (code == null) return;
await handleScan(code, session: session);
}
Future<void> navigateToHome(AuthSession session) async {
final navigator = navigatorKey.currentState;
if (navigator == null) return;
await navigator.pushAndRemoveUntil(
PageRouteBuilder<void>(
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);
}
}