mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 14:48:41 +00:00
use mutex when updating user
This commit is contained in:
parent
6946164d1e
commit
20030ccd14
23 changed files with 194 additions and 136 deletions
|
|
@ -44,6 +44,10 @@ class UserData {
|
|||
|
||||
DateTime? signalLastSignedPreKeyUpdated;
|
||||
|
||||
@JsonKey(defaultValue: false)
|
||||
bool identityBackupEnabled = false;
|
||||
DateTime? identityBackupLastBackupTime;
|
||||
|
||||
final int userId;
|
||||
|
||||
factory UserData.fromJson(Map<String, dynamic> json) =>
|
||||
|
|
|
|||
|
|
@ -44,7 +44,12 @@ UserData _$UserDataFromJson(Map<String, dynamic> json) => UserData(
|
|||
..signalLastSignedPreKeyUpdated =
|
||||
json['signalLastSignedPreKeyUpdated'] == null
|
||||
? null
|
||||
: DateTime.parse(json['signalLastSignedPreKeyUpdated'] as String);
|
||||
: DateTime.parse(json['signalLastSignedPreKeyUpdated'] as String)
|
||||
..identityBackupEnabled = json['identityBackupEnabled'] as bool? ?? false
|
||||
..identityBackupLastBackupTime =
|
||||
json['identityBackupLastBackupTime'] == null
|
||||
? null
|
||||
: DateTime.parse(json['identityBackupLastBackupTime'] as String);
|
||||
|
||||
Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
|
||||
'username': instance.username,
|
||||
|
|
@ -69,6 +74,9 @@ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
|
|||
'myBestFriendContactId': instance.myBestFriendContactId,
|
||||
'signalLastSignedPreKeyUpdated':
|
||||
instance.signalLastSignedPreKeyUpdated?.toIso8601String(),
|
||||
'identityBackupEnabled': instance.identityBackupEnabled,
|
||||
'identityBackupLastBackupTime':
|
||||
instance.identityBackupLastBackupTime?.toIso8601String(),
|
||||
'userId': instance.userId,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,9 @@ class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
|||
|
||||
notifyListeners();
|
||||
|
||||
var user = await getUser();
|
||||
if (user != null) {
|
||||
await updateUserdata((user) {
|
||||
user.themeMode = newThemeMode;
|
||||
await updateUser(user);
|
||||
}
|
||||
return user;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import 'package:package_info_plus/package_info_plus.dart';
|
|||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/app.dart';
|
||||
import 'package:twonly/src/database/twonly_database.dart';
|
||||
import 'package:twonly/src/model/json/userdata.dart';
|
||||
import 'package:twonly/src/model/protobuf/api/websocket/client_to_server.pbserver.dart';
|
||||
import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart';
|
||||
import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart'
|
||||
|
|
@ -347,11 +346,10 @@ class ApiService {
|
|||
server.Response_Ok ok = result.value;
|
||||
if (ok.hasAuthenticated()) {
|
||||
server.Response_Authenticated authenticated = ok.authenticated;
|
||||
UserData? user = await getUser();
|
||||
if (user != null) {
|
||||
updateUserdata((user) {
|
||||
user.subscriptionPlan = authenticated.plan;
|
||||
await updateUser(user);
|
||||
}
|
||||
return user;
|
||||
});
|
||||
}
|
||||
Log.info("websocket is authenticated");
|
||||
onAuthenticated();
|
||||
|
|
|
|||
|
|
@ -34,20 +34,24 @@ Future<ErrorCode?> isAllowedToSend() async {
|
|||
return ErrorCode.PlanNotAllowed;
|
||||
}
|
||||
if (user.subscriptionPlan == "Free") {
|
||||
int? todaysImageCounter = user.todaysImageCounter;
|
||||
if (user.lastImageSend != null && user.todaysImageCounter != null) {
|
||||
if (isToday(user.lastImageSend!)) {
|
||||
if (user.todaysImageCounter == 3) {
|
||||
return ErrorCode.PlanLimitReached;
|
||||
}
|
||||
user.todaysImageCounter = user.todaysImageCounter! + 1;
|
||||
todaysImageCounter = user.todaysImageCounter! + 1;
|
||||
} else {
|
||||
user.todaysImageCounter = 1;
|
||||
todaysImageCounter = 1;
|
||||
}
|
||||
} else {
|
||||
user.todaysImageCounter = 1;
|
||||
todaysImageCounter = 1;
|
||||
}
|
||||
user.lastImageSend = DateTime.now();
|
||||
await updateUser(user);
|
||||
await updateUserdata((user) {
|
||||
user.lastImageSend = DateTime.now();
|
||||
user.todaysImageCounter = todaysImageCounter;
|
||||
return user;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
20
lib/src/services/backup.identitiy.service.dart
Normal file
20
lib/src/services/backup.identitiy.service.dart
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import 'package:twonly/src/utils/storage.dart';
|
||||
|
||||
Future<bool> isIdentityBackupEnabled() async {
|
||||
final user = await getUser();
|
||||
if (user == null) return false;
|
||||
return user.identityBackupEnabled;
|
||||
}
|
||||
|
||||
Future<DateTime?> getLastIdentityBackup() async {
|
||||
final user = await getUser();
|
||||
if (user == null) return null;
|
||||
return user.identityBackupLastBackupTime;
|
||||
}
|
||||
|
||||
Future enableIdentityBackup() async {
|
||||
await updateUserdata((user) {
|
||||
user.identityBackupEnabled = false;
|
||||
return user;
|
||||
});
|
||||
}
|
||||
|
|
@ -21,8 +21,10 @@ Future syncFlameCounters() async {
|
|||
contacts.firstWhere((x) => x.totalMediaCounter == maxMessageCounter);
|
||||
|
||||
if (user.myBestFriendContactId != bestFriend.userId) {
|
||||
user.myBestFriendContactId = bestFriend.userId;
|
||||
await updateUser(user);
|
||||
await updateUserdata((user) {
|
||||
user.myBestFriendContactId = bestFriend.userId;
|
||||
return user;
|
||||
});
|
||||
}
|
||||
|
||||
for (Contact contact in contacts) {
|
||||
|
|
|
|||
|
|
@ -38,8 +38,10 @@ Future signalHandleNewServerConnection() async {
|
|||
Log.error("could not generate a new signed pre key!");
|
||||
return;
|
||||
}
|
||||
user.signalLastSignedPreKeyUpdated = DateTime.now();
|
||||
await updateUser(user);
|
||||
await updateUserdata((user) {
|
||||
user.signalLastSignedPreKeyUpdated = DateTime.now();
|
||||
return user;
|
||||
});
|
||||
Result res = await apiService.updateSignedPreKey(
|
||||
signedPreKey.id,
|
||||
signedPreKey.getKeyPair().publicKey.serialize(),
|
||||
|
|
@ -47,10 +49,10 @@ Future signalHandleNewServerConnection() async {
|
|||
);
|
||||
if (res.isError) {
|
||||
Log.error("could not update the signed pre key: ${res.error}");
|
||||
final UserData? user = await getUser();
|
||||
if (user == null) return;
|
||||
user.signalLastSignedPreKeyUpdated = null;
|
||||
await updateUser(user);
|
||||
await updateUserdata((user) {
|
||||
user.signalLastSignedPreKeyUpdated = null;
|
||||
return user;
|
||||
});
|
||||
} else {
|
||||
Log.info("updated signed pre key");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:twonly/src/model/json/userdata.dart';
|
||||
|
|
@ -33,18 +34,27 @@ Future<UserData?> getUser() async {
|
|||
|
||||
Future updateUsersPlan(BuildContext context, String planId) async {
|
||||
context.read<CustomChangeProvider>().plan = planId;
|
||||
var user = await getUser();
|
||||
if (user != null) {
|
||||
|
||||
await updateUserdata((user) {
|
||||
user.subscriptionPlan = planId;
|
||||
await updateUser(user);
|
||||
}
|
||||
return user;
|
||||
});
|
||||
|
||||
if (!context.mounted) return;
|
||||
context.read<CustomChangeProvider>().updatePlan(planId);
|
||||
}
|
||||
|
||||
Future updateUser(UserData userData) async {
|
||||
final storage = FlutterSecureStorage();
|
||||
storage.write(key: "userData", value: jsonEncode(userData));
|
||||
Mutex updateProtection = Mutex();
|
||||
|
||||
Future<UserData?> updateUserdata(Function(UserData userData) updateUser) async {
|
||||
return await updateProtection.protect<UserData?>(() async {
|
||||
final user = await getUser();
|
||||
if (user == null) return null;
|
||||
UserData updated = updateUser(user);
|
||||
final storage = FlutterSecureStorage();
|
||||
storage.write(key: "userData", value: jsonEncode(updated));
|
||||
return user;
|
||||
});
|
||||
}
|
||||
|
||||
Future<bool> deleteLocalUserData() async {
|
||||
|
|
|
|||
|
|
@ -558,11 +558,10 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
|||
onPressed: () async {
|
||||
useHighQuality = !useHighQuality;
|
||||
setState(() {});
|
||||
var user = await getUser();
|
||||
if (user != null) {
|
||||
await updateUserdata((user) {
|
||||
user.useHighQuality = useHighQuality;
|
||||
updateUser(user);
|
||||
}
|
||||
return user;
|
||||
});
|
||||
},
|
||||
),
|
||||
if (!hasAudioPermission)
|
||||
|
|
|
|||
|
|
@ -29,21 +29,21 @@ class _EmojisState extends State<Emojis> {
|
|||
}
|
||||
|
||||
Future selectEmojis(String emoji) async {
|
||||
final user = await getUser();
|
||||
if (user == null) return;
|
||||
if (user.lastUsedEditorEmojis == null) {
|
||||
user.lastUsedEditorEmojis = [emoji];
|
||||
} else {
|
||||
if (user.lastUsedEditorEmojis!.contains(emoji)) {
|
||||
user.lastUsedEditorEmojis!.remove(emoji);
|
||||
await updateUserdata((user) {
|
||||
if (user.lastUsedEditorEmojis == null) {
|
||||
user.lastUsedEditorEmojis = [emoji];
|
||||
} else {
|
||||
if (user.lastUsedEditorEmojis!.contains(emoji)) {
|
||||
user.lastUsedEditorEmojis!.remove(emoji);
|
||||
}
|
||||
user.lastUsedEditorEmojis!.insert(0, emoji);
|
||||
if (user.lastUsedEditorEmojis!.length > 12) {
|
||||
user.lastUsedEditorEmojis = user.lastUsedEditorEmojis!.sublist(0, 12);
|
||||
}
|
||||
user.lastUsedEditorEmojis!.toSet().toList();
|
||||
}
|
||||
user.lastUsedEditorEmojis!.insert(0, emoji);
|
||||
if (user.lastUsedEditorEmojis!.length > 12) {
|
||||
user.lastUsedEditorEmojis = user.lastUsedEditorEmojis!.sublist(0, 12);
|
||||
}
|
||||
user.lastUsedEditorEmojis!.toSet().toList();
|
||||
}
|
||||
await updateUser(user);
|
||||
return user;
|
||||
});
|
||||
if (!mounted) return;
|
||||
Navigator.pop(
|
||||
context,
|
||||
|
|
|
|||
|
|
@ -233,11 +233,10 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
|||
maxShowTime = gMediaShowInfinite;
|
||||
}
|
||||
setState(() {});
|
||||
var user = await getUser();
|
||||
if (user != null) {
|
||||
await updateUserdata((user) {
|
||||
user.defaultShowTime = maxShowTime;
|
||||
updateUser(user);
|
||||
}
|
||||
return user;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:twonly/src/services/backup.identitiy.service.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/views/settings/backup/twonly_identity_backup.view.dart';
|
||||
|
||||
|
|
@ -22,10 +23,10 @@ class _BackupViewState extends State<BackupView> {
|
|||
}
|
||||
|
||||
Future initAsync() async {
|
||||
setState(() {
|
||||
_twonlyIdBackupEnabled = true;
|
||||
_dataBackupEnabled = false;
|
||||
});
|
||||
_twonlyIdBackupEnabled = await isIdentityBackupEnabled();
|
||||
_twonlyIdLastBackup = await getLastIdentityBackup();
|
||||
_dataBackupEnabled = false;
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -37,7 +38,7 @@ class _BackupViewState extends State<BackupView> {
|
|||
body: ListView(
|
||||
children: [
|
||||
BackupOption(
|
||||
title: 'twonly-Identity Backup',
|
||||
title: 'twonly Safe',
|
||||
description:
|
||||
'Back up your twonly identity, as this is the only way to restore your account if you uninstall or lose your phone.',
|
||||
lastBackup: _twonlyIdLastBackup,
|
||||
|
|
@ -51,7 +52,7 @@ class _BackupViewState extends State<BackupView> {
|
|||
},
|
||||
),
|
||||
BackupOption(
|
||||
title: 'Daten-Backup',
|
||||
title: 'Daten-Backup (Coming Soon)',
|
||||
description:
|
||||
'This backup contains besides of your twonly-Identity also all of your media files. This backup will also be encrypted using a password chosen by the user but stored locally on the smartphone. You then have to ensure to manually copy it onto your laptop or device of your choice.',
|
||||
autoBackupEnabled: _dataBackupEnabled,
|
||||
|
|
|
|||
|
|
@ -13,12 +13,14 @@ class _TwonlyIdentityBackupViewState extends State<TwonlyIdentityBackupView> {
|
|||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("twonly-Identity Backup"),
|
||||
title: Text("twonly Safe"),
|
||||
),
|
||||
body: ListView(
|
||||
children: [
|
||||
Text(
|
||||
'Backup of your twonly-Identity. As twonly does not have any second factor like your phone number or email, this backup contains your twonly-Identity. If you lose your device, the only option to recover is with the twonly-ID Backup. This backup will be protected by a password chosen by you in the next step and anonymously uploaded to the twonly servers. Read more [here](https://twonly.eu/s/backup).'),
|
||||
],
|
||||
),
|
||||
body: ListView(children: [
|
||||
Text(
|
||||
'Backup of your twonly-Identity. As twonly does not have any second factor like your phone number or email, this backup contains your twonly-Identity. If you lose your device, the only option to recover is with the twonly-ID Backup. This backup will be protected by a password chosen by you in the next step and anonymously uploaded to the twonly servers. Read more [here](https://twonly.eu/s/backup).'),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,11 +36,10 @@ class _ChatReactionSelectionView extends State<ChatReactionSelectionView> {
|
|||
} else {
|
||||
if (selectedEmojis.length < 12) {
|
||||
selectedEmojis.add(emoji);
|
||||
var user = await getUser();
|
||||
if (user != null) {
|
||||
await updateUserdata((user) {
|
||||
user.preSelectedEmojies = selectedEmojis;
|
||||
await updateUser(user);
|
||||
}
|
||||
return user;
|
||||
});
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
|
|
@ -98,11 +97,10 @@ class _ChatReactionSelectionView extends State<ChatReactionSelectionView> {
|
|||
selectedEmojis =
|
||||
EmojiAnimation.animatedIcons.keys.toList().sublist(0, 6);
|
||||
setState(() {});
|
||||
var user = await getUser();
|
||||
if (user != null) {
|
||||
await updateUserdata((user) {
|
||||
user.preSelectedEmojies = selectedEmojis;
|
||||
await updateUser(user);
|
||||
}
|
||||
return user;
|
||||
});
|
||||
},
|
||||
child: Icon(Icons.settings_backup_restore_rounded),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -48,10 +48,10 @@ class _DataAndStorageViewState extends State<DataAndStorageView> {
|
|||
}
|
||||
|
||||
void toggleStoreInGallery() async {
|
||||
final user = await getUser();
|
||||
if (user == null) return;
|
||||
user.storeMediaFilesInGallery = !storeMediaFilesInGallery;
|
||||
await updateUser(user);
|
||||
await updateUserdata((u) {
|
||||
u.storeMediaFilesInGallery = !storeMediaFilesInGallery;
|
||||
return u;
|
||||
});
|
||||
initAsync();
|
||||
}
|
||||
|
||||
|
|
@ -179,10 +179,12 @@ class _AutoDownloadOptionsDialogState extends State<AutoDownloadOptionsDialog> {
|
|||
}
|
||||
|
||||
// Call the onUpdate callback to notify the parent widget
|
||||
final user = await getUser();
|
||||
if (user == null) return;
|
||||
user.autoDownloadOptions = autoDownloadOptions;
|
||||
await updateUser(user);
|
||||
|
||||
await updateUserdata((u) {
|
||||
u.autoDownloadOptions = autoDownloadOptions;
|
||||
return u;
|
||||
});
|
||||
|
||||
widget.onUpdate();
|
||||
setState(() {});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,10 +39,10 @@ class HelpView extends StatelessWidget {
|
|||
title: Text(context.lang.settingsResetTutorials),
|
||||
subtitle: Text(context.lang.settingsResetTutorialsDesc),
|
||||
onTap: () async {
|
||||
final user = await getUser();
|
||||
if (user == null) return;
|
||||
user.tutorialDisplayed = [];
|
||||
await updateUser(user);
|
||||
updateUserdata((user) {
|
||||
user.tutorialDisplayed = [];
|
||||
return user;
|
||||
});
|
||||
if (!context.mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import 'dart:math';
|
|||
import 'package:avatar_maker/avatar_maker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:twonly/src/model/json/userdata.dart';
|
||||
import 'package:twonly/src/services/api/messages.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import "package:get/get.dart";
|
||||
|
|
@ -12,17 +11,16 @@ class ModifyAvatar extends StatelessWidget {
|
|||
const ModifyAvatar({super.key});
|
||||
|
||||
Future updateUserAvatar(String json, String svg) async {
|
||||
UserData? user = await getUser();
|
||||
if (user == null) return null;
|
||||
|
||||
user.avatarJson = json;
|
||||
user.avatarSvg = svg;
|
||||
if (user.avatarCounter == null) {
|
||||
user.avatarCounter = 1;
|
||||
} else {
|
||||
user.avatarCounter = user.avatarCounter! + 1;
|
||||
}
|
||||
await updateUser(user);
|
||||
await updateUserdata((user) {
|
||||
user.avatarJson = json;
|
||||
user.avatarSvg = svg;
|
||||
if (user.avatarCounter == null) {
|
||||
user.avatarCounter = 1;
|
||||
} else {
|
||||
user.avatarCounter = user.avatarCounter! + 1;
|
||||
}
|
||||
return user;
|
||||
});
|
||||
await notifyContactsAboutProfileChange();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,16 +29,17 @@ class _ProfileViewState extends State<ProfileView> {
|
|||
setState(() {});
|
||||
}
|
||||
|
||||
Future updateUserDisplayname(String displayName) async {
|
||||
UserData? user = await getUser();
|
||||
if (user == null) return null;
|
||||
user.displayName = displayName;
|
||||
if (user.avatarCounter == null) {
|
||||
user.avatarCounter = 1;
|
||||
} else {
|
||||
user.avatarCounter = user.avatarCounter! + 1;
|
||||
}
|
||||
await updateUser(user);
|
||||
Future updateUserDisplayName(String displayName) async {
|
||||
await updateUserdata((user) {
|
||||
user.displayName = displayName;
|
||||
if (user.avatarCounter == null) {
|
||||
user.avatarCounter = 1;
|
||||
} else {
|
||||
user.avatarCounter = user.avatarCounter! + 1;
|
||||
}
|
||||
return user;
|
||||
});
|
||||
|
||||
await notifyContactsAboutProfileChange();
|
||||
initAsync();
|
||||
}
|
||||
|
|
@ -83,7 +84,7 @@ class _ProfileViewState extends State<ProfileView> {
|
|||
final displayName =
|
||||
await showDisplayNameChangeDialog(context, user!.displayName);
|
||||
if (context.mounted && displayName != null && displayName != "") {
|
||||
updateUserDisplayname(displayName);
|
||||
updateUserDisplayName(displayName);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:twonly/src/utils/misc.dart';
|
|||
import 'package:twonly/src/utils/storage.dart';
|
||||
import 'package:twonly/src/views/settings/account.view.dart';
|
||||
import 'package:twonly/src/views/settings/appearance.view.dart';
|
||||
import 'package:twonly/src/views/settings/backup/backup.view.dart';
|
||||
import 'package:twonly/src/views/settings/chat/chat_settings.view.dart';
|
||||
import 'package:twonly/src/views/settings/data_and_storage.view.dart';
|
||||
import 'package:twonly/src/views/settings/notification.view.dart';
|
||||
|
|
@ -120,16 +121,16 @@ class _SettingsMainViewState extends State<SettingsMainView> {
|
|||
}));
|
||||
},
|
||||
),
|
||||
// BetterListTile(
|
||||
// icon: Icons.lock_clock_rounded,
|
||||
// text: context.lang.settingsBackup,
|
||||
// onTap: () {
|
||||
// Navigator.push(context,
|
||||
// MaterialPageRoute(builder: (context) {
|
||||
// return BackupView();
|
||||
// }));
|
||||
// },
|
||||
// ),
|
||||
BetterListTile(
|
||||
icon: Icons.lock_clock_rounded,
|
||||
text: context.lang.settingsBackup,
|
||||
onTap: () {
|
||||
Navigator.push(context,
|
||||
MaterialPageRoute(builder: (context) {
|
||||
return BackupView();
|
||||
}));
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
BetterListTile(
|
||||
icon: FontAwesomeIcons.sun,
|
||||
|
|
|
|||
|
|
@ -14,24 +14,27 @@ import 'package:twonly/src/views/components/alert_dialog.dart';
|
|||
import 'package:twonly/src/views/settings/subscription/subscription.view.dart';
|
||||
|
||||
Future<List<Response_AddAccountsInvite>?> loadAdditionalUserInvites() async {
|
||||
List<Response_AddAccountsInvite>? ballance;
|
||||
final user = await getUser();
|
||||
if (user == null) return ballance;
|
||||
ballance = await apiService.getAdditionalUserInvites();
|
||||
final ballance = await apiService.getAdditionalUserInvites();
|
||||
if (ballance != null) {
|
||||
user.additionalUserInvites =
|
||||
jsonEncode(ballance.map((x) => x.writeToJson()).toList());
|
||||
await updateUser(user);
|
||||
} else if (user.lastPlanBallance != null) {
|
||||
await updateUserdata((u) {
|
||||
u.additionalUserInvites =
|
||||
jsonEncode(ballance.map((x) => x.writeToJson()).toList());
|
||||
return u;
|
||||
});
|
||||
return ballance;
|
||||
}
|
||||
final user = await getUser();
|
||||
if (user != null && user.lastPlanBallance != null) {
|
||||
try {
|
||||
List<String> decoded = jsonDecode(user.additionalUserInvites!);
|
||||
ballance =
|
||||
decoded.map((x) => Response_AddAccountsInvite.fromJson(x)).toList();
|
||||
return decoded
|
||||
.map((x) => Response_AddAccountsInvite.fromJson(x))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
Log.error("from json: $e");
|
||||
}
|
||||
}
|
||||
return ballance;
|
||||
return null;
|
||||
}
|
||||
|
||||
class AdditionalUsersView extends StatefulWidget {
|
||||
|
|
|
|||
|
|
@ -36,16 +36,18 @@ String localePrizing(BuildContext context, int cents) {
|
|||
}
|
||||
|
||||
Future<Response_PlanBallance?> loadPlanBalance({bool useCache = true}) async {
|
||||
Response_PlanBallance? ballance;
|
||||
final user = await getUser();
|
||||
if (user == null) return ballance;
|
||||
ballance = await apiService.getPlanBallance();
|
||||
final ballance = await apiService.getPlanBallance();
|
||||
if (ballance != null) {
|
||||
user.lastPlanBallance = ballance.writeToJson();
|
||||
await updateUser(user);
|
||||
} else if (user.lastPlanBallance != null && useCache) {
|
||||
updateUserdata((u) {
|
||||
u.lastPlanBallance = ballance.writeToJson();
|
||||
return u;
|
||||
});
|
||||
return ballance;
|
||||
}
|
||||
final user = await getUser();
|
||||
if (user != null && user.lastPlanBallance != null && useCache) {
|
||||
try {
|
||||
ballance = Response_PlanBallance.fromJson(
|
||||
return Response_PlanBallance.fromJson(
|
||||
user.lastPlanBallance!,
|
||||
);
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,12 @@ Future<bool> checkIfTutorialAlreadyShown(String tutorialId) async {
|
|||
return true;
|
||||
}
|
||||
user.tutorialDisplayed!.add(tutorialId);
|
||||
await updateUser(user);
|
||||
|
||||
await updateUserdata((u) {
|
||||
u.tutorialDisplayed = user.tutorialDisplayed;
|
||||
return u;
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue