import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/localization/generated/app_localizations.dart'; import 'package:twonly/src/providers/routing.provider.dart'; import 'package:twonly/src/providers/settings.provider.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/pow.dart'; import 'package:twonly/src/visual/components/app_outdated.comp.dart'; import 'package:twonly/src/visual/themes/dark.dart'; import 'package:twonly/src/visual/themes/light.dart'; import 'package:twonly/src/visual/views/critical_error.view.dart'; import 'package:twonly/src/visual/views/home.view.dart'; import 'package:twonly/src/visual/views/onboarding/onboarding.view.dart'; import 'package:twonly/src/visual/views/onboarding/register.view.dart'; import 'package:twonly/src/visual/views/settings/backup/backup_setup.view.dart'; import 'package:twonly/src/visual/views/unlock_twonly.view.dart'; class App extends StatefulWidget { const App({required this.storageError, super.key}); final bool storageError; @override State createState() => _AppState(); } class _AppState extends State with WidgetsBindingObserver { bool _wasPaused = false; @override void initState() { super.initState(); AppState.isAppInBackground = false; WidgetsBinding.instance.addObserver(this); } @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); if (state == AppLifecycleState.resumed) { if (_wasPaused) { AppState.isAppInBackground = false; twonlyDB.markUpdated(); unawaited(apiService.connect()); } } else if (state == AppLifecycleState.paused) { _wasPaused = true; AppState.isAppInBackground = true; } } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override Widget build(BuildContext context) { return ListenableBuilder( listenable: context.read(), builder: (context, child) { const localizationsDelegates = [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ]; const supportedLocales = [ Locale('en', ''), Locale('de', ''), ]; if (widget.storageError) { return MaterialApp( scaffoldMessengerKey: AppGlobalKeys.scaffoldMessengerKey, localizationsDelegates: localizationsDelegates, debugShowCheckedModeBanner: false, supportedLocales: supportedLocales, title: 'twonly', theme: lightTheme, darkTheme: darkTheme, themeMode: context.read().themeMode, home: const CriticalErrorView(), ); } return MaterialApp.router( routerConfig: routerProvider, scaffoldMessengerKey: AppGlobalKeys.scaffoldMessengerKey, localizationsDelegates: localizationsDelegates, debugShowCheckedModeBanner: false, supportedLocales: supportedLocales, title: 'twonly', theme: lightTheme, darkTheme: darkTheme, themeMode: context.read().themeMode, ); }, ); } } class AppMainWidget extends StatefulWidget { const AppMainWidget({ required this.initialPage, super.key, }); final int initialPage; @override State createState() => _AppMainWidgetState(); } class _AppMainWidgetState extends State { bool _showOnboarding = true; bool _isLoaded = false; bool _skipBackup = kDebugMode; bool _isTwonlyLocked = true; (Future?, bool) _proofOfWork = (null, false); @override void initState() { initAsync(); super.initState(); } Future initAsync() async { if (userService.isUserCreated) { if (_isTwonlyLocked) { // do not change in case twonly was already unlocked at some point _isTwonlyLocked = userService.currentUser.screenLockEnabled; } } else { // This means the user is in the onboarding screen, so start with the Proof of Work. final (proof, disabled) = await apiService.getProofOfWork(); if (proof != null) { Log.info('Starting with proof of work calculation.'); _proofOfWork = ( calculatePoW(proof.prefix, proof.difficulty.toInt()), false, ); } else { _proofOfWork = (null, disabled); } } setState(() { _isLoaded = true; }); } @override Widget build(BuildContext context) { if (!_isLoaded) { return Center(child: Container()); } late Widget child; if (userService.isUserCreated) { if (_isTwonlyLocked) { child = UnlockTwonlyView( callbackOnSuccess: () => setState(() { _isTwonlyLocked = false; }), ); } else if (userService.currentUser.twonlySafeBackup == null && !_skipBackup) { child = SetupBackupView( callBack: () => setState(() { _skipBackup = true; }), ); } else { child = HomeView( initialPage: widget.initialPage, ); } } else if (_showOnboarding) { child = OnboardingView( callbackOnSuccess: () => setState(() { _showOnboarding = false; }), ); } else { child = RegisterView( callbackOnSuccess: initAsync, proofOfWork: _proofOfWork, ); } return Stack( children: [ child, const AppOutdatedComp(), ], ); } }