From 80746b5139535a6163a573508087e63be5096bfc Mon Sep 17 00:00:00 2001 From: otsmr Date: Thu, 19 Jun 2025 16:10:20 +0200 Subject: [PATCH] fix #207 --- .vscode/launch.json | 271 ++ .../twonly_database/drift_schema_v12.json | 1 + lib/main.dart | 1 + .../daos/message_retransmissions.dao.dart | 25 + lib/src/database/daos/signal_dao.dart | 53 +- .../signal/connect_pre_key_store.dart | 19 - .../signal/connect_signed_pre_key_store.dart | 18 - .../tables/message_retransmissions.dart | 3 + lib/src/database/tables/messages_table.dart | 1 + lib/src/database/twonly_database.dart | 12 +- lib/src/database/twonly_database.g.dart | 64 + lib/src/database/twonly_database.steps.dart | 265 ++ lib/src/model/json/message.dart | 27 + lib/src/model/json/userdata.dart | 8 + lib/src/model/json/userdata.g.dart | 6 + lib/src/services/api/messages.dart | 78 +- lib/src/services/api/server_messages.dart | 104 +- lib/src/services/notification.service.dart | 9 + lib/src/services/signal/identity.signal.dart | 24 +- lib/src/services/signal/prekeys.signal.dart | 82 +- .../twonly_safe/create_backup.service.dart | 212 - .../create_backup.twonly_safe.dart | 18 +- .../twonly_safe/restore.twonly_safe.dart | 36 + lib/src/views/chats/chat_messages.view.dart | 2 +- lib/src/views/onboarding/register.view.dart | 2 +- .../views/settings/backup/backup.view.dart | 2 +- .../backup/twonly_safe_backup.view.dart | 11 +- .../twonly_database/generated/schema.dart | 5 +- .../twonly_database/generated/schema_v12.dart | 3883 +++++++++++++++++ 29 files changed, 4852 insertions(+), 390 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 drift_schemas/twonly_database/drift_schema_v12.json delete mode 100644 lib/src/services/twonly_safe/create_backup.service.dart create mode 100644 test/drift/twonly_database/generated/schema_v12.dart diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5e60659 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,271 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "twonly-app", + "request": "launch", + "type": "dart" + }, + { + "name": "twonly-app (profile mode)", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "twonly-app (release mode)", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "flutter_secure_storage", + "cwd": "dependencies/flutter_secure_storage", + "request": "launch", + "type": "dart" + }, + { + "name": "flutter_zxing", + "cwd": "dependencies/flutter_zxing", + "request": "launch", + "type": "dart" + }, + { + "name": "flutter_zxing (profile mode)", + "cwd": "dependencies/flutter_zxing", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "flutter_zxing (release mode)", + "cwd": "dependencies/flutter_zxing", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "flutter_secure_storage", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage", + "request": "launch", + "type": "dart" + }, + { + "name": "flutter_secure_storage (profile mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "flutter_secure_storage (release mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "flutter_secure_storage_darwin", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_darwin", + "request": "launch", + "type": "dart" + }, + { + "name": "flutter_secure_storage_darwin (profile mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_darwin", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "flutter_secure_storage_darwin (release mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_darwin", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "flutter_secure_storage_linux", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_linux", + "request": "launch", + "type": "dart" + }, + { + "name": "flutter_secure_storage_linux (profile mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_linux", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "flutter_secure_storage_linux (release mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_linux", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "flutter_secure_storage_platform_interface", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_platform_interface", + "request": "launch", + "type": "dart" + }, + { + "name": "flutter_secure_storage_platform_interface (profile mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_platform_interface", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "flutter_secure_storage_platform_interface (release mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_platform_interface", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "flutter_secure_storage_web", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_web", + "request": "launch", + "type": "dart" + }, + { + "name": "flutter_secure_storage_web (profile mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_web", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "flutter_secure_storage_web (release mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_web", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "flutter_secure_storage_windows", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_windows", + "request": "launch", + "type": "dart" + }, + { + "name": "flutter_secure_storage_windows (profile mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_windows", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "flutter_secure_storage_windows (release mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_windows", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "example", + "cwd": "dependencies/flutter_zxing/example", + "request": "launch", + "type": "dart" + }, + { + "name": "example (profile mode)", + "cwd": "dependencies/flutter_zxing/example", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "example (release mode)", + "cwd": "dependencies/flutter_zxing/example", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "zxscanner", + "cwd": "dependencies/flutter_zxing/zxscanner", + "request": "launch", + "type": "dart" + }, + { + "name": "zxscanner (profile mode)", + "cwd": "dependencies/flutter_zxing/zxscanner", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "zxscanner (release mode)", + "cwd": "dependencies/flutter_zxing/zxscanner", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "flutter_secure_storage_macos", + "cwd": "dependencies/flutter_secure_storage/archived_packages/flutter_secure_storage_macos", + "request": "launch", + "type": "dart" + }, + { + "name": "flutter_secure_storage_macos (profile mode)", + "cwd": "dependencies/flutter_secure_storage/archived_packages/flutter_secure_storage_macos", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "flutter_secure_storage_macos (release mode)", + "cwd": "dependencies/flutter_secure_storage/archived_packages/flutter_secure_storage_macos", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "example", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage/example", + "request": "launch", + "type": "dart" + }, + { + "name": "example (profile mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage/example", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "example (release mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage/example", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + { + "name": "example", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_windows/example", + "request": "launch", + "type": "dart" + }, + { + "name": "example (profile mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_windows/example", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "example (release mode)", + "cwd": "dependencies/flutter_secure_storage/flutter_secure_storage_windows/example", + "request": "launch", + "type": "dart", + "flutterMode": "release" + } + ] +} \ No newline at end of file diff --git a/drift_schemas/twonly_database/drift_schema_v12.json b/drift_schemas/twonly_database/drift_schema_v12.json new file mode 100644 index 0000000..751185a --- /dev/null +++ b/drift_schemas/twonly_database/drift_schema_v12.json @@ -0,0 +1 @@ +{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":false},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"contacts","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"username","getter_name":"username","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"UNIQUE","dialectAwareDefaultConstraints":{"sqlite":"UNIQUE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unique"]},{"name":"display_name","getter_name":"displayName","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"nick_name","getter_name":"nickName","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"avatar_svg","getter_name":"avatarSvg","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"my_avatar_counter","getter_name":"myAvatarCounter","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"accepted","getter_name":"accepted","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"accepted\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"accepted\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"requested","getter_name":"requested","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"requested\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"requested\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"blocked","getter_name":"blocked","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"blocked\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"blocked\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"verified","getter_name":"verified","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"verified\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"verified\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"archived","getter_name":"archived","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"archived\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"archived\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"pinned","getter_name":"pinned","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"pinned\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"pinned\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"deleted","getter_name":"deleted","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"deleted\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"deleted\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"also_best_friend","getter_name":"alsoBestFriend","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"also_best_friend\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"also_best_friend\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"delete_messages_after_x_minutes","getter_name":"deleteMessagesAfterXMinutes","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('1440')","default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]},{"name":"total_media_counter","getter_name":"totalMediaCounter","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"last_message_send","getter_name":"lastMessageSend","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"last_message_received","getter_name":"lastMessageReceived","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"last_flame_counter_change","getter_name":"lastFlameCounterChange","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"last_flame_sync","getter_name":"lastFlameSync","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"last_message_exchange","getter_name":"lastMessageExchange","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]},{"name":"flame_counter","getter_name":"flameCounter","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[],"explicit_pk":["user_id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"messages","was_declared_in_moor":false,"columns":[{"name":"contact_id","getter_name":"contactId","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES contacts (user_id)","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES contacts (user_id)"},"default_dart":null,"default_client_dart":null,"dsl_features":[{"foreign_key":{"to":{"table":"contacts","column":"user_id"},"initially_deferred":false,"on_update":null,"on_delete":null}}]},{"name":"message_id","getter_name":"messageId","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"message_other_id","getter_name":"messageOtherId","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"media_upload_id","getter_name":"mediaUploadId","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"media_download_id","getter_name":"mediaDownloadId","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"response_to_message_id","getter_name":"responseToMessageId","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"response_to_other_message_id","getter_name":"responseToOtherMessageId","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"acknowledge_by_user","getter_name":"acknowledgeByUser","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"acknowledge_by_user\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"acknowledge_by_user\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"media_stored","getter_name":"mediaStored","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"media_stored\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"media_stored\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"download_state","getter_name":"downloadState","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('2')","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(DownloadState.values)","dart_type_name":"DownloadState"}},{"name":"acknowledge_by_server","getter_name":"acknowledgeByServer","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"acknowledge_by_server\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"acknowledge_by_server\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"error_while_sending","getter_name":"errorWhileSending","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"error_while_sending\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"error_while_sending\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"kind","getter_name":"kind","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(MessageKind.values)","dart_type_name":"MessageKind"}},{"name":"content_json","getter_name":"contentJson","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"opened_at","getter_name":"openedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"send_at","getter_name":"sendAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":2,"references":[],"type":"table","data":{"name":"media_uploads","was_declared_in_moor":false,"columns":[{"name":"media_upload_id","getter_name":"mediaUploadId","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"state","getter_name":"state","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('\\'pending\\'')","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(UploadState.values)","dart_type_name":"UploadState"}},{"name":"metadata","getter_name":"metadata","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"MediaUploadMetadataConverter()","dart_type_name":"MediaUploadMetadata"}},{"name":"message_ids","getter_name":"messageIds","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"IntListTypeConverter()","dart_type_name":"List"}},{"name":"encryption_data","getter_name":"encryptionData","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"MediaEncryptionDataConverter()","dart_type_name":"MediaEncryptionData"}},{"name":"upload_tokens","getter_name":"uploadTokens","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"MediaUploadTokensConverter()","dart_type_name":"MediaUploadTokens"}},{"name":"already_notified","getter_name":"alreadyNotified","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('\\'[]\\'')","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"IntListTypeConverter()","dart_type_name":"List"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":3,"references":[],"type":"table","data":{"name":"media_downloads","was_declared_in_moor":false,"columns":[{"name":"message_id","getter_name":"messageId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"download_token","getter_name":"downloadToken","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"IntListTypeConverter()","dart_type_name":"List"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":4,"references":[],"type":"table","data":{"name":"signal_identity_key_stores","was_declared_in_moor":false,"columns":[{"name":"device_id","getter_name":"deviceId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"identity_key","getter_name":"identityKey","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[],"explicit_pk":["device_id","name"]}},{"id":5,"references":[],"type":"table","data":{"name":"signal_pre_key_stores","was_declared_in_moor":false,"columns":[{"name":"pre_key_id","getter_name":"preKeyId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"pre_key","getter_name":"preKey","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[],"explicit_pk":["pre_key_id"]}},{"id":6,"references":[],"type":"table","data":{"name":"signal_sender_key_stores","was_declared_in_moor":false,"columns":[{"name":"sender_key_name","getter_name":"senderKeyName","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"sender_key","getter_name":"senderKey","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[],"explicit_pk":["sender_key_name"]}},{"id":7,"references":[],"type":"table","data":{"name":"signal_session_stores","was_declared_in_moor":false,"columns":[{"name":"device_id","getter_name":"deviceId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"session_record","getter_name":"sessionRecord","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[],"explicit_pk":["device_id","name"]}},{"id":8,"references":[],"type":"table","data":{"name":"signal_contact_pre_keys","was_declared_in_moor":false,"columns":[{"name":"contact_id","getter_name":"contactId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"pre_key_id","getter_name":"preKeyId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"pre_key","getter_name":"preKey","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[],"explicit_pk":["contact_id","pre_key_id"]}},{"id":9,"references":[],"type":"table","data":{"name":"signal_contact_signed_pre_keys","was_declared_in_moor":false,"columns":[{"name":"contact_id","getter_name":"contactId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"signed_pre_key_id","getter_name":"signedPreKeyId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"signed_pre_key","getter_name":"signedPreKey","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"signed_pre_key_signature","getter_name":"signedPreKeySignature","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[],"explicit_pk":["contact_id"]}},{"id":10,"references":[0,1],"type":"table","data":{"name":"message_retransmissions","was_declared_in_moor":false,"columns":[{"name":"retransmission_id","getter_name":"retransmissionId","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"contact_id","getter_name":"contactId","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES contacts (user_id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES contacts (user_id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":[{"foreign_key":{"to":{"table":"contacts","column":"user_id"},"initially_deferred":false,"on_update":null,"on_delete":"cascade"}}]},{"name":"message_id","getter_name":"messageId","moor_type":"int","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES messages (message_id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES messages (message_id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":[{"foreign_key":{"to":{"table":"messages","column":"message_id"},"initially_deferred":false,"on_update":null,"on_delete":"cascade"}}]},{"name":"plaintext_content","getter_name":"plaintextContent","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"push_data","getter_name":"pushData","moor_type":"blob","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"will_not_get_a_c_k_by_user","getter_name":"willNotGetACKByUser","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"will_not_get_a_c_k_by_user\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"will_not_get_a_c_k_by_user\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"acknowledge_by_server_at","getter_name":"acknowledgeByServerAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}}]} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 07e36f4..90f287d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -44,6 +44,7 @@ void main() async { twonlyDB = TwonlyDatabase(); await twonlyDB.messagesDao.resetPendingDownloadState(); await twonlyDB.messagesDao.handleMediaFilesOlderThan7Days(); + await twonlyDB.signalDao.purgeOutDatedPreKeys(); // purge media files in the background purgeReceivedMediaFiles(); diff --git a/lib/src/database/daos/message_retransmissions.dao.dart b/lib/src/database/daos/message_retransmissions.dao.dart index f1f19a4..766984e 100644 --- a/lib/src/database/daos/message_retransmissions.dao.dart +++ b/lib/src/database/daos/message_retransmissions.dao.dart @@ -36,9 +36,34 @@ class MessageRetransmissionDao extends DatabaseAccessor ..where((t) => t.retransmissionId.equals(retransmissionId)); } + Future updateRetransmission( + int retransmissionId, + MessageRetransmissionsCompanion updatedValues, + ) { + return (update(messageRetransmissions) + ..where((c) => c.retransmissionId.equals(retransmissionId))) + .write(updatedValues); + } + + Future resetAckStatusForAllMessages() { + return ((update(messageRetransmissions)) + ..where((m) => m.willNotGetACKByUser.equals(false))) + .write( + MessageRetransmissionsCompanion( + acknowledgeByServerAt: Value(null), + ), + ); + } + Future deleteRetransmissionById(int retransmissionId) { return (delete(messageRetransmissions) ..where((t) => t.retransmissionId.equals(retransmissionId))) .go(); } + + Future deleteRetransmissionByMessageId(int messageId) { + return (delete(messageRetransmissions) + ..where((t) => t.messageId.equals(messageId))) + .go(); + } } diff --git a/lib/src/database/daos/signal_dao.dart b/lib/src/database/daos/signal_dao.dart index 8a9a2e8..e088e7c 100644 --- a/lib/src/database/daos/signal_dao.dart +++ b/lib/src/database/daos/signal_dao.dart @@ -1,11 +1,16 @@ import 'package:drift/drift.dart'; +import 'package:twonly/globals.dart'; import 'package:twonly/src/database/tables/signal_contact_prekey_table.dart'; import 'package:twonly/src/database/tables/signal_contact_signed_prekey_table.dart'; import 'package:twonly/src/database/twonly_database.dart'; +import 'package:twonly/src/utils/log.dart'; part 'signal_dao.g.dart'; -@DriftAccessor(tables: [SignalContactPreKeys, SignalContactSignedPreKeys]) +@DriftAccessor(tables: [ + SignalContactPreKeys, + SignalContactSignedPreKeys, +]) class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { // this constructor is required so that the main database can create an instance // of this object. @@ -19,6 +24,12 @@ class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { .go(); } + Future deleteAllPreKeysByContactId(int contactId) async { + await (delete(signalContactPreKeys) + ..where((t) => t.contactId.equals(contactId))) + .go(); + } + // 1: Count the number of pre-keys by contact ID Future countPreKeysByContactId(int contactId) { return (select(signalContactPreKeys) @@ -49,9 +60,13 @@ class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { // 3: Insert multiple pre-keys Future insertPreKeys( List preKeys) async { - await batch((batch) { - batch.insertAll(signalContactPreKeys, preKeys); - }); + for (final preKey in preKeys) { + try { + into(signalContactPreKeys).insert(preKey); + } catch (e) { + Log.error("$e"); + } + } } // 4: Get signed pre-key by contact ID @@ -64,12 +79,28 @@ class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { // 5: Insert or update signed pre-key by contact ID Future insertOrUpdateSignedPreKeyByContactId( SignalContactSignedPreKeysCompanion signedPreKey) async { - final existingKey = - await getSignedPreKeyByContactId(signedPreKey.contactId.value); - if (existingKey != null) { - await update(signalContactSignedPreKeys).replace(signedPreKey); - } else { - await into(signalContactSignedPreKeys).insert(signedPreKey); - } + await (delete(signalContactSignedPreKeys) + ..where((t) => t.contactId.equals(signedPreKey.contactId.value))) + .go(); + await into(signalContactSignedPreKeys).insert(signedPreKey); + } + + Future purgeOutDatedPreKeys() async { + // other pre keys are valid 25 days + await (delete(signalContactSignedPreKeys) + ..where((t) => (t.createdAt.isSmallerThanValue( + DateTime.now().subtract( + Duration(days: 25), + ), + )))) + .go(); + // own pre keys are valid for 40 days + await (delete(twonlyDB.signalPreKeyStores) + ..where((t) => (t.createdAt.isSmallerThanValue( + DateTime.now().subtract( + Duration(days: 40), + ), + )))) + .go(); } } diff --git a/lib/src/database/signal/connect_pre_key_store.dart b/lib/src/database/signal/connect_pre_key_store.dart index 2564d2a..1ecdc82 100644 --- a/lib/src/database/signal/connect_pre_key_store.dart +++ b/lib/src/database/signal/connect_pre_key_store.dart @@ -32,25 +32,6 @@ class ConnectPreKeyStore extends PreKeyStore { .go(); } - static Future getNextPreKeyId() async { - try { - String tableName = twonlyDB.signalPreKeyStores.actualTableName; - String columnName = twonlyDB.signalPreKeyStores.preKeyId.name; - - final result = await twonlyDB - .customSelect('SELECT MAX($columnName) AS max_id FROM $tableName') - .get(); - int? count = result.first.read('max_id'); - if (count == null) { - return 0; - } - return count + 1; - } catch (e) { - Log.error("$e"); - } - return null; - } - @override Future storePreKey(int preKeyId, PreKeyRecord record) async { final preKeyCompanion = SignalPreKeyStoresCompanion( diff --git a/lib/src/database/signal/connect_signed_pre_key_store.dart b/lib/src/database/signal/connect_signed_pre_key_store.dart index 2d7e5fd..faf1bf5 100644 --- a/lib/src/database/signal/connect_signed_pre_key_store.dart +++ b/lib/src/database/signal/connect_signed_pre_key_store.dart @@ -22,24 +22,6 @@ class ConnectSignedPreKeyStore extends SignedPreKeyStore { return store; } - Future getNextKeyId() async { - final storage = FlutterSecureStorage(); - final storeSerialized = await storage.read( - key: SecureStorageKeys.signalSignedPreKey, - ); - if (storeSerialized == null) { - return 0; - } - final storeHashMap = json.decode(storeSerialized); - var maxKeyId = 0; - for (final item in storeHashMap) { - if (maxKeyId < item[0]) { - maxKeyId = item[0]; - } - } - return maxKeyId + 1; - } - Future safeStore(HashMap store) async { final storage = FlutterSecureStorage(); var storeHashMap = []; diff --git a/lib/src/database/tables/message_retransmissions.dart b/lib/src/database/tables/message_retransmissions.dart index df745ad..a372654 100644 --- a/lib/src/database/tables/message_retransmissions.dart +++ b/lib/src/database/tables/message_retransmissions.dart @@ -15,5 +15,8 @@ class MessageRetransmissions extends Table { BlobColumn get plaintextContent => blob()(); BlobColumn get pushData => blob().nullable()(); + BoolColumn get willNotGetACKByUser => + boolean().withDefault(Constant(false))(); + DateTimeColumn get acknowledgeByServerAt => dateTime().nullable()(); } diff --git a/lib/src/database/tables/messages_table.dart b/lib/src/database/tables/messages_table.dart index 8876920..0642130 100644 --- a/lib/src/database/tables/messages_table.dart +++ b/lib/src/database/tables/messages_table.dart @@ -14,6 +14,7 @@ enum MessageKind { opened, ack, pushKey, + requestPushKey, receiveMediaError, signalDecryptError } diff --git a/lib/src/database/twonly_database.dart b/lib/src/database/twonly_database.dart index af91655..10a2b6a 100644 --- a/lib/src/database/twonly_database.dart +++ b/lib/src/database/twonly_database.dart @@ -53,7 +53,7 @@ class TwonlyDatabase extends _$TwonlyDatabase { TwonlyDatabase.forTesting(DatabaseConnection super.connection); @override - int get schemaVersion => 11; + int get schemaVersion => 12; static QueryExecutor _openConnection() { return driftDatabase( @@ -121,6 +121,10 @@ class TwonlyDatabase extends _$TwonlyDatabase { from10To11: (m, schema) async { m.createTable(messageRetransmissions); }, + from11To12: (m, schema) async { + m.addColumn(schema.messageRetransmissions, + schema.messageRetransmissions.willNotGetACKByUser); + }, ), ); } @@ -135,6 +139,12 @@ class TwonlyDatabase extends _$TwonlyDatabase { await delete(messageRetransmissions).go(); await delete(mediaDownloads).go(); await delete(mediaUploads).go(); + await update(contacts).write( + ContactsCompanion( + avatarSvg: Value(null), + myAvatarCounter: Value(0), + ), + ); await delete(signalContactPreKeys).go(); await delete(signalContactSignedPreKeys).go(); } diff --git a/lib/src/database/twonly_database.g.dart b/lib/src/database/twonly_database.g.dart index 7a74aa7..9edb1ca 100644 --- a/lib/src/database/twonly_database.g.dart +++ b/lib/src/database/twonly_database.g.dart @@ -4225,6 +4225,16 @@ class $MessageRetransmissionsTable extends MessageRetransmissions late final GeneratedColumn pushData = GeneratedColumn( 'push_data', aliasedName, true, type: DriftSqlType.blob, requiredDuringInsert: false); + static const VerificationMeta _willNotGetACKByUserMeta = + const VerificationMeta('willNotGetACKByUser'); + @override + late final GeneratedColumn willNotGetACKByUser = GeneratedColumn( + 'will_not_get_a_c_k_by_user', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("will_not_get_a_c_k_by_user" IN (0, 1))'), + defaultValue: Constant(false)); static const VerificationMeta _acknowledgeByServerAtMeta = const VerificationMeta('acknowledgeByServerAt'); @override @@ -4238,6 +4248,7 @@ class $MessageRetransmissionsTable extends MessageRetransmissions messageId, plaintextContent, pushData, + willNotGetACKByUser, acknowledgeByServerAt ]; @override @@ -4279,6 +4290,12 @@ class $MessageRetransmissionsTable extends MessageRetransmissions context.handle(_pushDataMeta, pushData.isAcceptableOrUnknown(data['push_data']!, _pushDataMeta)); } + if (data.containsKey('will_not_get_a_c_k_by_user')) { + context.handle( + _willNotGetACKByUserMeta, + willNotGetACKByUser.isAcceptableOrUnknown( + data['will_not_get_a_c_k_by_user']!, _willNotGetACKByUserMeta)); + } if (data.containsKey('acknowledge_by_server_at')) { context.handle( _acknowledgeByServerAtMeta, @@ -4304,6 +4321,8 @@ class $MessageRetransmissionsTable extends MessageRetransmissions DriftSqlType.blob, data['${effectivePrefix}plaintext_content'])!, pushData: attachedDatabase.typeMapping .read(DriftSqlType.blob, data['${effectivePrefix}push_data']), + willNotGetACKByUser: attachedDatabase.typeMapping.read(DriftSqlType.bool, + data['${effectivePrefix}will_not_get_a_c_k_by_user'])!, acknowledgeByServerAt: attachedDatabase.typeMapping.read( DriftSqlType.dateTime, data['${effectivePrefix}acknowledge_by_server_at']), @@ -4323,6 +4342,7 @@ class MessageRetransmission extends DataClass final int? messageId; final Uint8List plaintextContent; final Uint8List? pushData; + final bool willNotGetACKByUser; final DateTime? acknowledgeByServerAt; const MessageRetransmission( {required this.retransmissionId, @@ -4330,6 +4350,7 @@ class MessageRetransmission extends DataClass this.messageId, required this.plaintextContent, this.pushData, + required this.willNotGetACKByUser, this.acknowledgeByServerAt}); @override Map toColumns(bool nullToAbsent) { @@ -4343,6 +4364,7 @@ class MessageRetransmission extends DataClass if (!nullToAbsent || pushData != null) { map['push_data'] = Variable(pushData); } + map['will_not_get_a_c_k_by_user'] = Variable(willNotGetACKByUser); if (!nullToAbsent || acknowledgeByServerAt != null) { map['acknowledge_by_server_at'] = Variable(acknowledgeByServerAt); @@ -4361,6 +4383,7 @@ class MessageRetransmission extends DataClass pushData: pushData == null && nullToAbsent ? const Value.absent() : Value(pushData), + willNotGetACKByUser: Value(willNotGetACKByUser), acknowledgeByServerAt: acknowledgeByServerAt == null && nullToAbsent ? const Value.absent() : Value(acknowledgeByServerAt), @@ -4377,6 +4400,8 @@ class MessageRetransmission extends DataClass plaintextContent: serializer.fromJson(json['plaintextContent']), pushData: serializer.fromJson(json['pushData']), + willNotGetACKByUser: + serializer.fromJson(json['willNotGetACKByUser']), acknowledgeByServerAt: serializer.fromJson(json['acknowledgeByServerAt']), ); @@ -4390,6 +4415,7 @@ class MessageRetransmission extends DataClass 'messageId': serializer.toJson(messageId), 'plaintextContent': serializer.toJson(plaintextContent), 'pushData': serializer.toJson(pushData), + 'willNotGetACKByUser': serializer.toJson(willNotGetACKByUser), 'acknowledgeByServerAt': serializer.toJson(acknowledgeByServerAt), }; @@ -4401,6 +4427,7 @@ class MessageRetransmission extends DataClass Value messageId = const Value.absent(), Uint8List? plaintextContent, Value pushData = const Value.absent(), + bool? willNotGetACKByUser, Value acknowledgeByServerAt = const Value.absent()}) => MessageRetransmission( retransmissionId: retransmissionId ?? this.retransmissionId, @@ -4408,6 +4435,7 @@ class MessageRetransmission extends DataClass messageId: messageId.present ? messageId.value : this.messageId, plaintextContent: plaintextContent ?? this.plaintextContent, pushData: pushData.present ? pushData.value : this.pushData, + willNotGetACKByUser: willNotGetACKByUser ?? this.willNotGetACKByUser, acknowledgeByServerAt: acknowledgeByServerAt.present ? acknowledgeByServerAt.value : this.acknowledgeByServerAt, @@ -4424,6 +4452,9 @@ class MessageRetransmission extends DataClass ? data.plaintextContent.value : this.plaintextContent, pushData: data.pushData.present ? data.pushData.value : this.pushData, + willNotGetACKByUser: data.willNotGetACKByUser.present + ? data.willNotGetACKByUser.value + : this.willNotGetACKByUser, acknowledgeByServerAt: data.acknowledgeByServerAt.present ? data.acknowledgeByServerAt.value : this.acknowledgeByServerAt, @@ -4438,6 +4469,7 @@ class MessageRetransmission extends DataClass ..write('messageId: $messageId, ') ..write('plaintextContent: $plaintextContent, ') ..write('pushData: $pushData, ') + ..write('willNotGetACKByUser: $willNotGetACKByUser, ') ..write('acknowledgeByServerAt: $acknowledgeByServerAt') ..write(')')) .toString(); @@ -4450,6 +4482,7 @@ class MessageRetransmission extends DataClass messageId, $driftBlobEquality.hash(plaintextContent), $driftBlobEquality.hash(pushData), + willNotGetACKByUser, acknowledgeByServerAt); @override bool operator ==(Object other) => @@ -4461,6 +4494,7 @@ class MessageRetransmission extends DataClass $driftBlobEquality.equals( other.plaintextContent, this.plaintextContent) && $driftBlobEquality.equals(other.pushData, this.pushData) && + other.willNotGetACKByUser == this.willNotGetACKByUser && other.acknowledgeByServerAt == this.acknowledgeByServerAt); } @@ -4471,6 +4505,7 @@ class MessageRetransmissionsCompanion final Value messageId; final Value plaintextContent; final Value pushData; + final Value willNotGetACKByUser; final Value acknowledgeByServerAt; const MessageRetransmissionsCompanion({ this.retransmissionId = const Value.absent(), @@ -4478,6 +4513,7 @@ class MessageRetransmissionsCompanion this.messageId = const Value.absent(), this.plaintextContent = const Value.absent(), this.pushData = const Value.absent(), + this.willNotGetACKByUser = const Value.absent(), this.acknowledgeByServerAt = const Value.absent(), }); MessageRetransmissionsCompanion.insert({ @@ -4486,6 +4522,7 @@ class MessageRetransmissionsCompanion this.messageId = const Value.absent(), required Uint8List plaintextContent, this.pushData = const Value.absent(), + this.willNotGetACKByUser = const Value.absent(), this.acknowledgeByServerAt = const Value.absent(), }) : contactId = Value(contactId), plaintextContent = Value(plaintextContent); @@ -4495,6 +4532,7 @@ class MessageRetransmissionsCompanion Expression? messageId, Expression? plaintextContent, Expression? pushData, + Expression? willNotGetACKByUser, Expression? acknowledgeByServerAt, }) { return RawValuesInsertable({ @@ -4503,6 +4541,8 @@ class MessageRetransmissionsCompanion if (messageId != null) 'message_id': messageId, if (plaintextContent != null) 'plaintext_content': plaintextContent, if (pushData != null) 'push_data': pushData, + if (willNotGetACKByUser != null) + 'will_not_get_a_c_k_by_user': willNotGetACKByUser, if (acknowledgeByServerAt != null) 'acknowledge_by_server_at': acknowledgeByServerAt, }); @@ -4514,6 +4554,7 @@ class MessageRetransmissionsCompanion Value? messageId, Value? plaintextContent, Value? pushData, + Value? willNotGetACKByUser, Value? acknowledgeByServerAt}) { return MessageRetransmissionsCompanion( retransmissionId: retransmissionId ?? this.retransmissionId, @@ -4521,6 +4562,7 @@ class MessageRetransmissionsCompanion messageId: messageId ?? this.messageId, plaintextContent: plaintextContent ?? this.plaintextContent, pushData: pushData ?? this.pushData, + willNotGetACKByUser: willNotGetACKByUser ?? this.willNotGetACKByUser, acknowledgeByServerAt: acknowledgeByServerAt ?? this.acknowledgeByServerAt, ); @@ -4544,6 +4586,10 @@ class MessageRetransmissionsCompanion if (pushData.present) { map['push_data'] = Variable(pushData.value); } + if (willNotGetACKByUser.present) { + map['will_not_get_a_c_k_by_user'] = + Variable(willNotGetACKByUser.value); + } if (acknowledgeByServerAt.present) { map['acknowledge_by_server_at'] = Variable(acknowledgeByServerAt.value); @@ -4559,6 +4605,7 @@ class MessageRetransmissionsCompanion ..write('messageId: $messageId, ') ..write('plaintextContent: $plaintextContent, ') ..write('pushData: $pushData, ') + ..write('willNotGetACKByUser: $willNotGetACKByUser, ') ..write('acknowledgeByServerAt: $acknowledgeByServerAt') ..write(')')) .toString(); @@ -7107,6 +7154,7 @@ typedef $$MessageRetransmissionsTableCreateCompanionBuilder Value messageId, required Uint8List plaintextContent, Value pushData, + Value willNotGetACKByUser, Value acknowledgeByServerAt, }); typedef $$MessageRetransmissionsTableUpdateCompanionBuilder @@ -7116,6 +7164,7 @@ typedef $$MessageRetransmissionsTableUpdateCompanionBuilder Value messageId, Value plaintextContent, Value pushData, + Value willNotGetACKByUser, Value acknowledgeByServerAt, }); @@ -7175,6 +7224,10 @@ class $$MessageRetransmissionsTableFilterComposer ColumnFilters get pushData => $composableBuilder( column: $table.pushData, builder: (column) => ColumnFilters(column)); + ColumnFilters get willNotGetACKByUser => $composableBuilder( + column: $table.willNotGetACKByUser, + builder: (column) => ColumnFilters(column)); + ColumnFilters get acknowledgeByServerAt => $composableBuilder( column: $table.acknowledgeByServerAt, builder: (column) => ColumnFilters(column)); @@ -7240,6 +7293,10 @@ class $$MessageRetransmissionsTableOrderingComposer ColumnOrderings get pushData => $composableBuilder( column: $table.pushData, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get willNotGetACKByUser => $composableBuilder( + column: $table.willNotGetACKByUser, + builder: (column) => ColumnOrderings(column)); + ColumnOrderings get acknowledgeByServerAt => $composableBuilder( column: $table.acknowledgeByServerAt, builder: (column) => ColumnOrderings(column)); @@ -7303,6 +7360,9 @@ class $$MessageRetransmissionsTableAnnotationComposer GeneratedColumn get pushData => $composableBuilder(column: $table.pushData, builder: (column) => column); + GeneratedColumn get willNotGetACKByUser => $composableBuilder( + column: $table.willNotGetACKByUser, builder: (column) => column); + GeneratedColumn get acknowledgeByServerAt => $composableBuilder( column: $table.acknowledgeByServerAt, builder: (column) => column); @@ -7379,6 +7439,7 @@ class $$MessageRetransmissionsTableTableManager extends RootTableManager< Value messageId = const Value.absent(), Value plaintextContent = const Value.absent(), Value pushData = const Value.absent(), + Value willNotGetACKByUser = const Value.absent(), Value acknowledgeByServerAt = const Value.absent(), }) => MessageRetransmissionsCompanion( @@ -7387,6 +7448,7 @@ class $$MessageRetransmissionsTableTableManager extends RootTableManager< messageId: messageId, plaintextContent: plaintextContent, pushData: pushData, + willNotGetACKByUser: willNotGetACKByUser, acknowledgeByServerAt: acknowledgeByServerAt, ), createCompanionCallback: ({ @@ -7395,6 +7457,7 @@ class $$MessageRetransmissionsTableTableManager extends RootTableManager< Value messageId = const Value.absent(), required Uint8List plaintextContent, Value pushData = const Value.absent(), + Value willNotGetACKByUser = const Value.absent(), Value acknowledgeByServerAt = const Value.absent(), }) => MessageRetransmissionsCompanion.insert( @@ -7403,6 +7466,7 @@ class $$MessageRetransmissionsTableTableManager extends RootTableManager< messageId: messageId, plaintextContent: plaintextContent, pushData: pushData, + willNotGetACKByUser: willNotGetACKByUser, acknowledgeByServerAt: acknowledgeByServerAt, ), withReferenceMapper: (p0) => p0 diff --git a/lib/src/database/twonly_database.steps.dart b/lib/src/database/twonly_database.steps.dart index 3a45301..a8ca8c8 100644 --- a/lib/src/database/twonly_database.steps.dart +++ b/lib/src/database/twonly_database.steps.dart @@ -2465,6 +2465,263 @@ i1.GeneratedColumn _column_66(String aliasedName) => i1.GeneratedColumn _column_67(String aliasedName) => i1.GeneratedColumn('acknowledge_by_server_at', aliasedName, true, type: i1.DriftSqlType.dateTime); + +final class Schema12 extends i0.VersionedSchema { + Schema12({required super.database}) : super(version: 12); + @override + late final List entities = [ + contacts, + messages, + mediaUploads, + mediaDownloads, + signalIdentityKeyStores, + signalPreKeyStores, + signalSenderKeyStores, + signalSessionStores, + signalContactPreKeys, + signalContactSignedPreKeys, + messageRetransmissions, + ]; + late final Shape13 contacts = Shape13( + source: i0.VersionedTable( + entityName: 'contacts', + withoutRowId: false, + isStrict: false, + tableConstraints: [ + 'PRIMARY KEY(user_id)', + ], + columns: [ + _column_0, + _column_1, + _column_2, + _column_3, + _column_4, + _column_5, + _column_6, + _column_7, + _column_8, + _column_9, + _column_39, + _column_53, + _column_57, + _column_54, + _column_40, + _column_10, + _column_11, + _column_12, + _column_13, + _column_14, + _column_55, + _column_15, + _column_16, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape10 messages = Shape10( + source: i0.VersionedTable( + entityName: 'messages', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_17, + _column_18, + _column_19, + _column_48, + _column_49, + _column_20, + _column_21, + _column_22, + _column_52, + _column_23, + _column_24, + _column_25, + _column_26, + _column_27, + _column_28, + _column_29, + _column_30, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape7 mediaUploads = Shape7( + source: i0.VersionedTable( + entityName: 'media_uploads', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_41, + _column_42, + _column_56, + _column_44, + _column_45, + _column_46, + _column_47, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape9 mediaDownloads = Shape9( + source: i0.VersionedTable( + entityName: 'media_downloads', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_50, + _column_51, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape2 signalIdentityKeyStores = Shape2( + source: i0.VersionedTable( + entityName: 'signal_identity_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: [ + 'PRIMARY KEY(device_id, name)', + ], + columns: [ + _column_31, + _column_32, + _column_33, + _column_10, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape3 signalPreKeyStores = Shape3( + source: i0.VersionedTable( + entityName: 'signal_pre_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: [ + 'PRIMARY KEY(pre_key_id)', + ], + columns: [ + _column_34, + _column_35, + _column_10, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape4 signalSenderKeyStores = Shape4( + source: i0.VersionedTable( + entityName: 'signal_sender_key_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: [ + 'PRIMARY KEY(sender_key_name)', + ], + columns: [ + _column_36, + _column_37, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape5 signalSessionStores = Shape5( + source: i0.VersionedTable( + entityName: 'signal_session_stores', + withoutRowId: false, + isStrict: false, + tableConstraints: [ + 'PRIMARY KEY(device_id, name)', + ], + columns: [ + _column_31, + _column_32, + _column_38, + _column_10, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape14 signalContactPreKeys = Shape14( + source: i0.VersionedTable( + entityName: 'signal_contact_pre_keys', + withoutRowId: false, + isStrict: false, + tableConstraints: [ + 'PRIMARY KEY(contact_id, pre_key_id)', + ], + columns: [ + _column_58, + _column_34, + _column_35, + _column_10, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape15 signalContactSignedPreKeys = Shape15( + source: i0.VersionedTable( + entityName: 'signal_contact_signed_pre_keys', + withoutRowId: false, + isStrict: false, + tableConstraints: [ + 'PRIMARY KEY(contact_id)', + ], + columns: [ + _column_58, + _column_59, + _column_60, + _column_61, + _column_10, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape17 messageRetransmissions = Shape17( + source: i0.VersionedTable( + entityName: 'message_retransmissions', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_62, + _column_63, + _column_64, + _column_65, + _column_66, + _column_68, + _column_67, + ], + attachedDatabase: database, + ), + alias: null); +} + +class Shape17 extends i0.VersionedTable { + Shape17({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get retransmissionId => + columnsByName['retransmission_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get contactId => + columnsByName['contact_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get messageId => + columnsByName['message_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get plaintextContent => + columnsByName['plaintext_content']! as i1.GeneratedColumn; + i1.GeneratedColumn get pushData => + columnsByName['push_data']! as i1.GeneratedColumn; + i1.GeneratedColumn get willNotGetACKByUser => + columnsByName['will_not_get_a_c_k_by_user']! as i1.GeneratedColumn; + i1.GeneratedColumn get acknowledgeByServerAt => + columnsByName['acknowledge_by_server_at']! + as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_68(String aliasedName) => + i1.GeneratedColumn('will_not_get_a_c_k_by_user', aliasedName, false, + type: i1.DriftSqlType.bool, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'CHECK ("will_not_get_a_c_k_by_user" IN (0, 1))'), + defaultValue: const CustomExpression('0')); i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema2 schema) from1To2, required Future Function(i1.Migrator m, Schema3 schema) from2To3, @@ -2476,6 +2733,7 @@ i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema9 schema) from8To9, required Future Function(i1.Migrator m, Schema10 schema) from9To10, required Future Function(i1.Migrator m, Schema11 schema) from10To11, + required Future Function(i1.Migrator m, Schema12 schema) from11To12, }) { return (currentVersion, database) async { switch (currentVersion) { @@ -2529,6 +2787,11 @@ i0.MigrationStepWithVersion migrationSteps({ final migrator = i1.Migrator(database, schema); await from10To11(migrator, schema); return 11; + case 11: + final schema = Schema12(database: database); + final migrator = i1.Migrator(database, schema); + await from11To12(migrator, schema); + return 12; default: throw ArgumentError.value('Unknown migration from $currentVersion'); } @@ -2546,6 +2809,7 @@ i1.OnUpgrade stepByStep({ required Future Function(i1.Migrator m, Schema9 schema) from8To9, required Future Function(i1.Migrator m, Schema10 schema) from9To10, required Future Function(i1.Migrator m, Schema11 schema) from10To11, + required Future Function(i1.Migrator m, Schema12 schema) from11To12, }) => i0.VersionedSchema.stepByStepHelper( step: migrationSteps( @@ -2559,4 +2823,5 @@ i1.OnUpgrade stepByStep({ from8To9: from8To9, from9To10: from9To10, from10To11: from10To11, + from11To12: from11To12, )); diff --git a/lib/src/model/json/message.dart b/lib/src/model/json/message.dart index cbd8181..6148e6d 100644 --- a/lib/src/model/json/message.dart +++ b/lib/src/model/json/message.dart @@ -37,11 +37,13 @@ class MessageJson { final MessageKind kind; final MessageContent? content; final int? messageId; + int? retransId; DateTime timestamp; MessageJson({ required this.kind, this.messageId, + this.retransId, required this.content, required this.timestamp, }); @@ -57,6 +59,7 @@ class MessageJson { return MessageJson( kind: kind, messageId: (json['messageId'] as num?)?.toInt(), + retransId: (json['retransId'] as num?)?.toInt(), content: MessageContent.fromJson( kind, json['content'] as Map), timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp']), @@ -67,6 +70,7 @@ class MessageJson { 'kind': kind.name, 'content': content?.toJson(), 'messageId': messageId, + 'retransId': retransId, 'timestamp': timestamp.toUtc().millisecondsSinceEpoch, }; } @@ -90,6 +94,8 @@ class MessageContent { return ReopenedMediaFileContent.fromJson(json); case MessageKind.flameSync: return FlameSyncContent.fromJson(json); + case MessageKind.ack: + return AckContent.fromJson(json); default: return null; } @@ -216,6 +222,27 @@ class ReopenedMediaFileContent extends MessageContent { } } +class AckContent extends MessageContent { + int? messageIdToAck; + int retransIdToAck; + AckContent({required this.messageIdToAck, required this.retransIdToAck}); + + static AckContent fromJson(Map json) { + return AckContent( + messageIdToAck: json['messageIdToAck'], + retransIdToAck: json['retransIdToAck'], + ); + } + + @override + Map toJson() { + return { + 'messageIdToAck': messageIdToAck, + 'retransIdToAck': retransIdToAck, + }; + } +} + class ProfileContent extends MessageContent { String avatarSvg; String displayName; diff --git a/lib/src/model/json/userdata.dart b/lib/src/model/json/userdata.dart index 0362d94..b66c9cb 100644 --- a/lib/src/model/json/userdata.dart +++ b/lib/src/model/json/userdata.dart @@ -62,6 +62,14 @@ class UserData { DateTime? signalLastSignedPreKeyUpdated; + // -- Custom DATA -- + + @JsonKey(defaultValue: 100_000) + int currentPreKeyIndexStart = 100_000; + + @JsonKey(defaultValue: 100_000) + int currentSignedPreKeyIndexStart = 100_000; + // --- BACKUP --- DateTime? nextTimeToShowBackupNotice; diff --git a/lib/src/model/json/userdata.g.dart b/lib/src/model/json/userdata.g.dart index fe5796d..75a915d 100644 --- a/lib/src/model/json/userdata.g.dart +++ b/lib/src/model/json/userdata.g.dart @@ -48,6 +48,10 @@ UserData _$UserDataFromJson(Map json) => UserData( json['signalLastSignedPreKeyUpdated'] == null ? null : DateTime.parse(json['signalLastSignedPreKeyUpdated'] as String) + ..currentPreKeyIndexStart = + (json['currentPreKeyIndexStart'] as num?)?.toInt() ?? 100000 + ..currentSignedPreKeyIndexStart = + (json['currentSignedPreKeyIndexStart'] as num?)?.toInt() ?? 100000 ..nextTimeToShowBackupNotice = json['nextTimeToShowBackupNotice'] == null ? null : DateTime.parse(json['nextTimeToShowBackupNotice'] as String) @@ -83,6 +87,8 @@ Map _$UserDataToJson(UserData instance) => { 'myBestFriendContactId': instance.myBestFriendContactId, 'signalLastSignedPreKeyUpdated': instance.signalLastSignedPreKeyUpdated?.toIso8601String(), + 'currentPreKeyIndexStart': instance.currentPreKeyIndexStart, + 'currentSignedPreKeyIndexStart': instance.currentSignedPreKeyIndexStart, 'nextTimeToShowBackupNotice': instance.nextTimeToShowBackupNotice?.toIso8601String(), 'backupServer': instance.backupServer, diff --git a/lib/src/services/api/messages.dart b/lib/src/services/api/messages.dart index 31fd522..021c9c6 100644 --- a/lib/src/services/api/messages.dart +++ b/lib/src/services/api/messages.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:cryptography_plus/cryptography_plus.dart'; import 'package:drift/drift.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/database/twonly_database.dart'; @@ -9,60 +8,23 @@ import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/model/json/message.dart'; import 'package:twonly/src/model/json/userdata.dart'; import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart'; -import 'package:twonly/src/services/api/media_upload.dart'; import 'package:twonly/src/services/api/utils.dart'; import 'package:twonly/src/services/signal/encryption.signal.dart'; import 'package:twonly/src/services/notification.service.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/storage.dart'; -class DirtyResendingItem { - DirtyResendingItem({required this.gotLastAck}); - DateTime gotLastAck; - Timer? timer; -} - -class DirtyResending { - static final Map _gotLastAck = {}; - - static Future gotAckFromUser(int contactID) async { - _gotLastAck[contactID]?.timer?.cancel(); - - _gotLastAck[contactID] = DirtyResendingItem(gotLastAck: DateTime.now()); - _gotLastAck[contactID]?.timer = Timer(Duration(seconds: 10), () async { - _gotLastAck.remove(contactID); - _handleNonACKMessagesForUser(contactID); - }); - } - - static Future _handleNonACKMessagesForUser(int contactID) async { - final List toResendMessages = - await twonlyDB.messagesDao.getAllNonACKMessagesFromUser(); - - for (final Message message in toResendMessages) { - Log.info("Got newer ACKs from user ${message.messageId}"); - await twonlyDB.messagesDao.updateMessageByMessageId( - message.messageId, - MessagesCompanion( - errorWhileSending: Value(true), - ), - ); - } - } -} - -Future handleOlderNonAckMessages() async {} - Future tryTransmitMessages() async { final retransIds = await twonlyDB.messageRetransmissionDao.getRetransmitAbleMessages(); - if (retransIds.isEmpty) return; - Log.info("Retransmitting ${retransIds.length} text messages"); + if (retransIds.isEmpty) return; + for (final retransId in retransIds) { sendRetransmitMessage(retransId); + //twonlyDB.messageRetransmissionDao.deleteRetransmissionById(retransId); } } @@ -100,10 +62,6 @@ Future sendRetransmitMessage(int retransId) async { return; } - var hash = uint8ListToHex( - Uint8List.fromList((await Sha256().hash(encryptedBytes)).bytes)); - Log.info("Sending message: ${hash.substring(0, 10)}"); - Result resp = await apiService.sendTextMessage( retrans.contactId, encryptedBytes, @@ -142,13 +100,23 @@ Future sendRetransmitMessage(int retransId) async { } if (!retry) { - await twonlyDB.messageRetransmissionDao.deleteRetransmissionById(retransId); + if (retrans.willNotGetACKByUser) { + await twonlyDB.messageRetransmissionDao + .deleteRetransmissionById(retransId); + } else { + await twonlyDB.messageRetransmissionDao.updateRetransmission( + retransId, + MessageRetransmissionsCompanion( + acknowledgeByServerAt: Value(DateTime.now()), + ), + ); + } } } // encrypts and stores the message and then sends it in the background Future encryptAndSendMessageAsync(int? messageId, int userId, MessageJson msg, - {PushKind? pushKind}) async { + {PushKind? pushKind, bool willNotGetACKByUser = false}) async { if (gIsDemoUser) { return; } @@ -158,15 +126,13 @@ Future encryptAndSendMessageAsync(int? messageId, int userId, MessageJson msg, pushData = await getPushData(userId, pushKind); } - Uint8List plaintextContent = - Uint8List.fromList(gzip.encode(utf8.encode(jsonEncode(msg.toJson())))); - int? retransId = await twonlyDB.messageRetransmissionDao.insertRetransmission( MessageRetransmissionsCompanion( contactId: Value(userId), messageId: Value(messageId), - plaintextContent: Value(plaintextContent), + plaintextContent: Value(Uint8List(0)), pushData: Value(pushData), + willNotGetACKByUser: Value(willNotGetACKByUser), ), ); @@ -175,6 +141,16 @@ Future encryptAndSendMessageAsync(int? messageId, int userId, MessageJson msg, return; } + msg.retransId = retransId; + + Uint8List plaintextContent = + Uint8List.fromList(gzip.encode(utf8.encode(jsonEncode(msg.toJson())))); + + await twonlyDB.messageRetransmissionDao.updateRetransmission( + retransId, + MessageRetransmissionsCompanion( + plaintextContent: Value(plaintextContent))); + // this can now be done in the background... sendRetransmitMessage(retransId); } diff --git a/lib/src/services/api/server_messages.dart b/lib/src/services/api/server_messages.dart index d19129e..83ffca1 100644 --- a/lib/src/services/api/server_messages.dart +++ b/lib/src/services/api/server_messages.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'package:cryptography_plus/cryptography_plus.dart'; import 'package:drift/drift.dart'; import 'package:fixnum/fixnum.dart'; import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; @@ -14,13 +13,13 @@ import 'package:twonly/src/model/protobuf/api/websocket/client_to_server.pbserve import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart'; import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart' as server; -import 'package:twonly/src/services/api/media_upload.dart'; import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/services/api/utils.dart'; import 'package:twonly/src/services/api/media_download.dart'; import 'package:twonly/src/services/notification.service.dart'; import 'package:twonly/src/services/signal/encryption.signal.dart'; import 'package:twonly/src/services/signal/identity.signal.dart'; +import 'package:twonly/src/services/signal/prekeys.signal.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; @@ -36,9 +35,6 @@ Future handleServerMessage(server.ServerToClient msg) async { } else if (msg.v0.hasNewMessage()) { Uint8List body = Uint8List.fromList(msg.v0.newMessage.body); int fromUserId = msg.v0.newMessage.fromUserId.toInt(); - var hash = uint8ListToHex(Uint8List.fromList( - (await Sha256().hash(msg.v0.newMessage.body)).bytes)); - Log.info("Got new message from server: ${hash.substring(0, 10)}"); response = await handleNewMessage(fromUserId, body); } else { Log.error("Got a new message from the server: $msg"); @@ -56,9 +52,24 @@ Future handleServerMessage(server.ServerToClient msg) async { }); } +DateTime lastSignalDecryptMessage = DateTime.now().subtract(Duration(hours: 1)); +DateTime lastPushKeyRequest = DateTime.now().subtract(Duration(hours: 1)); + Future handleNewMessage(int fromUserId, Uint8List body) async { MessageJson? message = await signalDecryptMessage(fromUserId, body); if (message == null) { + await encryptAndSendMessageAsync( + null, + fromUserId, + MessageJson( + kind: MessageKind.signalDecryptError, + content: MessageContent(), + timestamp: DateTime.now(), + ), + ); + + Log.error("Could not decrypt others message!"); + // Message is not valid, so server can delete it var ok = client.Response_Ok()..none = true; return client.Response()..ok = ok; @@ -66,7 +77,58 @@ Future handleNewMessage(int fromUserId, Uint8List body) async { Log.info("Got: ${message.kind}"); + if (message.kind != MessageKind.ack && message.retransId != null) { + Log.info("Sending ACK for ${message.kind}"); + + /// ACK every message + await encryptAndSendMessageAsync( + null, + fromUserId, + MessageJson( + kind: MessageKind.ack, + messageId: null, + content: AckContent( + messageIdToAck: message.messageId, + retransIdToAck: message.retransId!), + timestamp: DateTime.now(), + ), + willNotGetACKByUser: true, + ); + } + switch (message.kind) { + case MessageKind.ack: + final content = message.content; + if (content is AckContent) { + if (content.messageIdToAck != null) { + final update = MessagesCompanion( + acknowledgeByUser: Value(true), + errorWhileSending: Value(false), + ); + await twonlyDB.messagesDao.updateMessageByOtherUser( + fromUserId, + content.messageIdToAck!, + update, + ); + } + + await twonlyDB.messageRetransmissionDao + .deleteRetransmissionById(content.retransIdToAck); + } + break; + case MessageKind.signalDecryptError: + if (lastSignalDecryptMessage + .isBefore(DateTime.now().subtract(Duration(seconds: 60)))) { + Log.error( + "Got signal decrypt error from other user! Sending all non ACK messages again."); + lastSignalDecryptMessage = DateTime.now(); + await twonlyDB.signalDao.deleteAllPreKeysByContactId(fromUserId); + await requestNewPrekeysForContact(fromUserId); + await twonlyDB.messageRetransmissionDao.resetAckStatusForAllMessages(); + tryTransmitMessages(); + } + + break; case MessageKind.contactRequest: return handleContactRequest(fromUserId, message); @@ -148,21 +210,12 @@ Future handleNewMessage(int fromUserId, Uint8List body) async { } break; - case MessageKind.ack: - final update = MessagesCompanion( - acknowledgeByUser: Value(true), - errorWhileSending: Value(false), - ); - await twonlyDB.messagesDao.updateMessageByOtherUser( - fromUserId, - message.messageId!, - update, - ); - - // search for older messages, that where not yet ack by the other party - DirtyResending.gotAckFromUser(fromUserId); - - break; + case MessageKind.requestPushKey: + if (lastPushKeyRequest + .isBefore(DateTime.now().subtract(Duration(seconds: 60)))) { + lastPushKeyRequest = DateTime.now(); + setupNotificationWithUsers(force: true); + } case MessageKind.pushKey: if (message.content != null) { @@ -277,17 +330,6 @@ Future handleNewMessage(int fromUserId, Uint8List body) async { } } - await encryptAndSendMessageAsync( - null, - fromUserId, - MessageJson( - kind: MessageKind.ack, - messageId: message.messageId!, - content: MessageContent(), - timestamp: DateTime.now(), - ), - ); - // unarchive contact when receiving a new message await twonlyDB.contactsDao.updateContact( fromUserId, diff --git a/lib/src/services/notification.service.dart b/lib/src/services/notification.service.dart index 8cab7e4..bd1a4e5 100644 --- a/lib/src/services/notification.service.dart +++ b/lib/src/services/notification.service.dart @@ -254,6 +254,15 @@ Future getPushData(int toUserId, PushKind kind) async { // this will be enforced after every app uses this system... :/ // return null; Log.error("Using insecure key as the receiver does not send a push key!"); + await encryptAndSendMessageAsync( + null, + toUserId, + my.MessageJson( + kind: MessageKind.requestPushKey, + content: my.MessageContent(), + timestamp: DateTime.now(), + ), + ); } } else { try { diff --git a/lib/src/services/signal/identity.signal.dart b/lib/src/services/signal/identity.signal.dart index dde8daf..009025b 100644 --- a/lib/src/services/signal/identity.signal.dart +++ b/lib/src/services/signal/identity.signal.dart @@ -3,7 +3,6 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/constants/secure_storage_keys.dart'; -import 'package:twonly/src/database/signal/connect_pre_key_store.dart'; import 'package:twonly/src/model/json/signal_identity.dart'; import 'package:twonly/src/database/signal/connect_signal_protocol_store.dart'; import 'package:twonly/src/model/json/userdata.dart'; @@ -59,9 +58,14 @@ Future signalHandleNewServerConnection() async { } Future> signalGetPreKeys() async { - int? start = await ConnectPreKeyStore.getNextPreKeyId(); - if (start == null) return []; - print(start); + final user = await getUser(); + if (user == null) return []; + + int start = user.currentPreKeyIndexStart; + await updateUserdata((user) { + user.currentPreKeyIndexStart += 200; + return user; + }); final preKeys = generatePreKeys(start, 200); final signalStore = await getSignalStore(); if (signalStore == null) return []; @@ -123,11 +127,17 @@ Future createIfNotExistsSignalIdentity() async { Future _getNewSignalSignedPreKey() async { var identityKeyPair = await getSignalIdentityKeyPair(); - if (identityKeyPair == null) return null; + final user = await getUser(); final signalStore = await getSignalStore(); - if (signalStore == null) return null; + if (identityKeyPair == null || signalStore == null || user == null) { + return null; + } - int signedPreKeyId = await signalStore.signedPreKeyStore.getNextKeyId(); + int signedPreKeyId = user.currentSignedPreKeyIndexStart; + await updateUserdata((user) { + user.currentSignedPreKeyIndexStart += 1; + return user; + }); final SignedPreKeyRecord signedPreKey = generateSignedPreKey( identityKeyPair, diff --git a/lib/src/services/signal/prekeys.signal.dart b/lib/src/services/signal/prekeys.signal.dart index 405e3c1..97ee205 100644 --- a/lib/src/services/signal/prekeys.signal.dart +++ b/lib/src/services/signal/prekeys.signal.dart @@ -1,4 +1,5 @@ import 'package:drift/drift.dart'; +import 'package:mutex/mutex.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/utils/log.dart'; @@ -18,51 +19,70 @@ class OtherPreKeys { final List signedPreKeySignature; } +Mutex requestNewKeys = Mutex(); +DateTime lastPreKeyRequest = DateTime.now().subtract(Duration(hours: 1)); +DateTime lastSignedPreKeyRequest = DateTime.now().subtract(Duration(hours: 1)); + Future requestNewPrekeysForContact(int contactId) async { - final otherKeys = await apiService.getPreKeysByUserId(contactId); - if (otherKeys != null) { - Log.info("got fresh pre keys from other $contactId!"); - final preKeys = otherKeys.preKeys - .map( - (preKey) => SignalContactPreKeysCompanion( - contactId: Value(contactId), - preKey: Value(Uint8List.fromList(preKey.prekey)), - preKeyId: Value(preKey.id.toInt()), - ), - ) - .toList(); - await twonlyDB.signalDao.insertPreKeys(preKeys); - } else { - Log.error("could not load new pre keys for user $contactId"); + if (lastPreKeyRequest + .isAfter(DateTime.now().subtract(Duration(seconds: 60)))) { + Log.info("last pre request was 60s before"); + return; } + lastPreKeyRequest = DateTime.now(); + requestNewKeys.protect(() async { + final otherKeys = await apiService.getPreKeysByUserId(contactId); + if (otherKeys != null) { + Log.info( + "got fresh ${otherKeys.preKeys.length} pre keys from other $contactId!"); + final preKeys = otherKeys.preKeys + .map( + (preKey) => SignalContactPreKeysCompanion( + contactId: Value(contactId), + preKey: Value(Uint8List.fromList(preKey.prekey)), + preKeyId: Value(preKey.id.toInt()), + ), + ) + .toList(); + await twonlyDB.signalDao.insertPreKeys(preKeys); + } else { + Log.error("could not load new pre keys for user $contactId"); + } + }); } Future getPreKeyByContactId(int contactId) async { int count = await twonlyDB.signalDao.countPreKeysByContactId(contactId); if (count < 10) { - Log.info( - "There are $count < 10 prekeys for $contactId. Loading fresh once from the server.", - ); + Log.info("Requesting new prekeys: $count < 10"); requestNewPrekeysForContact(contactId); } return twonlyDB.signalDao.popPreKeyByContactId(contactId); } Future requestNewSignedPreKeyForContact(int contactId) async { - final signedPreKey = await apiService.getSignedKeyByUserId(contactId); - if (signedPreKey != null) { - Log.info("got fresh signed pre keys from other $contactId!"); - await twonlyDB.signalDao.insertOrUpdateSignedPreKeyByContactId( - SignalContactSignedPreKeysCompanion( - contactId: Value(contactId), - signedPreKey: Value(Uint8List.fromList(signedPreKey.signedPrekey)), - signedPreKeySignature: - Value(Uint8List.fromList(signedPreKey.signedPrekeySignature)), - signedPreKeyId: Value(signedPreKey.signedPrekeyId.toInt()), - )); - } else { - Log.error("could not load new signed pre key for user $contactId"); + if (lastSignedPreKeyRequest + .isAfter(DateTime.now().subtract(Duration(seconds: 60)))) { + Log.info("last signed pre request was 60s before"); + return; } + lastSignedPreKeyRequest = DateTime.now(); + await requestNewKeys.protect(() async { + final signedPreKey = await apiService.getSignedKeyByUserId(contactId); + if (signedPreKey != null) { + Log.info("got fresh signed pre keys from other $contactId!"); + await twonlyDB.signalDao.insertOrUpdateSignedPreKeyByContactId( + SignalContactSignedPreKeysCompanion( + contactId: Value(contactId), + signedPreKey: Value(Uint8List.fromList(signedPreKey.signedPrekey)), + signedPreKeySignature: + Value(Uint8List.fromList(signedPreKey.signedPrekeySignature)), + signedPreKeyId: Value(signedPreKey.signedPrekeyId.toInt()), + )); + } else { + Log.error("could not load new signed pre key for user $contactId"); + } + }); } Future getSignedPreKeyByContactId( diff --git a/lib/src/services/twonly_safe/create_backup.service.dart b/lib/src/services/twonly_safe/create_backup.service.dart deleted file mode 100644 index c25cf56..0000000 --- a/lib/src/services/twonly_safe/create_backup.service.dart +++ /dev/null @@ -1,212 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'package:background_downloader/background_downloader.dart'; -import 'package:cryptography_plus/cryptography_plus.dart'; -import 'package:drift/drift.dart'; -import 'package:drift_flutter/drift_flutter.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:path/path.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:twonly/src/constants/secure_storage_keys.dart'; -import 'package:twonly/src/database/twonly_database.dart'; -import 'package:twonly/src/model/json/userdata.dart'; -import 'package:twonly/src/model/protobuf/backup/backup.pb.dart'; -import 'package:twonly/src/services/api/media_upload.dart'; -import 'package:twonly/src/services/twonly_safe/common.twonly_safe.dart'; -import 'package:twonly/src/utils/log.dart'; -import 'package:twonly/src/utils/storage.dart'; -import 'package:twonly/src/views/settings/backup/backup.view.dart'; - -Future performTwonlySafeBackup({bool force = false}) async { - final user = await getUser(); - - if (user == null || user.twonlySafeBackup == null || user.isDemoUser) { - Log.warn("perform twonly safe backup was called while it is disabled"); - return; - } - - if (user.twonlySafeBackup!.backupUploadState == - LastBackupUploadState.pending) { - Log.warn("Backup upload is already pending."); - return; - } - - DateTime? lastUpdateTime = user.twonlySafeBackup!.lastBackupDone; - if (!force && lastUpdateTime != null) { - if (lastUpdateTime.isAfter(DateTime.now().subtract(Duration(days: 1)))) { - return; - } - } - - Log.info("Starting new twonly Safe-Backup."); - - final baseDir = (await getApplicationSupportDirectory()).path; - - final backupDir = Directory(join(baseDir, "backup_twonly_safe/")); - await backupDir.create(recursive: true); - - final backupDatabaseFile = - File(join(backupDir.path, "twonly_database.backup.sqlite")); - - // copy database - final originalDatabase = File(join(baseDir, "twonly_database.sqlite")); - await originalDatabase.copy(backupDatabaseFile.path); - - driftRuntimeOptions.dontWarnAboutMultipleDatabases = true; - final backupDB = TwonlyDatabase( - driftDatabase( - name: "twonly_database.backup", - native: DriftNativeOptions( - databaseDirectory: () async { - return backupDir; - }, - ), - ), - ); - - await backupDB.deleteDataForTwonlySafe(); - - var secureStorageBackup = {}; - final storage = FlutterSecureStorage(); - secureStorageBackup[SecureStorageKeys.signalIdentity] = - await storage.read(key: SecureStorageKeys.signalIdentity); - secureStorageBackup[SecureStorageKeys.signalSignedPreKey] = - await storage.read(key: SecureStorageKeys.signalSignedPreKey); - - var userBackup = await getUser(); - if (userBackup == null) return; - // FILTER settings which should not be in the backup - userBackup.twonlySafeBackup = null; - userBackup.lastImageSend = null; - userBackup.todaysImageCounter = null; - userBackup.lastPlanBallance = ""; - userBackup.additionalUserInvites = ""; - userBackup.signalLastSignedPreKeyUpdated = null; - - secureStorageBackup[SecureStorageKeys.userData] = jsonEncode(userBackup); - - // Compress and convert backup data - - final twonlyDatabaseBytes = await backupDatabaseFile.readAsBytes(); - await backupDatabaseFile.delete(); - - final backupProto = TwonlySafeBackupContent( - secureStorageJson: jsonEncode(secureStorageBackup), - twonlyDatabase: twonlyDatabaseBytes, - ); - - final backupBytes = gzip.encode(backupProto.writeToBuffer()); - - final backupHash = uint8ListToHex((await Sha256().hash(backupBytes)).bytes); - - if (user.twonlySafeBackup!.lastBackupDone == null || - user.twonlySafeBackup!.lastBackupDone! - .isAfter(DateTime.now().subtract(Duration(days: 90)))) { - force = true; - } - - final lastHash = - await storage.read(key: SecureStorageKeys.twonlySafeLastBackupHash); - - if (lastHash != null && !force) { - if (backupHash == lastHash) { - Log.info("Since last backup nothing has changed."); - return; - } - } - await storage.write( - key: SecureStorageKeys.twonlySafeLastBackupHash, - value: backupHash, - ); - - // Encrypt backup data - - final xchacha20 = Xchacha20.poly1305Aead(); - final nonce = xchacha20.newNonce(); - - final secretBox = await xchacha20.encrypt( - backupBytes, - secretKey: SecretKey(user.twonlySafeBackup!.encryptionKey), - nonce: nonce, - ); - - final encryptedBackupBytes = (TwonlySafeBackupEncrypted( - mac: secretBox.mac.bytes, - nonce: nonce, - cipherText: secretBox.cipherText, - )).writeToBuffer(); - - Log.info("Backup files created."); - - var encryptedBackupBytesFile = - File(join(backupDir.path, "twonly_safe.backup")); - - await encryptedBackupBytesFile.writeAsBytes(encryptedBackupBytes); - - Log.info( - "Create twonly Safe backup with a size of ${encryptedBackupBytes.length} bytes."); - - if (user.backupServer != null) { - if (encryptedBackupBytes.length > user.backupServer!.maxBackupBytes) { - Log.error("Backup is to big for the alternative backup server."); - await updateUserdata((user) { - user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.failed; - return user; - }); - return; - } - } - - final task = UploadTask.fromFile( - taskId: "backup", - file: encryptedBackupBytesFile, - httpRequestMethod: "PUT", - url: (await getTwonlySafeBackupUrl())!, - requiresWiFi: true, - priority: 5, - retries: 2, - headers: { - "Content-Type": "application/octet-stream", - }, - ); - if (await FileDownloader().enqueue(task)) { - Log.info("Starting upload from twonly Safe backup."); - await updateUserdata((user) { - user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.pending; - user.twonlySafeBackup!.lastBackupDone = DateTime.now(); - user.twonlySafeBackup!.lastBackupSize = encryptedBackupBytes.length; - return user; - }); - gUpdateBackupView(); - } else { - Log.error("Error starting UploadTask for twonly Safe."); - } -} - -Future handleBackupStatusUpdate(TaskStatusUpdate update) async { - if (update.status == TaskStatus.failed || - update.status == TaskStatus.canceled) { - Log.error( - "twonly Safe upload failed. ${update.responseStatusCode} ${update.responseBody} ${update.responseHeaders} ${update.exception}"); - await updateUserdata((user) { - if (user.twonlySafeBackup != null) { - user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.failed; - } - return user; - }); - } else if (update.status == TaskStatus.complete) { - Log.error( - "twonly Safe uploaded with status code ${update.responseStatusCode}"); - await updateUserdata((user) { - if (user.twonlySafeBackup != null) { - user.twonlySafeBackup!.backupUploadState = - LastBackupUploadState.success; - } - return user; - }); - } else { - Log.info("Backup is in state: ${update.status}"); - return; - } - gUpdateBackupView(); -} diff --git a/lib/src/services/twonly_safe/create_backup.twonly_safe.dart b/lib/src/services/twonly_safe/create_backup.twonly_safe.dart index 5e1819c..02b6a8f 100644 --- a/lib/src/services/twonly_safe/create_backup.twonly_safe.dart +++ b/lib/src/services/twonly_safe/create_backup.twonly_safe.dart @@ -21,7 +21,7 @@ Future performTwonlySafeBackup({bool force = false}) async { final user = await getUser(); if (user == null || user.twonlySafeBackup == null || user.isDemoUser) { - // Log.warn("perform twonly safe backup was called while it is disabled"); + Log.warn("perform twonly safe backup was called while it is disabled"); return; } @@ -38,7 +38,7 @@ Future performTwonlySafeBackup({bool force = false}) async { } } - Log.info("Starting new twonly Safe-Backup."); + Log.info("Starting new twonly Safe-Backup!"); final baseDir = (await getApplicationSupportDirectory()).path; @@ -48,6 +48,9 @@ Future performTwonlySafeBackup({bool force = false}) async { final backupDatabaseFile = File(join(backupDir.path, "twonly_database.backup.sqlite")); + final backupDatabaseFileCleaned = + File(join(backupDir.path, "twonly_database.backup.cleaned.sqlite")); + // copy database final originalDatabase = File(join(baseDir, "twonly_database.sqlite")); await originalDatabase.copy(backupDatabaseFile.path); @@ -66,6 +69,10 @@ Future performTwonlySafeBackup({bool force = false}) async { await backupDB.deleteDataForTwonlySafe(); + await backupDB + .customStatement('VACUUM INTO ?', [backupDatabaseFileCleaned.path]); + backupDB.close(); + var secureStorageBackup = {}; final storage = FlutterSecureStorage(); secureStorageBackup[SecureStorageKeys.signalIdentity] = @@ -87,8 +94,11 @@ Future performTwonlySafeBackup({bool force = false}) async { // Compress and convert backup data - final twonlyDatabaseBytes = await backupDatabaseFile.readAsBytes(); + final twonlyDatabaseBytes = await backupDatabaseFileCleaned.readAsBytes(); await backupDatabaseFile.delete(); + await backupDatabaseFileCleaned.delete(); + + print("twonlyDatabaseBytes = ${twonlyDatabaseBytes.lengthInBytes}"); final backupProto = TwonlySafeBackupContent( secureStorageJson: jsonEncode(secureStorageBackup), @@ -163,8 +173,8 @@ Future performTwonlySafeBackup({bool force = false}) async { httpRequestMethod: "PUT", url: (await getTwonlySafeBackupUrl())!, requiresWiFi: true, - post: 'binary', priority: 5, + post: 'binary', retries: 2, headers: { "Content-Type": "application/octet-stream", diff --git a/lib/src/services/twonly_safe/restore.twonly_safe.dart b/lib/src/services/twonly_safe/restore.twonly_safe.dart index 6cb8c71..15c3997 100644 --- a/lib/src/services/twonly_safe/restore.twonly_safe.dart +++ b/lib/src/services/twonly_safe/restore.twonly_safe.dart @@ -7,6 +7,8 @@ import 'package:http/http.dart' as http; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; import 'package:twonly/src/constants/secure_storage_keys.dart'; +import 'package:twonly/src/database/tables/messages_table.dart'; +import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/model/json/userdata.dart'; import 'package:twonly/src/model/protobuf/backup/backup.pb.dart'; import 'package:twonly/src/services/twonly_safe/common.twonly_safe.dart'; @@ -85,6 +87,40 @@ Future handleBackupData( final originalDatabase = File(join(baseDir, "twonly_database.sqlite")); await originalDatabase.writeAsBytes(backupContent.twonlyDatabase); + /// When restoring the last message ID must be increased otherwise + /// receivers would mark them as duplicates as they where already + /// send. + final database = TwonlyDatabase(); + var lastMessageSend = 0; + int? randomUserId; + + final contacts = await database.contactsDao.getAllNotBlockedContacts(); + for (final contact in contacts) { + randomUserId = contact.userId; + final days = DateTime.now().difference(contact.lastMessageExchange).inDays; + if (days < lastMessageSend) { + lastMessageSend = days; + } + } + + if (randomUserId != null) { + // for each day add 400 message ids + var dummyMessagesCounter = (lastMessageSend + 1) * 400; + Log.info( + "Creating $dummyMessagesCounter dummy messages to increase message counter as last message was $lastMessageSend days ago."); + for (var i = 0; i < dummyMessagesCounter; i++) { + await database.messagesDao.insertMessage( + MessagesCompanion( + contactId: Value(randomUserId), + kind: Value(MessageKind.ack), + acknowledgeByServer: Value(true), + errorWhileSending: Value(true), + ), + ); + } + await database.messagesDao.deleteAllMessagesByContactId(randomUserId); + } + final storage = FlutterSecureStorage(); final secureStorage = jsonDecode(backupContent.secureStorageJson); diff --git a/lib/src/views/chats/chat_messages.view.dart b/lib/src/views/chats/chat_messages.view.dart index 6594925..2b6603f 100644 --- a/lib/src/views/chats/chat_messages.view.dart +++ b/lib/src/views/chats/chat_messages.view.dart @@ -288,7 +288,7 @@ class _ChatMessagesViewState extends State { TextMessageContent? content = TextMessageContent.fromJson( jsonDecode(messages[index].contentJson!)); if (EmojiAnimation.supported(content.text)) { - size = 95; + size = 99; } else { size = 11 + calculateNumberOfLines(content.text, diff --git a/lib/src/views/onboarding/register.view.dart b/lib/src/views/onboarding/register.view.dart index 1e92352..97adc30 100644 --- a/lib/src/views/onboarding/register.view.dart +++ b/lib/src/views/onboarding/register.view.dart @@ -218,7 +218,7 @@ class _RegisterViewState extends State { }, )); }, - label: Text("Restore identity"), + label: Text(context.lang.twonlySafeRecoverBtn), ), ], ), diff --git a/lib/src/views/settings/backup/backup.view.dart b/lib/src/views/settings/backup/backup.view.dart index 06323e2..a13c79a 100644 --- a/lib/src/views/settings/backup/backup.view.dart +++ b/lib/src/views/settings/backup/backup.view.dart @@ -59,7 +59,7 @@ class _BackupViewState extends State { String backupStatus(LastBackupUploadState status) { switch (status) { case LastBackupUploadState.none: - return ''; + return context.lang.backupPending; case LastBackupUploadState.pending: return context.lang.backupPending; case LastBackupUploadState.failed: diff --git a/lib/src/views/settings/backup/twonly_safe_backup.view.dart b/lib/src/views/settings/backup/twonly_safe_backup.view.dart index 34e66d1..578433a 100644 --- a/lib/src/views/settings/backup/twonly_safe_backup.view.dart +++ b/lib/src/views/settings/backup/twonly_safe_backup.view.dart @@ -22,7 +22,9 @@ class _TwonlyIdentityBackupViewState extends State { final TextEditingController repeatedPasswordCtrl = TextEditingController(); Future onPressedEnableTwonlySafe() async { - if (!mounted) return; + setState(() { + isLoading = true; + }); if (!await isSecurePassword(passwordCtrl.text)) { if (!mounted) return; bool ignore = await showAlertDialog( @@ -33,6 +35,11 @@ class _TwonlyIdentityBackupViewState extends State { customOk: context.lang.backupInsecurePasswordCancel, ); if (ignore) { + if (mounted) { + setState(() { + isLoading = false; + }); + } return; } } @@ -119,6 +126,7 @@ class _TwonlyIdentityBackupViewState extends State { child: Text( context.lang.backupPasswordRequirement, style: TextStyle( + fontSize: 13, color: ((passwordCtrl.text.length < 8 && passwordCtrl.text.isNotEmpty)) ? Colors.red @@ -143,6 +151,7 @@ class _TwonlyIdentityBackupViewState extends State { child: Text( context.lang.passwordRepeatedNotEqual, style: TextStyle( + fontSize: 13, color: (passwordCtrl.text != repeatedPasswordCtrl.text && repeatedPasswordCtrl.text.isNotEmpty) ? Colors.red diff --git a/test/drift/twonly_database/generated/schema.dart b/test/drift/twonly_database/generated/schema.dart index 1d78a44..073a860 100644 --- a/test/drift/twonly_database/generated/schema.dart +++ b/test/drift/twonly_database/generated/schema.dart @@ -14,6 +14,7 @@ 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; class GeneratedHelper implements SchemaInstantiationHelper { @override @@ -41,10 +42,12 @@ class GeneratedHelper implements SchemaInstantiationHelper { return v10.DatabaseAtV10(db); case 11: return v11.DatabaseAtV11(db); + case 12: + return v12.DatabaseAtV12(db); default: throw MissingSchemaException(version, versions); } } - static const versions = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + static const versions = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; } diff --git a/test/drift/twonly_database/generated/schema_v12.dart b/test/drift/twonly_database/generated/schema_v12.dart new file mode 100644 index 0000000..eeeaeb0 --- /dev/null +++ b/test/drift/twonly_database/generated/schema_v12.dart @@ -0,0 +1,3883 @@ +// dart format width=80 +// GENERATED CODE, DO NOT EDIT BY HAND. +// ignore_for_file: type=lint +import 'package:drift/drift.dart'; + +class Contacts extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Contacts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn userId = GeneratedColumn( + 'user_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: false); + late final GeneratedColumn username = GeneratedColumn( + 'username', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways('UNIQUE')); + late final GeneratedColumn displayName = GeneratedColumn( + 'display_name', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); + late final GeneratedColumn nickName = GeneratedColumn( + 'nick_name', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); + late final GeneratedColumn avatarSvg = GeneratedColumn( + 'avatar_svg', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); + late final GeneratedColumn myAvatarCounter = GeneratedColumn( + 'my_avatar_counter', aliasedName, false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0')); + late final GeneratedColumn accepted = GeneratedColumn( + 'accepted', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('CHECK ("accepted" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn requested = GeneratedColumn( + 'requested', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('CHECK ("requested" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn blocked = GeneratedColumn( + 'blocked', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('CHECK ("blocked" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn verified = GeneratedColumn( + 'verified', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('CHECK ("verified" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn archived = GeneratedColumn( + 'archived', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('CHECK ("archived" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn pinned = GeneratedColumn( + 'pinned', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('CHECK ("pinned" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn deleted = GeneratedColumn( + 'deleted', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('CHECK ("deleted" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn alsoBestFriend = GeneratedColumn( + 'also_best_friend', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("also_best_friend" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn deleteMessagesAfterXMinutes = + GeneratedColumn( + 'delete_messages_after_x_minutes', aliasedName, false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('1440')); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)')); + late final GeneratedColumn totalMediaCounter = GeneratedColumn( + 'total_media_counter', aliasedName, false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0')); + late final GeneratedColumn lastMessageSend = + GeneratedColumn('last_message_send', aliasedName, true, + type: DriftSqlType.dateTime, requiredDuringInsert: false); + late final GeneratedColumn lastMessageReceived = + GeneratedColumn('last_message_received', aliasedName, true, + type: DriftSqlType.dateTime, requiredDuringInsert: false); + late final GeneratedColumn lastFlameCounterChange = + GeneratedColumn('last_flame_counter_change', aliasedName, true, + type: DriftSqlType.dateTime, requiredDuringInsert: false); + late final GeneratedColumn lastFlameSync = + GeneratedColumn('last_flame_sync', aliasedName, true, + type: DriftSqlType.dateTime, requiredDuringInsert: false); + late final GeneratedColumn lastMessageExchange = + GeneratedColumn('last_message_exchange', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)')); + late final GeneratedColumn flameCounter = GeneratedColumn( + 'flame_counter', aliasedName, false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('0')); + @override + List get $columns => [ + userId, + username, + displayName, + nickName, + avatarSvg, + myAvatarCounter, + accepted, + requested, + blocked, + verified, + archived, + pinned, + deleted, + alsoBestFriend, + deleteMessagesAfterXMinutes, + createdAt, + totalMediaCounter, + lastMessageSend, + lastMessageReceived, + lastFlameCounterChange, + lastFlameSync, + lastMessageExchange, + flameCounter + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'contacts'; + @override + Set get $primaryKey => {userId}; + @override + ContactsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ContactsData( + userId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}user_id'])!, + username: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}username'])!, + displayName: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}display_name']), + nickName: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}nick_name']), + avatarSvg: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}avatar_svg']), + myAvatarCounter: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}my_avatar_counter'])!, + accepted: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}accepted'])!, + requested: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}requested'])!, + blocked: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}blocked'])!, + verified: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}verified'])!, + archived: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}archived'])!, + pinned: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}pinned'])!, + deleted: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}deleted'])!, + alsoBestFriend: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}also_best_friend'])!, + deleteMessagesAfterXMinutes: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}delete_messages_after_x_minutes'])!, + createdAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + totalMediaCounter: attachedDatabase.typeMapping.read( + DriftSqlType.int, data['${effectivePrefix}total_media_counter'])!, + lastMessageSend: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, data['${effectivePrefix}last_message_send']), + lastMessageReceived: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}last_message_received']), + lastFlameCounterChange: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}last_flame_counter_change']), + lastFlameSync: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, data['${effectivePrefix}last_flame_sync']), + lastMessageExchange: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}last_message_exchange'])!, + flameCounter: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}flame_counter'])!, + ); + } + + @override + Contacts createAlias(String alias) { + return Contacts(attachedDatabase, alias); + } +} + +class ContactsData extends DataClass implements Insertable { + final int userId; + final String username; + final String? displayName; + final String? nickName; + final String? avatarSvg; + final int myAvatarCounter; + final bool accepted; + final bool requested; + final bool blocked; + final bool verified; + final bool archived; + final bool pinned; + final bool deleted; + final bool alsoBestFriend; + final int deleteMessagesAfterXMinutes; + final DateTime createdAt; + final int totalMediaCounter; + final DateTime? lastMessageSend; + final DateTime? lastMessageReceived; + final DateTime? lastFlameCounterChange; + final DateTime? lastFlameSync; + final DateTime lastMessageExchange; + final int flameCounter; + const ContactsData( + {required this.userId, + required this.username, + this.displayName, + this.nickName, + this.avatarSvg, + required this.myAvatarCounter, + required this.accepted, + required this.requested, + required this.blocked, + required this.verified, + required this.archived, + required this.pinned, + required this.deleted, + required this.alsoBestFriend, + required this.deleteMessagesAfterXMinutes, + required this.createdAt, + required this.totalMediaCounter, + this.lastMessageSend, + this.lastMessageReceived, + this.lastFlameCounterChange, + this.lastFlameSync, + required this.lastMessageExchange, + required this.flameCounter}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['user_id'] = Variable(userId); + map['username'] = Variable(username); + if (!nullToAbsent || displayName != null) { + map['display_name'] = Variable(displayName); + } + if (!nullToAbsent || nickName != null) { + map['nick_name'] = Variable(nickName); + } + if (!nullToAbsent || avatarSvg != null) { + map['avatar_svg'] = Variable(avatarSvg); + } + map['my_avatar_counter'] = Variable(myAvatarCounter); + map['accepted'] = Variable(accepted); + map['requested'] = Variable(requested); + map['blocked'] = Variable(blocked); + map['verified'] = Variable(verified); + map['archived'] = Variable(archived); + map['pinned'] = Variable(pinned); + map['deleted'] = Variable(deleted); + map['also_best_friend'] = Variable(alsoBestFriend); + map['delete_messages_after_x_minutes'] = + Variable(deleteMessagesAfterXMinutes); + map['created_at'] = Variable(createdAt); + map['total_media_counter'] = Variable(totalMediaCounter); + if (!nullToAbsent || lastMessageSend != null) { + map['last_message_send'] = Variable(lastMessageSend); + } + if (!nullToAbsent || lastMessageReceived != null) { + map['last_message_received'] = Variable(lastMessageReceived); + } + if (!nullToAbsent || lastFlameCounterChange != null) { + map['last_flame_counter_change'] = + Variable(lastFlameCounterChange); + } + if (!nullToAbsent || lastFlameSync != null) { + map['last_flame_sync'] = Variable(lastFlameSync); + } + map['last_message_exchange'] = Variable(lastMessageExchange); + map['flame_counter'] = Variable(flameCounter); + return map; + } + + ContactsCompanion toCompanion(bool nullToAbsent) { + return ContactsCompanion( + userId: Value(userId), + username: Value(username), + displayName: displayName == null && nullToAbsent + ? const Value.absent() + : Value(displayName), + nickName: nickName == null && nullToAbsent + ? const Value.absent() + : Value(nickName), + avatarSvg: avatarSvg == null && nullToAbsent + ? const Value.absent() + : Value(avatarSvg), + myAvatarCounter: Value(myAvatarCounter), + accepted: Value(accepted), + requested: Value(requested), + blocked: Value(blocked), + verified: Value(verified), + archived: Value(archived), + pinned: Value(pinned), + deleted: Value(deleted), + alsoBestFriend: Value(alsoBestFriend), + deleteMessagesAfterXMinutes: Value(deleteMessagesAfterXMinutes), + createdAt: Value(createdAt), + totalMediaCounter: Value(totalMediaCounter), + lastMessageSend: lastMessageSend == null && nullToAbsent + ? const Value.absent() + : Value(lastMessageSend), + lastMessageReceived: lastMessageReceived == null && nullToAbsent + ? const Value.absent() + : Value(lastMessageReceived), + lastFlameCounterChange: lastFlameCounterChange == null && nullToAbsent + ? const Value.absent() + : Value(lastFlameCounterChange), + lastFlameSync: lastFlameSync == null && nullToAbsent + ? const Value.absent() + : Value(lastFlameSync), + lastMessageExchange: Value(lastMessageExchange), + flameCounter: Value(flameCounter), + ); + } + + factory ContactsData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ContactsData( + userId: serializer.fromJson(json['userId']), + username: serializer.fromJson(json['username']), + displayName: serializer.fromJson(json['displayName']), + nickName: serializer.fromJson(json['nickName']), + avatarSvg: serializer.fromJson(json['avatarSvg']), + myAvatarCounter: serializer.fromJson(json['myAvatarCounter']), + accepted: serializer.fromJson(json['accepted']), + requested: serializer.fromJson(json['requested']), + blocked: serializer.fromJson(json['blocked']), + verified: serializer.fromJson(json['verified']), + archived: serializer.fromJson(json['archived']), + pinned: serializer.fromJson(json['pinned']), + deleted: serializer.fromJson(json['deleted']), + alsoBestFriend: serializer.fromJson(json['alsoBestFriend']), + deleteMessagesAfterXMinutes: + serializer.fromJson(json['deleteMessagesAfterXMinutes']), + createdAt: serializer.fromJson(json['createdAt']), + totalMediaCounter: serializer.fromJson(json['totalMediaCounter']), + lastMessageSend: serializer.fromJson(json['lastMessageSend']), + lastMessageReceived: + serializer.fromJson(json['lastMessageReceived']), + lastFlameCounterChange: + serializer.fromJson(json['lastFlameCounterChange']), + lastFlameSync: serializer.fromJson(json['lastFlameSync']), + lastMessageExchange: + serializer.fromJson(json['lastMessageExchange']), + flameCounter: serializer.fromJson(json['flameCounter']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'userId': serializer.toJson(userId), + 'username': serializer.toJson(username), + 'displayName': serializer.toJson(displayName), + 'nickName': serializer.toJson(nickName), + 'avatarSvg': serializer.toJson(avatarSvg), + 'myAvatarCounter': serializer.toJson(myAvatarCounter), + 'accepted': serializer.toJson(accepted), + 'requested': serializer.toJson(requested), + 'blocked': serializer.toJson(blocked), + 'verified': serializer.toJson(verified), + 'archived': serializer.toJson(archived), + 'pinned': serializer.toJson(pinned), + 'deleted': serializer.toJson(deleted), + 'alsoBestFriend': serializer.toJson(alsoBestFriend), + 'deleteMessagesAfterXMinutes': + serializer.toJson(deleteMessagesAfterXMinutes), + 'createdAt': serializer.toJson(createdAt), + 'totalMediaCounter': serializer.toJson(totalMediaCounter), + 'lastMessageSend': serializer.toJson(lastMessageSend), + 'lastMessageReceived': serializer.toJson(lastMessageReceived), + 'lastFlameCounterChange': + serializer.toJson(lastFlameCounterChange), + 'lastFlameSync': serializer.toJson(lastFlameSync), + 'lastMessageExchange': serializer.toJson(lastMessageExchange), + 'flameCounter': serializer.toJson(flameCounter), + }; + } + + ContactsData copyWith( + {int? userId, + String? username, + Value displayName = const Value.absent(), + Value nickName = const Value.absent(), + Value avatarSvg = const Value.absent(), + int? myAvatarCounter, + bool? accepted, + bool? requested, + bool? blocked, + bool? verified, + bool? archived, + bool? pinned, + bool? deleted, + bool? alsoBestFriend, + int? deleteMessagesAfterXMinutes, + DateTime? createdAt, + int? totalMediaCounter, + Value lastMessageSend = const Value.absent(), + Value lastMessageReceived = const Value.absent(), + Value lastFlameCounterChange = const Value.absent(), + Value lastFlameSync = const Value.absent(), + DateTime? lastMessageExchange, + int? flameCounter}) => + ContactsData( + userId: userId ?? this.userId, + username: username ?? this.username, + displayName: displayName.present ? displayName.value : this.displayName, + nickName: nickName.present ? nickName.value : this.nickName, + avatarSvg: avatarSvg.present ? avatarSvg.value : this.avatarSvg, + myAvatarCounter: myAvatarCounter ?? this.myAvatarCounter, + accepted: accepted ?? this.accepted, + requested: requested ?? this.requested, + blocked: blocked ?? this.blocked, + verified: verified ?? this.verified, + archived: archived ?? this.archived, + pinned: pinned ?? this.pinned, + deleted: deleted ?? this.deleted, + alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, + deleteMessagesAfterXMinutes: + deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes, + createdAt: createdAt ?? this.createdAt, + totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter, + lastMessageSend: lastMessageSend.present + ? lastMessageSend.value + : this.lastMessageSend, + lastMessageReceived: lastMessageReceived.present + ? lastMessageReceived.value + : this.lastMessageReceived, + lastFlameCounterChange: lastFlameCounterChange.present + ? lastFlameCounterChange.value + : this.lastFlameCounterChange, + lastFlameSync: + lastFlameSync.present ? lastFlameSync.value : this.lastFlameSync, + lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, + flameCounter: flameCounter ?? this.flameCounter, + ); + ContactsData copyWithCompanion(ContactsCompanion data) { + return ContactsData( + userId: data.userId.present ? data.userId.value : this.userId, + username: data.username.present ? data.username.value : this.username, + displayName: + data.displayName.present ? data.displayName.value : this.displayName, + nickName: data.nickName.present ? data.nickName.value : this.nickName, + avatarSvg: data.avatarSvg.present ? data.avatarSvg.value : this.avatarSvg, + myAvatarCounter: data.myAvatarCounter.present + ? data.myAvatarCounter.value + : this.myAvatarCounter, + accepted: data.accepted.present ? data.accepted.value : this.accepted, + requested: data.requested.present ? data.requested.value : this.requested, + blocked: data.blocked.present ? data.blocked.value : this.blocked, + verified: data.verified.present ? data.verified.value : this.verified, + archived: data.archived.present ? data.archived.value : this.archived, + pinned: data.pinned.present ? data.pinned.value : this.pinned, + deleted: data.deleted.present ? data.deleted.value : this.deleted, + alsoBestFriend: data.alsoBestFriend.present + ? data.alsoBestFriend.value + : this.alsoBestFriend, + deleteMessagesAfterXMinutes: data.deleteMessagesAfterXMinutes.present + ? data.deleteMessagesAfterXMinutes.value + : this.deleteMessagesAfterXMinutes, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + totalMediaCounter: data.totalMediaCounter.present + ? data.totalMediaCounter.value + : this.totalMediaCounter, + lastMessageSend: data.lastMessageSend.present + ? data.lastMessageSend.value + : this.lastMessageSend, + lastMessageReceived: data.lastMessageReceived.present + ? data.lastMessageReceived.value + : this.lastMessageReceived, + lastFlameCounterChange: data.lastFlameCounterChange.present + ? data.lastFlameCounterChange.value + : this.lastFlameCounterChange, + lastFlameSync: data.lastFlameSync.present + ? data.lastFlameSync.value + : this.lastFlameSync, + lastMessageExchange: data.lastMessageExchange.present + ? data.lastMessageExchange.value + : this.lastMessageExchange, + flameCounter: data.flameCounter.present + ? data.flameCounter.value + : this.flameCounter, + ); + } + + @override + String toString() { + return (StringBuffer('ContactsData(') + ..write('userId: $userId, ') + ..write('username: $username, ') + ..write('displayName: $displayName, ') + ..write('nickName: $nickName, ') + ..write('avatarSvg: $avatarSvg, ') + ..write('myAvatarCounter: $myAvatarCounter, ') + ..write('accepted: $accepted, ') + ..write('requested: $requested, ') + ..write('blocked: $blocked, ') + ..write('verified: $verified, ') + ..write('archived: $archived, ') + ..write('pinned: $pinned, ') + ..write('deleted: $deleted, ') + ..write('alsoBestFriend: $alsoBestFriend, ') + ..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ') + ..write('createdAt: $createdAt, ') + ..write('totalMediaCounter: $totalMediaCounter, ') + ..write('lastMessageSend: $lastMessageSend, ') + ..write('lastMessageReceived: $lastMessageReceived, ') + ..write('lastFlameCounterChange: $lastFlameCounterChange, ') + ..write('lastFlameSync: $lastFlameSync, ') + ..write('lastMessageExchange: $lastMessageExchange, ') + ..write('flameCounter: $flameCounter') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hashAll([ + userId, + username, + displayName, + nickName, + avatarSvg, + myAvatarCounter, + accepted, + requested, + blocked, + verified, + archived, + pinned, + deleted, + alsoBestFriend, + deleteMessagesAfterXMinutes, + createdAt, + totalMediaCounter, + lastMessageSend, + lastMessageReceived, + lastFlameCounterChange, + lastFlameSync, + lastMessageExchange, + flameCounter + ]); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ContactsData && + other.userId == this.userId && + other.username == this.username && + other.displayName == this.displayName && + other.nickName == this.nickName && + other.avatarSvg == this.avatarSvg && + other.myAvatarCounter == this.myAvatarCounter && + other.accepted == this.accepted && + other.requested == this.requested && + other.blocked == this.blocked && + other.verified == this.verified && + other.archived == this.archived && + other.pinned == this.pinned && + other.deleted == this.deleted && + other.alsoBestFriend == this.alsoBestFriend && + other.deleteMessagesAfterXMinutes == + this.deleteMessagesAfterXMinutes && + other.createdAt == this.createdAt && + other.totalMediaCounter == this.totalMediaCounter && + other.lastMessageSend == this.lastMessageSend && + other.lastMessageReceived == this.lastMessageReceived && + other.lastFlameCounterChange == this.lastFlameCounterChange && + other.lastFlameSync == this.lastFlameSync && + other.lastMessageExchange == this.lastMessageExchange && + other.flameCounter == this.flameCounter); +} + +class ContactsCompanion extends UpdateCompanion { + final Value userId; + final Value username; + final Value displayName; + final Value nickName; + final Value avatarSvg; + final Value myAvatarCounter; + final Value accepted; + final Value requested; + final Value blocked; + final Value verified; + final Value archived; + final Value pinned; + final Value deleted; + final Value alsoBestFriend; + final Value deleteMessagesAfterXMinutes; + final Value createdAt; + final Value totalMediaCounter; + final Value lastMessageSend; + final Value lastMessageReceived; + final Value lastFlameCounterChange; + final Value lastFlameSync; + final Value lastMessageExchange; + final Value flameCounter; + const ContactsCompanion({ + this.userId = const Value.absent(), + this.username = const Value.absent(), + this.displayName = const Value.absent(), + this.nickName = const Value.absent(), + this.avatarSvg = const Value.absent(), + this.myAvatarCounter = const Value.absent(), + this.accepted = const Value.absent(), + this.requested = const Value.absent(), + this.blocked = const Value.absent(), + this.verified = const Value.absent(), + this.archived = const Value.absent(), + this.pinned = const Value.absent(), + this.deleted = const Value.absent(), + this.alsoBestFriend = const Value.absent(), + this.deleteMessagesAfterXMinutes = const Value.absent(), + this.createdAt = const Value.absent(), + this.totalMediaCounter = const Value.absent(), + this.lastMessageSend = const Value.absent(), + this.lastMessageReceived = const Value.absent(), + this.lastFlameCounterChange = const Value.absent(), + this.lastFlameSync = const Value.absent(), + this.lastMessageExchange = const Value.absent(), + this.flameCounter = const Value.absent(), + }); + ContactsCompanion.insert({ + this.userId = const Value.absent(), + required String username, + this.displayName = const Value.absent(), + this.nickName = const Value.absent(), + this.avatarSvg = const Value.absent(), + this.myAvatarCounter = const Value.absent(), + this.accepted = const Value.absent(), + this.requested = const Value.absent(), + this.blocked = const Value.absent(), + this.verified = const Value.absent(), + this.archived = const Value.absent(), + this.pinned = const Value.absent(), + this.deleted = const Value.absent(), + this.alsoBestFriend = const Value.absent(), + this.deleteMessagesAfterXMinutes = const Value.absent(), + this.createdAt = const Value.absent(), + this.totalMediaCounter = const Value.absent(), + this.lastMessageSend = const Value.absent(), + this.lastMessageReceived = const Value.absent(), + this.lastFlameCounterChange = const Value.absent(), + this.lastFlameSync = const Value.absent(), + this.lastMessageExchange = const Value.absent(), + this.flameCounter = const Value.absent(), + }) : username = Value(username); + static Insertable custom({ + Expression? userId, + Expression? username, + Expression? displayName, + Expression? nickName, + Expression? avatarSvg, + Expression? myAvatarCounter, + Expression? accepted, + Expression? requested, + Expression? blocked, + Expression? verified, + Expression? archived, + Expression? pinned, + Expression? deleted, + Expression? alsoBestFriend, + Expression? deleteMessagesAfterXMinutes, + Expression? createdAt, + Expression? totalMediaCounter, + Expression? lastMessageSend, + Expression? lastMessageReceived, + Expression? lastFlameCounterChange, + Expression? lastFlameSync, + Expression? lastMessageExchange, + Expression? flameCounter, + }) { + return RawValuesInsertable({ + if (userId != null) 'user_id': userId, + if (username != null) 'username': username, + if (displayName != null) 'display_name': displayName, + if (nickName != null) 'nick_name': nickName, + if (avatarSvg != null) 'avatar_svg': avatarSvg, + if (myAvatarCounter != null) 'my_avatar_counter': myAvatarCounter, + if (accepted != null) 'accepted': accepted, + if (requested != null) 'requested': requested, + if (blocked != null) 'blocked': blocked, + if (verified != null) 'verified': verified, + if (archived != null) 'archived': archived, + if (pinned != null) 'pinned': pinned, + if (deleted != null) 'deleted': deleted, + if (alsoBestFriend != null) 'also_best_friend': alsoBestFriend, + if (deleteMessagesAfterXMinutes != null) + 'delete_messages_after_x_minutes': deleteMessagesAfterXMinutes, + if (createdAt != null) 'created_at': createdAt, + if (totalMediaCounter != null) 'total_media_counter': totalMediaCounter, + if (lastMessageSend != null) 'last_message_send': lastMessageSend, + if (lastMessageReceived != null) + 'last_message_received': lastMessageReceived, + if (lastFlameCounterChange != null) + 'last_flame_counter_change': lastFlameCounterChange, + if (lastFlameSync != null) 'last_flame_sync': lastFlameSync, + if (lastMessageExchange != null) + 'last_message_exchange': lastMessageExchange, + if (flameCounter != null) 'flame_counter': flameCounter, + }); + } + + ContactsCompanion copyWith( + {Value? userId, + Value? username, + Value? displayName, + Value? nickName, + Value? avatarSvg, + Value? myAvatarCounter, + Value? accepted, + Value? requested, + Value? blocked, + Value? verified, + Value? archived, + Value? pinned, + Value? deleted, + Value? alsoBestFriend, + Value? deleteMessagesAfterXMinutes, + Value? createdAt, + Value? totalMediaCounter, + Value? lastMessageSend, + Value? lastMessageReceived, + Value? lastFlameCounterChange, + Value? lastFlameSync, + Value? lastMessageExchange, + Value? flameCounter}) { + return ContactsCompanion( + userId: userId ?? this.userId, + username: username ?? this.username, + displayName: displayName ?? this.displayName, + nickName: nickName ?? this.nickName, + avatarSvg: avatarSvg ?? this.avatarSvg, + myAvatarCounter: myAvatarCounter ?? this.myAvatarCounter, + accepted: accepted ?? this.accepted, + requested: requested ?? this.requested, + blocked: blocked ?? this.blocked, + verified: verified ?? this.verified, + archived: archived ?? this.archived, + pinned: pinned ?? this.pinned, + deleted: deleted ?? this.deleted, + alsoBestFriend: alsoBestFriend ?? this.alsoBestFriend, + deleteMessagesAfterXMinutes: + deleteMessagesAfterXMinutes ?? this.deleteMessagesAfterXMinutes, + createdAt: createdAt ?? this.createdAt, + totalMediaCounter: totalMediaCounter ?? this.totalMediaCounter, + lastMessageSend: lastMessageSend ?? this.lastMessageSend, + lastMessageReceived: lastMessageReceived ?? this.lastMessageReceived, + lastFlameCounterChange: + lastFlameCounterChange ?? this.lastFlameCounterChange, + lastFlameSync: lastFlameSync ?? this.lastFlameSync, + lastMessageExchange: lastMessageExchange ?? this.lastMessageExchange, + flameCounter: flameCounter ?? this.flameCounter, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (username.present) { + map['username'] = Variable(username.value); + } + if (displayName.present) { + map['display_name'] = Variable(displayName.value); + } + if (nickName.present) { + map['nick_name'] = Variable(nickName.value); + } + if (avatarSvg.present) { + map['avatar_svg'] = Variable(avatarSvg.value); + } + if (myAvatarCounter.present) { + map['my_avatar_counter'] = Variable(myAvatarCounter.value); + } + if (accepted.present) { + map['accepted'] = Variable(accepted.value); + } + if (requested.present) { + map['requested'] = Variable(requested.value); + } + if (blocked.present) { + map['blocked'] = Variable(blocked.value); + } + if (verified.present) { + map['verified'] = Variable(verified.value); + } + if (archived.present) { + map['archived'] = Variable(archived.value); + } + if (pinned.present) { + map['pinned'] = Variable(pinned.value); + } + if (deleted.present) { + map['deleted'] = Variable(deleted.value); + } + if (alsoBestFriend.present) { + map['also_best_friend'] = Variable(alsoBestFriend.value); + } + if (deleteMessagesAfterXMinutes.present) { + map['delete_messages_after_x_minutes'] = + Variable(deleteMessagesAfterXMinutes.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (totalMediaCounter.present) { + map['total_media_counter'] = Variable(totalMediaCounter.value); + } + if (lastMessageSend.present) { + map['last_message_send'] = Variable(lastMessageSend.value); + } + if (lastMessageReceived.present) { + map['last_message_received'] = + Variable(lastMessageReceived.value); + } + if (lastFlameCounterChange.present) { + map['last_flame_counter_change'] = + Variable(lastFlameCounterChange.value); + } + if (lastFlameSync.present) { + map['last_flame_sync'] = Variable(lastFlameSync.value); + } + if (lastMessageExchange.present) { + map['last_message_exchange'] = + Variable(lastMessageExchange.value); + } + if (flameCounter.present) { + map['flame_counter'] = Variable(flameCounter.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ContactsCompanion(') + ..write('userId: $userId, ') + ..write('username: $username, ') + ..write('displayName: $displayName, ') + ..write('nickName: $nickName, ') + ..write('avatarSvg: $avatarSvg, ') + ..write('myAvatarCounter: $myAvatarCounter, ') + ..write('accepted: $accepted, ') + ..write('requested: $requested, ') + ..write('blocked: $blocked, ') + ..write('verified: $verified, ') + ..write('archived: $archived, ') + ..write('pinned: $pinned, ') + ..write('deleted: $deleted, ') + ..write('alsoBestFriend: $alsoBestFriend, ') + ..write('deleteMessagesAfterXMinutes: $deleteMessagesAfterXMinutes, ') + ..write('createdAt: $createdAt, ') + ..write('totalMediaCounter: $totalMediaCounter, ') + ..write('lastMessageSend: $lastMessageSend, ') + ..write('lastMessageReceived: $lastMessageReceived, ') + ..write('lastFlameCounterChange: $lastFlameCounterChange, ') + ..write('lastFlameSync: $lastFlameSync, ') + ..write('lastMessageExchange: $lastMessageExchange, ') + ..write('flameCounter: $flameCounter') + ..write(')')) + .toString(); + } +} + +class Messages extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + Messages(this.attachedDatabase, [this._alias]); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', aliasedName, false, + type: DriftSqlType.int, + requiredDuringInsert: true, + defaultConstraints: + GeneratedColumn.constraintIsAlways('REFERENCES contacts (user_id)')); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', aliasedName, false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT')); + late final GeneratedColumn messageOtherId = GeneratedColumn( + 'message_other_id', aliasedName, true, + type: DriftSqlType.int, requiredDuringInsert: false); + late final GeneratedColumn mediaUploadId = GeneratedColumn( + 'media_upload_id', aliasedName, true, + type: DriftSqlType.int, requiredDuringInsert: false); + late final GeneratedColumn mediaDownloadId = GeneratedColumn( + 'media_download_id', aliasedName, true, + type: DriftSqlType.int, requiredDuringInsert: false); + late final GeneratedColumn responseToMessageId = GeneratedColumn( + 'response_to_message_id', aliasedName, true, + type: DriftSqlType.int, requiredDuringInsert: false); + late final GeneratedColumn responseToOtherMessageId = + GeneratedColumn('response_to_other_message_id', aliasedName, true, + type: DriftSqlType.int, requiredDuringInsert: false); + late final GeneratedColumn acknowledgeByUser = GeneratedColumn( + 'acknowledge_by_user', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("acknowledge_by_user" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn mediaStored = GeneratedColumn( + 'media_stored', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("media_stored" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn downloadState = GeneratedColumn( + 'download_state', aliasedName, false, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultValue: const CustomExpression('2')); + late final GeneratedColumn acknowledgeByServer = GeneratedColumn( + 'acknowledge_by_server', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("acknowledge_by_server" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn errorWhileSending = GeneratedColumn( + 'error_while_sending', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("error_while_sending" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn kind = GeneratedColumn( + 'kind', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true); + late final GeneratedColumn contentJson = GeneratedColumn( + 'content_json', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); + late final GeneratedColumn openedAt = GeneratedColumn( + 'opened_at', aliasedName, true, + type: DriftSqlType.dateTime, requiredDuringInsert: false); + late final GeneratedColumn sendAt = GeneratedColumn( + 'send_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)')); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)')); + @override + List get $columns => [ + contactId, + messageId, + messageOtherId, + mediaUploadId, + mediaDownloadId, + responseToMessageId, + responseToOtherMessageId, + acknowledgeByUser, + mediaStored, + downloadState, + acknowledgeByServer, + errorWhileSending, + kind, + contentJson, + openedAt, + sendAt, + updatedAt + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'messages'; + @override + Set get $primaryKey => {messageId}; + @override + MessagesData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MessagesData( + contactId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}contact_id'])!, + messageId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}message_id'])!, + messageOtherId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}message_other_id']), + mediaUploadId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}media_upload_id']), + mediaDownloadId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}media_download_id']), + responseToMessageId: attachedDatabase.typeMapping.read( + DriftSqlType.int, data['${effectivePrefix}response_to_message_id']), + responseToOtherMessageId: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}response_to_other_message_id']), + acknowledgeByUser: attachedDatabase.typeMapping.read( + DriftSqlType.bool, data['${effectivePrefix}acknowledge_by_user'])!, + mediaStored: attachedDatabase.typeMapping + .read(DriftSqlType.bool, data['${effectivePrefix}media_stored'])!, + downloadState: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}download_state'])!, + acknowledgeByServer: attachedDatabase.typeMapping.read( + DriftSqlType.bool, data['${effectivePrefix}acknowledge_by_server'])!, + errorWhileSending: attachedDatabase.typeMapping.read( + DriftSqlType.bool, data['${effectivePrefix}error_while_sending'])!, + kind: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}kind'])!, + contentJson: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}content_json']), + openedAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}opened_at']), + sendAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}send_at'])!, + updatedAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, + ); + } + + @override + Messages createAlias(String alias) { + return Messages(attachedDatabase, alias); + } +} + +class MessagesData extends DataClass implements Insertable { + final int contactId; + final int messageId; + final int? messageOtherId; + final int? mediaUploadId; + final int? mediaDownloadId; + final int? responseToMessageId; + final int? responseToOtherMessageId; + final bool acknowledgeByUser; + final bool mediaStored; + final int downloadState; + final bool acknowledgeByServer; + final bool errorWhileSending; + final String kind; + final String? contentJson; + final DateTime? openedAt; + final DateTime sendAt; + final DateTime updatedAt; + const MessagesData( + {required this.contactId, + required this.messageId, + this.messageOtherId, + this.mediaUploadId, + this.mediaDownloadId, + this.responseToMessageId, + this.responseToOtherMessageId, + required this.acknowledgeByUser, + required this.mediaStored, + required this.downloadState, + required this.acknowledgeByServer, + required this.errorWhileSending, + required this.kind, + this.contentJson, + this.openedAt, + required this.sendAt, + required this.updatedAt}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['contact_id'] = Variable(contactId); + map['message_id'] = Variable(messageId); + if (!nullToAbsent || messageOtherId != null) { + map['message_other_id'] = Variable(messageOtherId); + } + if (!nullToAbsent || mediaUploadId != null) { + map['media_upload_id'] = Variable(mediaUploadId); + } + if (!nullToAbsent || mediaDownloadId != null) { + map['media_download_id'] = Variable(mediaDownloadId); + } + if (!nullToAbsent || responseToMessageId != null) { + map['response_to_message_id'] = Variable(responseToMessageId); + } + if (!nullToAbsent || responseToOtherMessageId != null) { + map['response_to_other_message_id'] = + Variable(responseToOtherMessageId); + } + map['acknowledge_by_user'] = Variable(acknowledgeByUser); + map['media_stored'] = Variable(mediaStored); + map['download_state'] = Variable(downloadState); + map['acknowledge_by_server'] = Variable(acknowledgeByServer); + map['error_while_sending'] = Variable(errorWhileSending); + map['kind'] = Variable(kind); + if (!nullToAbsent || contentJson != null) { + map['content_json'] = Variable(contentJson); + } + if (!nullToAbsent || openedAt != null) { + map['opened_at'] = Variable(openedAt); + } + map['send_at'] = Variable(sendAt); + map['updated_at'] = Variable(updatedAt); + return map; + } + + MessagesCompanion toCompanion(bool nullToAbsent) { + return MessagesCompanion( + contactId: Value(contactId), + messageId: Value(messageId), + messageOtherId: messageOtherId == null && nullToAbsent + ? const Value.absent() + : Value(messageOtherId), + mediaUploadId: mediaUploadId == null && nullToAbsent + ? const Value.absent() + : Value(mediaUploadId), + mediaDownloadId: mediaDownloadId == null && nullToAbsent + ? const Value.absent() + : Value(mediaDownloadId), + responseToMessageId: responseToMessageId == null && nullToAbsent + ? const Value.absent() + : Value(responseToMessageId), + responseToOtherMessageId: responseToOtherMessageId == null && nullToAbsent + ? const Value.absent() + : Value(responseToOtherMessageId), + acknowledgeByUser: Value(acknowledgeByUser), + mediaStored: Value(mediaStored), + downloadState: Value(downloadState), + acknowledgeByServer: Value(acknowledgeByServer), + errorWhileSending: Value(errorWhileSending), + kind: Value(kind), + contentJson: contentJson == null && nullToAbsent + ? const Value.absent() + : Value(contentJson), + openedAt: openedAt == null && nullToAbsent + ? const Value.absent() + : Value(openedAt), + sendAt: Value(sendAt), + updatedAt: Value(updatedAt), + ); + } + + factory MessagesData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessagesData( + contactId: serializer.fromJson(json['contactId']), + messageId: serializer.fromJson(json['messageId']), + messageOtherId: serializer.fromJson(json['messageOtherId']), + mediaUploadId: serializer.fromJson(json['mediaUploadId']), + mediaDownloadId: serializer.fromJson(json['mediaDownloadId']), + responseToMessageId: + serializer.fromJson(json['responseToMessageId']), + responseToOtherMessageId: + serializer.fromJson(json['responseToOtherMessageId']), + acknowledgeByUser: serializer.fromJson(json['acknowledgeByUser']), + mediaStored: serializer.fromJson(json['mediaStored']), + downloadState: serializer.fromJson(json['downloadState']), + acknowledgeByServer: + serializer.fromJson(json['acknowledgeByServer']), + errorWhileSending: serializer.fromJson(json['errorWhileSending']), + kind: serializer.fromJson(json['kind']), + contentJson: serializer.fromJson(json['contentJson']), + openedAt: serializer.fromJson(json['openedAt']), + sendAt: serializer.fromJson(json['sendAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'contactId': serializer.toJson(contactId), + 'messageId': serializer.toJson(messageId), + 'messageOtherId': serializer.toJson(messageOtherId), + 'mediaUploadId': serializer.toJson(mediaUploadId), + 'mediaDownloadId': serializer.toJson(mediaDownloadId), + 'responseToMessageId': serializer.toJson(responseToMessageId), + 'responseToOtherMessageId': + serializer.toJson(responseToOtherMessageId), + 'acknowledgeByUser': serializer.toJson(acknowledgeByUser), + 'mediaStored': serializer.toJson(mediaStored), + 'downloadState': serializer.toJson(downloadState), + 'acknowledgeByServer': serializer.toJson(acknowledgeByServer), + 'errorWhileSending': serializer.toJson(errorWhileSending), + 'kind': serializer.toJson(kind), + 'contentJson': serializer.toJson(contentJson), + 'openedAt': serializer.toJson(openedAt), + 'sendAt': serializer.toJson(sendAt), + 'updatedAt': serializer.toJson(updatedAt), + }; + } + + MessagesData copyWith( + {int? contactId, + int? messageId, + Value messageOtherId = const Value.absent(), + Value mediaUploadId = const Value.absent(), + Value mediaDownloadId = const Value.absent(), + Value responseToMessageId = const Value.absent(), + Value responseToOtherMessageId = const Value.absent(), + bool? acknowledgeByUser, + bool? mediaStored, + int? downloadState, + bool? acknowledgeByServer, + bool? errorWhileSending, + String? kind, + Value contentJson = const Value.absent(), + Value openedAt = const Value.absent(), + DateTime? sendAt, + DateTime? updatedAt}) => + MessagesData( + contactId: contactId ?? this.contactId, + messageId: messageId ?? this.messageId, + messageOtherId: + messageOtherId.present ? messageOtherId.value : this.messageOtherId, + mediaUploadId: + mediaUploadId.present ? mediaUploadId.value : this.mediaUploadId, + mediaDownloadId: mediaDownloadId.present + ? mediaDownloadId.value + : this.mediaDownloadId, + responseToMessageId: responseToMessageId.present + ? responseToMessageId.value + : this.responseToMessageId, + responseToOtherMessageId: responseToOtherMessageId.present + ? responseToOtherMessageId.value + : this.responseToOtherMessageId, + acknowledgeByUser: acknowledgeByUser ?? this.acknowledgeByUser, + mediaStored: mediaStored ?? this.mediaStored, + downloadState: downloadState ?? this.downloadState, + acknowledgeByServer: acknowledgeByServer ?? this.acknowledgeByServer, + errorWhileSending: errorWhileSending ?? this.errorWhileSending, + kind: kind ?? this.kind, + contentJson: contentJson.present ? contentJson.value : this.contentJson, + openedAt: openedAt.present ? openedAt.value : this.openedAt, + sendAt: sendAt ?? this.sendAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + MessagesData copyWithCompanion(MessagesCompanion data) { + return MessagesData( + contactId: data.contactId.present ? data.contactId.value : this.contactId, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + messageOtherId: data.messageOtherId.present + ? data.messageOtherId.value + : this.messageOtherId, + mediaUploadId: data.mediaUploadId.present + ? data.mediaUploadId.value + : this.mediaUploadId, + mediaDownloadId: data.mediaDownloadId.present + ? data.mediaDownloadId.value + : this.mediaDownloadId, + responseToMessageId: data.responseToMessageId.present + ? data.responseToMessageId.value + : this.responseToMessageId, + responseToOtherMessageId: data.responseToOtherMessageId.present + ? data.responseToOtherMessageId.value + : this.responseToOtherMessageId, + acknowledgeByUser: data.acknowledgeByUser.present + ? data.acknowledgeByUser.value + : this.acknowledgeByUser, + mediaStored: + data.mediaStored.present ? data.mediaStored.value : this.mediaStored, + downloadState: data.downloadState.present + ? data.downloadState.value + : this.downloadState, + acknowledgeByServer: data.acknowledgeByServer.present + ? data.acknowledgeByServer.value + : this.acknowledgeByServer, + errorWhileSending: data.errorWhileSending.present + ? data.errorWhileSending.value + : this.errorWhileSending, + kind: data.kind.present ? data.kind.value : this.kind, + contentJson: + data.contentJson.present ? data.contentJson.value : this.contentJson, + openedAt: data.openedAt.present ? data.openedAt.value : this.openedAt, + sendAt: data.sendAt.present ? data.sendAt.value : this.sendAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ); + } + + @override + String toString() { + return (StringBuffer('MessagesData(') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('messageOtherId: $messageOtherId, ') + ..write('mediaUploadId: $mediaUploadId, ') + ..write('mediaDownloadId: $mediaDownloadId, ') + ..write('responseToMessageId: $responseToMessageId, ') + ..write('responseToOtherMessageId: $responseToOtherMessageId, ') + ..write('acknowledgeByUser: $acknowledgeByUser, ') + ..write('mediaStored: $mediaStored, ') + ..write('downloadState: $downloadState, ') + ..write('acknowledgeByServer: $acknowledgeByServer, ') + ..write('errorWhileSending: $errorWhileSending, ') + ..write('kind: $kind, ') + ..write('contentJson: $contentJson, ') + ..write('openedAt: $openedAt, ') + ..write('sendAt: $sendAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + contactId, + messageId, + messageOtherId, + mediaUploadId, + mediaDownloadId, + responseToMessageId, + responseToOtherMessageId, + acknowledgeByUser, + mediaStored, + downloadState, + acknowledgeByServer, + errorWhileSending, + kind, + contentJson, + openedAt, + sendAt, + updatedAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessagesData && + other.contactId == this.contactId && + other.messageId == this.messageId && + other.messageOtherId == this.messageOtherId && + other.mediaUploadId == this.mediaUploadId && + other.mediaDownloadId == this.mediaDownloadId && + other.responseToMessageId == this.responseToMessageId && + other.responseToOtherMessageId == this.responseToOtherMessageId && + other.acknowledgeByUser == this.acknowledgeByUser && + other.mediaStored == this.mediaStored && + other.downloadState == this.downloadState && + other.acknowledgeByServer == this.acknowledgeByServer && + other.errorWhileSending == this.errorWhileSending && + other.kind == this.kind && + other.contentJson == this.contentJson && + other.openedAt == this.openedAt && + other.sendAt == this.sendAt && + other.updatedAt == this.updatedAt); +} + +class MessagesCompanion extends UpdateCompanion { + final Value contactId; + final Value messageId; + final Value messageOtherId; + final Value mediaUploadId; + final Value mediaDownloadId; + final Value responseToMessageId; + final Value responseToOtherMessageId; + final Value acknowledgeByUser; + final Value mediaStored; + final Value downloadState; + final Value acknowledgeByServer; + final Value errorWhileSending; + final Value kind; + final Value contentJson; + final Value openedAt; + final Value sendAt; + final Value updatedAt; + const MessagesCompanion({ + this.contactId = const Value.absent(), + this.messageId = const Value.absent(), + this.messageOtherId = const Value.absent(), + this.mediaUploadId = const Value.absent(), + this.mediaDownloadId = const Value.absent(), + this.responseToMessageId = const Value.absent(), + this.responseToOtherMessageId = const Value.absent(), + this.acknowledgeByUser = const Value.absent(), + this.mediaStored = const Value.absent(), + this.downloadState = const Value.absent(), + this.acknowledgeByServer = const Value.absent(), + this.errorWhileSending = const Value.absent(), + this.kind = const Value.absent(), + this.contentJson = const Value.absent(), + this.openedAt = const Value.absent(), + this.sendAt = const Value.absent(), + this.updatedAt = const Value.absent(), + }); + MessagesCompanion.insert({ + required int contactId, + this.messageId = const Value.absent(), + this.messageOtherId = const Value.absent(), + this.mediaUploadId = const Value.absent(), + this.mediaDownloadId = const Value.absent(), + this.responseToMessageId = const Value.absent(), + this.responseToOtherMessageId = const Value.absent(), + this.acknowledgeByUser = const Value.absent(), + this.mediaStored = const Value.absent(), + this.downloadState = const Value.absent(), + this.acknowledgeByServer = const Value.absent(), + this.errorWhileSending = const Value.absent(), + required String kind, + this.contentJson = const Value.absent(), + this.openedAt = const Value.absent(), + this.sendAt = const Value.absent(), + this.updatedAt = const Value.absent(), + }) : contactId = Value(contactId), + kind = Value(kind); + static Insertable custom({ + Expression? contactId, + Expression? messageId, + Expression? messageOtherId, + Expression? mediaUploadId, + Expression? mediaDownloadId, + Expression? responseToMessageId, + Expression? responseToOtherMessageId, + Expression? acknowledgeByUser, + Expression? mediaStored, + Expression? downloadState, + Expression? acknowledgeByServer, + Expression? errorWhileSending, + Expression? kind, + Expression? contentJson, + Expression? openedAt, + Expression? sendAt, + Expression? updatedAt, + }) { + return RawValuesInsertable({ + if (contactId != null) 'contact_id': contactId, + if (messageId != null) 'message_id': messageId, + if (messageOtherId != null) 'message_other_id': messageOtherId, + if (mediaUploadId != null) 'media_upload_id': mediaUploadId, + if (mediaDownloadId != null) 'media_download_id': mediaDownloadId, + if (responseToMessageId != null) + 'response_to_message_id': responseToMessageId, + if (responseToOtherMessageId != null) + 'response_to_other_message_id': responseToOtherMessageId, + if (acknowledgeByUser != null) 'acknowledge_by_user': acknowledgeByUser, + if (mediaStored != null) 'media_stored': mediaStored, + if (downloadState != null) 'download_state': downloadState, + if (acknowledgeByServer != null) + 'acknowledge_by_server': acknowledgeByServer, + if (errorWhileSending != null) 'error_while_sending': errorWhileSending, + if (kind != null) 'kind': kind, + if (contentJson != null) 'content_json': contentJson, + if (openedAt != null) 'opened_at': openedAt, + if (sendAt != null) 'send_at': sendAt, + if (updatedAt != null) 'updated_at': updatedAt, + }); + } + + MessagesCompanion copyWith( + {Value? contactId, + Value? messageId, + Value? messageOtherId, + Value? mediaUploadId, + Value? mediaDownloadId, + Value? responseToMessageId, + Value? responseToOtherMessageId, + Value? acknowledgeByUser, + Value? mediaStored, + Value? downloadState, + Value? acknowledgeByServer, + Value? errorWhileSending, + Value? kind, + Value? contentJson, + Value? openedAt, + Value? sendAt, + Value? updatedAt}) { + return MessagesCompanion( + contactId: contactId ?? this.contactId, + messageId: messageId ?? this.messageId, + messageOtherId: messageOtherId ?? this.messageOtherId, + mediaUploadId: mediaUploadId ?? this.mediaUploadId, + mediaDownloadId: mediaDownloadId ?? this.mediaDownloadId, + responseToMessageId: responseToMessageId ?? this.responseToMessageId, + responseToOtherMessageId: + responseToOtherMessageId ?? this.responseToOtherMessageId, + acknowledgeByUser: acknowledgeByUser ?? this.acknowledgeByUser, + mediaStored: mediaStored ?? this.mediaStored, + downloadState: downloadState ?? this.downloadState, + acknowledgeByServer: acknowledgeByServer ?? this.acknowledgeByServer, + errorWhileSending: errorWhileSending ?? this.errorWhileSending, + kind: kind ?? this.kind, + contentJson: contentJson ?? this.contentJson, + openedAt: openedAt ?? this.openedAt, + sendAt: sendAt ?? this.sendAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (messageOtherId.present) { + map['message_other_id'] = Variable(messageOtherId.value); + } + if (mediaUploadId.present) { + map['media_upload_id'] = Variable(mediaUploadId.value); + } + if (mediaDownloadId.present) { + map['media_download_id'] = Variable(mediaDownloadId.value); + } + if (responseToMessageId.present) { + map['response_to_message_id'] = Variable(responseToMessageId.value); + } + if (responseToOtherMessageId.present) { + map['response_to_other_message_id'] = + Variable(responseToOtherMessageId.value); + } + if (acknowledgeByUser.present) { + map['acknowledge_by_user'] = Variable(acknowledgeByUser.value); + } + if (mediaStored.present) { + map['media_stored'] = Variable(mediaStored.value); + } + if (downloadState.present) { + map['download_state'] = Variable(downloadState.value); + } + if (acknowledgeByServer.present) { + map['acknowledge_by_server'] = Variable(acknowledgeByServer.value); + } + if (errorWhileSending.present) { + map['error_while_sending'] = Variable(errorWhileSending.value); + } + if (kind.present) { + map['kind'] = Variable(kind.value); + } + if (contentJson.present) { + map['content_json'] = Variable(contentJson.value); + } + if (openedAt.present) { + map['opened_at'] = Variable(openedAt.value); + } + if (sendAt.present) { + map['send_at'] = Variable(sendAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessagesCompanion(') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('messageOtherId: $messageOtherId, ') + ..write('mediaUploadId: $mediaUploadId, ') + ..write('mediaDownloadId: $mediaDownloadId, ') + ..write('responseToMessageId: $responseToMessageId, ') + ..write('responseToOtherMessageId: $responseToOtherMessageId, ') + ..write('acknowledgeByUser: $acknowledgeByUser, ') + ..write('mediaStored: $mediaStored, ') + ..write('downloadState: $downloadState, ') + ..write('acknowledgeByServer: $acknowledgeByServer, ') + ..write('errorWhileSending: $errorWhileSending, ') + ..write('kind: $kind, ') + ..write('contentJson: $contentJson, ') + ..write('openedAt: $openedAt, ') + ..write('sendAt: $sendAt, ') + ..write('updatedAt: $updatedAt') + ..write(')')) + .toString(); + } +} + +class MediaUploads extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MediaUploads(this.attachedDatabase, [this._alias]); + late final GeneratedColumn mediaUploadId = GeneratedColumn( + 'media_upload_id', aliasedName, false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT')); + late final GeneratedColumn state = GeneratedColumn( + 'state', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const CustomExpression('\'pending\'')); + late final GeneratedColumn metadata = GeneratedColumn( + 'metadata', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); + late final GeneratedColumn messageIds = GeneratedColumn( + 'message_ids', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); + late final GeneratedColumn encryptionData = GeneratedColumn( + 'encryption_data', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); + late final GeneratedColumn uploadTokens = GeneratedColumn( + 'upload_tokens', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); + late final GeneratedColumn alreadyNotified = GeneratedColumn( + 'already_notified', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: const CustomExpression('\'[]\'')); + @override + List get $columns => [ + mediaUploadId, + state, + metadata, + messageIds, + encryptionData, + uploadTokens, + alreadyNotified + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'media_uploads'; + @override + Set get $primaryKey => {mediaUploadId}; + @override + MediaUploadsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MediaUploadsData( + mediaUploadId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}media_upload_id'])!, + state: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}state'])!, + metadata: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}metadata']), + messageIds: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}message_ids']), + encryptionData: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}encryption_data']), + uploadTokens: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}upload_tokens']), + alreadyNotified: attachedDatabase.typeMapping.read( + DriftSqlType.string, data['${effectivePrefix}already_notified'])!, + ); + } + + @override + MediaUploads createAlias(String alias) { + return MediaUploads(attachedDatabase, alias); + } +} + +class MediaUploadsData extends DataClass + implements Insertable { + final int mediaUploadId; + final String state; + final String? metadata; + final String? messageIds; + final String? encryptionData; + final String? uploadTokens; + final String alreadyNotified; + const MediaUploadsData( + {required this.mediaUploadId, + required this.state, + this.metadata, + this.messageIds, + this.encryptionData, + this.uploadTokens, + required this.alreadyNotified}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['media_upload_id'] = Variable(mediaUploadId); + map['state'] = Variable(state); + if (!nullToAbsent || metadata != null) { + map['metadata'] = Variable(metadata); + } + if (!nullToAbsent || messageIds != null) { + map['message_ids'] = Variable(messageIds); + } + if (!nullToAbsent || encryptionData != null) { + map['encryption_data'] = Variable(encryptionData); + } + if (!nullToAbsent || uploadTokens != null) { + map['upload_tokens'] = Variable(uploadTokens); + } + map['already_notified'] = Variable(alreadyNotified); + return map; + } + + MediaUploadsCompanion toCompanion(bool nullToAbsent) { + return MediaUploadsCompanion( + mediaUploadId: Value(mediaUploadId), + state: Value(state), + metadata: metadata == null && nullToAbsent + ? const Value.absent() + : Value(metadata), + messageIds: messageIds == null && nullToAbsent + ? const Value.absent() + : Value(messageIds), + encryptionData: encryptionData == null && nullToAbsent + ? const Value.absent() + : Value(encryptionData), + uploadTokens: uploadTokens == null && nullToAbsent + ? const Value.absent() + : Value(uploadTokens), + alreadyNotified: Value(alreadyNotified), + ); + } + + factory MediaUploadsData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MediaUploadsData( + mediaUploadId: serializer.fromJson(json['mediaUploadId']), + state: serializer.fromJson(json['state']), + metadata: serializer.fromJson(json['metadata']), + messageIds: serializer.fromJson(json['messageIds']), + encryptionData: serializer.fromJson(json['encryptionData']), + uploadTokens: serializer.fromJson(json['uploadTokens']), + alreadyNotified: serializer.fromJson(json['alreadyNotified']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'mediaUploadId': serializer.toJson(mediaUploadId), + 'state': serializer.toJson(state), + 'metadata': serializer.toJson(metadata), + 'messageIds': serializer.toJson(messageIds), + 'encryptionData': serializer.toJson(encryptionData), + 'uploadTokens': serializer.toJson(uploadTokens), + 'alreadyNotified': serializer.toJson(alreadyNotified), + }; + } + + MediaUploadsData copyWith( + {int? mediaUploadId, + String? state, + Value metadata = const Value.absent(), + Value messageIds = const Value.absent(), + Value encryptionData = const Value.absent(), + Value uploadTokens = const Value.absent(), + String? alreadyNotified}) => + MediaUploadsData( + mediaUploadId: mediaUploadId ?? this.mediaUploadId, + state: state ?? this.state, + metadata: metadata.present ? metadata.value : this.metadata, + messageIds: messageIds.present ? messageIds.value : this.messageIds, + encryptionData: + encryptionData.present ? encryptionData.value : this.encryptionData, + uploadTokens: + uploadTokens.present ? uploadTokens.value : this.uploadTokens, + alreadyNotified: alreadyNotified ?? this.alreadyNotified, + ); + MediaUploadsData copyWithCompanion(MediaUploadsCompanion data) { + return MediaUploadsData( + mediaUploadId: data.mediaUploadId.present + ? data.mediaUploadId.value + : this.mediaUploadId, + state: data.state.present ? data.state.value : this.state, + metadata: data.metadata.present ? data.metadata.value : this.metadata, + messageIds: + data.messageIds.present ? data.messageIds.value : this.messageIds, + encryptionData: data.encryptionData.present + ? data.encryptionData.value + : this.encryptionData, + uploadTokens: data.uploadTokens.present + ? data.uploadTokens.value + : this.uploadTokens, + alreadyNotified: data.alreadyNotified.present + ? data.alreadyNotified.value + : this.alreadyNotified, + ); + } + + @override + String toString() { + return (StringBuffer('MediaUploadsData(') + ..write('mediaUploadId: $mediaUploadId, ') + ..write('state: $state, ') + ..write('metadata: $metadata, ') + ..write('messageIds: $messageIds, ') + ..write('encryptionData: $encryptionData, ') + ..write('uploadTokens: $uploadTokens, ') + ..write('alreadyNotified: $alreadyNotified') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(mediaUploadId, state, metadata, messageIds, + encryptionData, uploadTokens, alreadyNotified); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MediaUploadsData && + other.mediaUploadId == this.mediaUploadId && + other.state == this.state && + other.metadata == this.metadata && + other.messageIds == this.messageIds && + other.encryptionData == this.encryptionData && + other.uploadTokens == this.uploadTokens && + other.alreadyNotified == this.alreadyNotified); +} + +class MediaUploadsCompanion extends UpdateCompanion { + final Value mediaUploadId; + final Value state; + final Value metadata; + final Value messageIds; + final Value encryptionData; + final Value uploadTokens; + final Value alreadyNotified; + const MediaUploadsCompanion({ + this.mediaUploadId = const Value.absent(), + this.state = const Value.absent(), + this.metadata = const Value.absent(), + this.messageIds = const Value.absent(), + this.encryptionData = const Value.absent(), + this.uploadTokens = const Value.absent(), + this.alreadyNotified = const Value.absent(), + }); + MediaUploadsCompanion.insert({ + this.mediaUploadId = const Value.absent(), + this.state = const Value.absent(), + this.metadata = const Value.absent(), + this.messageIds = const Value.absent(), + this.encryptionData = const Value.absent(), + this.uploadTokens = const Value.absent(), + this.alreadyNotified = const Value.absent(), + }); + static Insertable custom({ + Expression? mediaUploadId, + Expression? state, + Expression? metadata, + Expression? messageIds, + Expression? encryptionData, + Expression? uploadTokens, + Expression? alreadyNotified, + }) { + return RawValuesInsertable({ + if (mediaUploadId != null) 'media_upload_id': mediaUploadId, + if (state != null) 'state': state, + if (metadata != null) 'metadata': metadata, + if (messageIds != null) 'message_ids': messageIds, + if (encryptionData != null) 'encryption_data': encryptionData, + if (uploadTokens != null) 'upload_tokens': uploadTokens, + if (alreadyNotified != null) 'already_notified': alreadyNotified, + }); + } + + MediaUploadsCompanion copyWith( + {Value? mediaUploadId, + Value? state, + Value? metadata, + Value? messageIds, + Value? encryptionData, + Value? uploadTokens, + Value? alreadyNotified}) { + return MediaUploadsCompanion( + mediaUploadId: mediaUploadId ?? this.mediaUploadId, + state: state ?? this.state, + metadata: metadata ?? this.metadata, + messageIds: messageIds ?? this.messageIds, + encryptionData: encryptionData ?? this.encryptionData, + uploadTokens: uploadTokens ?? this.uploadTokens, + alreadyNotified: alreadyNotified ?? this.alreadyNotified, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (mediaUploadId.present) { + map['media_upload_id'] = Variable(mediaUploadId.value); + } + if (state.present) { + map['state'] = Variable(state.value); + } + if (metadata.present) { + map['metadata'] = Variable(metadata.value); + } + if (messageIds.present) { + map['message_ids'] = Variable(messageIds.value); + } + if (encryptionData.present) { + map['encryption_data'] = Variable(encryptionData.value); + } + if (uploadTokens.present) { + map['upload_tokens'] = Variable(uploadTokens.value); + } + if (alreadyNotified.present) { + map['already_notified'] = Variable(alreadyNotified.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MediaUploadsCompanion(') + ..write('mediaUploadId: $mediaUploadId, ') + ..write('state: $state, ') + ..write('metadata: $metadata, ') + ..write('messageIds: $messageIds, ') + ..write('encryptionData: $encryptionData, ') + ..write('uploadTokens: $uploadTokens, ') + ..write('alreadyNotified: $alreadyNotified') + ..write(')')) + .toString(); + } +} + +class MediaDownloads extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MediaDownloads(this.attachedDatabase, [this._alias]); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + late final GeneratedColumn downloadToken = GeneratedColumn( + 'download_token', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true); + @override + List get $columns => [messageId, downloadToken]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'media_downloads'; + @override + Set get $primaryKey => const {}; + @override + MediaDownloadsData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MediaDownloadsData( + messageId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}message_id'])!, + downloadToken: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}download_token'])!, + ); + } + + @override + MediaDownloads createAlias(String alias) { + return MediaDownloads(attachedDatabase, alias); + } +} + +class MediaDownloadsData extends DataClass + implements Insertable { + final int messageId; + final String downloadToken; + const MediaDownloadsData( + {required this.messageId, required this.downloadToken}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['message_id'] = Variable(messageId); + map['download_token'] = Variable(downloadToken); + return map; + } + + MediaDownloadsCompanion toCompanion(bool nullToAbsent) { + return MediaDownloadsCompanion( + messageId: Value(messageId), + downloadToken: Value(downloadToken), + ); + } + + factory MediaDownloadsData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MediaDownloadsData( + messageId: serializer.fromJson(json['messageId']), + downloadToken: serializer.fromJson(json['downloadToken']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'messageId': serializer.toJson(messageId), + 'downloadToken': serializer.toJson(downloadToken), + }; + } + + MediaDownloadsData copyWith({int? messageId, String? downloadToken}) => + MediaDownloadsData( + messageId: messageId ?? this.messageId, + downloadToken: downloadToken ?? this.downloadToken, + ); + MediaDownloadsData copyWithCompanion(MediaDownloadsCompanion data) { + return MediaDownloadsData( + messageId: data.messageId.present ? data.messageId.value : this.messageId, + downloadToken: data.downloadToken.present + ? data.downloadToken.value + : this.downloadToken, + ); + } + + @override + String toString() { + return (StringBuffer('MediaDownloadsData(') + ..write('messageId: $messageId, ') + ..write('downloadToken: $downloadToken') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(messageId, downloadToken); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MediaDownloadsData && + other.messageId == this.messageId && + other.downloadToken == this.downloadToken); +} + +class MediaDownloadsCompanion extends UpdateCompanion { + final Value messageId; + final Value downloadToken; + final Value rowid; + const MediaDownloadsCompanion({ + this.messageId = const Value.absent(), + this.downloadToken = const Value.absent(), + this.rowid = const Value.absent(), + }); + MediaDownloadsCompanion.insert({ + required int messageId, + required String downloadToken, + this.rowid = const Value.absent(), + }) : messageId = Value(messageId), + downloadToken = Value(downloadToken); + static Insertable custom({ + Expression? messageId, + Expression? downloadToken, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (messageId != null) 'message_id': messageId, + if (downloadToken != null) 'download_token': downloadToken, + if (rowid != null) 'rowid': rowid, + }); + } + + MediaDownloadsCompanion copyWith( + {Value? messageId, + Value? downloadToken, + Value? rowid}) { + return MediaDownloadsCompanion( + messageId: messageId ?? this.messageId, + downloadToken: downloadToken ?? this.downloadToken, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (downloadToken.present) { + map['download_token'] = Variable(downloadToken.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MediaDownloadsCompanion(') + ..write('messageId: $messageId, ') + ..write('downloadToken: $downloadToken, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class SignalIdentityKeyStores extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + SignalIdentityKeyStores(this.attachedDatabase, [this._alias]); + late final GeneratedColumn deviceId = GeneratedColumn( + 'device_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + late final GeneratedColumn name = GeneratedColumn( + 'name', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true); + late final GeneratedColumn identityKey = + GeneratedColumn('identity_key', aliasedName, false, + type: DriftSqlType.blob, requiredDuringInsert: true); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)')); + @override + List get $columns => + [deviceId, name, identityKey, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'signal_identity_key_stores'; + @override + Set get $primaryKey => {deviceId, name}; + @override + SignalIdentityKeyStoresData map(Map data, + {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return SignalIdentityKeyStoresData( + deviceId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}device_id'])!, + name: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}name'])!, + identityKey: attachedDatabase.typeMapping + .read(DriftSqlType.blob, data['${effectivePrefix}identity_key'])!, + createdAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + ); + } + + @override + SignalIdentityKeyStores createAlias(String alias) { + return SignalIdentityKeyStores(attachedDatabase, alias); + } +} + +class SignalIdentityKeyStoresData extends DataClass + implements Insertable { + final int deviceId; + final String name; + final Uint8List identityKey; + final DateTime createdAt; + const SignalIdentityKeyStoresData( + {required this.deviceId, + required this.name, + required this.identityKey, + required this.createdAt}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['device_id'] = Variable(deviceId); + map['name'] = Variable(name); + map['identity_key'] = Variable(identityKey); + map['created_at'] = Variable(createdAt); + return map; + } + + SignalIdentityKeyStoresCompanion toCompanion(bool nullToAbsent) { + return SignalIdentityKeyStoresCompanion( + deviceId: Value(deviceId), + name: Value(name), + identityKey: Value(identityKey), + createdAt: Value(createdAt), + ); + } + + factory SignalIdentityKeyStoresData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return SignalIdentityKeyStoresData( + deviceId: serializer.fromJson(json['deviceId']), + name: serializer.fromJson(json['name']), + identityKey: serializer.fromJson(json['identityKey']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'deviceId': serializer.toJson(deviceId), + 'name': serializer.toJson(name), + 'identityKey': serializer.toJson(identityKey), + 'createdAt': serializer.toJson(createdAt), + }; + } + + SignalIdentityKeyStoresData copyWith( + {int? deviceId, + String? name, + Uint8List? identityKey, + DateTime? createdAt}) => + SignalIdentityKeyStoresData( + deviceId: deviceId ?? this.deviceId, + name: name ?? this.name, + identityKey: identityKey ?? this.identityKey, + createdAt: createdAt ?? this.createdAt, + ); + SignalIdentityKeyStoresData copyWithCompanion( + SignalIdentityKeyStoresCompanion data) { + return SignalIdentityKeyStoresData( + deviceId: data.deviceId.present ? data.deviceId.value : this.deviceId, + name: data.name.present ? data.name.value : this.name, + identityKey: + data.identityKey.present ? data.identityKey.value : this.identityKey, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('SignalIdentityKeyStoresData(') + ..write('deviceId: $deviceId, ') + ..write('name: $name, ') + ..write('identityKey: $identityKey, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + deviceId, name, $driftBlobEquality.hash(identityKey), createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is SignalIdentityKeyStoresData && + other.deviceId == this.deviceId && + other.name == this.name && + $driftBlobEquality.equals(other.identityKey, this.identityKey) && + other.createdAt == this.createdAt); +} + +class SignalIdentityKeyStoresCompanion + extends UpdateCompanion { + final Value deviceId; + final Value name; + final Value identityKey; + final Value createdAt; + final Value rowid; + const SignalIdentityKeyStoresCompanion({ + this.deviceId = const Value.absent(), + this.name = const Value.absent(), + this.identityKey = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + SignalIdentityKeyStoresCompanion.insert({ + required int deviceId, + required String name, + required Uint8List identityKey, + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : deviceId = Value(deviceId), + name = Value(name), + identityKey = Value(identityKey); + static Insertable custom({ + Expression? deviceId, + Expression? name, + Expression? identityKey, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (deviceId != null) 'device_id': deviceId, + if (name != null) 'name': name, + if (identityKey != null) 'identity_key': identityKey, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + SignalIdentityKeyStoresCompanion copyWith( + {Value? deviceId, + Value? name, + Value? identityKey, + Value? createdAt, + Value? rowid}) { + return SignalIdentityKeyStoresCompanion( + deviceId: deviceId ?? this.deviceId, + name: name ?? this.name, + identityKey: identityKey ?? this.identityKey, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (deviceId.present) { + map['device_id'] = Variable(deviceId.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (identityKey.present) { + map['identity_key'] = Variable(identityKey.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('SignalIdentityKeyStoresCompanion(') + ..write('deviceId: $deviceId, ') + ..write('name: $name, ') + ..write('identityKey: $identityKey, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class SignalPreKeyStores extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + SignalPreKeyStores(this.attachedDatabase, [this._alias]); + late final GeneratedColumn preKeyId = GeneratedColumn( + 'pre_key_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: false); + late final GeneratedColumn preKey = GeneratedColumn( + 'pre_key', aliasedName, false, + type: DriftSqlType.blob, requiredDuringInsert: true); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)')); + @override + List get $columns => [preKeyId, preKey, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'signal_pre_key_stores'; + @override + Set get $primaryKey => {preKeyId}; + @override + SignalPreKeyStoresData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return SignalPreKeyStoresData( + preKeyId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}pre_key_id'])!, + preKey: attachedDatabase.typeMapping + .read(DriftSqlType.blob, data['${effectivePrefix}pre_key'])!, + createdAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + ); + } + + @override + SignalPreKeyStores createAlias(String alias) { + return SignalPreKeyStores(attachedDatabase, alias); + } +} + +class SignalPreKeyStoresData extends DataClass + implements Insertable { + final int preKeyId; + final Uint8List preKey; + final DateTime createdAt; + const SignalPreKeyStoresData( + {required this.preKeyId, required this.preKey, required this.createdAt}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['pre_key_id'] = Variable(preKeyId); + map['pre_key'] = Variable(preKey); + map['created_at'] = Variable(createdAt); + return map; + } + + SignalPreKeyStoresCompanion toCompanion(bool nullToAbsent) { + return SignalPreKeyStoresCompanion( + preKeyId: Value(preKeyId), + preKey: Value(preKey), + createdAt: Value(createdAt), + ); + } + + factory SignalPreKeyStoresData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return SignalPreKeyStoresData( + preKeyId: serializer.fromJson(json['preKeyId']), + preKey: serializer.fromJson(json['preKey']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'preKeyId': serializer.toJson(preKeyId), + 'preKey': serializer.toJson(preKey), + 'createdAt': serializer.toJson(createdAt), + }; + } + + SignalPreKeyStoresData copyWith( + {int? preKeyId, Uint8List? preKey, DateTime? createdAt}) => + SignalPreKeyStoresData( + preKeyId: preKeyId ?? this.preKeyId, + preKey: preKey ?? this.preKey, + createdAt: createdAt ?? this.createdAt, + ); + SignalPreKeyStoresData copyWithCompanion(SignalPreKeyStoresCompanion data) { + return SignalPreKeyStoresData( + preKeyId: data.preKeyId.present ? data.preKeyId.value : this.preKeyId, + preKey: data.preKey.present ? data.preKey.value : this.preKey, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('SignalPreKeyStoresData(') + ..write('preKeyId: $preKeyId, ') + ..write('preKey: $preKey, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(preKeyId, $driftBlobEquality.hash(preKey), createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is SignalPreKeyStoresData && + other.preKeyId == this.preKeyId && + $driftBlobEquality.equals(other.preKey, this.preKey) && + other.createdAt == this.createdAt); +} + +class SignalPreKeyStoresCompanion + extends UpdateCompanion { + final Value preKeyId; + final Value preKey; + final Value createdAt; + const SignalPreKeyStoresCompanion({ + this.preKeyId = const Value.absent(), + this.preKey = const Value.absent(), + this.createdAt = const Value.absent(), + }); + SignalPreKeyStoresCompanion.insert({ + this.preKeyId = const Value.absent(), + required Uint8List preKey, + this.createdAt = const Value.absent(), + }) : preKey = Value(preKey); + static Insertable custom({ + Expression? preKeyId, + Expression? preKey, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (preKeyId != null) 'pre_key_id': preKeyId, + if (preKey != null) 'pre_key': preKey, + if (createdAt != null) 'created_at': createdAt, + }); + } + + SignalPreKeyStoresCompanion copyWith( + {Value? preKeyId, + Value? preKey, + Value? createdAt}) { + return SignalPreKeyStoresCompanion( + preKeyId: preKeyId ?? this.preKeyId, + preKey: preKey ?? this.preKey, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (preKeyId.present) { + map['pre_key_id'] = Variable(preKeyId.value); + } + if (preKey.present) { + map['pre_key'] = Variable(preKey.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('SignalPreKeyStoresCompanion(') + ..write('preKeyId: $preKeyId, ') + ..write('preKey: $preKey, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class SignalSenderKeyStores extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + SignalSenderKeyStores(this.attachedDatabase, [this._alias]); + late final GeneratedColumn senderKeyName = GeneratedColumn( + 'sender_key_name', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true); + late final GeneratedColumn senderKey = GeneratedColumn( + 'sender_key', aliasedName, false, + type: DriftSqlType.blob, requiredDuringInsert: true); + @override + List get $columns => [senderKeyName, senderKey]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'signal_sender_key_stores'; + @override + Set get $primaryKey => {senderKeyName}; + @override + SignalSenderKeyStoresData map(Map data, + {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return SignalSenderKeyStoresData( + senderKeyName: attachedDatabase.typeMapping.read( + DriftSqlType.string, data['${effectivePrefix}sender_key_name'])!, + senderKey: attachedDatabase.typeMapping + .read(DriftSqlType.blob, data['${effectivePrefix}sender_key'])!, + ); + } + + @override + SignalSenderKeyStores createAlias(String alias) { + return SignalSenderKeyStores(attachedDatabase, alias); + } +} + +class SignalSenderKeyStoresData extends DataClass + implements Insertable { + final String senderKeyName; + final Uint8List senderKey; + const SignalSenderKeyStoresData( + {required this.senderKeyName, required this.senderKey}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['sender_key_name'] = Variable(senderKeyName); + map['sender_key'] = Variable(senderKey); + return map; + } + + SignalSenderKeyStoresCompanion toCompanion(bool nullToAbsent) { + return SignalSenderKeyStoresCompanion( + senderKeyName: Value(senderKeyName), + senderKey: Value(senderKey), + ); + } + + factory SignalSenderKeyStoresData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return SignalSenderKeyStoresData( + senderKeyName: serializer.fromJson(json['senderKeyName']), + senderKey: serializer.fromJson(json['senderKey']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'senderKeyName': serializer.toJson(senderKeyName), + 'senderKey': serializer.toJson(senderKey), + }; + } + + SignalSenderKeyStoresData copyWith( + {String? senderKeyName, Uint8List? senderKey}) => + SignalSenderKeyStoresData( + senderKeyName: senderKeyName ?? this.senderKeyName, + senderKey: senderKey ?? this.senderKey, + ); + SignalSenderKeyStoresData copyWithCompanion( + SignalSenderKeyStoresCompanion data) { + return SignalSenderKeyStoresData( + senderKeyName: data.senderKeyName.present + ? data.senderKeyName.value + : this.senderKeyName, + senderKey: data.senderKey.present ? data.senderKey.value : this.senderKey, + ); + } + + @override + String toString() { + return (StringBuffer('SignalSenderKeyStoresData(') + ..write('senderKeyName: $senderKeyName, ') + ..write('senderKey: $senderKey') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(senderKeyName, $driftBlobEquality.hash(senderKey)); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is SignalSenderKeyStoresData && + other.senderKeyName == this.senderKeyName && + $driftBlobEquality.equals(other.senderKey, this.senderKey)); +} + +class SignalSenderKeyStoresCompanion + extends UpdateCompanion { + final Value senderKeyName; + final Value senderKey; + final Value rowid; + const SignalSenderKeyStoresCompanion({ + this.senderKeyName = const Value.absent(), + this.senderKey = const Value.absent(), + this.rowid = const Value.absent(), + }); + SignalSenderKeyStoresCompanion.insert({ + required String senderKeyName, + required Uint8List senderKey, + this.rowid = const Value.absent(), + }) : senderKeyName = Value(senderKeyName), + senderKey = Value(senderKey); + static Insertable custom({ + Expression? senderKeyName, + Expression? senderKey, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (senderKeyName != null) 'sender_key_name': senderKeyName, + if (senderKey != null) 'sender_key': senderKey, + if (rowid != null) 'rowid': rowid, + }); + } + + SignalSenderKeyStoresCompanion copyWith( + {Value? senderKeyName, + Value? senderKey, + Value? rowid}) { + return SignalSenderKeyStoresCompanion( + senderKeyName: senderKeyName ?? this.senderKeyName, + senderKey: senderKey ?? this.senderKey, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (senderKeyName.present) { + map['sender_key_name'] = Variable(senderKeyName.value); + } + if (senderKey.present) { + map['sender_key'] = Variable(senderKey.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('SignalSenderKeyStoresCompanion(') + ..write('senderKeyName: $senderKeyName, ') + ..write('senderKey: $senderKey, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class SignalSessionStores extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + SignalSessionStores(this.attachedDatabase, [this._alias]); + late final GeneratedColumn deviceId = GeneratedColumn( + 'device_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + late final GeneratedColumn name = GeneratedColumn( + 'name', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true); + late final GeneratedColumn sessionRecord = + GeneratedColumn('session_record', aliasedName, false, + type: DriftSqlType.blob, requiredDuringInsert: true); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)')); + @override + List get $columns => + [deviceId, name, sessionRecord, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'signal_session_stores'; + @override + Set get $primaryKey => {deviceId, name}; + @override + SignalSessionStoresData map(Map data, + {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return SignalSessionStoresData( + deviceId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}device_id'])!, + name: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}name'])!, + sessionRecord: attachedDatabase.typeMapping + .read(DriftSqlType.blob, data['${effectivePrefix}session_record'])!, + createdAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + ); + } + + @override + SignalSessionStores createAlias(String alias) { + return SignalSessionStores(attachedDatabase, alias); + } +} + +class SignalSessionStoresData extends DataClass + implements Insertable { + final int deviceId; + final String name; + final Uint8List sessionRecord; + final DateTime createdAt; + const SignalSessionStoresData( + {required this.deviceId, + required this.name, + required this.sessionRecord, + required this.createdAt}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['device_id'] = Variable(deviceId); + map['name'] = Variable(name); + map['session_record'] = Variable(sessionRecord); + map['created_at'] = Variable(createdAt); + return map; + } + + SignalSessionStoresCompanion toCompanion(bool nullToAbsent) { + return SignalSessionStoresCompanion( + deviceId: Value(deviceId), + name: Value(name), + sessionRecord: Value(sessionRecord), + createdAt: Value(createdAt), + ); + } + + factory SignalSessionStoresData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return SignalSessionStoresData( + deviceId: serializer.fromJson(json['deviceId']), + name: serializer.fromJson(json['name']), + sessionRecord: serializer.fromJson(json['sessionRecord']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'deviceId': serializer.toJson(deviceId), + 'name': serializer.toJson(name), + 'sessionRecord': serializer.toJson(sessionRecord), + 'createdAt': serializer.toJson(createdAt), + }; + } + + SignalSessionStoresData copyWith( + {int? deviceId, + String? name, + Uint8List? sessionRecord, + DateTime? createdAt}) => + SignalSessionStoresData( + deviceId: deviceId ?? this.deviceId, + name: name ?? this.name, + sessionRecord: sessionRecord ?? this.sessionRecord, + createdAt: createdAt ?? this.createdAt, + ); + SignalSessionStoresData copyWithCompanion(SignalSessionStoresCompanion data) { + return SignalSessionStoresData( + deviceId: data.deviceId.present ? data.deviceId.value : this.deviceId, + name: data.name.present ? data.name.value : this.name, + sessionRecord: data.sessionRecord.present + ? data.sessionRecord.value + : this.sessionRecord, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('SignalSessionStoresData(') + ..write('deviceId: $deviceId, ') + ..write('name: $name, ') + ..write('sessionRecord: $sessionRecord, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + deviceId, name, $driftBlobEquality.hash(sessionRecord), createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is SignalSessionStoresData && + other.deviceId == this.deviceId && + other.name == this.name && + $driftBlobEquality.equals(other.sessionRecord, this.sessionRecord) && + other.createdAt == this.createdAt); +} + +class SignalSessionStoresCompanion + extends UpdateCompanion { + final Value deviceId; + final Value name; + final Value sessionRecord; + final Value createdAt; + final Value rowid; + const SignalSessionStoresCompanion({ + this.deviceId = const Value.absent(), + this.name = const Value.absent(), + this.sessionRecord = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + SignalSessionStoresCompanion.insert({ + required int deviceId, + required String name, + required Uint8List sessionRecord, + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : deviceId = Value(deviceId), + name = Value(name), + sessionRecord = Value(sessionRecord); + static Insertable custom({ + Expression? deviceId, + Expression? name, + Expression? sessionRecord, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (deviceId != null) 'device_id': deviceId, + if (name != null) 'name': name, + if (sessionRecord != null) 'session_record': sessionRecord, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + SignalSessionStoresCompanion copyWith( + {Value? deviceId, + Value? name, + Value? sessionRecord, + Value? createdAt, + Value? rowid}) { + return SignalSessionStoresCompanion( + deviceId: deviceId ?? this.deviceId, + name: name ?? this.name, + sessionRecord: sessionRecord ?? this.sessionRecord, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (deviceId.present) { + map['device_id'] = Variable(deviceId.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (sessionRecord.present) { + map['session_record'] = Variable(sessionRecord.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('SignalSessionStoresCompanion(') + ..write('deviceId: $deviceId, ') + ..write('name: $name, ') + ..write('sessionRecord: $sessionRecord, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class SignalContactPreKeys extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + SignalContactPreKeys(this.attachedDatabase, [this._alias]); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + late final GeneratedColumn preKeyId = GeneratedColumn( + 'pre_key_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + late final GeneratedColumn preKey = GeneratedColumn( + 'pre_key', aliasedName, false, + type: DriftSqlType.blob, requiredDuringInsert: true); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)')); + @override + List get $columns => + [contactId, preKeyId, preKey, createdAt]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'signal_contact_pre_keys'; + @override + Set get $primaryKey => {contactId, preKeyId}; + @override + SignalContactPreKeysData map(Map data, + {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return SignalContactPreKeysData( + contactId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}contact_id'])!, + preKeyId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}pre_key_id'])!, + preKey: attachedDatabase.typeMapping + .read(DriftSqlType.blob, data['${effectivePrefix}pre_key'])!, + createdAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + ); + } + + @override + SignalContactPreKeys createAlias(String alias) { + return SignalContactPreKeys(attachedDatabase, alias); + } +} + +class SignalContactPreKeysData extends DataClass + implements Insertable { + final int contactId; + final int preKeyId; + final Uint8List preKey; + final DateTime createdAt; + const SignalContactPreKeysData( + {required this.contactId, + required this.preKeyId, + required this.preKey, + required this.createdAt}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['contact_id'] = Variable(contactId); + map['pre_key_id'] = Variable(preKeyId); + map['pre_key'] = Variable(preKey); + map['created_at'] = Variable(createdAt); + return map; + } + + SignalContactPreKeysCompanion toCompanion(bool nullToAbsent) { + return SignalContactPreKeysCompanion( + contactId: Value(contactId), + preKeyId: Value(preKeyId), + preKey: Value(preKey), + createdAt: Value(createdAt), + ); + } + + factory SignalContactPreKeysData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return SignalContactPreKeysData( + contactId: serializer.fromJson(json['contactId']), + preKeyId: serializer.fromJson(json['preKeyId']), + preKey: serializer.fromJson(json['preKey']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'contactId': serializer.toJson(contactId), + 'preKeyId': serializer.toJson(preKeyId), + 'preKey': serializer.toJson(preKey), + 'createdAt': serializer.toJson(createdAt), + }; + } + + SignalContactPreKeysData copyWith( + {int? contactId, + int? preKeyId, + Uint8List? preKey, + DateTime? createdAt}) => + SignalContactPreKeysData( + contactId: contactId ?? this.contactId, + preKeyId: preKeyId ?? this.preKeyId, + preKey: preKey ?? this.preKey, + createdAt: createdAt ?? this.createdAt, + ); + SignalContactPreKeysData copyWithCompanion( + SignalContactPreKeysCompanion data) { + return SignalContactPreKeysData( + contactId: data.contactId.present ? data.contactId.value : this.contactId, + preKeyId: data.preKeyId.present ? data.preKeyId.value : this.preKeyId, + preKey: data.preKey.present ? data.preKey.value : this.preKey, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('SignalContactPreKeysData(') + ..write('contactId: $contactId, ') + ..write('preKeyId: $preKeyId, ') + ..write('preKey: $preKey, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + contactId, preKeyId, $driftBlobEquality.hash(preKey), createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is SignalContactPreKeysData && + other.contactId == this.contactId && + other.preKeyId == this.preKeyId && + $driftBlobEquality.equals(other.preKey, this.preKey) && + other.createdAt == this.createdAt); +} + +class SignalContactPreKeysCompanion + extends UpdateCompanion { + final Value contactId; + final Value preKeyId; + final Value preKey; + final Value createdAt; + final Value rowid; + const SignalContactPreKeysCompanion({ + this.contactId = const Value.absent(), + this.preKeyId = const Value.absent(), + this.preKey = const Value.absent(), + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }); + SignalContactPreKeysCompanion.insert({ + required int contactId, + required int preKeyId, + required Uint8List preKey, + this.createdAt = const Value.absent(), + this.rowid = const Value.absent(), + }) : contactId = Value(contactId), + preKeyId = Value(preKeyId), + preKey = Value(preKey); + static Insertable custom({ + Expression? contactId, + Expression? preKeyId, + Expression? preKey, + Expression? createdAt, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (contactId != null) 'contact_id': contactId, + if (preKeyId != null) 'pre_key_id': preKeyId, + if (preKey != null) 'pre_key': preKey, + if (createdAt != null) 'created_at': createdAt, + if (rowid != null) 'rowid': rowid, + }); + } + + SignalContactPreKeysCompanion copyWith( + {Value? contactId, + Value? preKeyId, + Value? preKey, + Value? createdAt, + Value? rowid}) { + return SignalContactPreKeysCompanion( + contactId: contactId ?? this.contactId, + preKeyId: preKeyId ?? this.preKeyId, + preKey: preKey ?? this.preKey, + createdAt: createdAt ?? this.createdAt, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (preKeyId.present) { + map['pre_key_id'] = Variable(preKeyId.value); + } + if (preKey.present) { + map['pre_key'] = Variable(preKey.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('SignalContactPreKeysCompanion(') + ..write('contactId: $contactId, ') + ..write('preKeyId: $preKeyId, ') + ..write('preKey: $preKey, ') + ..write('createdAt: $createdAt, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class SignalContactSignedPreKeys extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + SignalContactSignedPreKeys(this.attachedDatabase, [this._alias]); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: false); + late final GeneratedColumn signedPreKeyId = GeneratedColumn( + 'signed_pre_key_id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + late final GeneratedColumn signedPreKey = + GeneratedColumn('signed_pre_key', aliasedName, false, + type: DriftSqlType.blob, requiredDuringInsert: true); + late final GeneratedColumn signedPreKeySignature = + GeneratedColumn('signed_pre_key_signature', aliasedName, false, + type: DriftSqlType.blob, requiredDuringInsert: true); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression( + 'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)')); + @override + List get $columns => [ + contactId, + signedPreKeyId, + signedPreKey, + signedPreKeySignature, + createdAt + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'signal_contact_signed_pre_keys'; + @override + Set get $primaryKey => {contactId}; + @override + SignalContactSignedPreKeysData map(Map data, + {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return SignalContactSignedPreKeysData( + contactId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}contact_id'])!, + signedPreKeyId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}signed_pre_key_id'])!, + signedPreKey: attachedDatabase.typeMapping + .read(DriftSqlType.blob, data['${effectivePrefix}signed_pre_key'])!, + signedPreKeySignature: attachedDatabase.typeMapping.read( + DriftSqlType.blob, + data['${effectivePrefix}signed_pre_key_signature'])!, + createdAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + ); + } + + @override + SignalContactSignedPreKeys createAlias(String alias) { + return SignalContactSignedPreKeys(attachedDatabase, alias); + } +} + +class SignalContactSignedPreKeysData extends DataClass + implements Insertable { + final int contactId; + final int signedPreKeyId; + final Uint8List signedPreKey; + final Uint8List signedPreKeySignature; + final DateTime createdAt; + const SignalContactSignedPreKeysData( + {required this.contactId, + required this.signedPreKeyId, + required this.signedPreKey, + required this.signedPreKeySignature, + required this.createdAt}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['contact_id'] = Variable(contactId); + map['signed_pre_key_id'] = Variable(signedPreKeyId); + map['signed_pre_key'] = Variable(signedPreKey); + map['signed_pre_key_signature'] = + Variable(signedPreKeySignature); + map['created_at'] = Variable(createdAt); + return map; + } + + SignalContactSignedPreKeysCompanion toCompanion(bool nullToAbsent) { + return SignalContactSignedPreKeysCompanion( + contactId: Value(contactId), + signedPreKeyId: Value(signedPreKeyId), + signedPreKey: Value(signedPreKey), + signedPreKeySignature: Value(signedPreKeySignature), + createdAt: Value(createdAt), + ); + } + + factory SignalContactSignedPreKeysData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return SignalContactSignedPreKeysData( + contactId: serializer.fromJson(json['contactId']), + signedPreKeyId: serializer.fromJson(json['signedPreKeyId']), + signedPreKey: serializer.fromJson(json['signedPreKey']), + signedPreKeySignature: + serializer.fromJson(json['signedPreKeySignature']), + createdAt: serializer.fromJson(json['createdAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'contactId': serializer.toJson(contactId), + 'signedPreKeyId': serializer.toJson(signedPreKeyId), + 'signedPreKey': serializer.toJson(signedPreKey), + 'signedPreKeySignature': + serializer.toJson(signedPreKeySignature), + 'createdAt': serializer.toJson(createdAt), + }; + } + + SignalContactSignedPreKeysData copyWith( + {int? contactId, + int? signedPreKeyId, + Uint8List? signedPreKey, + Uint8List? signedPreKeySignature, + DateTime? createdAt}) => + SignalContactSignedPreKeysData( + contactId: contactId ?? this.contactId, + signedPreKeyId: signedPreKeyId ?? this.signedPreKeyId, + signedPreKey: signedPreKey ?? this.signedPreKey, + signedPreKeySignature: + signedPreKeySignature ?? this.signedPreKeySignature, + createdAt: createdAt ?? this.createdAt, + ); + SignalContactSignedPreKeysData copyWithCompanion( + SignalContactSignedPreKeysCompanion data) { + return SignalContactSignedPreKeysData( + contactId: data.contactId.present ? data.contactId.value : this.contactId, + signedPreKeyId: data.signedPreKeyId.present + ? data.signedPreKeyId.value + : this.signedPreKeyId, + signedPreKey: data.signedPreKey.present + ? data.signedPreKey.value + : this.signedPreKey, + signedPreKeySignature: data.signedPreKeySignature.present + ? data.signedPreKeySignature.value + : this.signedPreKeySignature, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + ); + } + + @override + String toString() { + return (StringBuffer('SignalContactSignedPreKeysData(') + ..write('contactId: $contactId, ') + ..write('signedPreKeyId: $signedPreKeyId, ') + ..write('signedPreKey: $signedPreKey, ') + ..write('signedPreKeySignature: $signedPreKeySignature, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + contactId, + signedPreKeyId, + $driftBlobEquality.hash(signedPreKey), + $driftBlobEquality.hash(signedPreKeySignature), + createdAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is SignalContactSignedPreKeysData && + other.contactId == this.contactId && + other.signedPreKeyId == this.signedPreKeyId && + $driftBlobEquality.equals(other.signedPreKey, this.signedPreKey) && + $driftBlobEquality.equals( + other.signedPreKeySignature, this.signedPreKeySignature) && + other.createdAt == this.createdAt); +} + +class SignalContactSignedPreKeysCompanion + extends UpdateCompanion { + final Value contactId; + final Value signedPreKeyId; + final Value signedPreKey; + final Value signedPreKeySignature; + final Value createdAt; + const SignalContactSignedPreKeysCompanion({ + this.contactId = const Value.absent(), + this.signedPreKeyId = const Value.absent(), + this.signedPreKey = const Value.absent(), + this.signedPreKeySignature = const Value.absent(), + this.createdAt = const Value.absent(), + }); + SignalContactSignedPreKeysCompanion.insert({ + this.contactId = const Value.absent(), + required int signedPreKeyId, + required Uint8List signedPreKey, + required Uint8List signedPreKeySignature, + this.createdAt = const Value.absent(), + }) : signedPreKeyId = Value(signedPreKeyId), + signedPreKey = Value(signedPreKey), + signedPreKeySignature = Value(signedPreKeySignature); + static Insertable custom({ + Expression? contactId, + Expression? signedPreKeyId, + Expression? signedPreKey, + Expression? signedPreKeySignature, + Expression? createdAt, + }) { + return RawValuesInsertable({ + if (contactId != null) 'contact_id': contactId, + if (signedPreKeyId != null) 'signed_pre_key_id': signedPreKeyId, + if (signedPreKey != null) 'signed_pre_key': signedPreKey, + if (signedPreKeySignature != null) + 'signed_pre_key_signature': signedPreKeySignature, + if (createdAt != null) 'created_at': createdAt, + }); + } + + SignalContactSignedPreKeysCompanion copyWith( + {Value? contactId, + Value? signedPreKeyId, + Value? signedPreKey, + Value? signedPreKeySignature, + Value? createdAt}) { + return SignalContactSignedPreKeysCompanion( + contactId: contactId ?? this.contactId, + signedPreKeyId: signedPreKeyId ?? this.signedPreKeyId, + signedPreKey: signedPreKey ?? this.signedPreKey, + signedPreKeySignature: + signedPreKeySignature ?? this.signedPreKeySignature, + createdAt: createdAt ?? this.createdAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (signedPreKeyId.present) { + map['signed_pre_key_id'] = Variable(signedPreKeyId.value); + } + if (signedPreKey.present) { + map['signed_pre_key'] = Variable(signedPreKey.value); + } + if (signedPreKeySignature.present) { + map['signed_pre_key_signature'] = + Variable(signedPreKeySignature.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('SignalContactSignedPreKeysCompanion(') + ..write('contactId: $contactId, ') + ..write('signedPreKeyId: $signedPreKeyId, ') + ..write('signedPreKey: $signedPreKey, ') + ..write('signedPreKeySignature: $signedPreKeySignature, ') + ..write('createdAt: $createdAt') + ..write(')')) + .toString(); + } +} + +class MessageRetransmissions extends Table + with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + MessageRetransmissions(this.attachedDatabase, [this._alias]); + late final GeneratedColumn retransmissionId = GeneratedColumn( + 'retransmission_id', aliasedName, false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: + GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT')); + late final GeneratedColumn contactId = GeneratedColumn( + 'contact_id', aliasedName, false, + type: DriftSqlType.int, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES contacts (user_id) ON DELETE CASCADE')); + late final GeneratedColumn messageId = GeneratedColumn( + 'message_id', aliasedName, true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES messages (message_id) ON DELETE CASCADE')); + late final GeneratedColumn plaintextContent = + GeneratedColumn('plaintext_content', aliasedName, false, + type: DriftSqlType.blob, requiredDuringInsert: true); + late final GeneratedColumn pushData = GeneratedColumn( + 'push_data', aliasedName, true, + type: DriftSqlType.blob, requiredDuringInsert: false); + late final GeneratedColumn willNotGetACKByUser = GeneratedColumn( + 'will_not_get_a_c_k_by_user', aliasedName, false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("will_not_get_a_c_k_by_user" IN (0, 1))'), + defaultValue: const CustomExpression('0')); + late final GeneratedColumn acknowledgeByServerAt = + GeneratedColumn('acknowledge_by_server_at', aliasedName, true, + type: DriftSqlType.dateTime, requiredDuringInsert: false); + @override + List get $columns => [ + retransmissionId, + contactId, + messageId, + plaintextContent, + pushData, + willNotGetACKByUser, + acknowledgeByServerAt + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'message_retransmissions'; + @override + Set get $primaryKey => {retransmissionId}; + @override + MessageRetransmissionsData map(Map data, + {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MessageRetransmissionsData( + retransmissionId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}retransmission_id'])!, + contactId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}contact_id'])!, + messageId: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}message_id']), + plaintextContent: attachedDatabase.typeMapping.read( + DriftSqlType.blob, data['${effectivePrefix}plaintext_content'])!, + pushData: attachedDatabase.typeMapping + .read(DriftSqlType.blob, data['${effectivePrefix}push_data']), + willNotGetACKByUser: attachedDatabase.typeMapping.read(DriftSqlType.bool, + data['${effectivePrefix}will_not_get_a_c_k_by_user'])!, + acknowledgeByServerAt: attachedDatabase.typeMapping.read( + DriftSqlType.dateTime, + data['${effectivePrefix}acknowledge_by_server_at']), + ); + } + + @override + MessageRetransmissions createAlias(String alias) { + return MessageRetransmissions(attachedDatabase, alias); + } +} + +class MessageRetransmissionsData extends DataClass + implements Insertable { + final int retransmissionId; + final int contactId; + final int? messageId; + final Uint8List plaintextContent; + final Uint8List? pushData; + final bool willNotGetACKByUser; + final DateTime? acknowledgeByServerAt; + const MessageRetransmissionsData( + {required this.retransmissionId, + required this.contactId, + this.messageId, + required this.plaintextContent, + this.pushData, + required this.willNotGetACKByUser, + this.acknowledgeByServerAt}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['retransmission_id'] = Variable(retransmissionId); + map['contact_id'] = Variable(contactId); + if (!nullToAbsent || messageId != null) { + map['message_id'] = Variable(messageId); + } + map['plaintext_content'] = Variable(plaintextContent); + if (!nullToAbsent || pushData != null) { + map['push_data'] = Variable(pushData); + } + map['will_not_get_a_c_k_by_user'] = Variable(willNotGetACKByUser); + if (!nullToAbsent || acknowledgeByServerAt != null) { + map['acknowledge_by_server_at'] = + Variable(acknowledgeByServerAt); + } + return map; + } + + MessageRetransmissionsCompanion toCompanion(bool nullToAbsent) { + return MessageRetransmissionsCompanion( + retransmissionId: Value(retransmissionId), + contactId: Value(contactId), + messageId: messageId == null && nullToAbsent + ? const Value.absent() + : Value(messageId), + plaintextContent: Value(plaintextContent), + pushData: pushData == null && nullToAbsent + ? const Value.absent() + : Value(pushData), + willNotGetACKByUser: Value(willNotGetACKByUser), + acknowledgeByServerAt: acknowledgeByServerAt == null && nullToAbsent + ? const Value.absent() + : Value(acknowledgeByServerAt), + ); + } + + factory MessageRetransmissionsData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MessageRetransmissionsData( + retransmissionId: serializer.fromJson(json['retransmissionId']), + contactId: serializer.fromJson(json['contactId']), + messageId: serializer.fromJson(json['messageId']), + plaintextContent: + serializer.fromJson(json['plaintextContent']), + pushData: serializer.fromJson(json['pushData']), + willNotGetACKByUser: + serializer.fromJson(json['willNotGetACKByUser']), + acknowledgeByServerAt: + serializer.fromJson(json['acknowledgeByServerAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'retransmissionId': serializer.toJson(retransmissionId), + 'contactId': serializer.toJson(contactId), + 'messageId': serializer.toJson(messageId), + 'plaintextContent': serializer.toJson(plaintextContent), + 'pushData': serializer.toJson(pushData), + 'willNotGetACKByUser': serializer.toJson(willNotGetACKByUser), + 'acknowledgeByServerAt': + serializer.toJson(acknowledgeByServerAt), + }; + } + + MessageRetransmissionsData copyWith( + {int? retransmissionId, + int? contactId, + Value messageId = const Value.absent(), + Uint8List? plaintextContent, + Value pushData = const Value.absent(), + bool? willNotGetACKByUser, + Value acknowledgeByServerAt = const Value.absent()}) => + MessageRetransmissionsData( + retransmissionId: retransmissionId ?? this.retransmissionId, + contactId: contactId ?? this.contactId, + messageId: messageId.present ? messageId.value : this.messageId, + plaintextContent: plaintextContent ?? this.plaintextContent, + pushData: pushData.present ? pushData.value : this.pushData, + willNotGetACKByUser: willNotGetACKByUser ?? this.willNotGetACKByUser, + acknowledgeByServerAt: acknowledgeByServerAt.present + ? acknowledgeByServerAt.value + : this.acknowledgeByServerAt, + ); + MessageRetransmissionsData copyWithCompanion( + MessageRetransmissionsCompanion data) { + return MessageRetransmissionsData( + retransmissionId: data.retransmissionId.present + ? data.retransmissionId.value + : this.retransmissionId, + contactId: data.contactId.present ? data.contactId.value : this.contactId, + messageId: data.messageId.present ? data.messageId.value : this.messageId, + plaintextContent: data.plaintextContent.present + ? data.plaintextContent.value + : this.plaintextContent, + pushData: data.pushData.present ? data.pushData.value : this.pushData, + willNotGetACKByUser: data.willNotGetACKByUser.present + ? data.willNotGetACKByUser.value + : this.willNotGetACKByUser, + acknowledgeByServerAt: data.acknowledgeByServerAt.present + ? data.acknowledgeByServerAt.value + : this.acknowledgeByServerAt, + ); + } + + @override + String toString() { + return (StringBuffer('MessageRetransmissionsData(') + ..write('retransmissionId: $retransmissionId, ') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('plaintextContent: $plaintextContent, ') + ..write('pushData: $pushData, ') + ..write('willNotGetACKByUser: $willNotGetACKByUser, ') + ..write('acknowledgeByServerAt: $acknowledgeByServerAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + retransmissionId, + contactId, + messageId, + $driftBlobEquality.hash(plaintextContent), + $driftBlobEquality.hash(pushData), + willNotGetACKByUser, + acknowledgeByServerAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MessageRetransmissionsData && + other.retransmissionId == this.retransmissionId && + other.contactId == this.contactId && + other.messageId == this.messageId && + $driftBlobEquality.equals( + other.plaintextContent, this.plaintextContent) && + $driftBlobEquality.equals(other.pushData, this.pushData) && + other.willNotGetACKByUser == this.willNotGetACKByUser && + other.acknowledgeByServerAt == this.acknowledgeByServerAt); +} + +class MessageRetransmissionsCompanion + extends UpdateCompanion { + final Value retransmissionId; + final Value contactId; + final Value messageId; + final Value plaintextContent; + final Value pushData; + final Value willNotGetACKByUser; + final Value acknowledgeByServerAt; + const MessageRetransmissionsCompanion({ + this.retransmissionId = const Value.absent(), + this.contactId = const Value.absent(), + this.messageId = const Value.absent(), + this.plaintextContent = const Value.absent(), + this.pushData = const Value.absent(), + this.willNotGetACKByUser = const Value.absent(), + this.acknowledgeByServerAt = const Value.absent(), + }); + MessageRetransmissionsCompanion.insert({ + this.retransmissionId = const Value.absent(), + required int contactId, + this.messageId = const Value.absent(), + required Uint8List plaintextContent, + this.pushData = const Value.absent(), + this.willNotGetACKByUser = const Value.absent(), + this.acknowledgeByServerAt = const Value.absent(), + }) : contactId = Value(contactId), + plaintextContent = Value(plaintextContent); + static Insertable custom({ + Expression? retransmissionId, + Expression? contactId, + Expression? messageId, + Expression? plaintextContent, + Expression? pushData, + Expression? willNotGetACKByUser, + Expression? acknowledgeByServerAt, + }) { + return RawValuesInsertable({ + if (retransmissionId != null) 'retransmission_id': retransmissionId, + if (contactId != null) 'contact_id': contactId, + if (messageId != null) 'message_id': messageId, + if (plaintextContent != null) 'plaintext_content': plaintextContent, + if (pushData != null) 'push_data': pushData, + if (willNotGetACKByUser != null) + 'will_not_get_a_c_k_by_user': willNotGetACKByUser, + if (acknowledgeByServerAt != null) + 'acknowledge_by_server_at': acknowledgeByServerAt, + }); + } + + MessageRetransmissionsCompanion copyWith( + {Value? retransmissionId, + Value? contactId, + Value? messageId, + Value? plaintextContent, + Value? pushData, + Value? willNotGetACKByUser, + Value? acknowledgeByServerAt}) { + return MessageRetransmissionsCompanion( + retransmissionId: retransmissionId ?? this.retransmissionId, + contactId: contactId ?? this.contactId, + messageId: messageId ?? this.messageId, + plaintextContent: plaintextContent ?? this.plaintextContent, + pushData: pushData ?? this.pushData, + willNotGetACKByUser: willNotGetACKByUser ?? this.willNotGetACKByUser, + acknowledgeByServerAt: + acknowledgeByServerAt ?? this.acknowledgeByServerAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (retransmissionId.present) { + map['retransmission_id'] = Variable(retransmissionId.value); + } + if (contactId.present) { + map['contact_id'] = Variable(contactId.value); + } + if (messageId.present) { + map['message_id'] = Variable(messageId.value); + } + if (plaintextContent.present) { + map['plaintext_content'] = Variable(plaintextContent.value); + } + if (pushData.present) { + map['push_data'] = Variable(pushData.value); + } + if (willNotGetACKByUser.present) { + map['will_not_get_a_c_k_by_user'] = + Variable(willNotGetACKByUser.value); + } + if (acknowledgeByServerAt.present) { + map['acknowledge_by_server_at'] = + Variable(acknowledgeByServerAt.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MessageRetransmissionsCompanion(') + ..write('retransmissionId: $retransmissionId, ') + ..write('contactId: $contactId, ') + ..write('messageId: $messageId, ') + ..write('plaintextContent: $plaintextContent, ') + ..write('pushData: $pushData, ') + ..write('willNotGetACKByUser: $willNotGetACKByUser, ') + ..write('acknowledgeByServerAt: $acknowledgeByServerAt') + ..write(')')) + .toString(); + } +} + +class DatabaseAtV12 extends GeneratedDatabase { + DatabaseAtV12(QueryExecutor e) : super(e); + late final Contacts contacts = Contacts(this); + late final Messages messages = Messages(this); + late final MediaUploads mediaUploads = MediaUploads(this); + late final MediaDownloads mediaDownloads = MediaDownloads(this); + late final SignalIdentityKeyStores signalIdentityKeyStores = + SignalIdentityKeyStores(this); + late final SignalPreKeyStores signalPreKeyStores = SignalPreKeyStores(this); + late final SignalSenderKeyStores signalSenderKeyStores = + SignalSenderKeyStores(this); + late final SignalSessionStores signalSessionStores = + SignalSessionStores(this); + late final SignalContactPreKeys signalContactPreKeys = + SignalContactPreKeys(this); + late final SignalContactSignedPreKeys signalContactSignedPreKeys = + SignalContactSignedPreKeys(this); + late final MessageRetransmissions messageRetransmissions = + MessageRetransmissions(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + contacts, + messages, + mediaUploads, + mediaDownloads, + signalIdentityKeyStores, + signalPreKeyStores, + signalSenderKeyStores, + signalSessionStores, + signalContactPreKeys, + signalContactSignedPreKeys, + messageRetransmissions + ]; + @override + int get schemaVersion => 12; +}