import 'package:flutter/foundation.dart'; import '../models/verification.dart'; import '../services/verification.dart'; class VerificationProvider extends ChangeNotifier { VerificationProvider(this.service); final VerificationService service; VerificationState _state = const VerificationState(VerificationStatus.idle); VerificationState get state => _state; bool _disposed = false; int _generation = 0; Future send({required String email, required String locale}) => _run( () => service.send(email: email.trim(), locale: locale), VerificationStatus.sending, VerificationStatus.sent, ); Future confirm(String token) => _run( () => service.confirm(token: token), VerificationStatus.checking, VerificationStatus.verified, ); Future _run( Future Function() operation, VerificationStatus loading, VerificationStatus success, ) async { if (_disposed || _state.isLoading) return; final generation = ++_generation; _state = VerificationState(loading); notifyListeners(); if (_disposed || generation != _generation) return; try { final result = await operation(); if (_disposed || generation != _generation) return; _state = VerificationState( success, isSimulated: result.isSimulated, result: success == VerificationStatus.verified ? result : null, ); } catch (error) { if (_disposed || generation != _generation) return; final code = error is VerificationException ? error.code : VerificationError.internal; // Send failures must not be presented as confirmation-token failures. _state = VerificationState( loading == VerificationStatus.sending ? VerificationStatus.error : switch (code) { VerificationError.expired => VerificationStatus.expired, VerificationError.invalid => VerificationStatus.invalid, VerificationError.internal => VerificationStatus.error, VerificationError.needsAssistance => VerificationStatus.error, }, error: code, ); } notifyListeners(); } void reset() { if (_disposed) return; ++_generation; _state = const VerificationState(VerificationStatus.idle); notifyListeners(); } @override void dispose() { _disposed = true; ++_generation; super.dispose(); } }