/// Application entry point: wires services, Provider, deep links, and [MaterialApp]. library; import 'dart:async'; import 'package:app_links/app_links.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'providers/bank_provider.dart'; import 'providers/theme_provider.dart'; import 'screens/splash_screen.dart'; import 'services/storage_service.dart'; import 'utils/app_theme.dart'; import 'utils/constants.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); final storage = StorageService(); await storage.init(); runApp(MyApp(storage: storage)); } /// Root widget. Theme and bank controllers live here so every route /// can `context.watch` them. class MyApp extends StatefulWidget { const MyApp({super.key, required this.storage}); final StorageService storage; @override State createState() => _MyAppState(); } class _MyAppState extends State { late final BankController _bank; late final AppLinks _appLinks; StreamSubscription? _linkSub; @override void initState() { super.initState(); _bank = BankController()..refresh(); _appLinks = AppLinks(); _listenForBankRedirects(); } Future _listenForBankRedirects() async { try { final initial = await _appLinks.getInitialLink(); if (initial != null) { await _bank.handleRedirect(initial); } } catch (error, stackTrace) { debugPrint('Initial deep link failed: $error\n$stackTrace'); } _linkSub = _appLinks.uriLinkStream.listen( (uri) { unawaited(_bank.handleRedirect(uri)); }, onError: (Object error, StackTrace stackTrace) { debugPrint('Deep link stream error: $error\n$stackTrace'); }, ); } @override void dispose() { _linkSub?.cancel(); _bank.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => ThemeController(widget.storage)), ChangeNotifierProvider.value(value: _bank), ], child: const _MaterialRoot(), ); } } class _MaterialRoot extends StatelessWidget { const _MaterialRoot(); @override Widget build(BuildContext context) { final themeMode = context.watch().themeMode; return MaterialApp( title: kAppName, debugShowCheckedModeBanner: false, theme: AppTheme.light(), darkTheme: AppTheme.dark(), themeMode: themeMode, home: const SplashScreen(), ); } }