mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-05-25 05:22:13 +00:00
move user handling to a single user service
This commit is contained in:
parent
583368505d
commit
1e72883db0
31 changed files with 126 additions and 166 deletions
13
lib/app.dart
13
lib/app.dart
|
|
@ -11,7 +11,6 @@ import 'package:twonly/src/providers/purchases.provider.dart';
|
||||||
import 'package:twonly/src/providers/routing.provider.dart';
|
import 'package:twonly/src/providers/routing.provider.dart';
|
||||||
import 'package:twonly/src/providers/settings.provider.dart';
|
import 'package:twonly/src/providers/settings.provider.dart';
|
||||||
import 'package:twonly/src/services/subscription.service.dart';
|
import 'package:twonly/src/services/subscription.service.dart';
|
||||||
import 'package:twonly/src/services/user.service.dart';
|
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/pow.dart';
|
import 'package:twonly/src/utils/pow.dart';
|
||||||
import 'package:twonly/src/visual/components/app_outdated.comp.dart';
|
import 'package:twonly/src/visual/components/app_outdated.comp.dart';
|
||||||
|
|
@ -45,10 +44,9 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
|
|
||||||
Future<void> initAsync() async {
|
Future<void> initAsync() async {
|
||||||
try {
|
try {
|
||||||
final user = await getUser();
|
if (userService.isUserCreated && mounted) {
|
||||||
if (user != null && mounted) {
|
|
||||||
context.read<PurchasesProvider>().updatePlan(
|
context.read<PurchasesProvider>().updatePlan(
|
||||||
planFromString(user.subscriptionPlan),
|
planFromString(userService.currentUser.subscriptionPlan),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -142,7 +140,6 @@ class AppMainWidget extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppMainWidgetState extends State<AppMainWidget> {
|
class _AppMainWidgetState extends State<AppMainWidget> {
|
||||||
bool _isUserCreated = false;
|
|
||||||
bool _showOnboarding = true;
|
bool _showOnboarding = true;
|
||||||
bool _isLoaded = false;
|
bool _isLoaded = false;
|
||||||
Object? _storageError;
|
Object? _storageError;
|
||||||
|
|
@ -159,9 +156,7 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
||||||
|
|
||||||
Future<void> initAsync() async {
|
Future<void> initAsync() async {
|
||||||
try {
|
try {
|
||||||
_isUserCreated = await isUserCreated();
|
if (userService.isUserCreated) {
|
||||||
|
|
||||||
if (_isUserCreated) {
|
|
||||||
if (_isTwonlyLocked) {
|
if (_isTwonlyLocked) {
|
||||||
// do not change in case twonly was already unlocked at some point
|
// do not change in case twonly was already unlocked at some point
|
||||||
_isTwonlyLocked = userService.currentUser.screenLockEnabled;
|
_isTwonlyLocked = userService.currentUser.screenLockEnabled;
|
||||||
|
|
@ -202,7 +197,7 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
||||||
|
|
||||||
late Widget child;
|
late Widget child;
|
||||||
|
|
||||||
if (_isUserCreated) {
|
if (userService.isUserCreated) {
|
||||||
if (_isTwonlyLocked) {
|
if (_isTwonlyLocked) {
|
||||||
child = UnlockTwonlyView(
|
child = UnlockTwonlyView(
|
||||||
callbackOnSuccess: () => setState(() {
|
callbackOnSuccess: () => setState(() {
|
||||||
|
|
|
||||||
|
|
@ -107,9 +107,8 @@ void main() async {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final settingsController = SettingsChangeProvider();
|
final settingsController = SettingsChangeProvider()..loadSettings();
|
||||||
|
|
||||||
await settingsController.loadSettings();
|
|
||||||
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
||||||
|
|
||||||
await initFileDownloader();
|
await initFileDownloader();
|
||||||
|
|
@ -144,13 +143,13 @@ Future<void> runMigrations() async {
|
||||||
if (userService.currentUser.appVersion < 90) {
|
if (userService.currentUser.appVersion < 90) {
|
||||||
// BUG: Requested media files for reupload where not reuploaded because the wrong state...
|
// BUG: Requested media files for reupload where not reuploaded because the wrong state...
|
||||||
await twonlyDB.mediaFilesDao.updateAllRetransmissionUploadingState();
|
await twonlyDB.mediaFilesDao.updateAllRetransmissionUploadingState();
|
||||||
await updateUser((u) => u.appVersion = 90);
|
await UserService.update((u) => u.appVersion = 90);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userService.currentUser.appVersion < 91) {
|
if (userService.currentUser.appVersion < 91) {
|
||||||
// BUG: Requested media files for reupload where not reuploaded because the wrong state...
|
// BUG: Requested media files for reupload where not reuploaded because the wrong state...
|
||||||
await makeMigrationToVersion91();
|
await makeMigrationToVersion91();
|
||||||
await updateUser((u) => u.appVersion = 91);
|
await UserService.update((u) => u.appVersion = 91);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userService.currentUser.appVersion < 109) {
|
if (userService.currentUser.appVersion < 109) {
|
||||||
|
|
@ -163,6 +162,6 @@ Future<void> runMigrations() async {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await updateUser((u) => u.appVersion = 109);
|
await UserService.update((u) => u.appVersion = 109);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,8 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
_planSub = apiService.onPlanUpdated.listen(updatePlan);
|
_planSub = apiService.onPlanUpdated.listen(updatePlan);
|
||||||
_connSub = apiService.onConnectionStateUpdated.listen((_) async {
|
_connSub = apiService.onConnectionStateUpdated.listen((_) async {
|
||||||
try {
|
try {
|
||||||
final user = await getUser();
|
if (userService.isUserCreated) {
|
||||||
if (user != null) {
|
updatePlan(planFromString(userService.currentUser.subscriptionPlan));
|
||||||
updatePlan(planFromString(user.subscriptionPlan));
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
Log.error(e);
|
||||||
|
|
@ -95,8 +94,10 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final user = await getUser();
|
if (userService.isUserCreated &&
|
||||||
if (user != null && isPayingUser(planFromString(user.subscriptionPlan))) {
|
isPayingUser(
|
||||||
|
planFromString(userService.currentUser.subscriptionPlan),
|
||||||
|
)) {
|
||||||
Log.info('Started IPA timer for verification.');
|
Log.info('Started IPA timer for verification.');
|
||||||
globalForceIpaCheck = Timer(const Duration(seconds: 5), () async {
|
globalForceIpaCheck = Timer(const Duration(seconds: 5), () async {
|
||||||
Log.info(
|
Log.info(
|
||||||
|
|
@ -185,7 +186,7 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
// an ok authenticated which is processed in the apiProvider...
|
// an ok authenticated which is processed in the apiProvider...
|
||||||
if (res.isSuccess) {
|
if (res.isSuccess) {
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.subscriptionPlanIdStore = purchaseDetails.productID;
|
u.subscriptionPlanIdStore = purchaseDetails.productID;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -216,11 +217,10 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
purchaseDetails.error == null) {
|
purchaseDetails.error == null) {
|
||||||
globalForceIpaCheck?.cancel();
|
globalForceIpaCheck?.cancel();
|
||||||
|
|
||||||
final user = await getUser();
|
final currentPlan = userService.currentUser.subscriptionPlan;
|
||||||
|
|
||||||
if (user != null &&
|
if (currentPlan != SubscriptionPlan.Family.name &&
|
||||||
(user.subscriptionPlan != SubscriptionPlan.Family.name &&
|
currentPlan != SubscriptionPlan.Pro.name) {
|
||||||
user.subscriptionPlan != SubscriptionPlan.Pro.name)) {
|
|
||||||
for (var i = 0; i < 100; i++) {
|
for (var i = 0; i < 100; i++) {
|
||||||
if (apiService.isAuthenticated) {
|
if (apiService.isAuthenticated) {
|
||||||
Log.info(
|
Log.info(
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,19 @@
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/services/user.service.dart';
|
import 'package:twonly/src/services/user.service.dart';
|
||||||
import 'package:twonly/src/utils/log.dart';
|
|
||||||
|
|
||||||
class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
late ThemeMode _themeMode;
|
late ThemeMode _themeMode;
|
||||||
|
|
||||||
ThemeMode get themeMode => _themeMode;
|
ThemeMode get themeMode => _themeMode;
|
||||||
|
|
||||||
Future<void> loadSettings() async {
|
void loadSettings() {
|
||||||
try {
|
if (userService.isUserCreated) {
|
||||||
_themeMode = (await getUser())?.themeMode ?? ThemeMode.system;
|
_themeMode = userService.currentUser.themeMode;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
} catch (e) {
|
} else {
|
||||||
_themeMode = ThemeMode.system;
|
_themeMode = ThemeMode.system;
|
||||||
Log.error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,6 +26,6 @@ class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
await updateUser((u) => u.themeMode = newThemeMode);
|
await UserService.update((u) => u.themeMode = newThemeMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -354,7 +354,7 @@ class ApiService {
|
||||||
final ok = res.value as server.Response_Ok;
|
final ok = res.value as server.Response_Ok;
|
||||||
if (ok.hasAuthenticated()) {
|
if (ok.hasAuthenticated()) {
|
||||||
final authenticated = ok.authenticated;
|
final authenticated = ok.authenticated;
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
user.subscriptionPlan = authenticated.plan;
|
user.subscriptionPlan = authenticated.plan;
|
||||||
});
|
});
|
||||||
_planUpdateController.add(planFromString(authenticated.plan));
|
_planUpdateController.add(planFromString(authenticated.plan));
|
||||||
|
|
@ -470,8 +470,7 @@ class ApiService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final userData = await getUser();
|
if (userService.isUserCreated) return;
|
||||||
if (userData == null) return;
|
|
||||||
|
|
||||||
if (await tryAuthenticateWithToken()) {
|
if (await tryAuthenticateWithToken()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -501,7 +500,7 @@ class ApiService {
|
||||||
|
|
||||||
final getAuthToken = Handshake_GetAuthToken()
|
final getAuthToken = Handshake_GetAuthToken()
|
||||||
..response = signature
|
..response = signature
|
||||||
..userId = Int64(userData.userId);
|
..userId = Int64(userService.currentUser.userId);
|
||||||
|
|
||||||
final getauthtoken = Handshake()..getAuthToken = getAuthToken;
|
final getauthtoken = Handshake()..getAuthToken = getAuthToken;
|
||||||
|
|
||||||
|
|
@ -791,7 +790,7 @@ class ApiService {
|
||||||
Future<Response_PlanBallance?> loadPlanBalance({bool useCache = true}) async {
|
Future<Response_PlanBallance?> loadPlanBalance({bool useCache = true}) async {
|
||||||
final ballance = await getPlanBallance();
|
final ballance = await getPlanBallance();
|
||||||
if (ballance != null) {
|
if (ballance != null) {
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.lastPlanBallance = ballance.writeToJson();
|
u.lastPlanBallance = ballance.writeToJson();
|
||||||
});
|
});
|
||||||
return ballance;
|
return ballance;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ Future<void> enableTwonlySafe(String password) async {
|
||||||
userService.currentUser.username,
|
userService.currentUser.username,
|
||||||
);
|
);
|
||||||
|
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
user.twonlySafeBackup = TwonlySafeBackup(
|
user.twonlySafeBackup = TwonlySafeBackup(
|
||||||
encryptionKey: encryptionKey,
|
encryptionKey: encryptionKey,
|
||||||
backupId: backupId,
|
backupId: backupId,
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ Future<void> performTwonlySafeBackup({bool force = false}) async {
|
||||||
key: SecureStorageKeys.signalSignedPreKey,
|
key: SecureStorageKeys.signalSignedPreKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
final userBackup = await getUser();
|
final userBackup = await UserService.getUser();
|
||||||
if (userBackup == null) return;
|
if (userBackup == null) return;
|
||||||
// FILTER settings which should not be in the backup
|
// FILTER settings which should not be in the backup
|
||||||
userBackup
|
userBackup
|
||||||
|
|
@ -183,7 +183,7 @@ Future<void> performTwonlySafeBackup({bool force = false}) async {
|
||||||
if (encryptedBackupBytes.length >
|
if (encryptedBackupBytes.length >
|
||||||
userService.currentUser.backupServer!.maxBackupBytes) {
|
userService.currentUser.backupServer!.maxBackupBytes) {
|
||||||
Log.error('Backup is to big for the alternative backup server.');
|
Log.error('Backup is to big for the alternative backup server.');
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.failed;
|
user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.failed;
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
|
@ -203,7 +203,7 @@ Future<void> performTwonlySafeBackup({bool force = false}) async {
|
||||||
);
|
);
|
||||||
if (await FileDownloader().enqueue(task)) {
|
if (await FileDownloader().enqueue(task)) {
|
||||||
Log.info('Starting upload from twonly Backup.');
|
Log.info('Starting upload from twonly Backup.');
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.pending;
|
user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.pending;
|
||||||
user.twonlySafeBackup!.lastBackupDone = clock.now();
|
user.twonlySafeBackup!.lastBackupDone = clock.now();
|
||||||
user.twonlySafeBackup!.lastBackupSize = encryptedBackupBytes.length;
|
user.twonlySafeBackup!.lastBackupSize = encryptedBackupBytes.length;
|
||||||
|
|
@ -216,7 +216,7 @@ Future<void> performTwonlySafeBackup({bool force = false}) async {
|
||||||
Future<void> handleBackupStatusUpdate(TaskStatusUpdate update) async {
|
Future<void> handleBackupStatusUpdate(TaskStatusUpdate update) async {
|
||||||
if (update.status == TaskStatus.failed ||
|
if (update.status == TaskStatus.failed ||
|
||||||
update.status == TaskStatus.canceled) {
|
update.status == TaskStatus.canceled) {
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
if (user.twonlySafeBackup != null) {
|
if (user.twonlySafeBackup != null) {
|
||||||
user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.failed;
|
user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.failed;
|
||||||
}
|
}
|
||||||
|
|
@ -225,7 +225,7 @@ Future<void> handleBackupStatusUpdate(TaskStatusUpdate update) async {
|
||||||
Log.info(
|
Log.info(
|
||||||
'twonly Backup uploaded with status code ${update.responseStatusCode}',
|
'twonly Backup uploaded with status code ${update.responseStatusCode}',
|
||||||
);
|
);
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
if (user.twonlySafeBackup != null) {
|
if (user.twonlySafeBackup != null) {
|
||||||
user.twonlySafeBackup!.backupUploadState =
|
user.twonlySafeBackup!.backupUploadState =
|
||||||
LastBackupUploadState.success;
|
LastBackupUploadState.success;
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ Future<void> handleBackupData(
|
||||||
key: SecureStorageKeys.userData,
|
key: SecureStorageKeys.userData,
|
||||||
value: secureStorage[SecureStorageKeys.userData] as String,
|
value: secureStorage[SecureStorageKeys.userData] as String,
|
||||||
);
|
);
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.deviceId += 1;
|
u.deviceId += 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Future<void> syncFlameCounters({String? forceForGroup}) async {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (userService.currentUser.myBestFriendGroupId != bestFriend.groupId) {
|
if (userService.currentUser.myBestFriendGroupId != bestFriend.groupId) {
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
user.myBestFriendGroupId = bestFriend.groupId;
|
user.myBestFriendGroupId = bestFriend.groupId;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ Future<void> checkForTokenUpdates() async {
|
||||||
if (storedToken == null || fcmToken != storedToken) {
|
if (storedToken == null || fcmToken != storedToken) {
|
||||||
Log.info('Got new FCM TOKEN.');
|
Log.info('Got new FCM TOKEN.');
|
||||||
await storage.write(key: SecureStorageKeys.googleFcm, value: fcmToken);
|
await storage.write(key: SecureStorageKeys.googleFcm, value: fcmToken);
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.updateFCMToken = true;
|
u.updateFCMToken = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -61,7 +61,7 @@ Future<void> checkForTokenUpdates() async {
|
||||||
key: SecureStorageKeys.googleFcm,
|
key: SecureStorageKeys.googleFcm,
|
||||||
value: fcmToken,
|
value: fcmToken,
|
||||||
);
|
);
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.updateFCMToken = true;
|
u.updateFCMToken = true;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
@ -81,7 +81,7 @@ Future<void> initFCMAfterAuthenticated({bool force = false}) async {
|
||||||
final res = await apiService.updateFCMToken(storedToken);
|
final res = await apiService.updateFCMToken(storedToken);
|
||||||
if (res.isSuccess) {
|
if (res.isSuccess) {
|
||||||
Log.info('Uploaded new FCM token!');
|
Log.info('Uploaded new FCM token!');
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.updateFCMToken = false;
|
u.updateFCMToken = false;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ Future<void> signalHandleNewServerConnection() async {
|
||||||
Log.error('could not generate a new signed pre key!');
|
Log.error('could not generate a new signed pre key!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
user.signalLastSignedPreKeyUpdated = clock.now();
|
user.signalLastSignedPreKeyUpdated = clock.now();
|
||||||
});
|
});
|
||||||
final res = await apiService.updateSignedPreKey(
|
final res = await apiService.updateSignedPreKey(
|
||||||
|
|
@ -49,7 +49,7 @@ Future<void> signalHandleNewServerConnection() async {
|
||||||
);
|
);
|
||||||
if (res.isError) {
|
if (res.isError) {
|
||||||
Log.error('could not update the signed pre key: ${res.error}');
|
Log.error('could not update the signed pre key: ${res.error}');
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
user.signalLastSignedPreKeyUpdated = null;
|
user.signalLastSignedPreKeyUpdated = null;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -59,13 +59,9 @@ Future<void> signalHandleNewServerConnection() async {
|
||||||
|
|
||||||
Future<List<PreKeyRecord>> signalGetPreKeys() async {
|
Future<List<PreKeyRecord>> signalGetPreKeys() async {
|
||||||
return lockingSignalProtocol.protect(() async {
|
return lockingSignalProtocol.protect(() async {
|
||||||
final user = await getUser();
|
final start = userService.currentUser.currentPreKeyIndexStart;
|
||||||
if (user == null) return [];
|
await UserService.update((u) {
|
||||||
|
u.currentPreKeyIndexStart = (u.currentPreKeyIndexStart + 200) % maxValue;
|
||||||
final start = user.currentPreKeyIndexStart;
|
|
||||||
await updateUser((user) {
|
|
||||||
user.currentPreKeyIndexStart =
|
|
||||||
(user.currentPreKeyIndexStart + 200) % maxValue;
|
|
||||||
});
|
});
|
||||||
final preKeys = generatePreKeys(start, 200);
|
final preKeys = generatePreKeys(start, 200);
|
||||||
final signalStore = await getSignalStore();
|
final signalStore = await getSignalStore();
|
||||||
|
|
@ -138,14 +134,14 @@ Future<void> createIfNotExistsSignalIdentity() async {
|
||||||
Future<SignedPreKeyRecord?> _getNewSignalSignedPreKey() async {
|
Future<SignedPreKeyRecord?> _getNewSignalSignedPreKey() async {
|
||||||
return lockingSignalProtocol.protect(() async {
|
return lockingSignalProtocol.protect(() async {
|
||||||
var identityKeyPair = await getSignalIdentityKeyPair();
|
var identityKeyPair = await getSignalIdentityKeyPair();
|
||||||
final user = await getUser();
|
|
||||||
final signalStore = await getSignalStore();
|
final signalStore = await getSignalStore();
|
||||||
if (identityKeyPair == null || signalStore == null || user == null) {
|
if (identityKeyPair == null || signalStore == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final signedPreKeyId = user.currentSignedPreKeyIndexStart;
|
final signedPreKeyId =
|
||||||
await updateUser((user) {
|
userService.currentUser.currentSignedPreKeyIndexStart;
|
||||||
|
await UserService.update((user) {
|
||||||
user.currentSignedPreKeyIndexStart += 1;
|
user.currentSignedPreKeyIndexStart += 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,17 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
||||||
import 'package:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/constants/secure_storage.keys.dart';
|
import 'package:twonly/src/constants/secure_storage.keys.dart';
|
||||||
import 'package:twonly/src/model/json/userdata.model.dart';
|
import 'package:twonly/src/model/json/userdata.model.dart';
|
||||||
import 'package:twonly/src/providers/purchases.provider.dart';
|
|
||||||
import 'package:twonly/src/services/subscription.service.dart';
|
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/secure_storage.dart';
|
import 'package:twonly/src/utils/secure_storage.dart';
|
||||||
|
|
||||||
class UserService {
|
class UserService {
|
||||||
late UserData currentUser;
|
late UserData currentUser;
|
||||||
|
bool isUserCreated = false;
|
||||||
|
static final Mutex _updateProtection = Mutex();
|
||||||
|
|
||||||
final _userDataUpdateController = StreamController<void>.broadcast();
|
final _userDataUpdateController = StreamController<void>.broadcast();
|
||||||
Stream<void> get onUserUpdated => _userDataUpdateController.stream;
|
Stream<void> get onUserUpdated => _userDataUpdateController.stream;
|
||||||
|
|
@ -23,28 +20,11 @@ class UserService {
|
||||||
final user = await getUser();
|
final user = await getUser();
|
||||||
if (user == null) return false;
|
if (user == null) return false;
|
||||||
userService.currentUser = user;
|
userService.currentUser = user;
|
||||||
|
isUserCreated = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void triggerUserUpdate() {
|
static Future<UserData?> getUser() async {
|
||||||
_userDataUpdateController.add(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dispose() {
|
|
||||||
_userDataUpdateController.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> isUserCreated() async {
|
|
||||||
final user = await getUser();
|
|
||||||
if (user == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
userService.currentUser = user;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<UserData?> getUser() async {
|
|
||||||
try {
|
try {
|
||||||
final userDataJson = await SecureStorage.instance.read(
|
final userDataJson = await SecureStorage.instance.read(
|
||||||
key: SecureStorageKeys.userData,
|
key: SecureStorageKeys.userData,
|
||||||
|
|
@ -52,33 +32,19 @@ Future<UserData?> getUser() async {
|
||||||
if (userDataJson == null) {
|
if (userDataJson == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return UserData.fromJson(jsonDecode(userDataJson) as Map<String, dynamic>);
|
return UserData.fromJson(
|
||||||
|
jsonDecode(userDataJson) as Map<String, dynamic>,
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error('could not load user: $e');
|
Log.error('could not load user: $e');
|
||||||
rethrow; // Rethrow instead of returning null to distinguish error from missing user
|
rethrow; // Rethrow instead of returning null to distinguish error from missing user
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateUsersPlan(
|
static Future<void> update(
|
||||||
BuildContext context,
|
|
||||||
SubscriptionPlan plan,
|
|
||||||
) async {
|
|
||||||
context.read<PurchasesProvider>().plan = plan;
|
|
||||||
|
|
||||||
await updateUser((user) {
|
|
||||||
user.subscriptionPlan = plan.name;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!context.mounted) return;
|
|
||||||
context.read<PurchasesProvider>().updatePlan(plan);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mutex updateProtection = Mutex();
|
|
||||||
|
|
||||||
Future<void> updateUser(
|
|
||||||
void Function(UserData userData) updateUser,
|
void Function(UserData userData) updateUser,
|
||||||
) async {
|
) async {
|
||||||
await updateProtection.protect(() async {
|
await _updateProtection.protect(() async {
|
||||||
try {
|
try {
|
||||||
final user = await getUser();
|
final user = await getUser();
|
||||||
if (user == null) return;
|
if (user == null) return;
|
||||||
|
|
@ -87,7 +53,7 @@ Future<void> updateUser(
|
||||||
user.defaultShowTime = null;
|
user.defaultShowTime = null;
|
||||||
}
|
}
|
||||||
updateUser(user);
|
updateUser(user);
|
||||||
await const FlutterSecureStorage().write(
|
await SecureStorage.instance.write(
|
||||||
key: SecureStorageKeys.userData,
|
key: SecureStorageKeys.userData,
|
||||||
value: jsonEncode(user),
|
value: jsonEncode(user),
|
||||||
);
|
);
|
||||||
|
|
@ -99,3 +65,8 @@ Future<void> updateUser(
|
||||||
|
|
||||||
userService.triggerUserUpdate();
|
userService.triggerUserUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void triggerUserUpdate() {
|
||||||
|
_userDataUpdateController.add(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ class UserDiscoveryService {
|
||||||
userId: userService.currentUser.userId,
|
userId: userService.currentUser.userId,
|
||||||
publicKey: await getUserPublicKey(),
|
publicKey: await getUserPublicKey(),
|
||||||
);
|
);
|
||||||
await updateUser(
|
await UserService.update(
|
||||||
(u) => u
|
(u) => u
|
||||||
..isUserDiscoveryEnabled = true
|
..isUserDiscoveryEnabled = true
|
||||||
..minimumRequiredImagesExchanged = minimumRequiredImagesExchanged,
|
..minimumRequiredImagesExchanged = minimumRequiredImagesExchanged,
|
||||||
|
|
@ -168,7 +168,7 @@ class UserDiscoveryService {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> disable() async {
|
static Future<void> disable() async {
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.isUserDiscoveryEnabled = false;
|
u.isUserDiscoveryEnabled = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,13 +100,13 @@ Future<void> handleUserStudyUpload() async {
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
);
|
);
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.lastUserStudyDataUpload = DateTime.now();
|
u.lastUserStudyDataUpload = DateTime.now();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (response.statusCode == 404) {
|
if (response.statusCode == 404) {
|
||||||
// Token is unknown to the server...
|
// Token is unknown to the server...
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u
|
u
|
||||||
..lastUserStudyDataUpload = null
|
..lastUserStudyDataUpload = null
|
||||||
..userStudyParticipantsToken = null;
|
..userStudyParticipantsToken = null;
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
|
|
||||||
if (!_hasAudioPermission &&
|
if (!_hasAudioPermission &&
|
||||||
!userService.currentUser.requestedAudioPermission) {
|
!userService.currentUser.requestedAudioPermission) {
|
||||||
await updateUser((u) => u.requestedAudioPermission = true);
|
await UserService.update((u) => u.requestedAudioPermission = true);
|
||||||
await requestMicrophonePermission();
|
await requestMicrophonePermission();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
if (storeAsDefault) {
|
if (storeAsDefault) {
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
user.defaultShowTime = maxShowTime;
|
user.defaultShowTime = maxShowTime;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
if (!userService.currentUser.hideChangeLog &&
|
if (!userService.currentUser.hideChangeLog &&
|
||||||
userService.currentUser.lastChangeLogHash.toString() !=
|
userService.currentUser.lastChangeLogHash.toString() !=
|
||||||
changeLogHash.toString()) {
|
changeLogHash.toString()) {
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.lastChangeLogHash = changeLogHash;
|
u.lastChangeLogHash = changeLogHash;
|
||||||
});
|
});
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ class _RegisterViewState extends State<RegisterView> {
|
||||||
value: jsonEncode(userData),
|
value: jsonEncode(userData),
|
||||||
);
|
);
|
||||||
|
|
||||||
userService.currentUser = userData;
|
await userService.tryInit();
|
||||||
|
|
||||||
await apiService.authenticate();
|
await apiService.authenticate();
|
||||||
widget.callbackOnSuccess();
|
widget.callbackOnSuccess();
|
||||||
|
|
|
||||||
|
|
@ -73,19 +73,19 @@ class _AppearanceViewState extends State<AppearanceView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleShowFeedbackIcon() async {
|
Future<void> toggleShowFeedbackIcon() async {
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.showFeedbackShortcut = !u.showFeedbackShortcut;
|
u.showFeedbackShortcut = !u.showFeedbackShortcut;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleStartWithCameraOpen() async {
|
Future<void> toggleStartWithCameraOpen() async {
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.startWithCameraOpen = !u.startWithCameraOpen;
|
u.startWithCameraOpen = !u.startWithCameraOpen;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleShowImagePreviewWhenSending() async {
|
Future<void> toggleShowImagePreviewWhenSending() async {
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.showShowImagePreviewWhenSending = !u.showShowImagePreviewWhenSending;
|
u.showShowImagePreviewWhenSending = !u.showShowImagePreviewWhenSending;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ class _BackupServerViewState extends State<BackupServerView> {
|
||||||
retentionDays: data['retentionDays']! as int,
|
retentionDays: data['retentionDays']! as int,
|
||||||
maxBackupBytes: data['maxBackupBytes']! as int,
|
maxBackupBytes: data['maxBackupBytes']! as int,
|
||||||
);
|
);
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
user.backupServer = backupServer;
|
user.backupServer = backupServer;
|
||||||
});
|
});
|
||||||
if (mounted) Navigator.pop(context, backupServer);
|
if (mounted) Navigator.pop(context, backupServer);
|
||||||
|
|
@ -166,7 +166,7 @@ class _BackupServerViewState extends State<BackupServerView> {
|
||||||
Center(
|
Center(
|
||||||
child: OutlinedButton(
|
child: OutlinedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
user.backupServer = null;
|
user.backupServer = null;
|
||||||
});
|
});
|
||||||
if (context.mounted) Navigator.pop(context);
|
if (context.mounted) Navigator.pop(context);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class _ChatReactionSelectionView extends State<ChatReactionSelectionView> {
|
||||||
} else {
|
} else {
|
||||||
if (_selectedEmojis.length < 12) {
|
if (_selectedEmojis.length < 12) {
|
||||||
_selectedEmojis.add(emoji);
|
_selectedEmojis.add(emoji);
|
||||||
await updateUser((user) {
|
await UserService.update((user) {
|
||||||
user.preSelectedEmojies = _selectedEmojis;
|
user.preSelectedEmojies = _selectedEmojis;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -90,7 +90,7 @@ class _ChatReactionSelectionView extends State<ChatReactionSelectionView> {
|
||||||
padding: const EdgeInsets.only(bottom: 30),
|
padding: const EdgeInsets.only(bottom: 30),
|
||||||
child: FloatingActionButton(
|
child: FloatingActionButton(
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
onPressed: () => updateUser(
|
onPressed: () => UserService.update(
|
||||||
(u) => u.preSelectedEmojies = EmojiAnimationComp
|
(u) => u.preSelectedEmojies = EmojiAnimationComp
|
||||||
.animatedIcons
|
.animatedIcons
|
||||||
.keys
|
.keys
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,13 @@ class _DataAndStorageViewState extends State<DataAndStorageView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleStoreInGallery() async {
|
Future<void> toggleStoreInGallery() async {
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.storeMediaFilesInGallery = !u.storeMediaFilesInGallery;
|
u.storeMediaFilesInGallery = !u.storeMediaFilesInGallery;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleAutoStoreMediaFiles() async {
|
Future<void> toggleAutoStoreMediaFiles() async {
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.autoStoreAllSendUnlimitedMediaFiles =
|
u.autoStoreAllSendUnlimitedMediaFiles =
|
||||||
!u.autoStoreAllSendUnlimitedMediaFiles;
|
!u.autoStoreAllSendUnlimitedMediaFiles;
|
||||||
});
|
});
|
||||||
|
|
@ -227,7 +227,7 @@ class _AutoDownloadOptionsDialogState extends State<AutoDownloadOptionsDialog> {
|
||||||
|
|
||||||
// Call the onUpdate callback to notify the parent widget
|
// Call the onUpdate callback to notify the parent widget
|
||||||
|
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.autoDownloadOptions = autoDownloadOptions;
|
u.autoDownloadOptions = autoDownloadOptions;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,11 @@ class _DeveloperSettingsViewState extends State<DeveloperSettingsView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleDeveloperSettings() async {
|
Future<void> toggleDeveloperSettings() async {
|
||||||
await updateUser((u) => u.isDeveloper = !u.isDeveloper);
|
await UserService.update((u) => u.isDeveloper = !u.isDeveloper);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleVideoStabilization() async {
|
Future<void> toggleVideoStabilization() async {
|
||||||
await updateUser(
|
await UserService.update(
|
||||||
(u) => u.videoStabilizationEnabled = !u.videoStabilizationEnabled,
|
(u) => u.videoStabilizationEnabled = !u.videoStabilizationEnabled,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,8 +114,9 @@ class _ChangeLogViewState extends State<ChangeLogView> {
|
||||||
Text(context.lang.openChangeLog),
|
Text(context.lang.openChangeLog),
|
||||||
Switch(
|
Switch(
|
||||||
value: !userService.currentUser.hideChangeLog,
|
value: !userService.currentUser.hideChangeLog,
|
||||||
onChanged: (_) =>
|
onChanged: (_) => UserService.update(
|
||||||
updateUser((u) => u.hideChangeLog = !u.hideChangeLog),
|
(u) => u.hideChangeLog = !u.hideChangeLog,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ class HelpView extends StatefulWidget {
|
||||||
|
|
||||||
class _HelpViewState extends State<HelpView> {
|
class _HelpViewState extends State<HelpView> {
|
||||||
Future<void> toggleAllowErrorTrackingViaSentry() async {
|
Future<void> toggleAllowErrorTrackingViaSentry() async {
|
||||||
await updateUser(
|
await UserService.update(
|
||||||
(u) => u.allowErrorTrackingViaSentry = !u.allowErrorTrackingViaSentry,
|
(u) => u.allowErrorTrackingViaSentry = !u.allowErrorTrackingViaSentry,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +128,7 @@ class _HelpViewState extends State<HelpView> {
|
||||||
'Do you want to enable the developer settings?',
|
'Do you want to enable the developer settings?',
|
||||||
);
|
);
|
||||||
if (okay) {
|
if (okay) {
|
||||||
await updateUser((u) => u.isDeveloper = true);
|
await UserService.update((u) => u.isDeveloper = true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title: const Text(
|
title: const Text(
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,14 @@ class _PrivacyViewState extends State<PrivacyView> {
|
||||||
: context.lang.settingsScreenLockAuthMessageEnable,
|
: context.lang.settingsScreenLockAuthMessageEnable,
|
||||||
);
|
);
|
||||||
if (!isAuth) return;
|
if (!isAuth) return;
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.screenLockEnabled = !u.screenLockEnabled;
|
u.screenLockEnabled = !u.screenLockEnabled;
|
||||||
});
|
});
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleTypingIndicators() async {
|
Future<void> toggleTypingIndicators() async {
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u.typingIndicators = !u.typingIndicators;
|
u.typingIndicators = !u.typingIndicators;
|
||||||
});
|
});
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ class _UserDiscoverySettingsViewState extends State<UserDiscoverySettingsView> {
|
||||||
userService.currentUser.userDiscoveryThreshold !=
|
userService.currentUser.userDiscoveryThreshold !=
|
||||||
_userDiscoveryThreshold;
|
_userDiscoveryThreshold;
|
||||||
|
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
u
|
u
|
||||||
..minimumRequiredImagesExchanged = _minimumRequiredImagesExchanged
|
..minimumRequiredImagesExchanged = _minimumRequiredImagesExchanged
|
||||||
..userDiscoveryThreshold = _userDiscoveryThreshold;
|
..userDiscoveryThreshold = _userDiscoveryThreshold;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class _ModifyAvatarViewState extends State<ModifyAvatarView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateUserAvatar(String json, String svg) async {
|
Future<void> updateUserAvatar(String json, String svg) async {
|
||||||
await updateUser(
|
await UserService.update(
|
||||||
(u) => u
|
(u) => u
|
||||||
..avatarJson = json
|
..avatarJson = json
|
||||||
..avatarSvg = svg
|
..avatarSvg = svg
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ class _ProfileViewState extends State<ProfileView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateUserDisplayName(String displayName) async {
|
Future<void> updateUserDisplayName(String displayName) async {
|
||||||
await updateUser(
|
await UserService.update(
|
||||||
(u) => u
|
(u) => u
|
||||||
..displayName = displayName
|
..displayName = displayName
|
||||||
..avatarCounter = u.avatarCounter + 1,
|
..avatarCounter = u.avatarCounter + 1,
|
||||||
|
|
@ -93,7 +93,7 @@ class _ProfileViewState extends State<ProfileView> {
|
||||||
await removeTwonlySafeFromServer();
|
await removeTwonlySafeFromServer();
|
||||||
unawaited(performTwonlySafeBackup(force: true));
|
unawaited(performTwonlySafeBackup(force: true));
|
||||||
|
|
||||||
await updateUser(
|
await UserService.update(
|
||||||
(u) => u
|
(u) => u
|
||||||
..username = username
|
..username = username
|
||||||
..avatarCounter = u.avatarCounter + 1,
|
..avatarCounter = u.avatarCounter + 1,
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ class _UserStudyQuestionnaireViewState
|
||||||
Future<void> _submitData() async {
|
Future<void> _submitData() async {
|
||||||
await KeyValueStore.put(userStudySurveyKey, _responses);
|
await KeyValueStore.put(userStudySurveyKey, _responses);
|
||||||
|
|
||||||
await updateUser((u) {
|
await UserService.update((u) {
|
||||||
// generate a random participants id to identify data send later while keeping the user anonym
|
// generate a random participants id to identify data send later while keeping the user anonym
|
||||||
u
|
u
|
||||||
..userStudyParticipantsToken = getRandomString(25)
|
..userStudyParticipantsToken = getRandomString(25)
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ class _UserStudyWelcomeViewState extends State<UserStudyWelcomeView> {
|
||||||
Center(
|
Center(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await updateUser(
|
await UserService.update(
|
||||||
(u) => u.askedForUserStudyPermission = true,
|
(u) => u.askedForUserStudyPermission = true,
|
||||||
);
|
);
|
||||||
if (context.mounted) context.pop();
|
if (context.mounted) context.pop();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue