mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-05-25 05:22:13 +00:00
Fix: Some message where not marked as opened.
This commit is contained in:
parent
11c0ad908e
commit
0204a41d43
8 changed files with 240 additions and 187 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -10,6 +10,9 @@
|
||||||
.history
|
.history
|
||||||
.svn/
|
.svn/
|
||||||
.swiftpm/
|
.swiftpm/
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite-shm
|
||||||
|
*.sqlite-wal
|
||||||
migrate_working_dir/
|
migrate_working_dir/
|
||||||
|
|
||||||
# IntelliJ related
|
# IntelliJ related
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
- New: Tutorial on how to use zoom.
|
- New: Tutorial on how to use zoom.
|
||||||
- New: Manage storage view.
|
- New: Manage storage view.
|
||||||
- Improved: Media thumbnails for faster loading.
|
- Improved: Media thumbnails for faster loading.
|
||||||
|
- Fix: Some message where not marked as opened.
|
||||||
|
|
||||||
## 0.2.12
|
## 0.2.12
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,5 @@ class AppState {
|
||||||
static bool isInBackgroundTask = false;
|
static bool isInBackgroundTask = false;
|
||||||
static bool allowErrorTrackingViaSentry = false;
|
static bool allowErrorTrackingViaSentry = false;
|
||||||
static bool gotMessageFromServer = false;
|
static bool gotMessageFromServer = false;
|
||||||
static int latestAppVersionId = 115;
|
static int latestAppVersionId = 116;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
153
lib/main.dart
153
lib/main.dart
|
|
@ -1,10 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
|
||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
|
|
@ -15,33 +11,24 @@ import 'package:twonly/core/frb_generated.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/callbacks/callbacks.dart';
|
import 'package:twonly/src/callbacks/callbacks.dart';
|
||||||
import 'package:twonly/src/constants/secure_storage.keys.dart';
|
|
||||||
import 'package:twonly/src/database/signal/signal_signed_pre_key_store.dart'
|
|
||||||
show getSignalSignedPreKeyStoreOld;
|
|
||||||
import 'package:twonly/src/database/tables/contacts.table.dart';
|
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
|
||||||
import 'package:twonly/src/model/json/signal_identity.model.dart';
|
|
||||||
import 'package:twonly/src/providers/connection.provider.dart';
|
import 'package:twonly/src/providers/connection.provider.dart';
|
||||||
import 'package:twonly/src/providers/image_editor.provider.dart';
|
import 'package:twonly/src/providers/image_editor.provider.dart';
|
||||||
import 'package:twonly/src/providers/purchases.provider.dart';
|
import 'package:twonly/src/providers/purchases.provider.dart';
|
||||||
import 'package:twonly/src/providers/settings.provider.dart';
|
import 'package:twonly/src/providers/settings.provider.dart';
|
||||||
import 'package:twonly/src/services/api/mediafiles/download.api.dart';
|
|
||||||
import 'package:twonly/src/services/api/mediafiles/media_background.api.dart';
|
import 'package:twonly/src/services/api/mediafiles/media_background.api.dart';
|
||||||
import 'package:twonly/src/services/api/mediafiles/upload.api.dart';
|
import 'package:twonly/src/services/api/mediafiles/upload.api.dart';
|
||||||
import 'package:twonly/src/services/background/callback_dispatcher.background.dart';
|
import 'package:twonly/src/services/background/callback_dispatcher.background.dart';
|
||||||
import 'package:twonly/src/services/backup.service.dart';
|
import 'package:twonly/src/services/backup.service.dart';
|
||||||
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
||||||
import 'package:twonly/src/services/memories/memories.service.dart';
|
import 'package:twonly/src/services/memories/memories.service.dart';
|
||||||
|
import 'package:twonly/src/services/migrations.service.dart';
|
||||||
import 'package:twonly/src/services/notifications/fcm.notifications.dart';
|
import 'package:twonly/src/services/notifications/fcm.notifications.dart';
|
||||||
import 'package:twonly/src/services/notifications/setup.notifications.dart';
|
import 'package:twonly/src/services/notifications/setup.notifications.dart';
|
||||||
import 'package:twonly/src/services/user.service.dart';
|
|
||||||
import 'package:twonly/src/services/user_discovery.service.dart';
|
import 'package:twonly/src/services/user_discovery.service.dart';
|
||||||
import 'package:twonly/src/utils/avatars.dart';
|
import 'package:twonly/src/utils/avatars.dart';
|
||||||
import 'package:twonly/src/utils/exclusive_access.utils.dart';
|
import 'package:twonly/src/utils/exclusive_access.utils.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/startup_guard.dart';
|
import 'package:twonly/src/utils/startup_guard.dart';
|
||||||
import 'package:twonly/src/visual/views/onboarding/setup.view.dart';
|
|
||||||
|
|
||||||
final _initMutex = Mutex();
|
final _initMutex = Mutex();
|
||||||
|
|
||||||
|
|
@ -167,144 +154,6 @@ void main() async {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> runMigrations() async {
|
|
||||||
if (userService.currentUser.appVersion < 90) {
|
|
||||||
// BUG: Requested media files for reupload where not reuploaded because the wrong state...
|
|
||||||
await twonlyDB.mediaFilesDao.updateAllRetransmissionUploadingState();
|
|
||||||
await UserService.update((u) => u.appVersion = 90);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userService.currentUser.appVersion < 91) {
|
|
||||||
// BUG: Requested media files for reupload where not reuploaded because the wrong state...
|
|
||||||
await makeMigrationToVersion91();
|
|
||||||
await UserService.update((u) => u.appVersion = 91);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userService.currentUser.appVersion < 109) {
|
|
||||||
final contacts = await twonlyDB.contactsDao.getAllContacts();
|
|
||||||
for (final contact in contacts) {
|
|
||||||
if (contact.verified) {
|
|
||||||
await twonlyDB.keyVerificationDao.addKeyVerification(
|
|
||||||
contact.userId,
|
|
||||||
VerificationType.migratedFromOldVersion,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await UserService.update((u) {
|
|
||||||
u
|
|
||||||
..appVersion = 109
|
|
||||||
..skipSetupPages = true;
|
|
||||||
if (u.avatarSvg == null) {
|
|
||||||
u.currentSetupPage = SetupPages.profile.name;
|
|
||||||
} else {
|
|
||||||
u.currentSetupPage = SetupPages.shareYourFriends.name;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (userService.currentUser.appVersion < 113) {
|
|
||||||
var migrationSuccess = true;
|
|
||||||
final signalIdentity = await SecureStorage.instance.read(
|
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
key: SecureStorageKeys.signalIdentity,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (signalIdentity != null) {
|
|
||||||
try {
|
|
||||||
final decoded = jsonDecode(signalIdentity);
|
|
||||||
final identity = SignalIdentity.fromJson(
|
|
||||||
decoded as Map<String, dynamic>,
|
|
||||||
);
|
|
||||||
|
|
||||||
await RustKeyManager.importSignalIdentity(
|
|
||||||
identityKeyPairStructure: identity.identityKeyPairU8List,
|
|
||||||
registrationId: identity.registrationId,
|
|
||||||
signedPreKeyStore: await getSignalSignedPreKeyStoreOld(),
|
|
||||||
);
|
|
||||||
Log.info('Importing signal identiy to the rust key manager');
|
|
||||||
|
|
||||||
// Clean up old keys after successful migration
|
|
||||||
await SecureStorage.instance.delete(
|
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
key: SecureStorageKeys.signalIdentity,
|
|
||||||
);
|
|
||||||
await SecureStorage.instance.delete(
|
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
key: SecureStorageKeys.signalSignedPreKey,
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
Log.error('Failed to migrate signal identity: $e');
|
|
||||||
migrationSuccess = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (migrationSuccess) {
|
|
||||||
await UserService.update((u) {
|
|
||||||
u
|
|
||||||
..appVersion = 113
|
|
||||||
..canUseLoginTokenForAuth = false
|
|
||||||
// As usernames changes where not considered in the old version force users
|
|
||||||
// to reenter there passwords.
|
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
..twonlySafeBackup?.encryptionKey = []
|
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
..twonlySafeBackup?.backupId = [];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (userService.currentUser.appVersion < 114) {
|
|
||||||
final allMedia = await twonlyDB.mediaFilesDao
|
|
||||||
.select(twonlyDB.mediaFiles)
|
|
||||||
.get();
|
|
||||||
for (final media in allMedia) {
|
|
||||||
if (media.createdAtMonth == null) {
|
|
||||||
final monthStr = DateFormat('MMMM yyyy').format(media.createdAt);
|
|
||||||
await twonlyDB.mediaFilesDao.updateMedia(
|
|
||||||
media.mediaId,
|
|
||||||
MediaFilesCompanion(createdAtMonth: Value(monthStr)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await UserService.update((u) => u.appVersion = 114);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userService.currentUser.appVersion < 115) {
|
|
||||||
var migrationSuccess = true;
|
|
||||||
try {
|
|
||||||
final rustStore = await RustKeyManager.loadSignedPrekeys();
|
|
||||||
for (final entry in rustStore.entries) {
|
|
||||||
final companion = SignalSignedPreKeyStoresCompanion(
|
|
||||||
signedPreKeyId: Value(entry.key),
|
|
||||||
signedPreKey: Value(entry.value),
|
|
||||||
);
|
|
||||||
await twonlyDB
|
|
||||||
.into(twonlyDB.signalSignedPreKeyStores)
|
|
||||||
.insert(
|
|
||||||
companion,
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
);
|
|
||||||
await RustKeyManager.removeSignedPrekey(signedPreKeyId: entry.key);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
Log.error('Failed to migrate signed prekeys to Drift: $e');
|
|
||||||
migrationSuccess = false;
|
|
||||||
}
|
|
||||||
if (migrationSuccess) {
|
|
||||||
await UserService.update((u) => u.appVersion = 115);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kDebugMode) {
|
|
||||||
assert(
|
|
||||||
AppState.latestAppVersionId == 115,
|
|
||||||
'Forgot to update the target version in runMigrations() after incrementing AppState.latestAppVersionId.',
|
|
||||||
);
|
|
||||||
assert(
|
|
||||||
AppState.latestAppVersionId == userService.currentUser.appVersion,
|
|
||||||
"Migration incomplete: currentUser.appVersion (${userService.currentUser.appVersion}) does not match AppState.latestAppVersionId (${AppState.latestAppVersionId}). Ensure the user's appVersion is updated in the migration block.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> postStartupTasks() async {
|
Future<void> postStartupTasks() async {
|
||||||
Log.info('Post startup started.');
|
Log.info('Post startup started.');
|
||||||
unawaited(MemoriesService.prewarmCache());
|
unawaited(MemoriesService.prewarmCache());
|
||||||
|
|
|
||||||
|
|
@ -249,41 +249,49 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> handleMessagesOpened(
|
Future<void> handleMessagesOpened(
|
||||||
int contactId,
|
Value<int> contactId,
|
||||||
List<String> messageIds,
|
List<String> messageIds,
|
||||||
DateTime timestamp,
|
DateTime timestamp,
|
||||||
) async {
|
) async {
|
||||||
await batch((batch) async {
|
try {
|
||||||
|
await twonlyDB.batch((batch) async {
|
||||||
for (final messageId in messageIds) {
|
for (final messageId in messageIds) {
|
||||||
batch.insert(
|
batch.insert(
|
||||||
messageActions,
|
messageActions,
|
||||||
MessageActionsCompanion(
|
MessageActionsCompanion(
|
||||||
messageId: Value(messageId),
|
messageId: Value(messageId),
|
||||||
contactId: Value(contactId),
|
contactId: contactId,
|
||||||
type: const Value(MessageActionType.openedAt),
|
type: const Value(MessageActionType.openedAt),
|
||||||
actionAt: Value(timestamp),
|
actionAt: Value(timestamp),
|
||||||
),
|
),
|
||||||
mode: InsertMode.insertOrReplace,
|
mode: InsertMode.insertOrReplace,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
Log.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
for (final messageId in messageIds) {
|
for (final messageId in messageIds) {
|
||||||
|
try {
|
||||||
final isOpenedByAll = await haveAllMembers(
|
final isOpenedByAll = await haveAllMembers(
|
||||||
messageId,
|
messageId,
|
||||||
MessageActionType.openedAt,
|
MessageActionType.openedAt,
|
||||||
);
|
);
|
||||||
final now = clock.now();
|
final now = clock.now();
|
||||||
|
|
||||||
batch.update(
|
await (update(
|
||||||
twonlyDB.messages,
|
messages,
|
||||||
|
)..where((tbl) => tbl.messageId.equals(messageId))).write(
|
||||||
MessagesCompanion(
|
MessagesCompanion(
|
||||||
openedAt: Value(now),
|
openedAt: Value(now),
|
||||||
openedByAll: Value(isOpenedByAll ? now : null),
|
openedByAll: Value(isOpenedByAll ? now : null),
|
||||||
),
|
),
|
||||||
where: (tbl) => tbl.messageId.equals(messageId),
|
|
||||||
);
|
);
|
||||||
|
} catch (e) {
|
||||||
|
Log.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> handleMessageAckByServer(
|
Future<void> handleMessageAckByServer(
|
||||||
|
|
@ -309,6 +317,7 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
|
||||||
String messageId,
|
String messageId,
|
||||||
MessageActionType action,
|
MessageActionType action,
|
||||||
) async {
|
) async {
|
||||||
|
try {
|
||||||
final message = await twonlyDB.messagesDao
|
final message = await twonlyDB.messagesDao
|
||||||
.getMessageById(messageId)
|
.getMessageById(messageId)
|
||||||
.getSingleOrNull();
|
.getSingleOrNull();
|
||||||
|
|
@ -319,11 +328,16 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
|
||||||
|
|
||||||
final actions =
|
final actions =
|
||||||
await (select(messageActions)..where(
|
await (select(messageActions)..where(
|
||||||
(t) => t.type.equals(action.name) & t.messageId.equals(messageId),
|
(t) =>
|
||||||
|
t.type.equals(action.name) & t.messageId.equals(messageId),
|
||||||
))
|
))
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
return members.length == actions.length;
|
return members.length == actions.length;
|
||||||
|
} catch (e) {
|
||||||
|
Log.error(e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateMessageId(
|
Future<void> updateMessageId(
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:drift/drift.dart' show Value;
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart';
|
import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart';
|
||||||
import 'package:twonly/src/services/api/utils.api.dart';
|
import 'package:twonly/src/services/api/utils.api.dart';
|
||||||
|
|
@ -14,7 +15,7 @@ Future<void> handleMessageUpdate(
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
await twonlyDB.messagesDao.handleMessagesOpened(
|
await twonlyDB.messagesDao.handleMessagesOpened(
|
||||||
contactId,
|
Value(contactId),
|
||||||
messageUpdate.multipleTargetMessageIds,
|
messageUpdate.multipleTargetMessageIds,
|
||||||
fromTimestamp(messageUpdate.timestamp),
|
fromTimestamp(messageUpdate.timestamp),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
184
lib/src/services/migrations.service.dart
Normal file
184
lib/src/services/migrations.service.dart
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:clock/clock.dart';
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:twonly/core/bridge/wrapper/key_manager.dart';
|
||||||
|
import 'package:twonly/globals.dart';
|
||||||
|
import 'package:twonly/locator.dart';
|
||||||
|
import 'package:twonly/src/constants/secure_storage.keys.dart';
|
||||||
|
import 'package:twonly/src/database/signal/signal_signed_pre_key_store.dart'
|
||||||
|
show getSignalSignedPreKeyStoreOld;
|
||||||
|
import 'package:twonly/src/database/tables/contacts.table.dart';
|
||||||
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
import 'package:twonly/src/model/json/signal_identity.model.dart';
|
||||||
|
import 'package:twonly/src/services/api/mediafiles/download.api.dart';
|
||||||
|
import 'package:twonly/src/services/user.service.dart';
|
||||||
|
import 'package:twonly/src/utils/log.dart';
|
||||||
|
import 'package:twonly/src/utils/secure_storage.dart';
|
||||||
|
import 'package:twonly/src/visual/views/onboarding/setup.view.dart';
|
||||||
|
|
||||||
|
Future<void> runMigrations() async {
|
||||||
|
if (userService.currentUser.appVersion < 90) {
|
||||||
|
// BUG: Requested media files for reupload where not reuploaded because the wrong state...
|
||||||
|
await twonlyDB.mediaFilesDao.updateAllRetransmissionUploadingState();
|
||||||
|
await UserService.update((u) => u.appVersion = 90);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userService.currentUser.appVersion < 91) {
|
||||||
|
// BUG: Requested media files for reupload where not reuploaded because the wrong state...
|
||||||
|
await makeMigrationToVersion91();
|
||||||
|
await UserService.update((u) => u.appVersion = 91);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userService.currentUser.appVersion < 109) {
|
||||||
|
final contacts = await twonlyDB.contactsDao.getAllContacts();
|
||||||
|
for (final contact in contacts) {
|
||||||
|
if (contact.verified) {
|
||||||
|
await twonlyDB.keyVerificationDao.addKeyVerification(
|
||||||
|
contact.userId,
|
||||||
|
VerificationType.migratedFromOldVersion,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await UserService.update((u) {
|
||||||
|
u
|
||||||
|
..appVersion = 109
|
||||||
|
..skipSetupPages = true;
|
||||||
|
if (u.avatarSvg == null) {
|
||||||
|
u.currentSetupPage = SetupPages.profile.name;
|
||||||
|
} else {
|
||||||
|
u.currentSetupPage = SetupPages.shareYourFriends.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (userService.currentUser.appVersion < 113) {
|
||||||
|
var migrationSuccess = true;
|
||||||
|
final signalIdentity = await SecureStorage.instance.read(
|
||||||
|
// ignore: deprecated_member_use_from_same_package
|
||||||
|
key: SecureStorageKeys.signalIdentity,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (signalIdentity != null) {
|
||||||
|
try {
|
||||||
|
final decoded = jsonDecode(signalIdentity);
|
||||||
|
final identity = SignalIdentity.fromJson(
|
||||||
|
decoded as Map<String, dynamic>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await RustKeyManager.importSignalIdentity(
|
||||||
|
identityKeyPairStructure: identity.identityKeyPairU8List,
|
||||||
|
registrationId: identity.registrationId,
|
||||||
|
signedPreKeyStore: await getSignalSignedPreKeyStoreOld(),
|
||||||
|
);
|
||||||
|
Log.info('Importing signal identify to the rust key manager');
|
||||||
|
|
||||||
|
// Clean up old keys after successful migration
|
||||||
|
await SecureStorage.instance.delete(
|
||||||
|
// ignore: deprecated_member_use_from_same_package
|
||||||
|
key: SecureStorageKeys.signalIdentity,
|
||||||
|
);
|
||||||
|
await SecureStorage.instance.delete(
|
||||||
|
// ignore: deprecated_member_use_from_same_package
|
||||||
|
key: SecureStorageKeys.signalSignedPreKey,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
Log.error('Failed to migrate signal identity: $e');
|
||||||
|
migrationSuccess = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (migrationSuccess) {
|
||||||
|
await UserService.update((u) {
|
||||||
|
u
|
||||||
|
..appVersion = 113
|
||||||
|
..canUseLoginTokenForAuth = false
|
||||||
|
// As usernames changes where not considered in the old version force users
|
||||||
|
// to reenter there passwords.
|
||||||
|
// ignore: deprecated_member_use_from_same_package
|
||||||
|
..twonlySafeBackup?.encryptionKey = []
|
||||||
|
// ignore: deprecated_member_use_from_same_package
|
||||||
|
..twonlySafeBackup?.backupId = [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (userService.currentUser.appVersion < 114) {
|
||||||
|
final allMedia = await twonlyDB.mediaFilesDao
|
||||||
|
.select(twonlyDB.mediaFiles)
|
||||||
|
.get();
|
||||||
|
for (final media in allMedia) {
|
||||||
|
if (media.createdAtMonth == null) {
|
||||||
|
final monthStr = DateFormat('MMMM yyyy').format(media.createdAt);
|
||||||
|
await twonlyDB.mediaFilesDao.updateMedia(
|
||||||
|
media.mediaId,
|
||||||
|
MediaFilesCompanion(createdAtMonth: Value(monthStr)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await UserService.update((u) => u.appVersion = 114);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userService.currentUser.appVersion < 115) {
|
||||||
|
var migrationSuccess = true;
|
||||||
|
try {
|
||||||
|
final rustStore = await RustKeyManager.loadSignedPrekeys();
|
||||||
|
for (final entry in rustStore.entries) {
|
||||||
|
final companion = SignalSignedPreKeyStoresCompanion(
|
||||||
|
signedPreKeyId: Value(entry.key),
|
||||||
|
signedPreKey: Value(entry.value),
|
||||||
|
);
|
||||||
|
await twonlyDB
|
||||||
|
.into(twonlyDB.signalSignedPreKeyStores)
|
||||||
|
.insert(
|
||||||
|
companion,
|
||||||
|
mode: InsertMode.insertOrReplace,
|
||||||
|
);
|
||||||
|
await RustKeyManager.removeSignedPrekey(signedPreKeyId: entry.key);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Log.error('Failed to migrate signed prekeys to Drift: $e');
|
||||||
|
migrationSuccess = false;
|
||||||
|
}
|
||||||
|
if (migrationSuccess) {
|
||||||
|
await UserService.update((u) => u.appVersion = 115);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userService.currentUser.appVersion < 116) {
|
||||||
|
// Because of a Bug in the handleMessagesOpened function, some messages where not marked as opened. So use the logs,
|
||||||
|
// to mark the files as opened.
|
||||||
|
final logs = await loadLogFile();
|
||||||
|
final openedMessages = logs.split(
|
||||||
|
'messages.c2c.dart:12 > Opened message [',
|
||||||
|
);
|
||||||
|
for (final opened in openedMessages) {
|
||||||
|
final messageIds = opened.split(']');
|
||||||
|
if (messageIds.isNotEmpty) {
|
||||||
|
final now = clock.now();
|
||||||
|
for (final messageId in messageIds.first.split(',')) {
|
||||||
|
await (twonlyDB.update(
|
||||||
|
twonlyDB.messages,
|
||||||
|
)..where((tbl) => tbl.messageId.equals(messageId))).write(
|
||||||
|
MessagesCompanion(
|
||||||
|
openedAt: Value(now),
|
||||||
|
openedByAll: Value(now),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await UserService.update((u) => u.appVersion = 116);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kDebugMode) {
|
||||||
|
assert(
|
||||||
|
AppState.latestAppVersionId == 116,
|
||||||
|
'Forgot to update the target version in runMigrations() after incrementing AppState.latestAppVersionId.',
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
AppState.latestAppVersionId == userService.currentUser.appVersion,
|
||||||
|
"Migration incomplete: currentUser.appVersion (${userService.currentUser.appVersion}) does not match AppState.latestAppVersionId (${AppState.latestAppVersionId}). Ensure the user's appVersion is updated in the migration block.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -205,6 +205,8 @@ class _MessageInfoViewState extends State<MessageInfoView> {
|
||||||
Text(
|
Text(
|
||||||
'${context.lang.received}: ${friendlyDateTime(context, widget.message.ackByServer!)}',
|
'${context.lang.received}: ${friendlyDateTime(context, widget.message.ackByServer!)}',
|
||||||
),
|
),
|
||||||
|
if (userService.currentUser.isDeveloper)
|
||||||
|
Text('ID: ${widget.message.messageId}'),
|
||||||
if (messageHistory.isNotEmpty) ...[
|
if (messageHistory.isNotEmpty) ...[
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue