Fix: Problem with restoring from backup
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run

This commit is contained in:
otsmr 2026-03-14 00:37:54 +01:00
parent 5383496bb6
commit 371ebda666
38 changed files with 39 additions and 54081 deletions

View file

@ -2,11 +2,12 @@
## 0.0.98
- Fix: Problem during contact requests
- Fix: Problem with deleting a contact
- Improve: Video compression with progress updates
- Improve: Show message "Flames restored"
- Improve: Show toast message if user was added via QR
- Fix: Problem during contact requests
- Fix: Problem with deleting a contact
- Fix: Problem with restoring from backup
## 0.0.96

View file

@ -2,6 +2,8 @@
<application
android:label="twonly"
android:name="${applicationName}"
android:allowBackup="false"
android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"

@ -1 +1 @@
Subproject commit 33111edeb285db34edeb9fd21762825babe71ab0
Subproject commit 24d048b4abbe5c266b09965cc6f3ebdf83f97855

View file

@ -257,7 +257,7 @@ PODS:
- nanopb/encode (= 3.30910.0)
- nanopb/decode (3.30910.0)
- nanopb/encode (3.30910.0)
- no_screenshot (0.3.2-beta.3):
- no_screenshot (0.10.0):
- Flutter
- package_info_plus (0.4.5):
- Flutter
@ -266,7 +266,7 @@ PODS:
- pro_video_editor (0.0.1):
- Flutter
- PromisesObjC (2.4.0)
- restart_app (1.7.2):
- restart_app (1.7.3):
- Flutter
- SDWebImage (5.21.6):
- SDWebImage/Core (= 5.21.6)
@ -522,12 +522,12 @@ SPEC CHECKSUMS:
MLKitCommon: 47d47b50a031d00db62f1b0efe5a1d8b09a3b2e6
MLKitVision: 39a5a812db83c4a0794445088e567f3631c11961
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
no_screenshot: 5e345998c43ffcad5d6834f249590483fcc037bd
no_screenshot: 03c8ac6586f9652cd45e3d12d74e5992256403ac
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
pro_video_editor: 44ef9a6d48dbd757ed428cf35396dd05f35c7830
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
restart_app: 98825697952793b5a8e489df3d52ed5ac4fd536d
restart_app: 0714144901e260eae68f7afc2fc4aacc1a323ad2
SDWebImage: 1bb6a1b84b6fe87b972a102bdc77dd589df33477
SDWebImageWebPCoder: 0e06e365080397465cc73a7a9b472d8a3bd0f377
Sentry: b53951377b78e21a734f5dc8318e333dbfc682d7

View file

@ -1,4 +1,5 @@
import 'dart:async';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -16,10 +17,10 @@ import 'package:twonly/src/services/api.service.dart';
import 'package:twonly/src/services/api/mediafiles/download.service.dart';
import 'package:twonly/src/services/api/mediafiles/media_background.service.dart';
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
import 'package:twonly/src/services/backup/create.backup.dart';
import 'package:twonly/src/services/fcm.service.dart';
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
import 'package:twonly/src/services/notifications/setup.notifications.dart';
import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart';
import 'package:twonly/src/utils/avatars.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/storage.dart';

View file

@ -1,4 +1,5 @@
import 'dart:async';
import 'package:background_downloader/background_downloader.dart';
import 'package:clock/clock.dart';
import 'package:drift/drift.dart' show Value;
@ -8,8 +9,8 @@ import 'package:twonly/src/database/tables/mediafiles.table.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/services/api/mediafiles/download.service.dart';
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
import 'package:twonly/src/services/backup/create.backup.dart';
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart';
import 'package:twonly/src/utils/log.dart';
Future<void> initFileDownloader() async {

View file

@ -5,7 +5,7 @@ import 'package:hashlib/hashlib.dart';
import 'package:http/http.dart' as http;
import 'package:twonly/globals.dart';
import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart';
import 'package:twonly/src/services/backup/create.backup.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';

View file

@ -16,7 +16,7 @@ import 'package:twonly/src/constants/secure_storage_keys.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/model/protobuf/client/generated/backup.pb.dart';
import 'package:twonly/src/services/twonly_safe/common.twonly_safe.dart';
import 'package:twonly/src/services/backup/common.backup.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';

View file

@ -12,11 +12,11 @@ import 'package:path_provider/path_provider.dart';
import 'package:twonly/src/constants/secure_storage_keys.dart';
import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/model/protobuf/client/generated/backup.pb.dart';
import 'package:twonly/src/services/twonly_safe/common.twonly_safe.dart';
import 'package:twonly/src/services/backup/common.backup.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/storage.dart';
Future<void> recoverTwonlySafe(
Future<void> recoverBackup(
String username,
String password,
BackupServer? server,

View file

@ -21,12 +21,12 @@ Future<bool> isUserCreated() async {
}
Future<UserData?> getUser() async {
final userJson =
await const FlutterSecureStorage().read(key: SecureStorageKeys.userData);
if (userJson == null) {
return null;
}
try {
final userJson = await const FlutterSecureStorage()
.read(key: SecureStorageKeys.userData);
if (userJson == null) {
return null;
}
final userMap = jsonDecode(userJson) as Map<String, dynamic>;
final user = UserData.fromJson(userMap);
return user;

View file

@ -1,38 +0,0 @@
import 'package:flutter/material.dart';
import 'package:restart_app/restart_app.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
class DemoUserCard extends StatelessWidget {
const DemoUserCard({super.key});
@override
Widget build(BuildContext context) {
return ColoredBox(
color: isDarkMode(context) ? Colors.white : Colors.black,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'This is a Demo-Preview.',
textAlign: TextAlign.center,
style: TextStyle(
color: !isDarkMode(context) ? Colors.white : Colors.black,
fontSize: 18,
),
),
FilledButton(
onPressed: () async {
await deleteLocalUserData();
await Restart.restartApp(
notificationTitle: 'Demo-Mode exited.',
notificationBody: 'Click here to open the app again',
);
},
child: const Text('Register'),
),
],
),
);
}
}

View file

@ -4,7 +4,7 @@ import 'package:go_router/go_router.dart';
import 'package:restart_app/restart_app.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/services/twonly_safe/restore.twonly_safe.dart';
import 'package:twonly/src/services/backup/restore.backup.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';
@ -29,7 +29,7 @@ class _BackupRecoveryViewState extends State<BackupRecoveryView> {
});
try {
await recoverTwonlySafe(
await recoverBackup(
usernameCtrl.text,
passwordCtrl.text,
backupServer,
@ -38,6 +38,7 @@ class _BackupRecoveryViewState extends State<BackupRecoveryView> {
await Restart.restartApp(
notificationTitle: 'Backup successfully recovered.',
notificationBody: 'Click here to open the app again',
forceKill: true,
);
} catch (e) {
// in case something was already written from the backup...

View file

@ -140,6 +140,7 @@ class _AccountViewState extends State<AccountView> {
await Restart.restartApp(
notificationTitle: 'Account successfully deleted',
notificationBody: 'Click here to open the app again',
forceKill: true,
);
}
},

View file

@ -5,7 +5,7 @@ import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart';
import 'package:twonly/src/services/backup/create.backup.dart';
import 'package:twonly/src/utils/misc.dart';
void Function() gUpdateBackupView = () {};

View file

@ -4,7 +4,7 @@ import 'package:flutter/services.dart' show rootBundle;
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/services/twonly_safe/common.twonly_safe.dart';
import 'package:twonly/src/services/backup/common.backup.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';

View file

@ -66,6 +66,7 @@ class _DeveloperSettingsViewState extends State<DeveloperSettingsView> {
await Restart.restartApp(
notificationTitle: 'Account successfully deleted',
notificationBody: 'Click here to open the app again',
forceKill: true,
);
}
},

View file

@ -7,8 +7,8 @@ import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart';
import 'package:twonly/src/services/twonly_safe/common.twonly_safe.dart';
import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart';
import 'package:twonly/src/services/backup/common.backup.dart';
import 'package:twonly/src/services/backup/create.backup.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/components/better_list_title.dart';

View file

@ -1259,7 +1259,7 @@ packages:
path: "dependencies/no_screenshot"
relative: true
source: path
version: "0.4.0"
version: "1.0.0"
objective_c:
dependency: transitive
description:
@ -1538,11 +1538,10 @@ packages:
restart_app:
dependency: "direct main"
description:
name: restart_app
sha256: "0fd0a14cedfcd65d429588c204de44493866438391a9ee97ecf910ce591323ae"
url: "https://pub.dev"
source: hosted
version: "1.7.2"
path: "dependencies/restart_app"
relative: true
source: path
version: "1.7.3"
rxdart:
dependency: transitive
description:

View file

@ -110,6 +110,8 @@ dependencies:
dependency_overrides:
dots_indicator:
path: ./dependencies/dots_indicator
restart_app:
path: ./dependencies/restart_app
hashlib:
path: ./dependencies/hashlib
introduction_screen:

View file

@ -1,86 +0,0 @@
// dart format width=80
// GENERATED CODE, DO NOT EDIT BY HAND.
// ignore_for_file: type=lint
import 'package:drift/drift.dart';
import 'package:drift/internal/migrations.dart';
import 'schema_v1.dart' as v1;
import 'schema_v2.dart' as v2;
import 'schema_v3.dart' as v3;
import 'schema_v4.dart' as v4;
import 'schema_v5.dart' as v5;
import 'schema_v6.dart' as v6;
import 'schema_v7.dart' as v7;
import 'schema_v8.dart' as v8;
import 'schema_v9.dart' as v9;
import 'schema_v10.dart' as v10;
import 'schema_v11.dart' as v11;
import 'schema_v12.dart' as v12;
import 'schema_v13.dart' as v13;
import 'schema_v14.dart' as v14;
import 'schema_v15.dart' as v15;
import 'schema_v16.dart' as v16;
import 'schema_v17.dart' as v17;
class GeneratedHelper implements SchemaInstantiationHelper {
@override
GeneratedDatabase databaseForVersion(QueryExecutor db, int version) {
switch (version) {
case 1:
return v1.DatabaseAtV1(db);
case 2:
return v2.DatabaseAtV2(db);
case 3:
return v3.DatabaseAtV3(db);
case 4:
return v4.DatabaseAtV4(db);
case 5:
return v5.DatabaseAtV5(db);
case 6:
return v6.DatabaseAtV6(db);
case 7:
return v7.DatabaseAtV7(db);
case 8:
return v8.DatabaseAtV8(db);
case 9:
return v9.DatabaseAtV9(db);
case 10:
return v10.DatabaseAtV10(db);
case 11:
return v11.DatabaseAtV11(db);
case 12:
return v12.DatabaseAtV12(db);
case 13:
return v13.DatabaseAtV13(db);
case 14:
return v14.DatabaseAtV14(db);
case 15:
return v15.DatabaseAtV15(db);
case 16:
return v16.DatabaseAtV16(db);
case 17:
return v17.DatabaseAtV17(db);
default:
throw MissingSchemaException(version, versions);
}
}
static const versions = const [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17
];
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,100 +0,0 @@
// dart format width=80
// ignore_for_file: unused_local_variable, unused_import
import 'package:drift/drift.dart';
import 'package:drift_dev/api/migrations_native.dart';
import 'package:twonly/src/database/twonly_database_old.dart';
import 'package:flutter_test/flutter_test.dart';
import 'generated/schema.dart';
import 'generated/schema_v1.dart' as v1;
import 'generated/schema_v2.dart' as v2;
void main() {
driftRuntimeOptions.dontWarnAboutMultipleDatabases = true;
late SchemaVerifier verifier;
setUpAll(() {
verifier = SchemaVerifier(GeneratedHelper());
});
group('simple database migrations', () {
// These simple tests verify all possible schema updates with a simple (no
// data) migration. This is a quick way to ensure that written database
// migrations properly alter the schema.
const versions = GeneratedHelper.versions;
for (final (i, fromVersion) in versions.indexed) {
group('from $fromVersion', () {
for (final toVersion in versions.skip(i + 1)) {
test('to $toVersion', () async {
final schema = await verifier.schemaAt(fromVersion);
final db = TwonlyDatabaseOld(schema.newConnection());
await verifier.migrateAndValidate(db, toVersion);
await db.close();
});
}
});
}
});
// The following template shows how to write tests ensuring your migrations
// preserve existing data.
// Testing this can be useful for migrations that change existing columns
// (e.g. by alterating their type or constraints). Migrations that only add
// tables or columns typically don't need these advanced tests. For more
// information, see https://drift.simonbinder.eu/migrations/tests/#verifying-data-integrity
test('migration from v1 to v2 does not corrupt data', () async {
// Add data to insert into the old database, and the expected rows after the
// migration.
final oldContactsData = <v1.ContactsData>[];
final expectedNewContactsData = <v2.ContactsData>[];
final oldMessagesData = <v1.MessagesData>[];
final expectedNewMessagesData = <v2.MessagesData>[];
final oldSignalIdentityKeyStoresData = <v1.SignalIdentityKeyStoresData>[];
final expectedNewSignalIdentityKeyStoresData =
<v2.SignalIdentityKeyStoresData>[];
final oldSignalPreKeyStoresData = <v1.SignalPreKeyStoresData>[];
final expectedNewSignalPreKeyStoresData = <v2.SignalPreKeyStoresData>[];
final oldSignalSenderKeyStoresData = <v1.SignalSenderKeyStoresData>[];
final expectedNewSignalSenderKeyStoresData =
<v2.SignalSenderKeyStoresData>[];
final oldSignalSessionStoresData = <v1.SignalSessionStoresData>[];
final expectedNewSignalSessionStoresData = <v2.SignalSessionStoresData>[];
await verifier.testWithDataIntegrity(
oldVersion: 1,
newVersion: 2,
createOld: v1.DatabaseAtV1.new,
createNew: v2.DatabaseAtV2.new,
openTestedDatabase: TwonlyDatabaseOld.new,
createItems: (batch, oldDb) {
batch.insertAll(oldDb.contacts, oldContactsData);
batch.insertAll(oldDb.messages, oldMessagesData);
batch.insertAll(
oldDb.signalIdentityKeyStores, oldSignalIdentityKeyStoresData);
batch.insertAll(oldDb.signalPreKeyStores, oldSignalPreKeyStoresData);
batch.insertAll(
oldDb.signalSenderKeyStores, oldSignalSenderKeyStoresData);
batch.insertAll(oldDb.signalSessionStores, oldSignalSessionStoresData);
},
validateItems: (newDb) async {
expect(
expectedNewContactsData, await newDb.select(newDb.contacts).get());
expect(
expectedNewMessagesData, await newDb.select(newDb.messages).get());
expect(expectedNewSignalIdentityKeyStoresData,
await newDb.select(newDb.signalIdentityKeyStores).get());
expect(expectedNewSignalPreKeyStoresData,
await newDb.select(newDb.signalPreKeyStores).get());
expect(expectedNewSignalSenderKeyStoresData,
await newDb.select(newDb.signalSenderKeyStores).get());
expect(expectedNewSignalSessionStoresData,
await newDb.select(newDb.signalSessionStores).get());
},
);
});
}