import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:mnemo_cards_web_v2/di/user_scope/user_scope.dart'; import 'package:yx_scope_flutter/yx_scope_flutter.dart'; import 'package:yx_state_flutter/yx_state_flutter.dart'; import 'di/app_scope/app_scope_container.dart'; import 'di/app_scope/app_scope_holder.dart'; import 'domain/state/theme_state_manager.dart'; import 'main.dart' show scaffoldMessengerKey; import 'presentation/theme/app_colors.dart'; import 'presentation/theme/app_theme.dart'; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; /// Main application widget /// /// Wraps the entire app in ScopeProviders for AppScope and UserScope class App extends StatelessWidget { const App({ required this.appScopeHolder, super.key, }); final AppScopeHolder appScopeHolder; @override Widget build(BuildContext context) { return ScopeProvider( holder: appScopeHolder, child: ScopeBuilder.withPlaceholder( builder: (context, appScope) { return _AppInitializer(appScope: appScope); }, placeholder: const _LoadingPlaceholder(message: 'Инициализация...'), ), ); } } /// Initializes the app and handles auto-login class _AppInitializer extends StatefulWidget { const _AppInitializer({required this.appScope}); final AppScopeContainer appScope; @override State<_AppInitializer> createState() => _AppInitializerState(); } class _AppInitializerState extends State<_AppInitializer> { bool _isInitialized = false; @override void initState() { super.initState(); _initialize(); } @override void didUpdateWidget(_AppInitializer oldWidget) { super.didUpdateWidget(oldWidget); // Rebuild when UserScope changes if (mounted) { setState(() {}); } } /// Try Telegram Web App authentication /// Returns true if authentication was successful, false otherwise Future _tryTelegramWebAppAuth() async { try { log('Checking Telegram Web App authentication...', name: 'App'); // Try to authenticate with Telegram Web App final user = await widget.appScope.authService.loginWithTelegramWebApp(); if (user != null) { log('Telegram Web App authentication successful', name: 'App'); // Create UserScope if it doesn't exist if (widget.appScope.userScopeHolder.scope == null) { await widget.appScope.userScopeHolder.create(); } // Set authenticated user final userScope = widget.appScope.userScopeHolder.scope; if (userScope != null) { await userScope.userStateManager.setUser(user); // Notify router about auth change widget.appScope.userScopeHolder.notifyAuthChanged(); } // Return true to indicate successful authentication return true; } else { log('Telegram Web App authentication not available or failed', name: 'App'); return false; } } catch (e, s) { log('Error during Telegram Web App authentication', error: e, stackTrace: s); // Continue with normal flow - this is not a critical error return false; } } Future _initialize() async { try { log('Starting app initialization...', name: 'App'); // Try Telegram Web App authentication first final telegramAuthSuccess = await _tryTelegramWebAppAuth(); // If Telegram Web App auth succeeded, skip normal auto-login // (tokens are already saved and user is set) if (telegramAuthSuccess) { log('Telegram Web App auth succeeded, skipping normal auto-login', name: 'App'); } else { // Try auto-login with timeout log('Attempting auto-login...', name: 'App'); UserDto? user; try { user = await widget.appScope.authService.autoLogin().timeout( const Duration(seconds: 3), onTimeout: () { log('Auto-login timed out, continuing as guest', name: 'App'); return null; }, ); } catch (e) { log('Auto-login failed with error, continuing as guest', error: e, name: 'App'); user = null; } // Create UserScope if needed if (widget.appScope.userScopeHolder.scope == null) { log('Creating UserScope...', name: 'App'); await widget.appScope.userScopeHolder.create(); } if (user != null) { log('Auto-login successful, setting user', name: 'App'); await widget.appScope.userScopeHolder.scope!.userStateManager.setUser(user); // Notify router about auth change widget.appScope.userScopeHolder.notifyAuthChanged(); log('UserScope created and user set', name: 'App'); } else { log('No saved session, starting as guest', name: 'App'); } } log('Setting _isInitialized = true', name: 'App'); setState(() { _isInitialized = true; }); log('App initialization completed', name: 'App'); } catch (e) { log('Error during initialization', error: e, name: 'App'); // Continue as guest even if auto-login fails log('Continuing as guest after error', name: 'App'); setState(() { _isInitialized = true; }); } } @override Widget build(BuildContext context) { log('_AppInitializer build called, _isInitialized: $_isInitialized', name: 'App'); if (!_isInitialized) { log('Showing loading screen', name: 'App'); return _LoadingScreen(appScope: widget.appScope, message: 'Loading...'); } log('Building main app', name: 'App'); return StateBuilder( stateReadable: widget.appScope.themeManager, builder: (context, themeState, _) { log('StateBuilder builder called with themeState: ${themeState.mode}', name: 'App'); return _buildAppWithUserScope(themeState); }, ); } Widget _buildAppWithUserScope(ThemeState themeState) { Widget app = MaterialApp.router( title: 'Mnemo Cards', routerConfig: widget.appScope.router, theme: AppTheme.light, darkTheme: AppTheme.dark, themeMode: themeState.mode, scaffoldMessengerKey: scaffoldMessengerKey, debugShowCheckedModeBanner: false, ); // Wrap with UserScope provider only if UserScope exists if (widget.appScope.userScopeHolder.scope != null) { return ScopeProvider( holder: widget.appScope.userScopeHolder, child: app, ); } // For guest users, return app without UserScope provider return app; } } /// Плейсхолдер экрана загрузки (без доступа к теме) class _LoadingPlaceholder extends StatelessWidget { const _LoadingPlaceholder({required this.message}); final String message; @override Widget build(BuildContext context) { return MaterialApp( theme: AppTheme.light, home: Scaffold( backgroundColor: AppTheme.light.scaffoldBackgroundColor, body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( 'assets/images/el_sol.png', width: 120, height: 120, ), const SizedBox(height: 24), Text( message, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: AppColors.black, ), ), ], ), ), ), ); } } /// Экран загрузки class _LoadingScreen extends StatelessWidget { const _LoadingScreen({ required this.appScope, required this.message, }); final AppScopeContainer appScope; final String message; @override Widget build(BuildContext context) { return FutureBuilder( future: _getThemeState(), builder: (context, snapshot) { final themeState = snapshot.data ?? ThemeState(ThemeMode.system); final isDark = themeState.mode == ThemeMode.dark || (themeState.mode == ThemeMode.system && MediaQuery.platformBrightnessOf(context) == Brightness.dark); return MaterialApp( theme: AppTheme.light, darkTheme: AppTheme.dark, themeMode: themeState.mode, home: Scaffold( backgroundColor: isDark ? AppTheme.dark.scaffoldBackgroundColor : AppTheme.light.scaffoldBackgroundColor, body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( isDark ? 'assets/images/la_luna.png' : 'assets/images/el_sol.png', width: 120, height: 120, ), const SizedBox(height: 24), Text( message, style: TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: isDark ? AppColors.white : AppColors.black, ), ), ], ), ), ), ); }, ); } Future _getThemeState() async { try { return appScope.themeManager.state; } catch (e) { // Fallback to system theme if themeManager is not available return ThemeState(ThemeMode.system); } } }