import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:sxchnge_analytics/sxchnge_analytics.dart'; import 'package:sxchnge_auth/sxchnge_auth.dart'; import 'package:sxchnge_kyc/sxchnge_kyc.dart'; import 'package:sxchnge_theme/sxchnge_theme.dart'; import 'package:sxchnge_wallet/sxchnge_wallet.dart'; import 'providers/locale.dart'; import 'routing/router.dart'; import 'generated/i18n/app_localizations.dart'; Future main() async { final binding = WidgetsFlutterBinding.ensureInitialized(); final locale = await LocaleProvider.load(binding.platformDispatcher.locales); const apiUrl = String.fromEnvironment('SXCHNGE_API_URL'); const clientId = String.fromEnvironment('SXCHNGE_CLIENT_ID'); final backend = apiUrl.isEmpty ? null : BackendAuthServices(baseUri: Uri.parse(apiUrl), clientId: clientId); runApp(SxchngeApp(localeProvider: locale, backend: backend)); } class SxchngeApp extends StatefulWidget { const SxchngeApp({ super.key, this.localeProvider, this.backend, this.analyticsService, this.identityService, this.limitsService, this.walletService, this.twoFactorService, this.photoService = const FilePhotoService(), this.loginService = const DummyLoginService(), this.signupService = const DummySignupService(), this.verificationService = const DummyVerificationService(), }); final LocaleProvider? localeProvider; final BackendAuthServices? backend; final AnalyticsService? analyticsService; final IdentityService? identityService; final LimitsService? limitsService; final WalletService? walletService; final TwoFactorService? twoFactorService; final PhotoService photoService; final LoginService loginService; final SignupService signupService; final VerificationService verificationService; @override State createState() => _SxchngeAppState(); } class _SxchngeAppState extends State { late final _locale = widget.localeProvider ?? LocaleProvider(); late final _analytics = widget.analyticsService ?? DummyAnalyticsService(); late final _factors = widget.backend ?? widget.twoFactorService ?? DummyTwoFactorService(); late final _security = SecurityProvider(_factors, _analytics); late final _identity = widget.identityService ?? (widget.backend == null ? DummyIdentityService() : BackendIdentityService( baseUri: widget.backend!.baseUri, accessToken: () => widget.backend!.session?.accessToken, )); late final _walletService = widget.walletService ?? DummyWalletService( _identity, initialLocale: _locale.locale.languageCode, factors: _factors, ); late final _wallet = WalletProvider( _walletService, _analytics, factors: _factors, ); late final _limits = widget.limitsService ?? (_identity is BackendIdentityService ? BackendLimitsService(_identity) : _walletService is DummyWalletService ? WalletLimitsService(_walletService) : DummyLimitsService(_identity)); late final _journeys = JourneyRecorder(_analytics); late final _services = InstrumentedAuthServices( recorder: _journeys, loginService: GuardedLoginService( widget.backend ?? widget.loginService, _factors, ), signupService: widget.backend ?? widget.signupService, verificationService: widget.backend ?? widget.verificationService, ); late final _router = createAppRouter( authenticated: widget.backend == null ? null : () => widget.backend!.session != null, )..routeInformationProvider.addListener(_routeChanged); String _previousPath = '/'; @override void initState() { super.initState(); _previousPath = _router.routeInformationProvider.value.uri.path; } void _routeChanged() { final path = _router.routeInformationProvider.value.uri.path; if (path == '/' && _previousPath != '/' && _previousPath != '/two-factor') { _journeys.abandon(JourneyExit.navigation); } _previousPath = path; } @override void dispose() { _router.routeInformationProvider.removeListener(_routeChanged); _router.dispose(); _journeys.dispose(); _wallet.dispose(); _security.dispose(); if (_identity is BackendIdentityService) { _identity.close(); } _locale.dispose(); widget.backend?.close(); super.dispose(); } @override Widget build(BuildContext context) => MultiProvider( providers: [ ChangeNotifierProvider.value(value: _wallet), ChangeNotifierProvider.value(value: _security), Provider.value(value: _factors), Provider.value(value: _journeys), Provider.value(value: _analytics), Provider.value(value: _identity), Provider(create: (_) => IdentityOnboardingProvider(_identity)), Provider.value(value: _limits), Provider.value(value: widget.photoService), ChangeNotifierProvider.value(value: _locale), Provider.value(value: _services), ChangeNotifierProvider(create: (_) => LoginProvider(_services)), ChangeNotifierProvider(create: (_) => SignupProvider(_services)), ], child: Consumer( builder: (context, locale, _) => MaterialApp.router( onGenerateTitle: (context) => AppLocalizations.of(context)!.appTitle, debugShowCheckedModeBanner: false, theme: SxchngeTheme.light(), locale: locale.locale, localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, routerConfig: _router, ), ), ); }