mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-05-24 23:32:13 +00:00
207 lines
6 KiB
Dart
207 lines
6 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:firebase_messaging/firebase_messaging.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/onboarding/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<App> createState() => _AppState();
|
|
}
|
|
|
|
class _AppState extends State<App> 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<SettingsChangeProvider>(),
|
|
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<SettingsChangeProvider>().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<SettingsChangeProvider>().themeMode,
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class AppMainWidget extends StatefulWidget {
|
|
const AppMainWidget({
|
|
required this.initialPage,
|
|
super.key,
|
|
});
|
|
final int initialPage;
|
|
@override
|
|
State<AppMainWidget> createState() => _AppMainWidgetState();
|
|
}
|
|
|
|
class _AppMainWidgetState extends State<AppMainWidget> {
|
|
bool _showOnboarding = true;
|
|
bool _isLoaded = false;
|
|
bool _isTwonlyLocked = true;
|
|
|
|
(Future<int>?, bool) _proofOfWork = (null, false);
|
|
|
|
@override
|
|
void initState() {
|
|
initAsync();
|
|
super.initState();
|
|
}
|
|
|
|
Future<void> initAsync() async {
|
|
if (userService.isUserCreated) {
|
|
await FirebaseMessaging.instance.requestPermission();
|
|
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.skipSetupPages &&
|
|
userService.currentUser.currentSetupPage != null) {
|
|
// This will only be shown in case the user have not skipped
|
|
child = SetupView(
|
|
onUpdate: () => setState(() {
|
|
// userService.currentUser has updated...
|
|
}),
|
|
);
|
|
} 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(),
|
|
],
|
|
);
|
|
}
|
|
}
|