import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:sxchnge_analytics/sxchnge_analytics.dart'; import 'package:sxchnge_auth/sxchnge_auth.dart'; import '../generated/i18n/app_localizations.dart'; class FactorRouteRequest { const FactorRouteRequest(this.provider, this.summary); final TwoFactorProvider provider; final Widget? summary; } Future verifyFactor( BuildContext context, { required FactorChallenge challenge, required TwoFactorService service, required JourneyRecorder recorder, required JourneyKind journey, Widget? summary, }) async { final provider = TwoFactorProvider( service, challenge, recorder: recorder, journey: journey, ); FactorGrant? result; try { result = await context.push( '/two-factor', extra: FactorRouteRequest(provider, summary), ); return result; } finally { if (result == null) { final step = recorder.begin( journey, JourneyStep.factorVerification, simulated: service.isSimulated, ); recorder.finish(step, cancelled: true, simulated: service.isSimulated); } provider.dispose(); } } String factorErrorText(AppLocalizations l, FactorError error) => switch (error) { FactorError.invalid => l.factorInvalid, FactorError.expired => l.factorExpired, FactorError.locked => l.factorLocked, FactorError.cooldown => l.factorWait, FactorError.required => l.factorRequired, FactorError.unavailable => l.factorUnavailable, }; class FactorRoute extends StatefulWidget { const FactorRoute({super.key, required this.request}); final FactorRouteRequest request; @override State createState() => _FactorRouteState(); } class _FactorRouteState extends State { FactorRouteRequest get request => widget.request; @override void dispose() { request.provider.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final l = AppLocalizations.of(context)!; final purpose = request.provider.challenge.purpose; final purposeText = switch (purpose) { FactorPurpose.login => l.factorLogin, FactorPurpose.enable => l.factorEnableHelp, FactorPurpose.disable => l.factorDisableHelp, _ => l.factorMoney, }; final methodText = request.provider.challenge.method == FactorMethod.email ? l.factorEmail : l.factorAuthenticator; return TwoFactorPage( provider: request.provider, summary: request.summary, labels: TwoFactorLabels( title: l.factorTitle, description: '$purposeText $methodText', code: l.factorCode, confirm: l.factorConfirm, cancel: l.wClose, resend: l.factorResend, expired: request.provider.challenge.method == FactorMethod.email ? l.factorExpired : l.factorAppExpired, help: request.provider.challenge.method == FactorMethod.email ? l.factorHelp : l.factorAppHelp, errorText: (error) => error == FactorError.expired && request.provider.challenge.method == FactorMethod.authenticator ? l.factorAppExpired : factorErrorText(l, error), cooldownText: (seconds) => l.factorCooldown(seconds), ), onVerified: (grant) => context.pop(grant), onCancel: () => context.pop(), ); } }