mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-05-25 05:22:13 +00:00
rename global variables into app state
This commit is contained in:
parent
715774bd7f
commit
e945e30991
13 changed files with 82 additions and 75 deletions
|
|
@ -32,7 +32,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
globalIsAppInBackground = false;
|
AppState.isAppInBackground = false;
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
|
||||||
unawaited(initAsync());
|
unawaited(initAsync());
|
||||||
|
|
@ -54,13 +54,13 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
super.didChangeAppLifecycleState(state);
|
super.didChangeAppLifecycleState(state);
|
||||||
if (state == AppLifecycleState.resumed) {
|
if (state == AppLifecycleState.resumed) {
|
||||||
if (wasPaused) {
|
if (wasPaused) {
|
||||||
globalIsAppInBackground = false;
|
AppState.isAppInBackground = false;
|
||||||
twonlyDB.markUpdated();
|
twonlyDB.markUpdated();
|
||||||
unawaited(apiService.connect());
|
unawaited(apiService.connect());
|
||||||
}
|
}
|
||||||
} else if (state == AppLifecycleState.paused) {
|
} else if (state == AppLifecycleState.paused) {
|
||||||
wasPaused = true;
|
wasPaused = true;
|
||||||
globalIsAppInBackground = true;
|
AppState.isAppInBackground = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,7 +77,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
return MaterialApp.router(
|
return MaterialApp.router(
|
||||||
routerConfig: routerProvider,
|
routerConfig: routerProvider,
|
||||||
scaffoldMessengerKey: globalRootScaffoldMessengerKey,
|
scaffoldMessengerKey: AppGlobalKeys.scaffoldMessengerKey,
|
||||||
localizationsDelegates: const [
|
localizationsDelegates: const [
|
||||||
AppLocalizations.delegate,
|
AppLocalizations.delegate,
|
||||||
GlobalMaterialLocalizations.delegate,
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:camera/camera.dart';
|
import 'package:camera/camera.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
@ -17,6 +19,18 @@ class AppEnvironment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AppState {
|
||||||
|
static bool isAppInBackground = true;
|
||||||
|
static bool isInBackgroundTask = false;
|
||||||
|
static bool allowErrorTrackingViaSentry = false;
|
||||||
|
static bool gotMessageFromServer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppGlobalKeys {
|
||||||
|
static final GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey =
|
||||||
|
GlobalKey<ScaffoldMessengerState>();
|
||||||
|
}
|
||||||
|
|
||||||
late ApiService apiService;
|
late ApiService apiService;
|
||||||
|
|
||||||
// uses for background notification
|
// uses for background notification
|
||||||
|
|
@ -26,20 +40,4 @@ late TwonlyDB twonlyDB;
|
||||||
// which will update this global variable. The variable is set in the main.dart and after the user has registered in the register.view.dart
|
// which will update this global variable. The variable is set in the main.dart and after the user has registered in the register.view.dart
|
||||||
late UserData gUser;
|
late UserData gUser;
|
||||||
|
|
||||||
// The following global function can be called from anywhere to update
|
final userDataUpdateController = StreamController<void>.broadcast();
|
||||||
// the UI when something changed. The callbacks will be set by
|
|
||||||
// App widget.
|
|
||||||
|
|
||||||
// This callback called by the apiProvider
|
|
||||||
void Function() globalCallbackAppIsOutdated = () {};
|
|
||||||
void Function() globalCallbackNewDeviceRegistered = () {};
|
|
||||||
|
|
||||||
Map<String, VoidCallback> globalUserDataChangedCallBack = {};
|
|
||||||
|
|
||||||
bool globalIsAppInBackground = true;
|
|
||||||
bool globalIsInBackgroundTask = false;
|
|
||||||
bool globalAllowErrorTrackingViaSentry = false;
|
|
||||||
bool globalGotMessageFromServer = false;
|
|
||||||
|
|
||||||
final GlobalKey<ScaffoldMessengerState> globalRootScaffoldMessengerKey =
|
|
||||||
GlobalKey<ScaffoldMessengerState>();
|
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ void main() async {
|
||||||
gUser = user;
|
gUser = user;
|
||||||
|
|
||||||
if (user.allowErrorTrackingViaSentry) {
|
if (user.allowErrorTrackingViaSentry) {
|
||||||
globalAllowErrorTrackingViaSentry = true;
|
AppState.allowErrorTrackingViaSentry = true;
|
||||||
await SentryFlutter.init(
|
await SentryFlutter.init(
|
||||||
(options) => options
|
(options) => options
|
||||||
..dsn =
|
..dsn =
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,12 @@ class ApiService {
|
||||||
final _connectionStateController = StreamController<bool>.broadcast();
|
final _connectionStateController = StreamController<bool>.broadcast();
|
||||||
Stream<bool> get onConnectionStateUpdated => _connectionStateController.stream;
|
Stream<bool> get onConnectionStateUpdated => _connectionStateController.stream;
|
||||||
|
|
||||||
|
final _appOutdatedController = StreamController<void>.broadcast();
|
||||||
|
Stream<void> get onAppOutdated => _appOutdatedController.stream;
|
||||||
|
|
||||||
|
final _newDeviceRegisteredController = StreamController<void>.broadcast();
|
||||||
|
Stream<void> get onNewDeviceRegistered => _newDeviceRegisteredController.stream;
|
||||||
|
|
||||||
bool appIsOutdated = false;
|
bool appIsOutdated = false;
|
||||||
bool isAuthenticated = false;
|
bool isAuthenticated = false;
|
||||||
|
|
||||||
|
|
@ -97,12 +103,12 @@ class ApiService {
|
||||||
await initFCMAfterAuthenticated();
|
await initFCMAfterAuthenticated();
|
||||||
_connectionStateController.add(true);
|
_connectionStateController.add(true);
|
||||||
|
|
||||||
if (globalIsInBackgroundTask) {
|
if (AppState.isInBackgroundTask) {
|
||||||
await retransmitRawBytes();
|
await retransmitRawBytes();
|
||||||
await retransmitAllMessages();
|
await retransmitAllMessages();
|
||||||
await reuploadMediaFiles();
|
await reuploadMediaFiles();
|
||||||
await tryDownloadAllMediaFiles();
|
await tryDownloadAllMediaFiles();
|
||||||
} else if (!globalIsAppInBackground) {
|
} else if (!AppState.isAppInBackground) {
|
||||||
unawaited(retransmitRawBytes());
|
unawaited(retransmitRawBytes());
|
||||||
unawaited(retransmitAllMessages());
|
unawaited(retransmitAllMessages());
|
||||||
unawaited(tryDownloadAllMediaFiles());
|
unawaited(tryDownloadAllMediaFiles());
|
||||||
|
|
@ -140,7 +146,7 @@ class ApiService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> startReconnectionTimer() async {
|
Future<void> startReconnectionTimer() async {
|
||||||
if (globalIsInBackgroundTask) return;
|
if (AppState.isInBackgroundTask) return;
|
||||||
if (reconnectionTimer?.isActive ?? false) {
|
if (reconnectionTimer?.isActive ?? false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +154,7 @@ class ApiService {
|
||||||
reconnectionTimer = Timer(Duration(seconds: _reconnectionDelay), () async {
|
reconnectionTimer = Timer(Duration(seconds: _reconnectionDelay), () async {
|
||||||
reconnectionTimer = null;
|
reconnectionTimer = null;
|
||||||
// only try to reconnect in case the app is in the foreground
|
// only try to reconnect in case the app is in the foreground
|
||||||
if (!globalIsAppInBackground) {
|
if (!AppState.isAppInBackground) {
|
||||||
await connect();
|
await connect();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -353,14 +359,14 @@ class ApiService {
|
||||||
Log.warn('Got error from server: ${res.error}');
|
Log.warn('Got error from server: ${res.error}');
|
||||||
}
|
}
|
||||||
if (res.error == ErrorCode.AppVersionOutdated) {
|
if (res.error == ErrorCode.AppVersionOutdated) {
|
||||||
globalCallbackAppIsOutdated();
|
_appOutdatedController.add(null);
|
||||||
Log.warn('App Version is OUTDATED.');
|
Log.warn('App Version is OUTDATED.');
|
||||||
appIsOutdated = true;
|
appIsOutdated = true;
|
||||||
await close(() {});
|
await close(() {});
|
||||||
return Result.error(ErrorCode.InternalError);
|
return Result.error(ErrorCode.InternalError);
|
||||||
}
|
}
|
||||||
if (res.error == ErrorCode.NewDeviceRegistered) {
|
if (res.error == ErrorCode.NewDeviceRegistered) {
|
||||||
globalCallbackNewDeviceRegistered();
|
_newDeviceRegisteredController.add(null);
|
||||||
Log.warn(
|
Log.warn(
|
||||||
'Device is disabled, as a newer device restore twonly Backup.',
|
'Device is disabled, as a newer device restore twonly Backup.',
|
||||||
);
|
);
|
||||||
|
|
@ -416,7 +422,7 @@ class ApiService {
|
||||||
..userId = Int64(userId)
|
..userId = Int64(userId)
|
||||||
..appVersion = (await PackageInfo.fromPlatform()).version
|
..appVersion = (await PackageInfo.fromPlatform()).version
|
||||||
..deviceId = Int64(user.deviceId)
|
..deviceId = Int64(user.deviceId)
|
||||||
..inBackground = globalIsInBackgroundTask
|
..inBackground = AppState.isInBackgroundTask
|
||||||
..authToken = base64Decode(apiAuthToken);
|
..authToken = base64Decode(apiAuthToken);
|
||||||
|
|
||||||
final handshake = Handshake()..authenticate = authenticate;
|
final handshake = Handshake()..authenticate = authenticate;
|
||||||
|
|
@ -427,7 +433,7 @@ class ApiService {
|
||||||
if (result.isSuccess) {
|
if (result.isSuccess) {
|
||||||
Log.info('websocket is authenticated');
|
Log.info('websocket is authenticated');
|
||||||
isAuthenticated = true;
|
isAuthenticated = true;
|
||||||
if (globalIsInBackgroundTask) {
|
if (AppState.isInBackgroundTask) {
|
||||||
await onAuthenticated();
|
await onAuthenticated();
|
||||||
} else {
|
} else {
|
||||||
unawaited(onAuthenticated());
|
unawaited(onAuthenticated());
|
||||||
|
|
|
||||||
|
|
@ -593,9 +593,9 @@ Future<void> _uploadUploadRequest(MediaFileService media) async {
|
||||||
|
|
||||||
final connectivityResult = await Connectivity().checkConnectivity();
|
final connectivityResult = await Connectivity().checkConnectivity();
|
||||||
|
|
||||||
if (globalIsInBackgroundTask ||
|
if (AppState.isInBackgroundTask ||
|
||||||
!connectivityResult.contains(ConnectivityResult.mobile) &&
|
!connectivityResult.contains(ConnectivityResult.mobile) &&
|
||||||
!connectivityResult.contains(ConnectivityResult.wifi)) {
|
!connectivityResult.contains(ConnectivityResult.wifi)) {
|
||||||
// no internet, directly put it into the background...
|
// no internet, directly put it into the background...
|
||||||
await FileDownloader().enqueue(task);
|
await FileDownloader().enqueue(task);
|
||||||
await media.setUploadState(UploadState.backgroundUploadTaskStarted);
|
await media.setUploadState(UploadState.backgroundUploadTaskStarted);
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ Future<void> handleServerMessage(server.ServerToClient msg) async {
|
||||||
..response = response;
|
..response = response;
|
||||||
|
|
||||||
await apiService.sendResponse(ClientToServer()..v0 = v0);
|
await apiService.sendResponse(ClientToServer()..v0 = v0);
|
||||||
globalGotMessageFromServer = true;
|
AppState.gotMessageFromServer = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ Future<bool> initBackgroundExecution() async {
|
||||||
|
|
||||||
twonlyDB = TwonlyDB();
|
twonlyDB = TwonlyDB();
|
||||||
apiService = ApiService();
|
apiService = ApiService();
|
||||||
globalIsInBackgroundTask = true;
|
AppState.isInBackgroundTask = true;
|
||||||
|
|
||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -124,7 +124,7 @@ Future<void> handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!globalGotMessageFromServer) {
|
while (!AppState.gotMessageFromServer) {
|
||||||
if (stopwatch.elapsed.inSeconds >= 15) {
|
if (stopwatch.elapsed.inSeconds >= 15) {
|
||||||
Log.info('No new message from the server after 15 seconds.');
|
Log.info('No new message from the server after 15 seconds.');
|
||||||
break;
|
break;
|
||||||
|
|
@ -132,7 +132,7 @@ Future<void> handlePeriodicTask({int lastExecutionInSecondsLimit = 120}) async {
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalGotMessageFromServer) {
|
if (AppState.gotMessageFromServer) {
|
||||||
Log.info('Received a server message from the server.');
|
Log.info('Received a server message from the server.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ Future<void> handleRemoteMessage(RemoteMessage message) async {
|
||||||
if (!Platform.isAndroid) {
|
if (!Platform.isAndroid) {
|
||||||
Log.error('Got message in Dart while on iOS');
|
Log.error('Got message in Dart while on iOS');
|
||||||
}
|
}
|
||||||
if (message.notification != null && globalIsAppInBackground) {
|
if (message.notification != null && AppState.isAppInBackground) {
|
||||||
Log.error(
|
Log.error(
|
||||||
'Got notification but app is in background, so the SDK already have shown the message.',
|
'Got notification but app is in background, so the SDK already have shown the message.',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ class Log {
|
||||||
StackTrace? stackTrace,
|
StackTrace? stackTrace,
|
||||||
]) {
|
]) {
|
||||||
final message = filterLogMessage('$messageInput');
|
final message = filterLogMessage('$messageInput');
|
||||||
if (globalAllowErrorTrackingViaSentry) {
|
if (AppState.allowErrorTrackingViaSentry) {
|
||||||
try {
|
try {
|
||||||
throw Exception(message);
|
throw Exception(message);
|
||||||
} catch (exception, stackTrace) {
|
} catch (exception, stackTrace) {
|
||||||
|
|
|
||||||
|
|
@ -72,13 +72,8 @@ Future<UserData?> updateUserdata(
|
||||||
gUser = updated;
|
gUser = updated;
|
||||||
return updated;
|
return updated;
|
||||||
});
|
});
|
||||||
try {
|
userDataUpdateController.add(null);
|
||||||
for (final callBack in globalUserDataChangedCallBack.values) {
|
|
||||||
callBack();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
Log.error(e);
|
|
||||||
}
|
|
||||||
return userData;
|
return userData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -379,10 +379,10 @@ class MainCameraController {
|
||||||
}
|
}
|
||||||
await HapticFeedback.heavyImpact();
|
await HapticFeedback.heavyImpact();
|
||||||
if (verificationOk) {
|
if (verificationOk) {
|
||||||
globalRootScaffoldMessengerKey.currentState?.showSnackBar(
|
AppGlobalKeys.scaffoldMessengerKey.currentState?.showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(
|
content: Text(
|
||||||
globalRootScaffoldMessengerKey.currentContext?.lang
|
AppGlobalKeys.scaffoldMessengerKey.currentContext?.lang
|
||||||
.verifiedPublicKey(
|
.verifiedPublicKey(
|
||||||
getContactDisplayName(contact),
|
getContactDisplayName(contact),
|
||||||
) ??
|
) ??
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
@ -17,28 +18,36 @@ class _AppOutdatedState extends State<AppOutdated> {
|
||||||
bool appIsOutdated = false;
|
bool appIsOutdated = false;
|
||||||
bool newDeviceRegistered = false;
|
bool newDeviceRegistered = false;
|
||||||
|
|
||||||
|
late StreamSubscription<void> _subOutdated;
|
||||||
|
late StreamSubscription<void> _subNewDevice;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
globalCallbackAppIsOutdated = () {};
|
_subOutdated.cancel();
|
||||||
globalCallbackNewDeviceRegistered = () {};
|
_subNewDevice.cancel();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
globalCallbackAppIsOutdated = () async {
|
|
||||||
await context.read<CustomChangeProvider>().updateConnectionState(false);
|
|
||||||
setState(() {
|
|
||||||
appIsOutdated = true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
globalCallbackNewDeviceRegistered = () async {
|
|
||||||
await context.read<CustomChangeProvider>().updateConnectionState(false);
|
|
||||||
setState(() {
|
|
||||||
newDeviceRegistered = true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_subOutdated = apiService.onAppOutdated.listen((_) async {
|
||||||
|
if (mounted) {
|
||||||
|
await context.read<CustomChangeProvider>().updateConnectionState(false);
|
||||||
|
setState(() {
|
||||||
|
appIsOutdated = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_subNewDevice = apiService.onNewDeviceRegistered.listen((_) async {
|
||||||
|
if (mounted) {
|
||||||
|
await context.read<CustomChangeProvider>().updateConnectionState(false);
|
||||||
|
setState(() {
|
||||||
|
newDeviceRegistered = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,12 @@ class AvatarIcon extends StatefulWidget {
|
||||||
|
|
||||||
class _AvatarIconState extends State<AvatarIcon> {
|
class _AvatarIconState extends State<AvatarIcon> {
|
||||||
List<Contact> _avatarContacts = [];
|
List<Contact> _avatarContacts = [];
|
||||||
String? _globalUserDataCallBackId;
|
|
||||||
String? _avatarSvg;
|
String? _avatarSvg;
|
||||||
|
|
||||||
StreamSubscription<List<Contact>>? groupStream;
|
StreamSubscription<List<Contact>>? groupStream;
|
||||||
StreamSubscription<List<Contact>>? contactsStream;
|
StreamSubscription<List<Contact>>? contactsStream;
|
||||||
StreamSubscription<Contact?>? contactStream;
|
StreamSubscription<Contact?>? contactStream;
|
||||||
|
StreamSubscription<void>? _userDataSub;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|
@ -46,9 +46,7 @@ class _AvatarIconState extends State<AvatarIcon> {
|
||||||
groupStream?.cancel();
|
groupStream?.cancel();
|
||||||
contactStream?.cancel();
|
contactStream?.cancel();
|
||||||
contactsStream?.cancel();
|
contactsStream?.cancel();
|
||||||
if (_globalUserDataCallBackId != null) {
|
_userDataSub?.cancel();
|
||||||
globalUserDataChangedCallBack.remove(_globalUserDataCallBackId);
|
|
||||||
}
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,16 +93,17 @@ class _AvatarIconState extends State<AvatarIcon> {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
});
|
});
|
||||||
} else if (widget.myAvatar) {
|
} else if (widget.myAvatar) {
|
||||||
_globalUserDataCallBackId = 'avatar_${getRandomString(10)}';
|
_userDataSub = userDataUpdateController.stream.listen((_) {
|
||||||
globalUserDataChangedCallBack[_globalUserDataCallBackId!] = () {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (gUser.avatarSvg != null) {
|
if (gUser.avatarSvg != null) {
|
||||||
_avatarSvg = gUser.avatarSvg;
|
_avatarSvg = gUser.avatarSvg;
|
||||||
} else {
|
} else {
|
||||||
_avatarContacts = [];
|
_avatarContacts = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
});
|
||||||
if (gUser.avatarSvg != null) {
|
if (gUser.avatarSvg != null) {
|
||||||
_avatarSvg = gUser.avatarSvg;
|
_avatarSvg = gUser.avatarSvg;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue