137 lines
3.9 KiB
Dart
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);
|
|
}
|
|
} |